A full-stack learning path
This curriculum assumes you are already comfortable reading and changing application code. It does not begin with HTML, TypeScript syntax, or CRUD. It focuses on the places where owning a complete production system requires a different mental model than owning one code path.
Your strongest starting instincts
The architecture work behind EverDuet repeatedly starts from useful engineering questions:
- Does the user-visible flow feel immediate?
- Is this complexity justified for today's workload?
- Can developers make a change confidently?
- Is the project understandable enough to maintain?
- What happens when usage grows?
- Why this technology instead of the popular alternative?
Those are systems questions already. The learning goal is to connect each instinct to the mechanism that answers it.
| Existing instinct | Full-stack mechanism to deepen |
|---|---|
| “This page should return instantly” | navigation phases, request waterfalls, cache scope, query plans |
| “Don't over-engineer” | explicit scale triggers and failure-cost analysis |
| “Why BullMQ?” | delivery semantics, idempotency, broker versus library versus protocol |
| “Tests should be blazing fast” | risk-based test tiers, deterministic contracts, resource budgets |
| “The build uses too much memory” | process topology, peak concurrency, container build graphs |
| “Make maintenance automatic” | release gates, health semantics, migrations, dependency policy |
Recommended order
1. Learn to place truth
Read data model and invariants, then inspect the relationship migration and packages/core/src/relationships.ts.
Focus on the difference between:
- a TypeScript type;
- a route validation rule;
- a domain authorization rule;
- a transaction;
- a database invariant.
Checkpoint: explain why disabling a button prevents duplicate intent but cannot prevent a database race.
2. Separate identity from permission
Read authentication and security, then trace one cookie-authenticated route and one bearer-authenticated /api/v1 route.
Focus on:
- session versus access token;
- authentication versus resource authorization;
- CSRF versus token replay;
- public API contract versus internal domain operation.
Checkpoint: given a valid token, list every fact the server still must load before revealing a partner answer.
3. Treat performance as a path
Read performance and caching, then inspect the prompt route and navigation components.
Break one navigation into:
intent → prefetch → server scheduling → database reads → response transfer
→ React rendering → pending feedback → focus restorationCheckpoint: if the query is 12 ms but navigation is 900 ms, name three measurements you need before adding Redis.
4. Learn distributed-work semantics
Read queues and asynchronous work, then run the queue canary locally if Redis is available.
Focus on:
- at-least-once delivery and duplicate work;
- producer versus worker retry behavior;
- idempotent handler design;
- durable event state versus transient queue state;
- operational health beyond a Redis
PING.
Checkpoint: design a notification job payload that contains no private answer content and can be safely retried.
5. Read deployment as executable architecture
Read operations on Coolify, then follow the Dockerfile and both Compose files.
Focus on:
- image build versus container runtime;
- one-shot migration completion versus long-running health;
- private network exposure versus public routing;
- release dependency ordering;
- production verification versus “the deploy command returned.”
Checkpoint: explain why a healthy old web container is safer than starting new code after a failed migration.
6. Connect confidence to risk
Read testing and delivery, then inspect scripts/test-changed-plan.mjs and its tests.
Focus on choosing the cheapest test that can observe the failure:
- unit for pure rules;
- real PostgreSQL for concurrency and triggers;
- route tests for HTTP contracts;
- browser tests for auth and interaction;
- Compose for release ordering.
Checkpoint: identify a bug that a Prisma mock can never prove is fixed.
Message queue vocabulary bridge
These names live at different abstraction levels:
| Name | What it is | Best mental model |
|---|---|---|
| Redis | In-memory data server with persistence options | The storage/coordination substrate BullMQ uses |
| BullMQ | Node/TypeScript job-queue library on Redis | Jobs, retries, delays, workers, events |
| RabbitMQ | Dedicated message broker, commonly using AMQP | Exchanges route messages to queues and consumers acknowledge delivery |
| Mosquitto | MQTT broker | Lightweight topic pub/sub, especially device and telemetry communication |
| Graphile Worker | PostgreSQL-backed job runner | Transaction-friendly jobs without a separate Redis broker |
The important comparison is not popularity alone. Ask which semantics the workload needs, which system is already operated, and whether a dedicated broker's routing and delivery features justify its cost.
For EverDuet, BullMQ is a small TypeScript-friendly learning seam on private Redis. RabbitMQ would teach richer broker topology but add an operator. MQTT is designed around topic-based device communication, not durable application jobs. Graphile Worker would reuse PostgreSQL but was not the chosen ecosystem investment.
Scope guardrails
Part of full-stack ownership is knowing which legitimate concerns do not deserve attention yet. EverDuet keeps these choices explicit:
- native mobile stays a far-future possibility, so the domain remains client-neutral without building mobile infrastructure;
- email delivery stays out because it adds a paid external service without improving the current personal workflow;
- disk-capacity engineering is deferred because storage is not a measured constraint;
- queue infrastructure is a learning-ready seam, not permission to move ordinary request work into jobs;
- new product features are less valuable now than a calm UI and low-maintenance release path.
This is not ignoring architecture. It is architecture constrained by evidence. Record the trigger that would reopen a decision, then spend attention on the boundaries that are already real.
How to study each lesson
Use a three-pass loop:
- Predict: before reading the source, write which layer should own the rule.
- Trace: follow the real call path and note every trust or failure boundary.
- Challenge: change one constraint—two replicas, 10,000 prompts, unavailable Redis—and decide what must change.
Avoid memorizing the exact EverDuet implementation. The transferable skill is recognizing ownership, consistency, and failure semantics in a new system.
Practice choosing the owning boundary
These scenarios test reasoning across the stack, not framework trivia.
Two invitation-accept requests reach different web processes at nearly the same time. Both read one active member.
What should finally prevent a third active member?
Suggested capstone exercises
These do not need to become product features. They are bounded architecture exercises:
- Draw the sequence diagram for invitation acceptance under two concurrent requests.
- Write a failure table for the prompt response path: database unavailable, notification write fails, cache revalidation fails, client disconnects after commit.
- Propose one real BullMQ notification handler with an idempotency key and durable delivery record.
- Calculate a database connection budget for one, two, and four web replicas given a fixed provider limit.
- Explain how you would deploy a nullable column, backfill it, make it required, and later remove the old field without downtime.
- Add one architecture decision to this site using constraint, decision, cost, and revisit trigger.
Continue with the system map, then follow the sequence above.