Files
seminarhof-e2e-mqo7np5j/docs/process/discovery-playbook.md
2026-06-21 22:00:02 +02:00

18 KiB
Raw Blame History

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 ").
    • 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.