|
| 1 | +# Architecture |
| 2 | + |
| 3 | +## High-Level System |
| 4 | + |
| 5 | +```mermaid |
| 6 | +flowchart LR |
| 7 | + U[Browser] --> C[Next.js Client App] |
| 8 | + C --> SA[Next.js Server Actions] |
| 9 | + SA --> GH[GitHub REST + GraphQL APIs] |
| 10 | + C --> OA[Express OAuth Service] |
| 11 | + OA --> GHO[GitHub OAuth Endpoints] |
| 12 | +``` |
| 13 | + |
| 14 | +## Services |
| 15 | + |
| 16 | +### Frontend (`client/`) |
| 17 | + |
| 18 | +- Framework: Next.js App Router + React |
| 19 | +- Responsibilities: |
| 20 | + - UI rendering |
| 21 | + - Auth flow initiation and callback handling |
| 22 | + - Server actions for GitHub data read/write |
| 23 | + - Route protection via middleware |
| 24 | + |
| 25 | +### OAuth Service (`server/`) |
| 26 | + |
| 27 | +- Framework: Express |
| 28 | +- Responsibilities: |
| 29 | + - Return safe OAuth config (`/api/auth/config`) |
| 30 | + - Exchange OAuth code for token (`/api/auth/exchange`) |
| 31 | + - Fetch GitHub user profile during exchange |
| 32 | + |
| 33 | +## Authentication Flow |
| 34 | + |
| 35 | +```mermaid |
| 36 | +sequenceDiagram |
| 37 | + participant B as Browser |
| 38 | + participant N as Next.js Client |
| 39 | + participant S as Express OAuth Server |
| 40 | + participant G as GitHub |
| 41 | +
|
| 42 | + B->>N: Click "Sign in with GitHub" |
| 43 | + N->>S: GET /api/auth/config |
| 44 | + S-->>N: client_id, redirect_uri |
| 45 | + N->>G: Redirect to /login/oauth/authorize (PKCE + state) |
| 46 | + G-->>B: Redirect to /auth/callback?code=...&state=... |
| 47 | + B->>N: Load callback page |
| 48 | + N->>S: POST /api/auth/exchange (code, verifier) |
| 49 | + S->>G: Exchange code for token |
| 50 | + S->>G: Fetch /user |
| 51 | + S-->>N: access_token + user |
| 52 | + N->>N: Set httpOnly auth cookie via server action |
| 53 | + N-->>B: Redirect to /workspace |
| 54 | +``` |
| 55 | + |
| 56 | +## Runtime Request Patterns |
| 57 | + |
| 58 | +### Read Path |
| 59 | + |
| 60 | +1. UI component calls server action in `client/app/actions/github.ts` |
| 61 | +2. Action calls `githubReadJson` (`client/lib/github/server.ts`) |
| 62 | +3. Wrapper adds GitHub auth headers and caching policy |
| 63 | +4. Response is mapped to app types in `client/lib/github/mappers.ts` |
| 64 | +5. UI renders normalized data |
| 65 | + |
| 66 | +### Write Path |
| 67 | + |
| 68 | +1. UI component calls server action in `client/app/actions/issues.ts` |
| 69 | +2. Action calls `githubWriteJson` with no-store cache |
| 70 | +3. On success, action calls `revalidateTag('github')` |
| 71 | +4. Updated entity is returned and local UI state is patched |
| 72 | + |
| 73 | +### Linked Pull Request Lookup |
| 74 | + |
| 75 | +- Issue list batches lookups by repository |
| 76 | +- GraphQL query uses `issueOrPullRequest(number: ...)` |
| 77 | +- Non-issue nodes are ignored to avoid failures on PR numbers |
| 78 | + |
| 79 | +## Caching Model |
| 80 | + |
| 81 | +- Read calls default to `revalidate: 60` seconds and tag `github` |
| 82 | +- Write calls are always `no-store` |
| 83 | +- Mutations trigger cache invalidation via `revalidateTag('github')` |
| 84 | + |
| 85 | +## Route Segmentation |
| 86 | + |
| 87 | +- Public routes: `client/app/(public)/...` |
| 88 | +- Authenticated workspace: `client/app/(auth)/...` |
| 89 | +- Middleware enforces token presence for `/workspace` |
| 90 | + |
| 91 | +## Error Handling |
| 92 | + |
| 93 | +- Client actions normalize user-facing messages with `getErrorMessage` |
| 94 | +- Errors are reported through `reportClientError` telemetry utility |
| 95 | +- Workspace has dedicated `loading` and `error` boundaries |
| 96 | + |
| 97 | +## Security Notes |
| 98 | + |
| 99 | +- Access token stored in `httpOnly` cookie |
| 100 | +- OAuth `state` and PKCE verifier validated on callback |
| 101 | +- Session reset route clears auth cookies and performs safe redirect |
| 102 | +- OAuth server validates redirect URI mismatch attempts |
0 commit comments