Before you open 40 files, hold one picture in your head. Everything in this repo hangs off a single loop: Template → Assessment → Response → Report. Learn the loop, and every folder has a place.
Defines what to ask: title, scale (1–5 by default), domains → questions. Created manually or AI-generated. components/template-editor.tsx · app/actions/templates.ts:generateTemplate
Binds a template to a team + due date. Gets a inviteToken = nanoid(32) — the shareable link. app/actions/assessments.ts:createAssessment · status: draft | active | closed
Respondent picks a scale value per question. Stored as answers: Record<questionId, number|string> jsonb. app/respond/[token]/page.tsx · components/respond-form.tsx · submitResponse
Averages, distributions, radar & bar charts (Recharts). Computed in the report page, rendered by MaturityReport. app/(app)/assessments/[id]/report/page.tsx · components/maturity-report.tsx
Every repo has "where do I look?" districts. Here there are four.
app/(app)/* is the authed shell (sidebar guard). app/respond/[token] is public. app/actions/* is where mutations live — not app/api (only auth there). If you add a feature that writes data, it starts in app/actions.
Feature files: template-editor, respond-form, maturity-report, new-assessment-form. Primitives in components/ui/* are shadcn (base-nova). Styles in app/globals.css.
lib/db/schema.ts is your Rosetta Stone (Drizzle tables). db/migrations/*.sql is the DDL — Drizzle never migrates. db/run.js just loads .env.development.local for dbmate. lib/auth.ts + lib/llm.ts + lib/crypto.ts explain auth/LLM/BYOK.
6 specs: promo credits, dbmate refactor, usage log, PostHog, template rules, AI research. Read a spec before you touch its feature — it's the closest thing to ADRs here. docs/issues-tracker + docs/demo give lineage.
lib/db/schema.ts — what data exists
app/actions/templates.ts — how the core domain mutates
AGENTS.md — how this repo wants you to work (pnpm, lint, server actions, Drizzle+dbmate)
Tip: AGENTS.md:7 — single quotes, no semicolons, strict TS, functional, server actions for mutations, Drizzle for queries, dbmate for migrations. Violate this and CI will tell you.
Open these three files in order. You don't need to understand every line — just see the token move.
1. app/actions/assessments.ts → createAssessment()
- nanoid(32) → inviteToken, status defaults to 'draft'
2. app/(app)/assessments/[id]/page.tsx
- shows InviteLinkBox with /respond/[token]
3. app/respond/[token]/page.tsx → components/respond-form.tsx
- public route, checks assessment.status === 'active'
- submitResponse() writes responses.answers (jsonb)
app/(app)/layout.tsx:10 guards the whole (app) group — getSession() → redirect('/sign-in'). But /respond/[token] lives outside that group on purpose. That's why respondents need no login.
The repo looks big at first (29 routes, 33 components, 9 lib files). In practice it's four tables you care about this week: templates, assessments, responses, llm_keys. Everything else is auth/credits scaffolding. Nail the loop, then add scaffolding.
Effortful recall builds storage strength. Pick, get feedback instantly. All choices are the same length on purpose — no formatting clues.
Which order is the core product loop?
Where do data mutations belong in this repo?
Which route is intentionally public (no login)?
What's the split between Drizzle and dbmate here?
Scores are not stored — this is for your memory, not for grading.
If you read one file after this lesson, make it lib/db/schema.ts. It's ~200 lines and tells you every table the product cares about. Then skim AGENTS.md for how to work here without friction.
Citations: loop from app/actions/templates.ts + app/actions/assessments.ts + app/respond/[token]/page.tsx; conventions from AGENTS.md:1-15; UI from components.json + app/globals.css.
We'll get pnpm dev + pnpm db:migrate working, understand why db/run.js exists, and know what "merge to main auto-deploys" means for you.
Crafted for maturity-se onboarding · Glossary · Mission · Resources