Round system redesign: Phases 1-7 complete

Full pipeline/track/stage architecture replacing the legacy round system.

Schema: 11 new models (Pipeline, Track, Stage, StageTransition,
ProjectStageState, RoutingRule, Cohort, CohortProject, LiveProgressCursor,
OverrideAction, AudienceVoter) + 8 new enums.

Backend: 9 new routers (pipeline, stage, routing, stageFiltering,
stageAssignment, cohort, live, decision, award) + 6 new services
(stage-engine, routing-engine, stage-filtering, stage-assignment,
stage-notifications, live-control).

Frontend: Pipeline wizard (17 components), jury stage pages (7),
applicant pipeline pages (3), public stage pages (2), admin pipeline
pages (5), shared stage components (3), SSE route, live hook.

Phase 6 refit: 23 routers/services migrated from roundId to stageId,
all frontend components refitted. Deleted round.ts (985 lines),
roundTemplate.ts, round-helpers.ts, round-settings.ts, round-type-settings.tsx,
10 legacy admin pages, 7 legacy jury pages, 3 legacy dialogs.

Phase 7 validation: 36 tests (10 unit + 8 integration files) all passing,
TypeScript 0 errors, Next.js build succeeds, 13 integrity checks,
legacy symbol sweep clean, auto-seed on first Docker startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 13:57:09 +01:00
parent 8a328357e3
commit 331b67dae0
256 changed files with 29117 additions and 21424 deletions

66
tests/setup.ts Normal file
View File

@@ -0,0 +1,66 @@
/**
* Vitest global setup
*
* Provides:
* - `prisma` a PrismaClient connected to DATABASE_URL (or DATABASE_URL_TEST)
* - `createTestContext(user)` builds a tRPC-compatible context with an
* authenticated user so callers can invoke router procedures directly.
* - `createCaller(router, user)` shorthand for creating a type-safe caller
* from any tRPC router.
*
* Test isolation strategy: each test file should use `cleanupTestData()` in
* afterAll to remove data it created, keyed by unique program/user names.
*/
import { PrismaClient } from '@prisma/client'
import { afterAll } from 'vitest'
import type { UserRole } from '@prisma/client'
export const prisma = new PrismaClient({
datasourceUrl: process.env.DATABASE_URL_TEST ?? process.env.DATABASE_URL,
})
afterAll(async () => {
await prisma.$disconnect()
})
/**
* Build a fake tRPC context with an authenticated user.
* The returned object matches the shape expected by tRPC middleware
* (session.user, prisma, ip, userAgent).
*/
export function createTestContext(user: {
id: string
email: string
name?: string | null
role: UserRole
}) {
return {
session: {
user: {
id: user.id,
email: user.email,
name: user.name ?? user.email,
role: user.role,
},
expires: new Date(Date.now() + 86_400_000).toISOString(),
},
prisma,
ip: '127.0.0.1',
userAgent: 'vitest',
}
}
/**
* Create a tRPC caller for a given router, authenticated as `user`.
* Usage:
* const caller = createCaller(pipelineRouter, adminUser)
* const result = await caller.create({ ... })
*/
export function createCaller<TRouter extends { createCaller: (ctx: any) => any }>(
routerModule: { createCaller: (ctx: any) => any },
user: { id: string; email: string; name?: string | null; role: UserRole },
) {
const ctx = createTestContext(user)
return routerModule.createCaller(ctx)
}