Skip to content

feat: backend and frontend integration - #4

Merged
JakubPatkowski merged 1 commit into
masterfrom
3-feat-backend-and-frontend-connection
Jun 4, 2026
Merged

feat: backend and frontend integration#4
JakubPatkowski merged 1 commit into
masterfrom
3-feat-backend-and-frontend-connection

Conversation

@JakubPatkowski

Copy link
Copy Markdown
Owner

No description provided.

@JakubPatkowski
JakubPatkowski requested a review from Hiubertus June 4, 2026 10:49
@JakubPatkowski JakubPatkowski self-assigned this Jun 4, 2026
Copilot AI review requested due to automatic review settings June 4, 2026 10:49
@JakubPatkowski JakubPatkowski added the need review need review label Jun 4, 2026
@JakubPatkowski JakubPatkowski linked an issue Jun 4, 2026 that may be closed by this pull request

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates the frontend with the backend API by introducing a centralized Axios client with refresh-token handling, adopting React Query for data fetching/caching, and adding/rewiring key screens (home, thread detail, auth, profiles, admin). On the backend, it adds “engagement” endpoints (likes + user stats), category ownership, and post-icon support to match the new UI capabilities.

Changes:

  • Frontend: add React Query infrastructure + API resource layer, and replace mock views with real API-driven pages (posts, comments tree, auth, admin, files/media, likes).
  • Backend: add engagement module (likes, featured post, user stats view) and extend files/categories to support ownership-gated category images and thread icons.
  • UI/UX: substantial CSS/layout work for 3-panel home/thread pages, modals/forms, and consistent loading/empty/error states.

Reviewed changes

