Maturity-SE Onboarding Lesson 1 of 5 • 8 min
Start here — you don't know what you don't know yet

The 60-second mental model

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.

⏱ 8 min 🎯 One win: explain the loop + point to where each step lives 📍 Mission: onboarding
The loop — memorize this shape

Template → Assessment → Response → Report

1

Template — the questionnaire

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

↓ visibility: private → public (gallery) · clona ble, but cloned → cannot re-publish
2

Assessment — the instance

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

↓ share /respond/[token] — no auth required
3

Response — one person's answers

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

↓ aggregate per domain / per question
4

Report — the read-out

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

Say it back: "I create a template (what to ask), spin up an assessment (who + when, with a token), collect responses (one jsonb blob each), and read a report (aggregated scores)." If you can say that, you already orient faster than most day-one engineers.
Where things live — 4 districts

Don't memorize files. Learn the districts.

Every repo has "where do I look?" districts. Here there are four.

🏠 app/
App Router — routes + server actions

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.

🧩 components/
UI — feature components + ui primitives

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/
DB, auth, LLM, crypto — the engine room

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.

📄 docs/spec/
Why, not just how

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.

Three files to open first — always

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:7single quotes, no semicolons, strict TS, functional, server actions for mutations, Drizzle for queries, dbmate for migrations. Violate this and CI will tell you.

Practice — trace one thread end-to-end (2 min)

Follow the invite token

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)
Heads-up: 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.
Field note

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.

Retrieval — make it stick

Check yourself (no peeking)

Effortful recall builds storage strength. Pick, get feedback instantly. All choices are the same length on purpose — no formatting clues.

Q1 — The loop1 / 4

Which order is the core product loop?

Q2 — Where mutations live2 / 4

Where do data mutations belong in this repo?

Q3 — Public vs authed3 / 4

Which route is intentionally public (no login)?

Q4 — Drizzle vs dbmate4 / 4

What's the split between Drizzle and dbmate here?

Scores are not stored — this is for your memory, not for grading.

Go deeper — one primary source

Read the schema next

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.

Crafted for maturity-se onboarding · Glossary · Mission · Resources