# migrations are named

always generate migrations with an explicit snake_case feature name so files
read like a changelog (`0002_trail_social.sql`, `0005_trail_posts.sql`):

```
bun db:generate --name <snake_case_feature>
```

never accept drizzle-kit's random default name.

# raw sql subqueries must spell out correlated column refs

in a single-table select (no joins), drizzle renders interpolated schema
columns unqualified (`${schema.conversations.id}` → `"id"`), so inside a
raw `sql` subquery with its own from-alias the ref silently binds to the
inner table instead of correlating. write the outer table's columns as
literals (`conversations.id`) — see `unreadCountSql` in
`src/services/dms.ts`. joins qualify columns, which is why
`trailSummarySelect` gets away with interpolation.