Copilot reviewed 68 out of 68 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
frontend/src/utils/format.js New formatting helpers (time ago, excerpts, glyphs, initials).
frontend/src/utils/commentTree.js Build nested comment tree from flat backend list.
frontend/src/styles/globals.css Major styling updates for integration-era UI (layout, modals, forms, comments, panels).
frontend/src/services/api.js Deprecated axios singleton; now re-export alias to new API client.
frontend/src/query/queryClient.js React Query global configuration.
frontend/src/query/keys.js Centralized React Query key factory.
frontend/src/pages/UserProfilePage.jsx New public user profile page wired to /users/:id and user posts.
frontend/src/pages/RegisterPage.jsx New registration page wired to AuthContext.
frontend/src/pages/ProfilePage.jsx Replace mock profile with authenticated profile data + avatar upload + user posts.
frontend/src/pages/PostPage.jsx New thread detail page with comments tree, attachments, meta panels, and edit/delete actions.
frontend/src/pages/OpinionsPage.jsx Replaces “reviews” mock with real posts list + category filter + pagination.
frontend/src/pages/LoginPage.jsx New login page wired to AuthContext.
frontend/src/pages/HomePage.jsx Reworked home to API-driven categories/posts, featured thread, and side panels.
frontend/src/pages/AdminPage.jsx New admin UI for user roles/permissions/status (permission-gated).
frontend/src/main.jsx Add QueryClientProvider + AuthProvider into app bootstrap.
frontend/src/i18n/translations.js Extend translations for new UI strings (auth/common/compose/admin/post).
frontend/src/hooks/useFiles.js React Query hooks for files: list, upload, attach, avatar/category/post icon setters.
frontend/src/hooks/useEngagement.js React Query hooks for likes/state toggles, featured post, user stats.
frontend/src/hooks/useContentQueries.js React Query hooks for categories/tags/posts/comments CRUD + pagination.
frontend/src/hooks/useAdmin.js React Query hooks for admin user management mutations.
frontend/src/components/TopBar.jsx Session-aware top bar (login vs avatar menu) + mobile hamburger.
frontend/src/components/ThreadGlyph.jsx Thread icon component (post icon → category glyph → placeholder).
frontend/src/components/SubNav.jsx Adds placeholder tabs + mobile dropdown behavior.
frontend/src/components/States.jsx Shared Loading/Empty/Error/NotSupported UI states.
frontend/src/components/Panels.jsx API-driven tags panel + “not supported yet” top users panel.
frontend/src/components/Modal.jsx Shared modal overlay component (Esc/click-away close).
frontend/src/components/MarkdownEditor.jsx Rich(ish) markdown editor with inline upload insertion.
frontend/src/components/Markdown.jsx Safe markdown rendering (MarkdownIt + DOMPurify).
frontend/src/components/LikeButton.jsx Like button with count and optimistic toggle.
frontend/src/components/Layout.jsx Mobile nav open/close state and route-change handling.
frontend/src/components/Icon.jsx Adds new icons used by integration UI.
frontend/src/components/files/FileUploader.jsx Multi-file upload with progress + orphan cleanup on remove.
frontend/src/components/files/Attachments.jsx Render attachments by kind (gallery/video/audio/docs).
frontend/src/components/compose/NewPostModal.jsx Create/edit thread modal with tags, attachments, and icon selection.
frontend/src/components/compose/NewCategoryModal.jsx Create category modal with optional icon upload.
frontend/src/components/compose/IconPicker.jsx Shared image picker for thread/category icons.
frontend/src/components/comments/CommentNode.jsx Comment tree node with edit/reply/delete, attachments, likes.
frontend/src/components/comments/CommentForm.jsx Comment creation form with attachments.
frontend/src/components/CategoryGlyph.jsx Category image glyph with fallback text glyph.
frontend/src/components/Avatar.jsx User avatar image with fallback initials.
frontend/src/auth/ProtectedRoute.jsx Route guard for authenticated pages.
frontend/src/auth/AuthContext.jsx Session bootstrap via refresh cookie; in-memory access token; logout clears query cache.
frontend/src/App.jsx Adds routes for posts, auth, admin, public user profiles, and protected profile/admin.
frontend/src/api/resources.js Thin resource wrappers mapping 1:1 to backend endpoints.
frontend/src/api/client.js Central axios client with single-flight refresh + normalized error shape.
frontend/package.json Add @tanstack/react-query dependency.
docs/09-frontend-backend-integration-audit.md Integration audit doc (currently out of sync with this PR).
backend/app/modules/identity/domain/permission.py Adds category.create to permission catalogue and default user perms.
backend/app/modules/files/presentation/routers/files.py Ownership-gated category images + new post icon endpoints.
backend/app/modules/files/infrastructure/unit_of_work.py Add query for current post icon file id.
backend/app/modules/files/infrastructure/repositories/file_repo.py Map new POST_ICON owner type to owner_post_id.
backend/app/modules/files/domain/value_objects.py Add FileOwnerType.POST_ICON.
backend/app/modules/files/domain/events.py Add PostIconChanged domain event.
backend/app/modules/files/application/use_cases/set_post_icon.py New use case: upload + set post icon, delete previous icon.
backend/app/modules/files/application/use_cases/get_owner_image.py Add GetPostIconUseCase.
backend/app/modules/files/application/use_cases/init.py Export new post icon use cases.
backend/app/modules/files/application/ports.py Add current_post_icon_file_public_id port.
backend/app/modules/files/application/commands.py Add SetPostIconCommand.
backend/app/modules/engagement/router.py New engagement endpoints (likes, featured post, user stats).
backend/app/modules/engagement/init.py Engagement module package init.
backend/app/modules/content/presentation/routers/categories.py Adds category owner_id plumbing (list + set owner on create).
backend/app/modules/content/presentation/dto/category_dto.py Adds owner_id to category responses.
backend/app/models/category.py Adds owner_id FK to Category ORM.
backend/app/main.py Mount engagement router.
backend/app/container.py Wire new post icon use cases.
backend/alembic/versions/0009_post_icon_owner_type.py Migration: add post_icon enum value.
backend/alembic/versions/0008_reactions_owner_userstats.py Migration: reactions table + category.owner_id + user_stats view.
backend/alembic/versions/0007_grant_category_create.py Migration: grant category.create permission to all roles.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +10 to +13
const [failed, setFailed] = useState(false);
// po zmianie awatara (version) spróbuj załadować ponownie
useEffect(() => setFailed(false), [version]);

