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

17 KiB

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.tscreateTRPCReact<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