Skip to content

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 instinctFull-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

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:

text
intent → prefetch → server scheduling → database reads → response transfer
       → React rendering → pending feedback → focus restoration

Checkpoint: 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:

NameWhat it isBest mental model
RedisIn-memory data server with persistence optionsThe storage/coordination substrate BullMQ uses
BullMQNode/TypeScript job-queue library on RedisJobs, retries, delays, workers, events
RabbitMQDedicated message broker, commonly using AMQPExchanges route messages to queues and consumers acknowledge delivery
MosquittoMQTT brokerLightweight topic pub/sub, especially device and telemetry communication
Graphile WorkerPostgreSQL-backed job runnerTransaction-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:

  1. Predict: before reading the source, write which layer should own the rule.
  2. Trace: follow the real call path and note every trust or failure boundary.
  3. 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.

Architecture checkpoints

Practice choosing the owning boundary

These scenarios test reasoning across the stack, not framework trivia.

Concurrency1 of 6

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?

Choose one answer
Score: 0

Suggested capstone exercises

These do not need to become product features. They are bounded architecture exercises:

  1. Draw the sequence diagram for invitation acceptance under two concurrent requests.
  2. Write a failure table for the prompt response path: database unavailable, notification write fails, cache revalidation fails, client disconnects after commit.
  3. Propose one real BullMQ notification handler with an idempotency key and durable delivery record.
  4. Calculate a database connection budget for one, two, and four web replicas given a fixed provider limit.
  5. Explain how you would deploy a nullable column, backfill it, make it required, and later remove the old field without downtime.
  6. Add one architecture decision to this site using constraint, decision, cost, and revisit trigger.

Continue with the system map, then follow the sequence above.

Built as a living architecture notebook for a personal project.