Comment on lines +10 to +13
export function CategoryGlyph({ categoryId, name, version = 0 }) {
const [failed, setFailed] = useState(false);
useEffect(() => setFailed(false), [version]);

Comment on lines +45 to +47
<div className="profile-av-wrap">
<Avatar userId={u.public_id ?? id} username={u.username} size="xl" />
</div>
Comment on lines +69 to +71
<SectionHead title={p.tabsAct} meta={`@${u.username}`} />
<UserThreads userId={u.public_id ?? id} lang={lang} t={t} />
</div>
Comment on lines +78 to +88
{postsQ.hasNextPage && (
<div className="center-row">
<button
type="button"
className="btn"
onClick={() => postsQ.fetchNextPage()}
disabled={postsQ.isFetchingNextPage}
>
{postsQ.isFetchingNextPage ? t.common.loading : t.common.retry}
</button>
</div>
Comment on lines +218 to +224
function AuthorPanel({ author, href, t, lang }) {
const navigate = useNavigate();
const statsQ = useUserStats(author?.public_id);
const postsQ = usePosts(author?.public_id ? { author_id: author.public_id, limit: 5 } : {});
const s = statsQ.data;
const labels = t.profile.stats;
const myPosts = (postsQ.data?.items ?? []).slice(0, 5);
Comment on lines 406 to +429
async def set_category_image(
category_id: UUID,
user: Annotated[CurrentUser, Depends(requires("category.manage"))],
db: DbSession,
user: Annotated[CurrentUser, Depends(requires("category.create"))],
uc: Annotated[SetCategoryImageUseCase, Depends(get_set_category_image_uc)],
file: UploadFile = File(...),
) -> FileResponse:
# Ownership: właściciel kategorii LUB moderator (category.manage).
owner_row = db.execute(
text(
"SELECT u.public_id FROM categories c "
"LEFT JOIN users u ON u.id = c.owner_id "
"WHERE c.public_id = :cid"
),
{"cid": str(category_id)},
).first()
if owner_row is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Category not found")
is_owner = owner_row[0] is not None and str(owner_row[0]) == str(user.public_id)
if not is_owner and not user.has("category.manage"):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only the category owner or a moderator can set its image",
)
Comment on lines +472 to +497
async def set_post_icon(
post_id: UUID,
db: DbSession,
user: CurrentUser,
uc: Annotated[SetPostIconUseCase, Depends(get_set_post_icon_uc)],
file: UploadFile = File(...),
) -> FileResponse:
# Autoryzacja: autor wątku LUB moderator (post.update.any).
author_row = db.execute(
text(
"SELECT u.public_id FROM posts p "
"LEFT JOIN users u ON u.id = p.author_id "
"WHERE p.public_id = :pid"
),
{"pid": str(post_id)},
).first()
if author_row is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Post not found"
)
is_author = author_row[0] is not None and str(author_row[0]) == str(user.public_id)
if not is_author and not user.has("post.update.any"):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only the thread author or a moderator can set its icon",
)
Comment on lines 48 to +63
async def list_categories(
db: DbSession,
uc: Annotated[ListCategoriesUseCase, Depends(get_list_categories_uc)],
) -> list[CategoryResponse]:
result = await uc.execute()
_raise_if_error(result)
return [CategoryResponse.from_summary(c) for c in result.value] # type: ignore[union-attr]
# Dociągnij właścicieli jednym zapytaniem (public_id kategorii → public_id ownera).
owners = {
str(row[0]): row[1]
for row in db.execute(
text(
"SELECT c.public_id, u.public_id FROM categories c "
"LEFT JOIN users u ON u.id = c.owner_id"
)
).all()
}
Comment on lines 76 to +96
async def create_category(
body: CreateCategoryRequest,
_user=Depends(requires("category.manage")),
db: DbSession,
user=Depends(requires("category.create")),
uc: CreateCategoryUseCase = Depends(get_create_category_uc),
) -> CategoryResponse:
result = await uc.execute(body.to_command())
_raise_if_error(result)
return CategoryResponse.from_summary(result.value) # type: ignore[union-attr]
summary = result.value # type: ignore[union-attr]
# Zapisz właściciela kategorii (twórcę). Robione osobnym UPDATE-em, żeby nie
# mieszać ownershipu do agregatu domenowego Category.
db.execute(
text(
"UPDATE categories SET owner_id = "
"(SELECT id FROM users WHERE public_id = :uid) "
"WHERE public_id = :cid"
),
{"uid": str(user.public_id), "cid": str(summary.public_id)},
)
db.commit()
return CategoryResponse.from_summary(summary, owner_id=user.public_id)
@JakubPatkowski
JakubPatkowski merged commit e474a39 into master Jun 4, 2026
1 check passed
@JakubPatkowski
JakubPatkowski deleted the 3-feat-backend-and-frontend-connection branch June 4, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

need review need review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: backend and frontend connection

2 participants