# v-b0 — Baseline

**New concepts:** none. This is the floor — a database and an auto-generated REST
API over it, and nothing else.

## What's here
- `db` — PostgreSQL 16.3
- `apiserver` — PostgREST 13, auto-generating a REST API from the schema
- `init.sql` — one table (`candidates`) with seed data

## Deliberate anti-patterns (we fix these on purpose, later)
| Anti-pattern | Fixed in |
|---|---|
| PostgREST connects as the Postgres **superuser** | v-b3 |
| Password inline in `compose.yml` | v-b4 |
| **Ephemeral** storage — data dies on teardown | v-b1 |
| Implicit default network | v-b1 |
| `depends_on` waits for container start, not DB readiness | v-b2 |

## Run it
```
docker compose up -d
curl http://localhost:3000/candidates
```
Expect a JSON array of five candidates.

## Verification (prove the concept AND the failure mode)
1. **API works:** `curl http://localhost:3000/` returns the OpenAPI root.
2. **Data reads:** `curl http://localhost:3000/candidates` returns 5 rows.
3. **Prove ephemeral storage (the pain that motivates v-b1):**
   ```
   curl -X POST http://localhost:3000/candidates -H "Content-Type: application/json" -d '{"name":"Ginny"}'
   docker compose down
   docker compose up -d
   curl http://localhost:3000/candidates
   ```
   Ginny is **gone**. Only the 5 `init.sql` rows come back. Storage did not persist.

## Teardown
```
docker compose down
```

## Secrets policy

**Local-only dev defaults.** The Basic tier keeps clearly-labelled literals so the lesson runs with no setup: `devpassword` (postgres superuser, inline in `compose.yml`). They are teaching values: **never reuse them** anywhere reachable from a network, and never copy them into a real deployment. Every published port in this variant binds to `127.0.0.1` only. Real, random, per-install secrets start at v-b8 (generated by `install.sh`) and the Intermediate tier (v-i2…v-i5). A committed `.env.secret` is never acceptable; only `*.example` files are tracked.
