Tradeoff explorer
Good architecture is not a list of technologies. It is a set of decisions whose benefits exceed their costs under known constraints.
Architecture is constraints made explicit
Change the question, then compare the chosen boundary with plausible alternatives.
Two users can accept invitations concurrently. A UI check cannot serialize those writes.
PostgreSQL constraints + domain transactions
React state
Only describes one browser and disappears on refresh.
Route-only checks
Two server requests can pass the same check before either commits.
Distributed locks
Adds a new failure mode when a row lock and database trigger already solve it.
The recurring decision pattern
EverDuet uses a four-part record for important choices:
- Constraint: what is true about the product or operating environment?
- Decision: what boundary or mechanism fits that constraint?
- Cost: what new complexity or limitation does the decision introduce?
- Trigger: what evidence would justify revisiting it?
Example: offset pagination
| Part | EverDuet answer |
|---|---|
| Constraint | The published prompt library is small and users benefit from direct page numbers. |
| Decision | Use indexed offset pagination. |
| Cost | Deep offsets eventually scan and discard more rows. |
| Trigger | Thousands 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
Change the evidence, not the ambition
These are teaching thresholds, not capacity promises. They show which decisions depend on scale.
- 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 choice | Evidence that changes it |
|---|---|
| One web replica | Sustained traffic or availability needs exceed one process |
| Instance-local rate limiting | A second replica makes enforcement inconsistent |
| Offset prompt pagination | Measured query degradation at large history depth |
| PostgreSQL private reads | Repeated expensive reads dominate traces and have a clear invalidation owner |
| Queue canary only | Optional retry-safe follow-up work dominates request latency |
| One Compose release | A service needs independent ownership, scaling, or availability |
| GitHub-rendered internal docs | The 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.