Building Apps with AILesson 11 of 87

Contents

Building Apps with AI

Lesson 11 of 87. Sign in to keep your place.

Module 2 · Saying what you want, precisely enough

The data model comes before the screens

9 min read

Which shape is this relationshipOne bookingMany bookingsOne customerOne to oneusually one tableOne to manylink on the many sideMany customersMany to onethe same, reversedMany to manyneeds a join tableSaying which one you have is most of the design. Many-to-many is the one a model skips, stuffing acomma-separated list into a text column instead, which works until you need to search it.
Saying which one you have is most of the design. Many-to-many is the one a model skips, stuffing a comma-separated list into a text column instead, which works until you need to search it.

Figure

Screens are cheap, data is not

A screen can be redrawn in ten minutes. A data model with a mistake in it is still with you in six months, because by then there are two thousand rows shaped by that mistake, code in nine files that assumes it, and a migration nobody wants to run.

So before the first screen, spend fifteen minutes on the nouns.

Write the nouns and what each one holds

For a salon booking app:

Text
customer   id, name, phone, created_at
stylist    id, name, works_monday..works_sunday
service    id, name, duration_minutes, price_paise
booking    id, customer_id, stylist_id, service_id,
           starts_at, status, created_at

Four nouns, about twenty fields, and you have just made every decision that matters. Notice what the writing forced you to settle:

A booking points at a service, so its duration comes from the service. Which means changing a haircut from 30 to 45 minutes changes every future booking, and possibly every past one. Is that what you want? You now have to answer, which is the point.

Price is price_paise, an integer. Money in floating-point numbers produces 0.1 + 0.2 = 0.30000000000000004, and eventually an invoice that is one paisa wrong and cannot be explained. Store the smallest unit as an integer, always. Rupees, cents, kobo, centavos.

status exists, so a cancelled booking is a booking with a status rather than a deleted row. Deleted rows cannot be counted, audited or restored.

The four relationship shapes

Almost everything is one of these, and saying which is most of the design:

One to many. One customer has many bookings. The many side holds the link: booking.customer_id. This is the common case and models get it right.

Many to many. A stylist can perform many services and a service can be performed by many stylists. This needs a third table: stylist_service with two ids and nothing else. Models often skip this and stuff a comma-separated list into a text column, which works until you need to search it.

One to one. Rare, and usually a sign that two tables should be one.

Belongs to nothing. A settings row, a price list. Fine, but ask whether it should belong to an account, because the day you have two salons the answer becomes yes and the migration is painful.

Three questions that prevent most redesigns

What happens when this is deleted? If a customer is deleted, do their bookings go? Stay as orphans? Keep the name as a snapshot? There is no default right answer, and the database will pick one for you if you do not.

What has to be true across two rows? “Two bookings cannot overlap for the same stylist” is not a property of one booking. It cannot be enforced by a field. It needs a check when writing, and ideally a constraint in the database, and it is exactly the rule a model will implement in the browser where it does nothing.

What do you need to know later that you are not storing? created_at on everything, always. The day somebody asks how many bookings you took in July, a missing timestamp means the answer does not exist and cannot be reconstructed.

Hand it over as text

The block of nouns above, pasted into your tool, is worth more than four paragraphs of description. It removes the guesswork about field names, which is what makes a model write customerName in one file and customer_name in the next.

One useful instruction to add: generate the schema from this and stop. Do not build any screens yet. Then read what came back and check the column types, because that is where the quiet decisions hide: a phone number stored as a number loses its leading zero, and a date stored as text cannot be sorted correctly.

Draw it if it helps

Four boxes and some arrows on paper is a perfectly good entity diagram. If you want it on a screen, draw.io and Excalidraw are free and need no account, and dbdiagram.io turns a text description into a diagram directly. None of this is required. The nouns list does the work; the picture only makes it easier to argue about.

The limitation

You will get this wrong the first time. Everybody does: the thing you learn in week three changes what week one should have been. That is not a reason to spend a month planning. It is a reason to know how to change a schema safely, which is a whole lesson later in this course, and to make the first version small enough that changing it is cheap.

Every lesson here is open. Your progress is recorded once you pass the Building with AI exam.

Check your understanding

A model stores a service’s price in a column of type decimal and a stylist’s list of services as a comma-separated text field. Which is the more serious problem, and why?

Pick the one you would defend. Your answer stays private.

Next lesson · 8 minSlicing a feature so every step is checkable

Stuck on something?Ask Beatriz, your AI tutor

How to cite: Addaly (2026) ‘The data model comes before the screens’, in Building Apps with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-apps-with-ai/the-data-model-before-the-screens (Accessed: 13 October 2026).