Appearance
8 · Data Modeling & Backend Patterns
10. 11. 2026 · Slides
Materials for this seminar accumulate here: the task, the prompts, the homework.
Code is cheap, data isn't
Your agent rewrites a controller in two minutes. The table under it holds everything your users ever wrote, and it outlives every version of the code. So the data model is where it pays to slow down: design first, then code, and don't blindly take your agent's first proposal.
Three questions for any data model
Ask them about every schema your agent proposes. They are also the review checklist for today's task.
- Does it do what the product wants? Go through the request sentence by sentence. Everything the user should see needs data behind it, and it has to be easy to get out ("all replies to this quack", "how many people voted for each option").
- How is the data read and written? The default is one source of truth: an author's name copied onto every quack goes stale the day they rename themselves. But something read far more often than it changes can earn a copy (a counter, a precomputed feed). That's a decision: write it down.
- What happens on delete? Delete the related rows too, keep them, or block the delete. That's a product decision, not a technical one.
Don't forget the migration
Every change to the data model needs a migration. Production already holds your users' data, and we don't want to lose it.
Your agent knows best practices. It doesn't know your product. Relations, constraints, enums, indexes, naming: it gets those right without you. What it won't know is where the product is heading:
- Enum or table? Moods are an enum with four values. If the product wants to add new ones without a deploy, they belong in a table.
- What comes next? The product owner mentioned a quack could have several moods at once. Shape the model for it now, or when it actually comes?
- What does "deleted" mean? Gone for good, or kept as "deleted" because of the replies under it? The product decides, not the database.
- How much of it will there be? Counting likes on every read is fine for hundreds of users, not for millions. Where will you be in a year?
Weigh what the product needs today and what it will need tomorrow: what's likely to change, and what would that change cost?
Decisions like these get written down in a document of their own, called an ADR.
Watch out for overengineering
Don't build ahead for things that will most likely never come. Every extra feature adds complexity and maintenance burden.
Architecture Decision Record (ADR)
A short file, one decision, and above all why. Lives in docs/adr/0001-short-name.md, numbered. An ADR is never rewritten: when you change your mind, a new ADR replaces the old one, and the old one stays as history.
markdown
# 0001 · <decision in a few words>
Status: Accepted · <date>
## Context
What problem we have and what limits the solution.
## Decision
What we chose, in one or two sentences.
## Options considered
Each option you rejected, and why.
## Consequences
What changes for the rest of the app. What gets harder.- For your team: in three months nobody remembers why it's built this way. A new teammate reads it instead of asking, and old arguments don't start again. Use ADRs in your team project too.
- For your agent: it copies the patterns in your code, but it can't read from the code why they are that way. It remembers nothing between sessions. Without the ADR it will happily propose the option you already rejected.
- When to write one: there were several reasonable options and the choice is hard to undo (data model, a library, app structure). Not for every small thing.
An index: docs/adr/README.md. One line per ADR: number, title, status, one sentence. Your agent reads the index and opens only the ADRs that matter for the change, instead of all of them.
CLAUDE.md or an ADR? CLAUDE.md says what to do; the agent loads it every session, so keep it short. An ADR says why; it's read when the topic comes up. CLAUDE.md only points to the index; the why stays in the ADR. The rules you've been adding since week 3 stay where they are.
Your task: replies
"People discuss under quacks by posting a new quack that starts with '@name …', and nobody can tell what anyone is replying to. I want people to reply to a quack and see the replies under it. Replies belong to the people who wrote them: if an author deletes a quack that already has replies, the replies must not disappear with it. At the same time, when someone deletes their quack, its content has to really disappear from the app."
„Lidi pod quackem diskutují tak, že napíšou nový quack, který začíná ‚@jméno…‘, a nikdo pak neví, kdo na co reaguje. Chci, aby šlo na quack odpovědět a aby byly odpovědi vidět pod ním. Odpovědi patří lidem, kteří je napsali: když autor smaže quack, na který už někdo odpověděl, odpovědi s ním nesmí zmizet. Zároveň když někdo svůj quack smaže, jeho obsah musí z aplikace opravdu zmizet.“
Design first. Use the two prompts below, in this order, then build.
- Delete from week 5 works? The task builds on it.
- Design →
story.md(prompt 1). The agent asks about the product, the data and where it lands in the code. Every decision that shapes the data model comes with options. You choose. At the end it proposes the schema and checks it against the three questions, the migration included. - ADR →
docs/adr/0001-….md(prompt 2), a line in the indexdocs/adr/README.md, and a pointer to the index inCLAUDE.md. Let your agent write it, and iterate if needed. - Build it: reply → show replies → delete.
Prompts
1 · Design
text
We're designing a new feature before any code exists. Don't write code yet.
Request from our product owner:
<paste the request>
Interview me one question at a time until the story has no open questions. Cover:
- what the user sees and does
- what data we store and how it links to what's already in schema.prisma
- where it lands in the code: which module, which existing features it touches
Whenever a decision shapes the data model, give me 2–3 options with pros, cons
and what would be hard to change later. Recommend one, then let me choose.
Then propose the change to schema.prisma (no other code yet) and answer:
1. Can everything the user sees be read from this model with simple queries?
List the queries.
2. Is anything stored twice? If so, why, and what keeps the copies up to date?
3. What happens to related rows when a quack is deleted?
4. Will the migration run on a production database that already has data?
Finally write story.md: the story, acceptance criteria, a Decisions section
(each decision with the option we rejected and why), and the proposed schema.2 · ADR
text
Read the Decisions in story.md. Pick the one that is hardest to undo and affects
more of the app than this feature. Write it up as docs/adr/0001-<short-name>.md
with: Status, Context, Decision, Options considered (including the rejected ones
and why), Consequences (what changes for the rest of the app).
Add a line for it to docs/adr/README.md, the index of all ADRs (create it if
it doesn't exist): number, title, status, one sentence.
Then add one line to CLAUDE.md: before changing the data model or the structure
of the app, check the index in docs/adr/README.md.Prompty česky
1 · Návrh
text
Navrhujeme novou featuru, ještě než existuje kód. Zatím nepiš kód.
Požadavek od product ownera:
<vlož požadavek>
Ptej se mě po jedné otázce, dokud ve story nezůstane žádná otevřená otázka. Pokryj:
- co uživatel vidí a dělá
- jaká data ukládáme a jak navazují na to, co už je v schema.prisma
- kam to v kódu přistane: který modul, kterých existujících featur se to dotkne
U každého rozhodnutí, které ovlivní datový model, mi dej 2–3 varianty s výhodami,
nevýhodami a tím, co by se později špatně měnilo. Jednu doporuč a nech mě vybrat.
Pak navrhni změnu schema.prisma (zatím žádný další kód) a odpověz:
1. Dá se všechno, co uživatel vidí, z tohohle modelu přečíst jednoduchými dotazy?
Vypiš dotazy.
2. Je něco uložené dvakrát? Pokud ano, proč, a co udrží kopie aktuální?
3. Co se stane se souvisejícími řádky, když se quack smaže?
4. Projde migrace na produkční databázi, ve které už jsou data?
Nakonec napiš story.md: story, akceptační kritéria, sekci Rozhodnutí
(u každého zamítnutá varianta a proč) a navržené schéma.2 · ADR
text
Přečti si Rozhodnutí ve story.md. Vyber to, které se nejhůř vrací a dotýká se
víc než jen této featury. Zapiš ho jako docs/adr/0001-<kratky-nazev>.md:
Status, Kontext, Rozhodnutí, Zvažované varianty (i zamítnuté a proč),
Důsledky (co se změní pro zbytek aplikace).
Přidej za něj řádek do docs/adr/README.md, rozcestníku všech ADR (když neexistuje,
založit ho): číslo, název, status, jedna věta.
Pak přidej do CLAUDE.md jednu řádku: před změnou datového modelu nebo struktury
aplikace se podívej do rozcestníku docs/adr/README.md.Hints
- Your delete is probably a real
DELETEtoday. If your ADR decides otherwise, the delete from week 5 changes too. That's the point of the ADR: one rule for the whole app. - Deleted means deleted everywhere. Check the feed, the replies, and the search from week 3.
- Rejected option missing from the ADR? Ask: "What did we decide against, and why?" An ADR without the alternatives is just a description.
Finished early?
- Reply to a reply.
- Another ADR.
Done means
story.mdhas no open questionsdocs/adr/0001-….mdrecords how Quacker deletes content and which option you rejected; it's listed in the indexdocs/adr/README.md, andCLAUDE.mdpoints to that index- in production: the feed shows at least one quack with replies
- deleting a quack with replies does what your ADR says, and its text shows up nowhere: not in the feed, the replies or the search
- merged into
main, deployed, posted in Seminars
Homework
Everything above merged and deployed by Sunday midnight. Post in the Seminars channel on Teams:
text
Live app: <URL>
Replies PR: <link>