# ADR-0005: Column type vocabulary

## Status

Accepted

## Context

Real RDBMS engines expose many type variants that exist for
historical, performance, or platform reasons. A learner does not
benefit from picking between `VARCHAR(255)`, `TEXT`, `CHAR(40)`,
and `CLOB`. We control the user-facing surface and can present a
small, semantically clear set of types that maps cleanly to the
chosen backend (SQLite STRICT, ADR-0002).

We also want to teach two distinct lessons about identifiers:

1. The default, easiest path: a simple auto-incrementing integer
   primary key. Used in 90% of intro examples.
2. Why integers aren't always the right answer: short random
   identifiers that survive merging data sets, sharing, or
   migration without collisions.

Real UUIDs (36 characters) are too wide to display comfortably in
TUI columns and exceed what learners actually need to understand
the concept.

## Decision

The user-facing column type vocabulary is:

| User-facing type | SQLite STRICT mapping | Notes                                     |
|------------------|-----------------------|-------------------------------------------|
| `text`           | `TEXT`                | Strings of any length.                    |
| `int`            | `INTEGER`             | Plain integer.                            |
| `real`           | `REAL`                | IEEE-754 double.                          |
| `decimal`        | `TEXT`                | Stored as decimal string; rendered numeric. |
| `bool`           | `INTEGER`             | 0/1 internally; `true`/`false` rendered.  |
| `date`           | `TEXT`                | ISO 8601 (`YYYY-MM-DD`).                  |
| `datetime`       | `TEXT`                | ISO 8601 (`YYYY-MM-DDTHH:MM:SS[.fff][Z]`).|
| `blob`           | `BLOB`                | Binary data.                              |
| `serial`         | `INTEGER PK AUTOINC.` | Auto-incrementing integer; PK by default. |
| `shortid`        | `TEXT`                | 10–12 char base58 random; PK by default.  |

`shortid` uses base58 (no ambiguous `0`/`O`/`I`/`l`) and is
generated client-side at insert time when the column has no value
supplied.

Decimal is stored as text to preserve precision — applications
that need numeric comparison must use the engine's casts; this is
acceptable for a teaching context and the constraint is documented.

**Compound primary keys are supported.** They are essential for
junction tables in m:n relationships (e.g. `OrderLines` keyed on
`(order_id, product_id)`) and skipping them would teach the wrong
lesson. The simplified DSL provides natural syntax for them
(specifics in a later ADR).

True UUIDs are intentionally **not** in the type set.

## Consequences

- The type system is small enough to teach in five minutes.
- Mapping to SQLite STRICT is mechanical and lossless for the
  intended use cases.
- The shortid generator is a small, well-tested utility — bounded
  scope, no third-party dependency required.
- Junction tables and other compound-key scenarios are
  first-class, reinforcing relational fundamentals.
- Learners who later need a true UUID column will find that the
  app does not provide one; this is a deliberate trade-off in
  favour of TUI legibility.
