Lesson 1 · Foundations

Postgres & the relational model

Tables, rows, relationships — the model everything else rests on.

Your win: explain what a relational database is, and why we reach for an RDBMS like Postgres instead of a plain key-value store — grounded in the emails table your services already read and write.

Data lives in tables

A relational database organises data into tables (formally, relations). A table is a set of rows, and every row has the same fixed set of typed columns.1 That's it — but the discipline of "every row has the same shape, and the database enforces it" is what makes it powerful.

table: emails ┌────────────┬──────────────┬──────────┬──────────────┬────────────┐ │ email_id │ subject │ status │ resource_path│ deleted_at │ ← columns ├────────────┼──────────────┼──────────┼──────────────┼────────────┤ │ 01H8X… │ Welcome │ SENT │ jprep │ (null) │ ← a row │ 01H8Y… │ Reset link │ QUEUED │ jprep │ (null) │ └────────────┴──────────────┴──────────┴──────────────┴────────────┘

Tables relate to each other

The "relational" part is that tables reference one another. Each email has many recipients, stored in a separate email_recipients table that points back via a foreign key. The database refuses to store a recipient for an email that doesn't exist — referential integrity, enforced for you.

Why an RDBMS (not a key-value store)? Four things you get that a plain KV store doesn't: (1) a declarative query language — SQL, where you say what you want and the database decides how; (2) enforced structure & constraints (types, unique, foreign keys); (3) ACID transactions (all-or-nothing changes); (4) the ability to join & aggregate across tables.

Your code, exactly

The emails table is a real relation defined in a migration; spike reads and writes it every time someone sends an email:

migrations/notificationmgmt/1004_migrate.up.sql · internal/spike/.../domain/model/email.go
CREATE TABLE emails (
    email_id      text,              -- the primary key column
    subject       text,
    content       jsonb,
    resource_path text NOT NULL,     -- the tenant (Part 6)
    CONSTRAINT pk__emails PRIMARY KEY (email_id)
);
Anchor In Go this table is the Email struct (email.go:9) — one Go field per column, mapped by FieldMap(). ⚠️ Note: spike has no database of its own — the emails table lives in the notificationmgmt DB that spike reads/writes. (DB ownership is mapped in repo-postgres-map.md.)

SQL is declarative — remember this

When you write SELECT … WHERE …, you don't tell Postgres how to find the rows (scan? use an index? which join order?). You describe the result; the query planner figures out the plan. That separation is the whole reason indexes and query tuning (Parts 3–4) are a thing — you influence the how indirectly.

Read this next

PostgreSQL Tutorial — relational concepts & SQL

The official gentle intro to relational databases and the SQL language. Pair with the example-driven PostgreSQL Tutorial site.

postgresql.org/docs — tutorial
postgresqltutorial.com

Check yourself (from memory)

Q1. In the relational model, data is organised into…

Tables (relations): rows with a fixed set of typed columns, related to each other via keys.

Q2. SQL is a…

You describe the result; the planner decides how to compute it. That's why tuning (Parts 3–4) exists.

Q3. A foreign key exists to…

It enforces referential integrity — you can't reference a row that doesn't exist (e.g. a recipient for a missing email).
What is a relational database, and what does an RDBMS give you over a plain key-value store?
recall, then click to reveal
A relational database stores data in tables (relations) — sets of rows with fixed, typed columns — and expresses relationships via keys (e.g. email_recipients references emails). Over a plain KV store, an RDBMS like Postgres adds: a declarative query language (SQL — say what, it decides how), enforced structure & constraints (types, NOT NULL, unique, foreign keys), ACID transactions, and the ability to join & aggregate across tables.
Curious how Postgres compares to MySQL, or where a NoSQL/document store fits? Ask me. I'm your teacher for this course.

1. PostgreSQL — The relational data model.