Files
MOPC-Portal/.planning/codebase/STRUCTURE.md
Matt 8cc86bae20 docs: map existing codebase
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:14:08 +01:00

328 lines
17 KiB
Markdown

# Codebase Structure
**Analysis Date:** 2026-02-26
## Directory Layout
```
MOPC/
├── prisma/ # Database schema and migrations
│ ├── schema.prisma # Single source of truth for all models
│ ├── seed.ts # Seed script (imports from docs/CSV files)
│ └── migrations/ # Prisma migration history (auto-generated)
├── src/
│ ├── app/ # Next.js App Router — all routes
│ │ ├── (admin)/ # Admin dashboard route group (SUPER_ADMIN, PROGRAM_ADMIN)
│ │ ├── (jury)/ # Jury evaluation route group (JURY_MEMBER)
│ │ ├── (applicant)/ # Applicant dashboard route group (APPLICANT)
│ │ ├── (mentor)/ # Mentor workspace route group (MENTOR)
│ │ ├── (observer)/ # Observer read-only route group (OBSERVER)
│ │ ├── (auth)/ # Public auth pages (login, verify, onboarding)
│ │ ├── (public)/ # Fully public pages (apply, vote, live-scores)
│ │ ├── (settings)/ # User settings (profile)
│ │ └── api/ # API routes (tRPC, auth, cron, SSE, files, health)
│ ├── components/ # React components organized by domain
│ │ ├── admin/ # Admin-specific components
│ │ ├── jury/ # Jury-specific components
│ │ ├── applicant/ # Applicant-specific components
│ │ ├── mentor/ # Mentor-specific components
│ │ ├── observer/ # Observer-specific components
│ │ ├── public/ # Public-facing components
│ │ ├── forms/ # Shared form components (apply wizard, COI dialog)
│ │ ├── charts/ # Chart/visualization components
│ │ ├── dashboard/ # Dashboard widgets
│ │ ├── layouts/ # Navigation layouts per role (sidebar, nav bars)
│ │ ├── shared/ # Reusable cross-domain components
│ │ └── ui/ # shadcn/ui primitives
│ ├── server/ # Server-only code
│ │ ├── routers/ # tRPC domain routers (44+ files)
│ │ │ └── _app.ts # Root router composing all domains
│ │ ├── services/ # Business logic services
│ │ ├── utils/ # Server utilities (audit, ai-usage, image-upload)
│ │ ├── trpc.ts # tRPC init, middleware, procedure types
│ │ └── context.ts # tRPC context factory (session + prisma + IP)
│ ├── lib/ # Shared libraries (client + server)
│ │ ├── trpc/ # tRPC client (client.ts), server caller (server.ts)
│ │ ├── storage/ # Storage provider abstraction (S3/local)
│ │ ├── whatsapp/ # WhatsApp notification client
│ │ ├── auth.ts # NextAuth full configuration
│ │ ├── auth.config.ts # Edge-compatible auth config (middleware)
│ │ ├── auth-redirect.ts # requireRole() server helper
│ │ ├── prisma.ts # Prisma singleton with connection pooling
│ │ ├── logger.ts # Structured logger (tagged, level-aware)
│ │ ├── email.ts # Nodemailer email sender
│ │ ├── minio.ts # MinIO client initialization
│ │ ├── openai.ts # OpenAI client initialization
│ │ ├── rate-limit.ts # In-memory rate limiter
│ │ ├── feature-flags.ts # DB-backed feature flags
│ │ ├── round-config.ts # Round config helper utilities
│ │ ├── utils.ts # General utilities (cn, formatters)
│ │ └── [others] # countries, pdf-generator, typeform, notion, etc.
│ ├── types/ # TypeScript type definitions
│ │ ├── competition.ts # Composite types for Competition/Round domain
│ │ ├── competition-configs.ts # Per-RoundType Zod schemas + inferred types
│ │ └── wizard-config.ts # Application wizard configuration types
│ ├── hooks/ # Custom React hooks
│ │ ├── use-debounce.ts
│ │ ├── use-live-voting-sse.ts # SSE subscription for live voting
│ │ └── use-stage-live-sse.ts # SSE subscription for live stage
│ └── contexts/ # React contexts
│ └── edition-context.tsx # Edition/Program selector context
├── tests/ # Test files (Vitest)
│ ├── setup.ts # Test setup (prisma client, helpers)
│ ├── helpers.ts # Test factories (createTestUser, createTestCompetition, etc.)
│ └── unit/ # Unit test files
├── docs/ # Internal documentation and architecture notes
├── docker/ # Docker Compose configs and Nginx config
├── public/ # Static assets (fonts, images, maps)
├── scripts/ # Utility scripts
├── middleware.ts # Next.js edge middleware (auth check)
├── next.config.ts # Next.js config (standalone output, legacy redirects)
└── prisma/ # (see above)
```
## Directory Purposes
**`src/app/(admin)/admin/`:**
- Purpose: All admin pages behind SUPER_ADMIN/PROGRAM_ADMIN role gate
- Contains: Competition management, round config, project management, jury groups, members, programs, reports, audit, awards, settings, messages, mentors, partners, learning
- Key files: `layout.tsx` (role guard + edition selector), `admin/page.tsx` (dashboard), `admin/rounds/[roundId]/page.tsx` (round detail — largest page)
**`src/app/(jury)/jury/`:**
- Purpose: Jury evaluation interface behind JURY_MEMBER role gate
- Contains: Competitions list, round overview, project list, evaluate page, deliberation, live voting, learning resources, awards
- Key files: `layout.tsx` (role guard + onboarding check), `competitions/[roundId]/projects/[projectId]/evaluate/page.tsx` (evaluation form)
**`src/app/(applicant)/applicant/`:**
- Purpose: Applicant dashboard behind APPLICANT role gate
- Contains: Competition progress, documents, evaluations received, mentor chat, resources, team
- Key files: `layout.tsx`, `applicant/page.tsx`
**`src/app/(mentor)/mentor/`:**
- Purpose: Mentor workspace behind MENTOR role gate
- Contains: Project list, workspace per project, resources
- Key files: `layout.tsx`, `mentor/workspace/[projectId]/page.tsx`
**`src/app/(observer)/observer/`:**
- Purpose: Read-only view behind OBSERVER role gate
- Contains: Projects, reports
- Key files: `layout.tsx`
**`src/app/(public)/`:**
- Purpose: No-auth-required pages
- Contains: Application form (`apply/[slug]`), edition application (`apply/edition/[programSlug]`), live scores display (`live-scores/[sessionId]`), audience vote (`vote/[sessionId]`), submission status (`my-submission/[id]`), email change password
- Key files: `apply/[slug]/page.tsx` (application wizard)
**`src/app/(auth)/`:**
- Purpose: Auth flow pages
- Contains: Login, verify (magic link), verify-email, accept-invite, onboarding, set-password, error
- Key files: `login/page.tsx`, `onboarding/page.tsx`, `accept-invite/page.tsx`
**`src/app/api/`:**
- Purpose: Next.js route handlers for non-tRPC API
- Contains:
- `trpc/[trpc]/` — tRPC HTTP adapter (GET + POST)
- `auth/[...nextauth]/` — NextAuth handler
- `cron/` — Cron job endpoints (audit-cleanup, digest, draft-cleanup, reminders)
- `live-voting/stream/` — SSE stream for live voting
- `files/bulk-download/` — Bulk file download handler
- `storage/local/` — Local dev storage handler
- `health/` — DB health check endpoint
**`src/server/routers/`:**
- Purpose: tRPC domain routers, one file per domain
- Contains: 44+ router files assembled in `_app.ts`
- Key files: `competition.ts`, `round.ts`, `roundEngine.ts`, `evaluation.ts`, `filtering.ts`, `deliberation.ts`, `resultLock.ts`, `roundAssignment.ts`, `assignment.ts`, `project.ts`, `user.ts`, `program.ts`
**`src/server/services/`:**
- Purpose: All business logic — state machines, AI integrations, external service calls
- Contains:
- `round-engine.ts` — Round and project state machine
- `deliberation.ts` — Deliberation session lifecycle (DELIB_OPEN → VOTING → TALLYING → DELIB_LOCKED)
- `round-assignment.ts` — Jury assignment generation with policy enforcement
- `smart-assignment.ts` — Scoring algorithm (tag overlap, bio match, workload, geo-diversity, COI, availability)
- `submission-manager.ts` — Submission window lifecycle and file requirement enforcement
- `result-lock.ts` — Immutable result locking with snapshot
- `live-control.ts` — Live ceremony cursor management
- `competition-context.ts` — Cross-cutting context resolver
- `ai-filtering.ts`, `ai-assignment.ts`, `ai-evaluation-summary.ts`, `ai-tagging.ts`, `ai-award-eligibility.ts`, `ai-shortlist.ts` — AI feature services
- `anonymization.ts` — PII stripping before AI calls
- `notification.ts`, `in-app-notification.ts`, `evaluation-reminders.ts`, `email-digest.ts` — Notification services
- `assignment-policy.ts`, `assignment-intent.ts` — Policy governance for assignments
- `mentor-matching.ts`, `mentor-workspace.ts` — Mentor domain services
**`src/components/admin/round/`:**
- Purpose: Components for the round detail page (the most complex admin page)
- Key files: `filtering-dashboard.tsx`, `project-states-table.tsx`
**`src/components/admin/rounds/config/`:**
- Purpose: Per-RoundType config form sections
- Contains: Config UI for each round type (`intake-config.tsx`, `evaluation-config.tsx`, etc.)
**`src/components/shared/`:**
- Purpose: Domain-agnostic reusable components
- Contains: `page-header.tsx`, `status-badge.tsx`, `file-upload.tsx`, `file-viewer.tsx`, `pagination.tsx`, `notification-bell.tsx`, `edition-selector.tsx`, `empty-state.tsx`, `loading-spinner.tsx`, and others
**`src/components/ui/`:**
- Purpose: shadcn/ui primitive components (never modified directly)
- Contains: `button.tsx`, `card.tsx`, `dialog.tsx`, `form.tsx`, `select.tsx`, `table.tsx`, etc.
**`src/components/layouts/`:**
- Purpose: Role-specific navigation shells
- Contains: `admin-sidebar.tsx`, `jury-nav.tsx`, `mentor-nav.tsx`, `observer-nav.tsx`, `applicant-nav.tsx`, `role-nav.tsx`, `admin-edition-wrapper.tsx`
**`src/lib/trpc/`:**
- Purpose: tRPC client configuration
- Contains:
- `client.ts``createTRPCReact<AppRouter>()` export (client components use `import { trpc } from '@/lib/trpc/client'`)
- `server.ts` — Server-side caller for Server Components
- `index.ts` — Provider setup (TRPCProvider + QueryClientProvider)
**`src/types/`:**
- Purpose: Shared TypeScript types not generated by Prisma
- Contains:
- `competition.ts` — Composite types with nested relations (e.g., `CompetitionWithRounds`, `RoundWithRelations`)
- `competition-configs.ts` — Per-RoundType Zod config schemas and inferred TypeScript types
- `wizard-config.ts` — Application wizard step configuration types
## Key File Locations
**Entry Points:**
- `middleware.ts` — Edge middleware (auth check before every request)
- `src/app/api/trpc/[trpc]/route.ts` — tRPC HTTP handler
- `src/app/api/auth/[...nextauth]/route.ts` — Auth handler
- `src/server/routers/_app.ts` — Root tRPC router
**Configuration:**
- `prisma/schema.prisma` — Database schema
- `next.config.ts` — Next.js configuration + legacy route redirects
- `src/lib/auth.config.ts` — Edge-compatible NextAuth config + Session type augmentations
- `src/lib/auth.ts` — Full NextAuth configuration with providers
- `src/server/trpc.ts` — tRPC initialization and all procedure type definitions
- `src/server/context.ts` — tRPC context (session, prisma, ip, userAgent)
- `tsconfig.json` — TypeScript strict mode config with `@/` path alias
**Core Logic:**
- `src/server/services/round-engine.ts` — Round state machine
- `src/server/services/deliberation.ts` — Deliberation state machine
- `src/server/services/round-assignment.ts` — Assignment generation
- `src/server/services/smart-assignment.ts` — Scoring algorithm
- `src/server/services/competition-context.ts` — Context resolver
- `src/types/competition-configs.ts` — Zod schemas for round configs
- `src/server/utils/audit.ts` — Audit logging utility
**Testing:**
- `tests/setup.ts` — Vitest setup with Prisma client
- `tests/helpers.ts` — Test data factories
- `tests/unit/` — Unit test files
- `vitest.config.ts` — Vitest configuration
## Naming Conventions
**Files:**
- kebab-case for all source files: `round-engine.ts`, `admin-sidebar.tsx`, `use-live-voting-sse.ts`
- Router files match domain name: `competition.ts`, `roundEngine.ts` (camelCase variants also seen for compound names)
- Service files use kebab-case: `round-assignment.ts`, `ai-filtering.ts`, `result-lock.ts`
**Directories:**
- kebab-case for all directories: `admin/`, `round-assignment/`, `apply-steps/`
- Route group segments use parentheses per Next.js convention: `(admin)`, `(jury)`, `(public)`
- Dynamic segments use square brackets: `[roundId]`, `[projectId]`, `[trpc]`
**Components:**
- PascalCase exports: `AdminSidebar`, `FilteringDashboard`, `JurorProgressDashboard`
- Component files kebab-case: `admin-sidebar.tsx`, `filtering-dashboard.tsx`
**Types:**
- `type` keyword preferred over `interface` (TypeScript strict mode project)
- Prisma-generated types used directly where possible; composite types in `src/types/`
- Zod schemas named `[Domain]ConfigSchema`; inferred types named `[Domain]Config`
## Where to Add New Code
**New tRPC Domain Router:**
- Router file: `src/server/routers/[domain].ts`
- Register in: `src/server/routers/_app.ts`
- Follow pattern: import from `../trpc`, use typed procedure (`adminProcedure`, `juryProcedure`, etc.), call `logAudit()` on mutations
**New Business Logic Service:**
- Implementation: `src/server/services/[domain].ts`
- Accept `prisma: PrismaClient | any` as parameter (for transaction compatibility)
- Return typed result objects `{ success: boolean, errors?: string[] }` for state machine functions
- Call `logAudit()` for all state changes
- Never import tRPC types — services are tRPC-agnostic
**New Admin Page:**
- Page file: `src/app/(admin)/admin/[section]/page.tsx`
- Layout guard is inherited from `src/app/(admin)/layout.tsx` — no additional role check needed
- Use `export const dynamic = 'force-dynamic'` for data-fetching pages
- Fetch data server-side in page component using `auth()` + `prisma` directly, or use client component with tRPC hooks
**New Jury Page:**
- Page file: `src/app/(jury)/jury/[section]/page.tsx`
- Layout guard in `src/app/(jury)/layout.tsx` checks `JURY_MEMBER` role and onboarding completion
**New Public Page:**
- Page file: `src/app/(public)/[section]/page.tsx`
- No auth guard — fully public
**New Component (domain-specific):**
- Admin component: `src/components/admin/[subdomain]/[component-name].tsx`
- Jury component: `src/components/jury/[component-name].tsx`
- Shared component: `src/components/shared/[component-name].tsx`
**New shadcn/ui Primitive:**
- Location: `src/components/ui/[component].tsx` (generated via `npx shadcn@latest add [component]`)
**New Round Config Schema:**
- Add Zod schema to `src/types/competition-configs.ts` following existing pattern
- Add to `RoundConfigMap` discriminated union
- Update `validateRoundConfig()` and `safeValidateRoundConfig()` switch statements
- Add config UI component to `src/components/admin/rounds/config/`
**Utilities:**
- Shared server+client helpers: `src/lib/utils.ts` or new `src/lib/[utility].ts`
- Server-only utilities: `src/server/utils/[utility].ts`
- Custom React hooks: `src/hooks/use-[name].ts`
## Special Directories
**`prisma/migrations/`:**
- Purpose: Auto-generated SQL migration files
- Generated: Yes (by `prisma migrate dev`)
- Committed: Yes
**`.next/`:**
- Purpose: Next.js build output cache
- Generated: Yes
- Committed: No
**`docs/`:**
- Purpose: Internal architecture notes, redesign plans, GDPR documentation, feature plans
- Generated: No
- Committed: Yes
**`prototypes/`:**
- Purpose: HTML/CSS prototype mockups for admin redesign
- Generated: No
- Committed: Yes
**`docker/`:**
- Purpose: Docker Compose files for production and dev stacks; Nginx reverse proxy config
- Generated: No
- Committed: Yes
**`.planning/`:**
- Purpose: GSD planning documents (codebase analysis, implementation plans)
- Generated: By GSD tooling
- Committed: No (gitignored)
**`.serena/`:**
- Purpose: Serena MCP project cache and memories
- Generated: Yes
- Committed: No
---
*Structure analysis: 2026-02-26*