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 handlercron/— Cron job endpoints (audit-cleanup, digest, draft-cleanup, reminders)live-voting/stream/— SSE stream for live votingfiles/bulk-download/— Bulk file download handlerstorage/local/— Local dev storage handlerhealth/— 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 machinedeliberation.ts— Deliberation session lifecycle (DELIB_OPEN → VOTING → TALLYING → DELIB_LOCKED)round-assignment.ts— Jury assignment generation with policy enforcementsmart-assignment.ts— Scoring algorithm (tag overlap, bio match, workload, geo-diversity, COI, availability)submission-manager.ts— Submission window lifecycle and file requirement enforcementresult-lock.ts— Immutable result locking with snapshotlive-control.ts— Live ceremony cursor managementcompetition-context.ts— Cross-cutting context resolverai-filtering.ts,ai-assignment.ts,ai-evaluation-summary.ts,ai-tagging.ts,ai-award-eligibility.ts,ai-shortlist.ts— AI feature servicesanonymization.ts— PII stripping before AI callsnotification.ts,in-app-notification.ts,evaluation-reminders.ts,email-digest.ts— Notification servicesassignment-policy.ts,assignment-intent.ts— Policy governance for assignmentsmentor-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 useimport { trpc } from '@/lib/trpc/client')server.ts— Server-side caller for Server Componentsindex.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 typeswizard-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 handlersrc/app/api/auth/[...nextauth]/route.ts— Auth handlersrc/server/routers/_app.ts— Root tRPC router
Configuration:
prisma/schema.prisma— Database schemanext.config.ts— Next.js configuration + legacy route redirectssrc/lib/auth.config.ts— Edge-compatible NextAuth config + Session type augmentationssrc/lib/auth.ts— Full NextAuth configuration with providerssrc/server/trpc.ts— tRPC initialization and all procedure type definitionssrc/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 machinesrc/server/services/deliberation.ts— Deliberation state machinesrc/server/services/round-assignment.ts— Assignment generationsrc/server/services/smart-assignment.ts— Scoring algorithmsrc/server/services/competition-context.ts— Context resolversrc/types/competition-configs.ts— Zod schemas for round configssrc/server/utils/audit.ts— Audit logging utility
Testing:
tests/setup.ts— Vitest setup with Prisma clienttests/helpers.ts— Test data factoriestests/unit/— Unit test filesvitest.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:
typekeyword preferred overinterface(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.), calllogAudit()on mutations
New Business Logic Service:
- Implementation:
src/server/services/[domain].ts - Accept
prisma: PrismaClient | anyas 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()+prismadirectly, 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.tsxchecksJURY_MEMBERrole 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 vianpx shadcn@latest add [component])
New Round Config Schema:
- Add Zod schema to
src/types/competition-configs.tsfollowing existing pattern - Add to
RoundConfigMapdiscriminated union - Update
validateRoundConfig()andsafeValidateRoundConfig()switch statements - Add config UI component to
src/components/admin/rounds/config/
Utilities:
- Shared server+client helpers:
src/lib/utils.tsor newsrc/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