โš™๏ธ Deep Dive

State, Tasks & Time โ€” Under the Hood

The one-query list's real cost, transitions in code vs. constraints, and where the non-transactional writes are luck vs. design.

Anatomy of the one-query list

The application list (packages/db/src/applications.ts:384) is the most-read query in the product. It joins four tables, aggregates three document counts with FILTER clauses, and pulls the latest substate via a correlated subquery โ€” one round trip, any volume.

PieceCostNotes
Base join (apps ร— postings ร— companies)O(n)1:1 joins on primary keys; n = user's applications
Document left-joins before GROUP BYO(nยทd) intermediate rowsd = docs per application; the row explosion GROUP BY collapses
count(distinct) FILTER (where โ€ฆ) ร—3per-group hashingThree needs facts from one pass โ€” the FILTER clause is the star
Latest-substate correlated subqueryO(log e) per appIndex on application_events(application_id); LIMIT 1 descending
Transition check on writeO(1)Map lookup + array includes over โ‰ค3 elements
Weekly scoreboard countO(log n + k)Status + appliedAt predicates over the user-status index

Two scaling observations. First, count(distinct) is the expensive aggregate โ€” it must track seen IDs per group. At 100 applications it's invisible; at 100k rows-per-group you'd restructure (lateral subqueries per count, or counter columns maintained by triggers โ€” a stored-state tradeoff you'd now make with data). Second, the query has no LIMIT: it returns the user's entire pipeline. Fine at n=200; the pagination decision is deferred until a human actually has more applications than a screen โ€” deferral with a known exit, the recurring move in this codebase.

The read-model split matters for testability economics too: createApplicationReadModel(executeQuery) separates row-mapping (unit-tested with fixture rows, milliseconds) from SQL (integration-tested on PGlite, seconds). Fast tests get run; slow tests get skipped โ€” structuring code so the cheap tests cover the logic is performance engineering of the development loop itself.

The decision: transitions asserted in application code

Chosen
Transition map in core + assert at every write

The rule lives beside its unit tests โ€” every edge, valid and invalid, is enumerated in the suite.

Readable error messages ("Invalid transition: offer โ†’ saved") and self-loop allowance for idempotency.

Only enforced through the store โ€” raw SQL (a migration, a console session) can write any status.

Alternative
Database triggers / CHECK constraints

Enforced against every writer, including manual SQL.

Transition logic in PL/pgSQL: harder to test, version, and read; error messages surface as constraint violations.

Alternative
Full event sourcing (status = fold of events)

Perfect audit and time travel; transitions validated at fold time.

Read-side complexity everywhere for a product whose reads dominate. Wera keeps the events table as an audit log and the status as a column โ€” the hybrid that takes the cheap 80%.

Note the same hybrid on substates: they're events (latest one wins) while status is a column. The dividing line is query frequency โ€” status filters every list; substate renders on detail rows. Frequently-filtered facts earn columns and indexes; occasionally-read nuances can stay in the log. That's a transferable rubric, not a compromise.

Delivery semantics got the same explicit treatment: claimDueEmailReminders implements at-most-once. The alternative โ€” send first, mark after, retry on crash โ€” is at-least-once and needs consumer-side dedup (an idempotent send key at Resend). For deadline nudges, a rare missed email beats a double email that erodes trust in every future nudge. The semantics follow the product, not the other way around.

Where non-transactional is fine โ€” and where it's luck

Almost no multi-statement flow here runs in a database transaction (the HTTP driver makes interactive transactions awkward). Each case deserves its own verdict:

  • markApplied read-then-write: two simultaneous clicks both read ready_to_apply, both write applied. The second write is a self-loop โ€” harmless. The event log may record two mark_applied events: acceptable for an audit trail. Verdict: designed. The idempotency comes from the transition semantics, not a lock.
  • Applied-then-crash before task upsert: status flips but the follow-up task never appears. No retry exists (it's a server action, not a queued job). Verdict: accepted gap โ€” self-healing would mean deriving "needs follow-up task" the way needs-flags are derived, an exercise below.
  • Reminder stuck in sending: crash between claim and send. Visible via status, but nothing re-claims it automatically. Compare discovery's stale-running sweep โ€” the same pattern exists one module over and hasn't been applied here yet. Verdict: known debt with an in-repo precedent.
  • Weekly plan regeneration: generateWeeklyPlan deletes open items then re-inserts from current tasks โ€” but completed items survive (the delete filters status = 'open'). Re-planning never erases evidence of finished work. Verdict: designed, and quietly elegant.
โš ๏ธ
The lost-update that isn't

updateApplicationStatus is a classic check-then-act: read status, assert transition, write. Interleave two different transitions (close vs. apply) and the last write wins with no error โ€” a textbook lost update. Why is it tolerable here? Single user, and every path writes an event row, so the audit trail shows what happened even when the column's final value is the race's coin flip. Now imagine 100 users sharing a recruiting pipeline: you'd add optimistic concurrency (WHERE status = $expected on the UPDATE, exactly like the reminder claim). The fix pattern is already in the codebase โ€” recognizing when it must migrate from reminders to statuses is the senior-engineer judgment.

Make it yours

๐Ÿ›  Exercise 1
Make status updates race-proof

Rewrite updateApplicationStatus using the claim pattern: UPDATE โ€ฆ SET status = $to WHERE id = $id AND status = $from RETURNING *, and treat zero rows as "the world moved โ€” reload and retry." Update the unit tests for every transition edge.

Hint

The transition assert now runs BEFORE the update (using the caller's believed from), and the WHERE clause enforces it atomically. You've merged the check and the act.

๐Ÿ›  Exercise 2
Heal the stuck reminders

Port discovery's stale-sweep to reminders: at the start of each delivery run, reset sending rows older than N minutes back to scheduled. What delivery semantics did you just change โ€” and what new duplicate-email scenario did you create? Write it down before you decide N.

Hint

You moved from at-most-once toward at-least-once: a claim whose send actually succeeded but crashed before marking will be re-sent after N. That's the trade; make it visible in the run's return counts.

๐Ÿ›  Exercise 3
Derive the follow-up need

Design "needs follow-up task" as a derived flag (like needs-flags) instead of relying on markApplied's write-time task creation: applied-family status + no open follow-up task + appliedAt older than X days โ‡’ surface it. Which failure mode from Section 3 does this erase entirely?

Hint

The applied-then-crash gap disappears: a missing task is no longer a lost side effect, because the need is recomputed from facts on every read. Derivation as self-healing.

๐Ÿ“–
Aggregate expressions & FILTER โ€” PostgreSQL manual

The count(โ€ฆ) FILTER (WHERE โ€ฆ) construct powering three needs-facts in one query pass.

๐Ÿ“–
Transaction Isolation โ€” PostgreSQL manual

Lost updates, read committed, and what the database would and wouldn't have saved you from here.

๐Ÿ“–
CQRS โ€” martinfowler.com

The read-model idea behind createApplicationReadModel, including Fowler's warning about using the full pattern too eagerly โ€” advice this codebase visibly took.