Brief
You are building Conduit, a Medium-style publishing platform: users register and log in, write and edit articles in Markdown, follow authors, favorite articles, comment, and browse a global or personalized feed filtered by tags. The twist: the product spec and the API contract are already fixed — the RealWorld project publishes both. Your job is everything the spec leaves open: architecture, data model, state design, testing, and delivery. Treat it as a real product handed to a senior engineer: no shortcuts you would not defend in review.
Instructions
Milestone 1 — the API
- Implement the full RealWorld endpoint set: authentication (register/login/current
user/update), profiles (+ follow/unfollow), articles (CRUD, list with tag/author/
favorited filters, personal feed, pagination via
limit/offset), comments, favorites, tags. - Architecture is hexagonal: a domain core with no framework or SQL imports; ports for persistence, identity, and clock; HTTP and Postgres as adapters. The domain is developed test-first.
- Auth: JWT via the
Authorization: Token <jwt>scheme; passwords hashed with a modern KDF (argon2/bcrypt); authorization enforced in the domain (only the author edits an article, etc.). - Errors follow the spec's
{"errors": {"field": ["message"]}}shape with correct status codes (401/403/404/422).
Milestone 2 — the frontend
- All Conduit pages: home (global/your feed, tag filter, pagination), auth pages, editor (create/edit), article view with comments and favoriting, profile with tabs, settings.
- State discipline is the assignment: server data lives in a query cache with explicit invalidation; filters, tab, and page number live in the URL (a refresh loses nothing); forms in a form library with field-level errors from the API's 422s; optimistic updates for favorite/follow.
- TypeScript strict; API types generated or hand-derived from the contract in one place; styling built on semantic design tokens.
Milestone 3 — quality
- Component/integration tests with Testing Library + MSW covering: feed rendering and pagination, auth flows including failure states, editor validation, favoriting with optimistic rollback on error.
- Playwright E2E for the money path: register → publish → see it in the feed → comment → favorite, running against the real API in CI.
- Accessibility:
axereports zero violations per page; the money path is completable by keyboard alone. - Performance: a Lighthouse/CWV budget file exists and CI fails when the home feed breaks it.
Milestone 4 — rendering migration
- Port the SPA to a meta-framework. The public feed and article pages render on the server (crawlable without JS); authenticated pages choose CSR/SSR deliberately, each choice written down.
- Measure TTFB, LCP, and INP on a throttled profile before and after; produce the comparison table and a paragraph of honest conclusions.
Milestone 5 — ship
- One-command local stack (compose or equivalent); production deploy of API + frontend + Postgres behind TLS.
- Structured JSON logs with request IDs across frontend → API; an uptime check on the feed; a tagged release deploys from CI with no manual steps.
Constraints
- The API contract is law: do not invent, rename, or "improve" endpoints — milestone 1 is judged by someone else's tests.
- No ORM-driven design: the domain model comes first, persistence adapts to it.
- No mocking your own modules in frontend tests; the network boundary (MSW) is the only seam.
- Each milestone lands as a reviewable PR train on its own;
mainis deployable after every merge.
Acceptance
- M1: the official RealWorld API test collection (Postman/newman) passes 100% against your endpoint; domain test suite runs without HTTP or DB; a fresh clone reaches green in one documented command.
- M2: every page functions against your API; a full-page refresh on any filtered/ paginated view restores the exact state from the URL; zero duplicated server state outside the query cache (code-reviewable claim).
- M3: CI runs unit + integration + E2E + axe + CWV budget and blocks on each; the E2E money path passes against a clean database.
- M4: public pages render meaningful HTML with JavaScript disabled; the before/after metrics table exists and the after is not worse on LCP.
- M5:
git tag→ live deployment with no human in the loop; logs show one request traceable end to end; the uptime check has fired at least once in anger (kill the API and watch it).
Related
- RealWorld full-stack build — the exercise note this is the subject of.
- RealWorld docs — the canonical spec, API contract, and test collection.
- Birthday Greetings — hexagonal extraction — subject — the small-scale rehearsal of the same architectural bar.