Files
seminarhof-e2e-mqo0qs8e/docs/process/discovery-playbook.md
2026-06-21 18:46:29 +02:00

447 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Discovery & Scoping Playbook
A repeatable method for going from "handover document + a folder of legacy
spreadsheets" to "buildable platform with locked decisions, persisted memory,
and a vetted business-owner sign-off". Designed to be driven by a human
with an AI coding assistant (Claude Code, Cursor, etc.) — not by the AI
alone.
The method works because each phase produces a **durable artifact** that
the next phase consumes. No phase relies on conversation history; if a
session ends, the next one resumes from the artifacts.
A worked example using this method is in `seminarhof-walkthrough.md`.
---
## Phase 0 — Repo init from template
**Goal.** Get a working repo on disk with the template's stack already
wired, plus a private working tree where production data can land
without ever touching git.
**Steps**
1. Create the empty remote repo (org-scoped, private by default).
2. Copy the template into a temp dir, init git, push to the new remote.
3. Move the working copy out of the temp dir into a permanent location.
4. **Before anything else**: extend `.gitignore` to cover all paths that
will hold production data, handover documents, or scrubbed data
derived from production data:
```
data/seed/
data/seed-scrubbed/
docs/handover/
```
5. Create empty `data/seed/` and `data/seed-scrubbed/` directories so
the AI can drop scripts referencing them without errors.
**Artifacts.** A pushed-to-main empty-template repo + gitignore lockdown.
**Anti-pattern.** Letting the AI commit a CSV before gitignore is set up.
Once production data hits a public remote, you can't un-leak it — even
after a force-push, the data is in clones and CI logs.
---
## Phase 1 — Inventory the inputs
**Goal.** Convert every source document (handover PDF, sample
spreadsheets, screenshots, hand-drawn diagrams) into a single
**structured inventory document** before designing anything.
**Why first.** Every later phase references the inventory. If you skip
straight to schema design, you'll model what you assume the source data
looks like rather than what it actually contains, and you'll re-discover
columns by accident two weeks in.
**Steps**
1. For each spreadsheet / source workbook, capture:
- Tab names and tab purposes
- Per-tab column list with your best-guess interpretation
- Cell value vocabulary if the cells aren't simple values (codes,
bracketed conventions, abbreviations, etc.)
2. For each source PDF (floor plans, AGB, etc.), extract structure into
tables — e.g. one row per room with whatever attributes are visible.
3. For each artifact, record what's **confirmed** vs **best-guess**.
Best-guesses become open questions later.
4. Cross-reference between artifacts to surface contradictions (e.g.
"this name appears here but not on the floor plan").
**Artifacts.**
- `docs/handover/csv-inventory.md` — structure of every source spreadsheet
- `docs/handover/rooms-inventory.md` (or similar per major artifact)
- Scribbled best-guess tables marked clearly as such
**Tip — anchoring.** When you later ask the business owner about a
column or value, anchor every question to its source artifact ("In
**Belegungsplan** the column `auto-renewal-2`…"). It eliminates
ambiguity for the owner and lets you trace each decision back to its
trigger.
---
## Phase 2 — Privacy-first data handling
**Goal.** Get useful structural insight from production data without
ever letting raw personal data reach an LLM API.
**Why this matters.** Most LLM APIs retain inputs for ~30 days for
trust & safety. A single conversational `cat` of a customer CSV
becomes a GDPR Art. 9 (special-category) breach if dietary, allergy,
or health data is in it. The fix is structural, not policy: the AI
cannot leak data it never saw.
**Method**
1. Owner exports CSVs / Excel from source systems and drops them in
`data/seed/` (gitignored).
2. AI writes a **scrubber script** — pure stdlib, no deps — that:
- Reads every CSV in `data/seed/`
- Detects PII columns by header heuristics in the local language
(German + English in our case)
- Detects PII patterns regardless of column (email, phone, IBAN
regex)
- Replaces values with **deterministic fakes** (hash → fake, so the
same input maps to the same fake — preserves foreign-key integrity
and repeated-organisation grouping)
- Blanks notes/comments columns by default (highest-risk free text)
- Outputs to `data/seed-scrubbed/` (also gitignored)
3. AI never reads `data/seed/`. Only ever reads `data/seed-scrubbed/`.
**What survives in scrubbed output:** column names, row counts, value
patterns, dates, statuses, room numbers, dietary text values, prices.
Enough to design schema honestly.
**What never reaches the AI:** real names, emails, phones, addresses,
IBANs, free-text notes.
**Artifacts.**
- `scripts/scrub-csvs.mjs` (or equivalent)
- `data/seed/` and `data/seed-scrubbed/` populated locally; both
gitignored
**Anti-pattern.** "I'll just paste a few rows in chat to show structure."
A few rows is enough to identify individuals via correlation; resist.
Structure can always be conveyed via column names + 2 obviously-fake
sample rows (`Max Mustermann`).
**Edge case the owner will raise.** "But the structure is messy and you
need to see real values to make sense of it." This is when the scrubber
earns its keep — they get to keep the messiness, you get to read the
output safely.
---
## Phase 3 — Question discipline
**Goal.** Convert ambiguity into locked decisions one at a time, with
rationale, anchored to source.
**The core rule.** Ask **one** question per turn. Multi-question batches
encourage thin answers and mask cross-question contradictions.
**Question shape that works**
```
In <source artifact>, <specific anchor> — <plain question>?
[24 options, each with a one-line consequence]
```
Each option must spell out what *changes in the platform* if it's
chosen. "Cleaner" is not a consequence; "no `house_half` column on
rooms" is.
**When the owner picks an option** → lock it. Move on.
**When the owner says "I don't know"** → log to a single deferred-items
file with the consequence, and move on. Don't argue.
**When the owner gives a free-text answer that doesn't match the
options** → restate it in one line ("Got it — X."), confirm, lock,
move on. The options were a forcing function, not a constraint.
**When the owner asks "what would you recommend?"** → answer in one
sentence with the trade-off, then bring them back to deciding. Don't
make the decision for them.
**Artifacts.**
- Running `docs/handover/open-questions.md` — every deferred question
with its rationale (so anyone can pick it up later without re-deriving
the context)
- Memory entries for locked decisions (Phase 4)
**Anti-pattern.** Asking "are you sure?" after every answer. Lock the
decision and move forward; if it turns out wrong, the audit log of
locked decisions makes it cheap to revisit.
**Anti-pattern.** Asking infrastructure questions (DB engine, hosting,
file storage) when the chosen framework already provides them. Skip
those entirely; they aren't business decisions.
---
## Phase 4 — Lock decisions in memory
**Goal.** Make decisions survive session boundaries.
**Why.** Conversation context disappears when the session ends. A
locked decision that lives only in conversation is a decision that
will be re-litigated the next time someone (you, the AI, a teammate)
opens a new session.
**Steps**
1. As decisions are locked in Phase 3, mirror them into a memory file
under `~/.claude/projects/<project-key>/memory/`.
2. The memory file is a *living* artifact — append new locks, update
superseded ones (don't pile contradictions), remove decisions that
were rolled back.
3. Reference the memory file from `MEMORY.md` so future sessions
auto-load it.
4. Distinguish **business decisions** (locked, in memory) from
**infra decisions** (defer to framework, don't pretend to lock).
**Artifacts.**
- `~/.claude/projects/<project-key>/memory/project_<name>.md`
- `MEMORY.md` link
**What goes in memory.** Locked rules: status enums, pricing logic,
auth model, multi-tenancy stance, scope exclusions, deferred items,
privacy guardrails. The shape of decisions, not the implementation.
**What does *not* go in memory.** Code, file paths, line numbers, the
contents of any source data file. Those rot fast and you can re-read
them from disk any time.
---
## Phase 5 — Generate a business-owner interview prompt
**Goal.** Hand the open questions back to the non-technical business
owner in a form they can answer without a developer babysitting them.
**The artifact.** A single self-contained markdown file the owner
pastes into a fresh AI session. The file contains:
1. A how-to-use header (paste this whole file into Claude/ChatGPT, etc.)
2. Instructions to the LLM (interview tone, ask one at a time, restate
in plain language, push back on vagueness, don't accept "we'll
figure it out")
3. Background section: what the business is, what the platform replaces,
what's already decided (so the LLM doesn't re-open settled ground)
4. Each open question, complete with a *why-it-matters* rationale the
LLM reuses verbatim
5. Output spec — the LLM must produce a single answers document at the
end, with a specific structure, that the owner sends back
**Why this works.** The owner can answer at their own pace, in their
own language. The LLM acts as a patient interviewer rather than a
form. Vague answers get probed automatically. The output document is
mechanical to consume back into the project.
**Artifacts.**
- `docs/handover/business-requirements-prompt.md`
- (later) `docs/handover/business-requirements-answers.md`
**Anti-pattern.** Sending a 20-row spreadsheet to the owner and asking
them to fill it in. Spreadsheets get half-answered or skipped on the
hard items. A guided conversational interview surfaces edge cases the
owner wouldn't have thought to flag.
---
## Phase 6 — Receive answers, propagate, re-lock
**Goal.** Take the owner's answers and propagate them through every
artifact built so far.
**Steps**
1. Save the raw answers verbatim as `business-requirements-answers.md`.
2. For each answered question:
- If it overrides a best-guess in an inventory document, update the
inventory with the authoritative value (mark the source: "confirmed
by owner on <date>").
- Move the question out of `open-questions.md`.
- Add the locked rule to memory (Phase 4 file).
3. Items marked `DEFER` stay in `open-questions.md` with the next
decision-maker named. They are the only thing that file should
contain after Phase 6.
**Artifacts.**
- `business-requirements-answers.md` (verbatim)
- Updated inventories with `confirmed by` notes
- Slimmed-down `open-questions.md`
- Updated memory file
**The discipline test.** After Phase 6, a brand-new AI session opening
this repo should be able to design the schema purely from the
artifacts in the repo and memory — no conversation history needed. If
that's not true, an artifact is missing.
---
## Phase 7 — UI design before code
**Goal.** Decide what each portal *looks like* and *contains* before
writing components.
**Why this is its own phase.** The data model is now locked, but a
data model alone doesn't tell you what the UI is. Two valid designs
can sit on the same schema and feel like different products.
**Method**
1. Identify the surfaces (in this template's case: client portal, admin,
staff, public).
2. For each surface, decide:
- Audience and primary jobs-to-be-done
- Default landing screen (what they see when they log in)
- Density and tone (warm/dense/minimal/marketing)
- Mobile vs desktop priority
- Shared theme tokens vs surface-specific overrides
3. For the **highest-stakes surface** (usually admin), drill into the
landing screen's sections one at a time, the same way Phase 3 drills
into business questions.
**Artifacts.**
- `docs/design/<surface>.md` per portal — sections, components,
interactions
- Reference screenshots from the owner where they exist
**Anti-pattern.** "Same theme, same components everywhere." A
client-facing card-based dashboard makes admin Christina cry when she
needs to manage 200 bookings across 5 years. Same tokens; different
component vocabularies per surface.
---
## Phase 7.5 — Acceptance scenarios before code
**Goal.** Every workflow that's about to be built has a `.feature` file
*before* a line of implementation code is written.
**Why this is its own phase.** Acceptance scenarios written *after* the
code rationalise whatever shipped — they validate the implementation,
not the requirement. Written *before*, they pin the requirement and
double as the build's definition of done. They also surface
contradictions in the locked decisions that schema design and UI
mockups didn't catch (e.g. "the feature says clients can do X, but role
matrix in memory says only admins can").
**Method**
1. For each surface from Phase 7, list the workflows that have to work
end-to-end (login, view-own-bookings, room-assignment,
create-invoice, etc.).
2. For each workflow, write a Cucumber `.feature` file with at least
one happy-path scenario and one role-gating / permission scenario.
Use the generic step library from the e2e harness; project-specific
steps come later.
3. Auth is **always the first feature**. Without it the rest of the
scenarios can't even reach a logged-in state.
4. Don't write the step *implementations* yet beyond the generic ones
(`I visit`, `I log in as`, `I see`). Project-specific steps land in
Phase 8 alongside the code they exercise.
**Artifacts.**
- `e2e/tests/features/auth.feature` — first, always
- `e2e/tests/features/<workflow>.feature` — one per locked workflow
- A failing test run (red) — the baseline against which Phase 8
progress is measured
**Anti-pattern.** "We'll add tests once it's working." Tests added
after-the-fact tend to mirror the code's shape rather than the
requirement's shape, and they don't catch the gaps the requirement
process should have caught. The whole point of Phase 7.5 is that the
test is the requirement, in executable form.
**Anti-pattern.** Writing 40 detailed scenarios up front. Cover the
locked workflows with **one happy path + one critical edge each**.
Exhaustive scenario coverage is a Phase 9 activity (regression as the
product grows), not a Phase 7.5 one.
---
## Phase 8 — Build (vertical slice)
**Goal.** Ship a slice that touches every layer (DB → backend → API →
UI) for one real workflow, instead of completing a full layer at a
time.
**Why.** Layer-at-a-time builds discover integration problems last,
when they're most expensive. Vertical-slice builds discover them in
week one.
**Build auth first.** Before any feature work: real login, real
sessions, real role enforcement. Every later function takes its
`userId` and `role` from the session, never from a `DEMO_USER`
constant or an input parameter. Skipping this and "wiring auth at the
end" sounds cheap but isn't — every function signature, every UI page,
every permission check has to be retrofitted, contracts re-versioned,
seeds re-hashed, and route guards added across the whole app. Doing it
first costs a day; doing it last costs a week and leaves footguns in
every file you didn't revisit.
**What "auth first" means concretely:**
1. Sessions table + cookie middleware (or equivalent for the chosen
stack) live before the first feature function is written.
2. Password hashing uses a runtime-portable primitive (WebCrypto
PBKDF2, Argon2-wasm, etc.) — not bcrypt/node:crypto if the target
includes edge runtimes.
3. Seed data includes hashed passwords for every demo role from day
one. Demo passwords are documented in seed comments only, never in
memory or repo docs.
4. `pikkuFunc` (or the equivalent session-required handler) is the
default; sessionless handlers are the explicit, justified
exception.
5. UI has a `RequireAuth` wrapper with a `roles` prop *before* the
first protected page is built.
**Steps**
1. Land auth as the first vertical slice (login → cookie → `me` → role
guard on one trivial admin page).
2. Pick the next workflow that exercises the trickiest parts of the
schema (in our case: client logs in → views their booking → fills
room plan → admin sees the update → kitchen view reflects it).
3. Build only what that workflow needs at every layer.
4. Once it's working end-to-end, expand sideways.
**Artifacts.**
- A demoable URL
- A short loom-style "what works, what doesn't" note for the owner
**Anti-pattern.** "We'll wire real auth at the end, just hard-code
`DEMO_USER` for now." Every function written under that assumption
takes a `userId` input parameter that has to be deleted later, and
every UI mutation passes it explicitly. Retrofitting means touching
every file twice and re-versioning every contract.
---
## Cross-phase rules
**Auto mode.** When the owner has set the AI to "auto" / "execute
without confirming", still pause for irreversible actions: deleting
data, force-pushing, or actions that touch shared systems. Authorisation
to "go fast" is not authorisation to be careless.
**Memory hygiene.** When a locked decision is later overridden, *update*
the memory file rather than appending a contradiction. Stale memory is
worse than no memory.
**Confidentiality.** Treat any owner-shared spreadsheet, screenshot, or
PDF as containing data the org has not authorised to share with an AI
provider. Either scrub it (Phase 2) or extract structure manually before
ingesting.
**Documentation order.** Inventory → questions → answers → memory →
design → acceptance scenarios → code. Skipping inventory or questions
costs more downstream than the time saved. Skipping acceptance
scenarios means the build's definition of done is "feels right when I
click around" — which is how `DEMO_USER` constants ship to production.