Skip to content

Commit f4fe970

Browse files
docs: add copilot instructions for project guidelines (#196)
* docs: add copilot instructions for project guidelines and commit conventions * fix: add .env to .gitignore to exclude environment variable files * docs: update copilot instructions and README for consistency and clarity * docs: update copilot instructions for clarity and project overview --------- Co-authored-by: Antoni Czaplicki <[email protected]>
1 parent fe02248 commit f4fe970

3 files changed

Lines changed: 173 additions & 2 deletions

File tree

.github/copilot-instructions.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Copilot Instructions — Testownik Solvro Frontend
2+
3+
## Project Overview
4+
5+
A quiz/study platform for Wrocław University of Technology students, built by KN Solvro. Next.js 16 App Router + React
6+
19 + TanStack Query v5 + Tailwind CSS v4 + shadcn/ui (Radix). Backend is a separate Django REST API (
7+
`Solvro/backend-testownik`). UI strings are in **Polish**; code identifiers are in **English**.
8+
9+
## Architecture
10+
11+
### Page Pattern (SSR ↔ Client split)
12+
13+
Every route follows a two-file convention in `src/app/<route>/`:
14+
15+
- **`page.tsx`** — Server Component. Reads cookies via `next/headers`, creates a `QueryClient`, prefetches data through
16+
service classes, wraps content in `<HydrationBoundary>`. Exports `metadata` (Polish titles).
17+
- **`client.tsx`** — Client Component (`"use client"`). Named export `XxxPageClient`. Consumes hydrated queries and
18+
accesses `AppContext` for auth/services.
19+
20+
Reference: `src/app/quizzes/page.tsx``src/app/quizzes/client.tsx`.
21+
22+
Some simpler pages (e.g. `grades`, `create-quiz`) skip SSR prefetching and render the client component directly.
23+
24+
### Service Layer (`src/services/`)
25+
26+
Class-based API services extending `BaseApiService`. Accessed via singleton `ServiceRegistry` exposed through React
27+
Context (`AppContext`). Three services: `QuizService`, `UserService`, `ImageService`.
28+
29+
Access pattern in client components:
30+
31+
```ts
32+
const { services, isGuest } = useContext(AppContext);
33+
const quizzes = await services.quiz.getQuizzes();
34+
```
35+
36+
### Auth
37+
38+
JWT (HS256) stored in cookies (`access_token`, `refresh_token`). Guest mode uses `is_guest` cookie. Client-side decoding
39+
via `jose.decodeJwt()` (no verification). Server-side verification via `jose.jwtVerify()` with `JWT_SECRET` env var.
40+
Auth context is provided by `AppContextProvider` in `src/app-context-provider.tsx`.
41+
42+
### State Management & Data Fetching
43+
44+
**TanStack Query v5** exclusively (no Redux/Zustand). Single `QueryClientProvider` at app root (
45+
`src/app/providers.tsx`).
46+
47+
**SSR-first pattern:** Prefer server-side data prefetch + hydration over client-only fetches. A typical page:
48+
49+
1. Server (`page.tsx`) calls `queryClient.prefetchQuery()` with the service
50+
2. Dehydrates state: `<HydrationBoundary state={dehydrate(queryClient)}>`
51+
3. Client reads hydrated cache immediately (no duplicate fetch)
52+
53+
Example: `src/app/quizzes/page.tsx` prefetches `["user-quizzes", isGuest]` — client hook in `useQuizzes()` uses the same
54+
key.
55+
56+
**Query keys** include `isGuest` flag for cache segmentation. Default `staleTime` is 60s (`src/lib/query-client.ts`).
57+
Keep keys consistent between SSR prefetch and client hooks.
58+
59+
### Middleware & Auth Guards
60+
61+
`src/proxy.ts` (Next.js middleware) enforces auth on protected routes (`/profile`, `/quizzes`, `/grades`,
62+
`/create-quiz`, `/edit-quiz`, `/import-quiz`). Handles:
63+
64+
- Token validation and refresh (expires with 30s buffer)
65+
- Automatic token refresh using `POST /token/refresh/`
66+
- Fallback to login redirect if no valid token
67+
- Cookie forwarding from backend responses
68+
69+
### Env Variables
70+
71+
Validated with `@t3-oss/env-nextjs` + Zod in `src/env.ts`. Required: `NEXT_PUBLIC_API_URL`. Optional:
72+
`NEXT_PUBLIC_TURN_USERNAME`, `NEXT_PUBLIC_TURN_CREDENTIAL` (TURN relay for P2P), `JWT_SECRET` (server),
73+
`INTERNAL_API_KEY` (server).
74+
75+
## Key Conventions
76+
77+
- **Path alias:** `@/` maps to `src/` (tsconfig paths)
78+
- **UI components:** shadcn/ui in `src/components/ui/`, project components alongside in `src/components/`
79+
- **Hooks:** `src/hooks/use-{feature}.ts` (kebab-case). Feature-specific hooks may be colocated (e.g.
80+
`src/components/quiz/hooks/`)
81+
- **Validation:** Zod v4 schemas in `src/lib/schemas/`
82+
83+
### Commit Format
84+
85+
Use **Conventional Commits** via `@solvro/config` commitlint enforcement.
86+
87+
**Format:** `<type>(optional scope): present-tense description in English`
88+
89+
**Types:** `feat`, `fix`, `refactor`, `chore`, `docs`, `ci`, `test`, `build`, `release`
90+
91+
**Examples:**
92+
93+
- `feat(quiz): add cross-device quiz continuity`
94+
- `fix(auth): correct token refresh timeout`
95+
- `refactor(editor): simplify question form`
96+
- `test(hooks): add useQuizzes integration tests`
97+
98+
### Branch Naming
99+
100+
**Format:** `<prefix>/<issue>-short-description`
101+
102+
**Prefixes:** `feat/`, `fix/`, `hotfix/`, `design/`, `refactor/`, `test/`, `docs/`
103+
104+
**Examples:**
105+
106+
- `feat/123-add-solvro-auth`
107+
- `fix/87-fix-date-display`
108+
- `refactor/210-quiz-import-logic`
109+
110+
### Code Style
111+
112+
- **Formatting:** Prettier via `@solvro/config/prettier` — auto-run on commit via husky + lint-staged
113+
- **Linting:** ESLint flat config via `@solvro/config/eslint` (see `eslint.config.js`)
114+
115+
## Commands
116+
117+
| Task | Command |
118+
| ---------- | ----------------------------------------- |
119+
| Dev server | `npm run dev` |
120+
| Build | `npm run build` |
121+
| Lint | `npm run lint` / `npm run lint:fix` |
122+
| Format | `npm run format` / `npm run format:check` |
123+
| Type check | `npm run typecheck` |
124+
| Tests | `npm run test` (Vitest) |
125+
126+
## Cross-Device Quiz Continuity (PeerJS)
127+
128+
Users can sync quiz progress across devices (desktop, tablet, mobile) via WebRTC peer-to-peer.
129+
130+
**Hook:** `src/components/quiz/hooks/use-quiz-continuity.ts` — manages `Peer` connections, device discovery, and message
131+
types (`initial_sync`, `question_update`, `answer_checked`, ping/pong for connection health).
132+
133+
**UI:** `src/components/quiz/continuity-dialog.tsx` — displays connected peers by device type (icon per device), shows "
134+
host" badge for primary device.
135+
136+
**RTC config** uses STUN/TURN servers from env vars `NEXT_PUBLIC_TURN_USERNAME` and `NEXT_PUBLIC_TURN_CREDENTIAL` for
137+
NAT traversal. Fallback to public Google STUN if TURN unavailable.
138+
139+
## Testing
140+
141+
- **Framework:** Vitest 4 + jsdom + React Testing Library + MSW 2
142+
- **Test files:** `.spec.ts`/`.spec.tsx` — unit tests colocated with source in `src/lib/`, page tests in
143+
`src/__tests__/pages/`
144+
- **MSW handlers:** `src/test-utils/mocks/handlers.ts` — mocks backend API endpoints
145+
- **Test providers:** Wrap components in `<Providers>` from `src/test-utils/providers.tsx` (accepts `guest` flag,
146+
`accessToken`)
147+
- **Token generation:** Use `generateTestToken()` from `src/test-utils/token-factory.ts` for auth in tests
148+
- **Setup:** `src/test-utils/setup.ts` polyfills JSDOM gaps and configures MSW lifecycle (`beforeAll`/`afterEach`/
149+
`afterAll`)
150+
- **Pattern:** Page tests use a `setup()` helper that renders in providers and returns action helpers
151+
152+
## File Structure Quick Reference
153+
154+
```
155+
src/
156+
app/ # Next.js App Router pages (page.tsx + client.tsx)
157+
services/ # API service classes (BaseApiService → Quiz/User/Image)
158+
components/
159+
ui/ # shadcn/ui primitives (do not edit manually — use shadcn CLI)
160+
quiz/ # Quiz feature components, hooks, helpers
161+
navbar/ # Navigation components
162+
hooks/ # Global custom hooks
163+
lib/
164+
auth/ # JWT utilities, constants, types
165+
schemas/ # Zod validation schemas
166+
cookies.ts # Cookie helpers (js-cookie wrapper)
167+
api.ts # API_URL export
168+
types/ # TypeScript interfaces (quiz.ts, user.ts, common.ts)
169+
test-utils/ # Test providers, MSW mocks, token factory
170+
```

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ coverage
2727
.next
2828
.eslintcache
2929
/tsconfig.tsbuildinfo
30+
.env
3031
next-env.d.ts

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ Chcesz pomóc w rozwoju Testownika? Let's go!
8686
1. Sforkuj repozytorium (tylko jeśli jeszcze nie jesteś w teamie testownika)
8787
2. Stwórz branch dla swojej funkcji (`git checkout -b feat/amazing-feature`)
8888
3. Commituj zmiany (`git commit -m 'feat: add amazing feature'`)
89-
4. Wypchnij branch (`git push origin feature/amazing-feature`)
89+
4. Wypchnij branch (`git push origin feat/amazing-feature`)
9090
5. Otwórz Pull Request
9191

9292
Aby było nam wszystkim łatwiej stosuj się do tych zasad przy tworzeniu branchy oraz commitów.
9393

9494
### 🪾 Nazewnictwo branchy
9595

96-
Każdy branch powinien zawierać **prefiks określający typ zmiany** oraz **numer GitHub Issue**.
96+
Każdy branch powinien zawierać **prefiks określający typ zmiany** oraz **numer GitHub Issue** (jeżeli dotyczy).
9797

9898
**Format**
9999

0 commit comments

Comments
 (0)