Skip to content

Tradeoff explorer

Good architecture is not a list of technologies. It is a set of decisions whose benefits exceed their costs under known constraints.

Decision lab

Architecture is constraints made explicit

Change the question, then compare the chosen boundary with plausible alternatives.

Constraint

Two users can accept invitations concurrently. A UI check cannot serialize those writes.

Chosen

PostgreSQL constraints + domain transactions

Not now

React state

Only describes one browser and disappears on refresh.

Not now

Route-only checks

Two server requests can pass the same check before either commits.

Not now

Distributed locks

Adds a new failure mode when a row lock and database trigger already solve it.

Revisit triggerRevisit only if relationship state moves outside one PostgreSQL authority.

The recurring decision pattern

EverDuet uses a four-part record for important choices:

  1. Constraint: what is true about the product or operating environment?
  2. Decision: what boundary or mechanism fits that constraint?
  3. Cost: what new complexity or limitation does the decision introduce?
  4. Trigger: what evidence would justify revisiting it?

Example: offset pagination

PartEverDuet answer
ConstraintThe published prompt library is small and users benefit from direct page numbers.
DecisionUse indexed offset pagination.
CostDeep offsets eventually scan and discard more rows.
TriggerThousands of prompts plus materially slower measured queries.

“Cursor pagination scales better” is true but incomplete. It also changes navigation semantics and implementation complexity. The trigger makes the tradeoff concrete.

Decisions that optimize learning

Some boundaries exist partly because this is an architecture-learning project.

Public API

The web app is the only planned client, but a small OpenAPI boundary teaches client-neutral authorization and contract generation. The cost is another test and validation surface. The boundary stays narrow to keep that cost bounded.

BullMQ worker

The queue foundation teaches typed async contracts, retries, and worker lifecycle. The cost is Redis and another container. No product mutation is moved there until traces justify eventual consistency.

Separate admin app

The split teaches service authorization and release topology while reducing accidental admin exposure. The cost is duplicated Next.js build overhead and some shared-shell repetition.

Learning value can justify complexity in a personal project—but it should be named honestly instead of disguised as a scale requirement.

Decisions driven by emotional safety

Product context changes engineering tradeoffs:

  • partner answers are never cached casually;
  • reveal state is explicit server state, not a client animation convention;
  • old relationship responses keep their original scope;
  • notifications avoid putting intimate text into event payloads;
  • optimistic UI is used only where recovery and user understanding remain clear.

Privacy is not only a security checklist. It changes data identity, cache design, logs, queue payloads, and UX states.

Try changing the scale evidence

Scale simulator

Change the evidence, not the ambition

These are teaching thresholds, not capacity promises. They show which decisions depend on scale.

What changes at this shape?
  • Keep the simple in-process limiter; there is only one authority to coordinate.
  • Keep offset pagination because direct page navigation is useful and the collection is small.
  • Do not add replicas or caches without latency, connection, or throughput evidence.

When “not now” becomes “yes”

Current choiceEvidence that changes it
One web replicaSustained traffic or availability needs exceed one process
Instance-local rate limitingA second replica makes enforcement inconsistent
Offset prompt paginationMeasured query degradation at large history depth
PostgreSQL private readsRepeated expensive reads dominate traces and have a clear invalidation owner
Queue canary onlyOptional retry-safe follow-up work dominates request latency
One Compose releaseA service needs independent ownership, scaling, or availability
GitHub-rendered internal docsThe learning content benefits from navigation and interaction—this site was that trigger

A checklist for future decisions

Before adding infrastructure, ask:

  • What measured problem does it solve?
  • Which current source of truth remains authoritative?
  • What happens when the new component is unavailable?
  • How is work retried, deduplicated, or reconciled?
  • Who owns invalidation or lifecycle cleanup?
  • Can the release gate prove the new path works?
  • What specific signal would cause us to remove or replace it?

Continue with the guided code tour to connect these choices to files.

Built as a living architecture notebook for a personal project.