Skip to content

Project stage 3: Add and connect an Express API

You will complete and integrate Stage 3 of Delivery Board. The accepted application will run as two local processes: an Express API owns the work-item collection, and the React client consumes that API through a validated adapter.

The finished stage will keep loading, populated, empty, failure, retry, update-pending, update-success, and update-failure results distinct. It will also add one independently specified API variation: an optional status query on the collection route. Automated tests, deliberate failure checks, real-browser evidence, review, and fresh-clone recovery will protect the complete connection.

This assignment does not add a database, authentication, public server, or PHP runtime. PHP remains a valid alternative server stack. Delivery Board uses Node, Express, and TypeScript so you can apply the same JavaScript-derived model across client and server while concentrating on transferable HTTP, JSON, validation, testing, and process boundaries.

What you will practice

  • Integrate an Express application, in-memory store, runtime validation, HTTP routes, and a React API adapter into one coherent local system.
  • Extend an API from a written request-and-response contract without weakening its existing behavior.
  • Treat route parameters, query values, request bodies, and successful response JSON as untrusted runtime input.
  • Distinguish server-owned state, validated client state, URL state, derived interface values, and temporary request state.
  • Use automated tests and controlled failures to prove selected server and client contracts.
  • Verify two cooperating processes through direct HTTP checks and real browser interaction.
  • Review, document, integrate, and recover a connected application with an explainable Git history.
  • Explain which implementation details are TypeScript-specific and which API responsibilities transfer to PHP.
  • New: A six-record server seed, optional status query contract, query runtime validation, three query tests, one payload-limit test, Stage 3 evidence document, server and client sensitivity proofs, complete connected-system review, accepted integration, and fresh-clone two-process recovery.
  • Reused: The private Delivery Board repository, feature/express-api, the three lesson commits, Express 5, Node 24 LTS, TypeScript, the application and listener split, in-memory store, four existing routes, JSON error envelope, Vitest, Supertest, React Testing Library, validated fetch adapter, Vite proxy, loading and mutation states, Sass, README, GitHub pull requests, and the Stage 2 collaboration workflow.

Starting point

Before you start

  • Project stage 2 is accepted on the private repository remote main branch.
  • The completed server-foundation, API-development, and API-consumption lessons exist as separate commits on feature/express-api.
  • The branch is clean. Client and API tests, typecheck, lint, build, direct HTTP checks, and the current connected browser matrix pass.
  • The Express process owns a copied in-memory collection. Restarting the process restores its seed data.
  • The React client requests relative /api paths and validates every successful response before accepting it as state.
  • One branch author and a different reviewer are available. An approved individual route uses the teacher as reviewer.
  • Use fictional data only. Do not add personal data, credentials, secrets, real customer records, or private school information.
  • No starter download, second product repository, database service, hosting account, or PHP installation is required.
Current state
The guided feature branch contains a working connected application with the original server seed, eight API tests, and the client tests from the lessons. It does not yet contain independent data variation, the required status-query contract, Stage 3 evidence, complete product review, accepted integration, or fresh-clone recovery.
First action
Open the Delivery Board repository, run git fetch origin, git status, and git log --oneline origin/main..HEAD, then record the branch author, reviewer, current head commit, existing route contracts, test counts, and first active checkpoint in docs/stage-3-verification.md.
First checkpoint
The evidence document identifies the exact branch and base, maps every required API and connected-client contract, and records the passing guided baseline before product source changes.
Help trigger
Open the assistance beside the current checkpoint or ask for help if the branch base is unclear, a lesson commit is missing, two contributors plan to edit the same branch, a request changes the wrong process, a query value reaches the store before validation, one test changes another test's data, the client accepts invalid success JSON, a retry or update failure loses the last trusted state, the Vite proxy hides a direct API problem, review feedback lacks an observable result, or integration would require a force push.

Requirements

The required assignment is complete when every applicable criterion below is met.

Deliverables and product boundary

  • Continue the existing private Delivery Board repository. Do not create a second product repository or replace its Git history.
  • Deliver the accepted Stage 3 result on remote main through one reviewed feature/express-api pull request.
  • Preserve the three lesson outcomes as separate focused commits. Add focused assignment commits for data and query variation, test expansion, evidence, and review responses when required.
  • Update README.md and add docs/stage-3-verification.md with current contracts, ownership, test results, browser evidence, review, limits, and recovery.
  • Keep node_modules, dist, coverage output, temporary screenshots, credentials, local environment files, and private reflections outside Git.

Server architecture and data ownership

  • Keep server/app.ts responsible for Express configuration and server/index.ts responsible for process configuration and the local listener.
  • Keep createApp injectable so each API test can use a fresh application and fresh store without opening the normal port.
  • Keep the work-item store responsible for a copied collection and copied return values. Route handlers must not expose a mutable store array.
  • Submit at least six fictional server-owned work items with unique IDs, nonempty text, unique labels within each item, and at least two items in each supported status.
  • Keep WorkStatus limited to planned, active, or done and WorkItem limited to id, title, description, status, and labels.
  • Keep all API responses under /api on Cache-Control: no-store and keep X-Powered-By disabled.
  • Keep JSON request parsing at a 10kb limit and keep malformed and oversized JSON responses inside the documented error envelope.
  • Keep process memory as the only persistence layer. A normal Express restart must restore the committed seed.

Required API contracts

  • Keep GET /api/health with its existing 200 health representation.
  • Keep GET /api/work-items without a query as status 200 and the complete collection envelope.
  • Keep GET /api/work-items/:itemId as status 200 for a known item and status 404 with WORK_ITEM_NOT_FOUND for an unknown item.
  • Keep PATCH /api/work-items/:itemId/status as status 200 for a valid change, status 400 for invalid input, and status 404 for an unknown item.
  • Keep API_ROUTE_NOT_FOUND distinct from a missing work-item resource.
  • Add optional GET /api/work-items?status=<status>. One planned, active, or done value returns status 200 and only matching records in the normal collection envelope.
  • Treat an absent status query as the complete collection. Do not treat an empty status value as absent.
  • Return status 400 with error code INVALID_STATUS_FILTER when status is empty, unsupported, or supplied more than once.
  • Validate the query value before calling a filtered store operation. Do not use an assertion or cast to turn external input into WorkStatus.
  • Keep exact route ordering so a collection query reaches the collection handler and static API paths are not mistaken for item IDs.
  • Document every required method, path, input, success status, response shape, failure status, and error code before implementing the query variation.

React client and trust boundary

  • Keep all client requests relative to /api. Only Vite configuration may name the local Express target.
  • Keep one replaceable WorkItemsApi boundary outside React components and inject a deterministic implementation in client tests.
  • Treat every response body as unknown until its envelope, exact item keys, values, label uniqueness, and collection ID uniqueness pass runtime validation.
  • Keep network, HTTP, JSON, and contract failures distinct inside the adapter and expose only concise safe messages to the interface.
  • Keep initial loading, populated success, empty success, initial failure, retry loading, update pending, and update failure as observable results.
  • Abort or ignore an obsolete collection result so an older request cannot replace the current result.
  • Wait for a validated update representation before replacing an item. Confirm that the returned ID and status match the request.
  • Disable status-update actions while one update is pending and identify the selected pending action in visible and accessible text.
  • Keep the last accepted item after update failure, show retryable feedback, and move focus to that stable feedback.
  • Keep filtered-card focus recovery after successful status updates.
  • Keep the client fixture deleted. The server seed is the only work-item fixture used by the running application.
  • The client may keep its existing local status filter. The new server query must not replace the client filter unless the team also redesigns counts, route loading, caching, and tests as an optional extension.

Automated tests and failure evidence

  • Provide at least twelve API tests. Keep the eight guided contracts and add valid status query, invalid status query, repeated status query, and oversized JSON body contracts.
  • Create a fresh application and seed for each API test. No API test may depend on another test running first.
  • Use Supertest against the Express application rather than opening or reusing port 3000.
  • Provide at least twelve client tests across focused adapter, component, and routed-application boundaries.
  • Keep the eight Stage 2 user contracts and cover initial loading, failed load and retry, invalid successful API response, and failed update without local mutation.
  • Use semantic queries and visible results for component behavior. Use transport inputs and returned or rejected values at the adapter boundary.
  • Run one controlled server mutation that incorrectly accepts an invalid query value and prove that the selected API test fails for the intended reason.
  • Run one controlled client mutation that incorrectly accepts invalid successful JSON or mutates state before update success and prove that the selected client test fails for the intended reason.
  • Restore each mutation immediately. The final suite must contain no .only, .skip, deliberate defect, stale debug output, changed seed, or unexplained snapshot.
  • Make npm test, npm run typecheck, npm run lint, and npm run build pass from the committed dependency graph.

Accessibility and connected browser behavior

  • Keep one stable main element and one page h1 for every rendered route result, including loading and initial failure.
  • Use native links, buttons, selects, headings, lists, articles, labels, and status or alert regions for their intended semantics.
  • Keep every required action operable with pointer, Tab, Shift+Tab, Enter, Space, and native select keys as appropriate.
  • Keep visible focus through route navigation, retained card actions, filtered-card removal, initial retry, and failed status updates.
  • Do not communicate loading, failure, pending state, current route, filter state, or work status through color alone.
  • Meet WCAG AA text contrast and preserve a visible focus indicator in the selected design.
  • Keep required content usable at 320 CSS pixels and 200 percent browser zoom without clipped text, overlapping controls, or horizontal page scrolling.
  • Verify direct API responses separately from proxied browser behavior so a working Vite page does not hide a stopped or incorrect Express process.

Collaboration, documentation, and delivery

  • Assign one branch author, one reviewer, and one integration owner. The author and reviewer must be different people.
  • Use the teacher as reviewer for an approved individual route. Do not create another account or simulate review.
  • The pull request must state the outcome, API contracts, client states, commit sequence, automated evidence, process and browser evidence, known limits, and requested review focus.
  • The reviewer must run or inspect both processes and record one specific API observation, one connected-client observation, and one source-or-test observation.
  • When no defect is found, the reviewer must state the exact request, interaction, and relationship that passed. Do not invent a defect.
  • The author must respond to every review item with a focused change or an evidence-based explanation and repeat the affected verification.
  • Update the feature branch from remote main through an ordinary merge when it is behind. Do not force push through unexplained history.
  • Merge only after approval and final passing checks. Preserve focused commits with a merge commit when the repository supports it.
  • After integration, every contributor must pull remote main, install committed dependencies, repeat the full gate, and finish on clean synchronized main.
  • Verify the complete two-process result from a fresh clone without a source edit.
  • Keep private personal reflection in Teams, not in the shared repository.

Design freedom

  • Choose the fictional work-item titles, descriptions, labels, IDs, and initial distribution within the required data boundaries.
  • Choose the internal name and module location for the status-query parser when its ownership remains clear and tests exercise its public result.
  • Choose whether filtering happens in the store or a route-owned copy after query validation. The store must still protect its owned collection.
  • Choose the color palette, type stack, spacing, surfaces, and responsive card layout within the accessibility requirements.
  • Choose which valid and invalid status values support the two sensitivity proofs.
  • Choose whether the reviewer uses a separate clone or an existing clean working copy.

Out of scope for Stage 3

  • Do not add a database, ORM, authentication, authorization, user account, token, session, secret, payment, file upload, email service, or production API host.
  • Do not add unrestricted CORS. The required client uses the Vite development and preview proxy on one browser origin.
  • Do not add PHP as a second required runtime. Compare concepts in documentation without maintaining duplicate servers.
  • Do not add WebSockets, server-sent events, offline synchronization, optimistic concurrency, background jobs, or multi-user conflict resolution.
  • Do not add a runtime-schema library, global client state library, query cache library, CSS framework, server-side rendering, or Docker unless approved as separate optional research.
  • Do not require public deployment, continuous integration, coverage percentages, browser automation, load testing, or security certification.
  • Do not add Capacitor, Android, iOS, native plugins, app-store accounts, emulators, or physical-device requirements yet.
  • Do not include optional extension work in the required estimate, definition of done, or assessment result.

Stage 3 is complete when every applicable requirement above is met and all of these results are true:

  • feature/express-api contains focused foundation, API, connection, product-variation, test, and evidence history based on accepted Stage 2 main;
  • the Express server owns six or more valid fictional records and resets them on process restart;
  • every required health, collection, filtered collection, item, status-update, malformed-body, oversized-body, missing-resource, and missing-route contract returns the documented status, headers, and JSON shape;
  • the React client accepts only validated collection and update representations and exposes every required load and update state with intentional focus behavior;
  • twelve or more API tests and twelve or more client tests pass in one deterministic command, and the two controlled mutations prove selected tests can fail for their intended reasons;
  • typecheck, lint, test, and build pass from the committed dependency graph;
  • direct HTTP requests plus development and built-preview process pairs pass the required success, failure, retry, restart, route, keyboard, focus, 320-pixel, 200%-zoom, overflow, and Console checks;
  • README and docs/stage-3-verification.md state the tested commit, contracts, process order, evidence, review, PHP transfer, limits, and recovery path;
  • a different person has reviewed the API, connected behavior, and one source-or-test relationship, and every review item has an author response;
  • the approved branch is merged, remote and local main contain the Stage 3 result, and every normal working tree is clean;
  • a fresh clone passes install, all automated checks, build, direct API smoke checks, and the connected browser smoke path without a source edit; and
  • the Teams submission contains the repository, pull request, final commit, roles, evidence, and reflection described below.

Checkpoint 1: Establish the Stage 3 evidence contract

Section titled “Checkpoint 1: Establish the Stage 3 evidence contract”

Only the branch author edits feature/express-api. The reviewer works from a separate working copy or waits for a published review state. Do not alternate uncoordinated writes to one branch.

Inspect the current relationship:

Identify the Stage 3 branch
git status
git branch --show-current
git fetch origin
git log --oneline origin/main..HEAD
git log --oneline HEAD..origin/main
npm ci
npm test
npm run typecheck
npm run lint
npm run build

Continue only when:

  • the working tree is clean;
  • the branch is feature/express-api;
  • the three lesson commits appear after the accepted Stage 2 base;
  • current server and client tests pass; and
  • any newer accepted main work is understood and merged before product changes.

If remote main contains accepted work that the branch lacks, merge it normally:

Integrate current remote main when required
git merge --no-edit origin/main
npm test
npm run typecheck
npm run lint
npm run build

If a conflict stops the merge, inspect each conflict against the final Stage 3 contract. Abort with git merge --abort when the intended combined result is unclear. Do not force push to conceal the difference.

Create docs/stage-3-verification.md:

docs/stage-3-verification.md — starting structure
# Stage 3 verification: Express API and connected client
## Ownership and tested state
- Branch author:
- Reviewer:
- Integration owner:
- Feature branch: feature/express-api
- Current feature commit:
- Stage 2 base commit:
- Node and npm versions:
- Browser and operating system:
- Test data: Fictional work items only
## API contracts
| ID | Request | Expected result | Plausible regression | Evidence state |
| --- | --- | --- | --- | --- |
| API-01 | GET /api/health | 200 health JSON | Process runs but route is absent | Not verified |
Add API-02 through API-12 before product changes.
## Client contracts
Add CLIENT-01 through CLIENT-12 from the requirements.
## Automated and sensitivity evidence
## Direct HTTP and process evidence
## Connected browser evidence
## Review and responses
## Limits and Stage 4 handoff

Map API-01 through API-12 to health, full collection, valid status filter, invalid status filter, repeated status filter, known item, missing item, valid update, invalid update, malformed JSON, oversized JSON, and missing API route.

Map CLIENT-01 through CLIENT-12 to the eight accepted Stage 2 client contracts plus initial loading, initial failure and retry, invalid successful response, and failed update without local mutation.

Record a command result as Pass, Issue, or Blocked. A blocked result names the missing condition and next action. It is not a pass.

Assistance 1 — Identify the branch and evidence owners

Use git branch –show-current, git status, and both log comparisons. Name the person who can push the feature branch, the different person who will review it, and the person who will merge after approval.

Assistance 2 — Separate the two test portfolios

API contracts start from method, URL, headers, body, status, and JSON. Client contracts start from rendered state, user action, accessible result, retained data, and focus. A client test does not replace an API test, and an API test does not prove browser behavior.

Assistance 3 — Build the 24-row contract map

Copy the twelve API and twelve client names from this checkpoint. For each row, add one plausible wrong result. Use that wrong result to decide whether existing evidence is sufficient or a focused test is still required.

Checkpoint: The connected branch has a testable evidence contract

What now works
The exact base, branch, roles, guided commits, package versions, twelve API contracts, twelve client contracts, baseline commands, and first unverified result are recorded before product source changes.
Files changed
docs/stage-3-verification.md, README.md, Local and remote Git history
What remains
Adapt the server-owned data and implement the independently specified status-query contract without changing accepted client behavior.
Next action
Write the status-query request, success, and failure examples in README, then select six fictional seed records that meet the required distribution.
If it does not work
Return to the last clean feature commit, compare it with remote main again, and restore the 24-row evidence map before editing server source.

Checkpoint 2: Adapt the API and add the status query

Section titled “Checkpoint 2: Adapt the API and add the status query”

Write the contract before source code:

README.md — required collection-query contract
GET /api/work-items
→ 200 {"data":[all current work items]}
GET /api/work-items?status=planned
→ 200 {"data":[only planned work items]}
GET /api/work-items?status=
GET /api/work-items?status=blocked
GET /api/work-items?status=planned&status=done
→ 400 {
"error": {
"code": "INVALID_STATUS_FILTER",
"message": "Status must be one of: planned, active, done."
}
}

The exact human-readable message can differ when README and tests agree. The stable error code, status, and accepted values cannot differ.

Replace the guided seed with at least six fictional records. Confirm:

  • every ID matches the client contract;
  • every title and description contains non-whitespace text;
  • labels are strings and unique within one record;
  • record IDs are unique across the collection;
  • planned, active, and done each occur at least twice; and
  • one long title, description, or label provides wrapping evidence.

Do not recreate a client fixture. Update fixture-owned API and client expectations to use the accepted server data or injected test values.

Express query input is not a WorkStatus. It can be absent, a string, an array, or another parsed shape. The parser must produce one of these results:

Input state Parser result Route result
No status key No filter Complete collection
One allowed string Valid WorkStatus Matching collection
Empty string Invalid 400 error envelope
Unsupported string Invalid 400 error envelope
Repeated key or array Invalid 400 error envelope

Validate first. Call the store only with undefined or a valid WorkStatus. Keep the unfiltered store behavior available for existing client requests.

Add or adapt API tests until all twelve required contracts have named evidence. Include these query cases:

Required query test outcomes
valid status → 200, only matching items, no nonmatching item
unsupported status → 400, INVALID_STATUS_FILTER, no state change
repeated status → 400, INVALID_STATUS_FILTER, no state change

Add the oversized-body case with a generated string inside the test. Do not commit a large fixture. Confirm status 413 and PAYLOAD_TOO_LARGE.

Temporarily change the query validator so one unsupported value is accepted. Run only the matching invalid-query test. Record:

  • the temporary value;
  • expected consumer consequence;
  • focused command;
  • expected failure versus actual failure; and
  • restored commit or file state.

Restore the correct validator immediately and run the full API suite. Do not continue with a deliberate invalid branch.

Start the normal server only after application-bound tests pass:

Verify the adapted API
npm test
npm run typecheck
npm run lint
npm run start:server

From a second terminal, verify health, full collection, all three valid filters, empty or invalid filter, repeated filter, known item, unknown item, valid update, invalid update, malformed JSON, oversized JSON, and unmatched API route. Inspect status, content type, cache header, and JSON. Stop the exact server process, start it again, and confirm that the seed state returns.

Commit the server data and query work as focused changes after the full repository gate passes.

Assistance 1 — Trace the collection query

Follow request URL → Express query value → parser result → route decision → store list operation → copied records → JSON envelope. Stop at the first place where an external value is asserted, trusted, or changes state.

Assistance 2 — Distinguish absent from invalid

An absent key requests the existing full collection. An empty string is a supplied value that fails the allowed-value check. Repeated keys are ambiguous and fail rather than selecting the first or last value silently.

Assistance 3 — Keep test state independent

Create one application with a fresh copied seed inside each test or setup. Send an update only inside the test that needs it. If another test sees that update, locate a module-level application, store, or mutable seed that escaped test ownership.

Checkpoint: The independently varied API has bounded input and evidence

What now works
Six or more server-owned records meet the data contract, absent and valid status queries return the intended collections, invalid and repeated values return the stable 400 error, twelve isolated API tests pass, one controlled validator defect was detected and restored, and process restart restores the seed.
Files changed
server/data/initial-work-items.ts, server/app.ts, server/store, server/validation, server tests, README.md, docs/stage-3-verification.md
What remains
Reconcile the React client with the varied server data and complete the twelve-contract client portfolio.
Next action
Start the verified server and Vite client, load the unfiltered board, and compare the rendered records with the direct collection response before changing client code.
If it does not work
Restore the last passing server commit, run one API test by name, verify one direct request, then reapply one query or seed change at a time.

Checkpoint 3: Verify client trust and recovery behavior

Section titled “Checkpoint 3: Verify client trust and recovery behavior”

The React client does not need to consume the new optional query. It already loads the complete collection, derives its local counts, preserves item detail routes, and filters through URL state. Keeping that design avoids a partial remote collection becoming the source for incorrect totals or missing detail routes.

Verify the client against the varied server seed:

  1. A cold request renders all accepted server records.
  2. Every valid URL filter derives the correct client result and counts.
  3. Known detail routes resolve against current accepted client state.
  4. A successful status update uses the validated returned item.
  5. Reload keeps the server update while Express remains active.
  6. Express restart restores the committed server seed.

If a test assumed one guided title or ID, decide whether that value belongs to the test setup or the product contract. Keep focused tests deterministic through injected values. Do not make product tests contact a live server.

Map at least twelve cases across focused component, adapter, and routed-application tests:

ID Required client result
CLIENT-01 Empty collection has specific text and no empty semantic list
CLIENT-02 Valid URL filter selects and renders the matching collection
CLIENT-03 Status transition renders the accepted result and feedback
CLIENT-04 Filtered-card removal moves focus to current feedback
CLIENT-05 Unsupported URL filter recovers to all items visibly
CLIENT-06 Updated item detail shows current accepted state
CLIENT-07 Unknown item ID has specific recovery
CLIENT-08 Path navigation updates title, current navigation, and heading focus
CLIENT-09 Initial request exposes loading before data
CLIENT-10 Initial failure exposes retry and a later request can succeed
CLIENT-11 Invalid 200 JSON is rejected as a contract failure
CLIENT-12 Failed update keeps accepted state and focuses failure feedback

Test the API adapter through a controlled fetch double. Test components through rendered roles and names. Test route and state behavior through the real App with an injected WorkItemsApi. No automated client test needs Express or Vite running.

Choose one reversible defect:

  • remove the duplicate-ID rejection from collection parsing;
  • accept an unsupported status string;
  • replace state before the update promise resolves; or
  • clear the accepted collection after update failure.

Run only the selected test. Confirm that it fails because the wrong client outcome appears. Restore the correct source immediately, repeat the selected test, then run the complete suite.

Use process state, injected test doubles, or one local response fixture to create failures. Do not commit a route that exists only to fail and do not edit React state in browser developer tools.

Required manual connected paths:

  • initial load with Express stopped, then retry after Express starts;
  • successful load followed by Express stopping, then failed status update;
  • successful update after Express restarts;
  • one malformed successful response in the adapter test only; and
  • one obsolete collection result that cannot replace a newer attempt, when the guided client includes that test.
Verify both automated portfolios
npm test
npm run typecheck
npm run lint
npm run build
git diff --check

Record total test files, total passed tests, controlled failure results, and restored final commands. A high count does not replace the required contract map.

Assistance 1 — Locate each client responsibility

Fetch method, path, headers, JSON parsing, and response validation belong in the API adapter. Accepted collection and request attempt belong near App. Filter derivation and feedback belong on the board page. Pending labels belong at the action component. Tests inject the boundary they do not intend to exercise.

Assistance 2 — Trace one failed update

Follow button activation → pending identity → disabled actions → adapter request → rejected result → unchanged accepted collection → specific feedback → focused feedback → available retry. Identify the first missing transition rather than rewriting the full path.

Assistance 3 — Separate contract validation from TypeScript

The client declaration describes values after parsing. The HTTP body starts as unknown. Check envelope shape, exact keys, field values, label and ID uniqueness, then construct new trusted values. A cast skips this evidence and does not become safe because the server repository uses the same type name.

Checkpoint: The client accepts only current validated server evidence

What now works
The varied seed renders correctly, twelve named client contracts pass without a live process, invalid success JSON is rejected, failed updates keep accepted state, retry can recover, one controlled client defect was detected and restored, and the complete static and build gate passes.
Files changed
src/api/work-items-api.ts, src/App.tsx, src/pages, src/components, Client tests, README.md, docs/stage-3-verification.md
What remains
Verify the complete two-process system in development and from built assets, including stopped-process recovery and real browser constraints.
Next action
Start Express in Terminal 1 and Vite in Terminal 2, then open the exact route and process matrix in a current browser.
If it does not work
Return to injected client tests first, restore one passing adapter contract, then add the real API process and finally the Vite proxy.

Checkpoint 4: Verify the two-process application

Section titled “Checkpoint 4: Verify the two-process application”

Use three terminals:

Terminal 1 — run the API
npm run start:server
Terminal 2 — run the client
npm run dev
Terminal 3 — inspect direct API responses
curl.exe -i http://127.0.0.1:3000/api/health
curl.exe -i http://127.0.0.1:3000/api/work-items
curl.exe -i "http://127.0.0.1:3000/api/work-items?status=planned"

Use the URL each process reports. Do not start a second copy when a required port is already owned by the current project. Stop only processes that you started.

Record method, complete URL, request body when present, expected status, actual status, content type, cache header, response code or representation, and tested commit for:

  • health;
  • complete collection;
  • planned, active, and done filtered collections;
  • empty, unsupported, and repeated status filters;
  • one known and one unknown item;
  • one valid and one invalid update;
  • malformed JSON;
  • oversized JSON; and
  • unmatched API route.

Confirm that direct requests fail to connect after Express stops. A connection failure is not an API 404 or application error response.

With both processes active, verify:

Browser path Required result
Cold / Loading then complete server collection
/?status=<valid> Matching select, items, counts, and URL
/?status=unsupported Visible fallback and complete collection
/guide Guide heading, title, current navigation, and focus
/work-items/<known-id> Matching current server item
/work-items/<unknown-id> Specific missing-item recovery
/does-not-exist General page-not-found recovery
One status action Pending state, accepted update, current message, and focus

Reload after the successful update. The updated value must remain while Express stays active. Restart Express, reload the client, and confirm the committed seed value returns.

  1. Stop Express before the first client load.
  2. Confirm the unavailable heading, concise alert, retry button, and no false empty result.
  3. Start Express and activate retry without reloading the browser page.
  4. Confirm loading followed by the complete collection.
  5. Stop Express after a successful load.
  6. Activate one status action.
  7. Confirm pending state, unchanged accepted status, retryable failure feedback, focused feedback, and re-enabled actions.
  8. Start Express and repeat the action successfully.

Use a current browser and record:

  • Tab and Shift+Tab through primary navigation, filter, status actions, detail links, and retry when visible;
  • Enter on links and buttons, Space on buttons, and native select keyboard operation;
  • visible focus through route navigation, retained updates, filtered-card removal, and failures;
  • one page h1 and one stable main in loading, success, empty, and failure results;
  • 320 CSS pixels;
  • 200 percent zoom at a normal desktop width;
  • long title, description, label, error, action, and navigation wrapping;
  • no horizontal page scrolling or clipped controls;
  • no color-only meaning; and
  • no unexpected Console error or warning.

Stop Vite development. Keep Express active. Run:

Build and preview the connected application
npm run build
npm run preview

Repeat cold load, one valid filtered route, one known and one unknown detail, one status update, initial failure and retry, 320-pixel, zoom, keyboard, focus, overflow, and Console checks. The local preview proxy proves built client assets against the local API. It does not prove deployment, HTTPS, public routing, database persistence, or production CORS.

Stop preview and Express. Confirm that neither URL still responds.

README and docs/stage-3-verification.md must state:

  • two runtime processes and exact start, order, stop, and recovery actions;
  • API route and error table, including the status query;
  • server data lifetime and restart reset;
  • client proxy, response validation, state, retry, pending, and failure behavior;
  • API and client test counts plus sensitivity evidence;
  • direct HTTP, development, and preview browser matrices;
  • tested commit, environment, browser, issues, and retests;
  • why the client uses the unfiltered collection for local counts and routes;
  • PHP transfer: the same HTTP and validation responsibilities with different runtime and framework syntax;
  • current limits; and
  • Stage 4 handoff: cross-platform design and packaging will reuse the relative API boundary but will not make a local desktop API publicly reachable.
Assistance 1 — Identify which process failed

Request http://127.0.0.1:3000/api/health directly. If it fails, inspect Express first. If it passes but the browser /api request fails, inspect the Vite URL and proxy. If the response passes but the page fails, inspect adapter validation and React state.

Assistance 2 — Record exact recovery conditions

Write process state → request or action → expected result → actual result → focus target → Console or terminal evidence. Restart only the stopped project process and repeat the same path before editing source.

Assistance 3 — Verify the system by boundary

Express process → direct HTTP contract → Vite proxy → fetch adapter → runtime parser → accepted App state → route and derived view → interaction → feedback and focus → responsive CSS. Repair the earliest boundary that disagrees with evidence.

Checkpoint: The connected system has named real-runtime evidence

What now works
Direct API requests, development and preview process pairs, server restart, initial retry, update failure, routes, keyboard, focus, 320 pixels, 200 percent zoom, overflow, and Console checks have current evidence tied to one commit and environment.
Files changed
README.md, docs/stage-3-verification.md, Direct HTTP evidence, Development and preview browser evidence
What remains
Publish the complete branch, conduct independent review, respond to findings, integrate the accepted result, and verify remote main from a fresh clone.
Next action
Inspect the complete diff and commit sequence, rerun the full automated gate with no local process active, then push feature/express-api for review.
If it does not work
Return to the last passing automated result, reproduce one direct request and one browser path with exact process state, and update its evidence before requesting review.

Checkpoint 5: Review, integrate, and recover Stage 3

Section titled “Checkpoint 5: Review, integrate, and recover Stage 3”

The branch author inspects the complete change before publication:

Inspect and publish the Stage 3 branch
git status --short
git diff
git fetch origin
git log --oneline origin/main..HEAD
npm test
npm run typecheck
npm run lint
npm run build
git push -u origin feature/express-api

The working tree must be clean. No server, Vite, or preview process should remain active.

The pull-request description must include:

  • Outcome: Express owns the runtime collection and React consumes validated API representations.
  • API scope: Route table, status query, input validation, error codes, memory lifetime, and limits.
  • Client scope: Relative requests, adapter validation, load and update states, retry, and focus behavior.
  • Commit sequence: Server foundation → validated API → API consumption → Stage 3 variation and evidence → review responses.
  • Automated evidence: Exact command, API and client counts, and both restored sensitivity proofs.
  • Runtime evidence: Direct HTTP, development pair, preview pair, stopped-process recovery, restart reset, keyboard, viewport, zoom, and Console.
  • Known limits: No database, auth, public server, deployment, production CORS decision, conflict policy, or offline behavior.
  • Review focus: Query validation, store copies, middleware and route order, response parsing, obsolete-result cleanup, failure state, focus, and test isolation.
  • Evidence locations: README and docs/stage-3-verification.md.

The reviewer checks out the published branch in a clean working copy:

Reviewer — verify the published Stage 3 branch
git fetch origin
git switch --track origin/feature/express-api
npm ci
npm test
npm run typecheck
npm run lint
npm run build

If the branch already exists locally, switch to it and use git pull --ff-only instead of creating another tracking branch.

The reviewer then starts Express and the built client preview. They perform at least:

  • one full and one valid filtered direct API request;
  • one invalid or repeated status-query request;
  • one valid status update and one invalid request body;
  • one cold client load and one valid URL filter;
  • one initial failure and retry or one failed update with retained state;
  • one known and one unknown client route;
  • one keyboard and focus path;
  • one 320-pixel or 200%-zoom check;
  • inspection of one server validation or store-copy relationship; and
  • inspection of one client parser, cleanup, or test-isolation relationship.

The review records three specific observations:

  1. API request, expected contract, and actual contract;
  2. client route or action, expected result, and actual result; and
  3. source-or-test relationship, inspected evidence, and consequence.

Passing evidence is valid review evidence. Do not invent a defect.

For each observation or request, the author:

  1. reproduces or inspects the exact condition;
  2. records whether the observation is confirmed;
  3. makes the smallest required change or explains why current behavior meets the contract;
  4. runs the focused API, client, or browser path;
  5. runs the complete gate when source changes;
  6. commits and pushes a focused response when required; and
  7. replies with the result and evidence.

Update the verification document. The reviewer approves only when the result, tests, documentation, and evidence agree.

If the branch is behind or conflicted, update it through an ordinary merge:

Update the reviewed branch from current main
git status
git fetch origin
git log --oneline HEAD..origin/main
git merge --no-edit origin/main
npm test
npm run typecheck
npm run lint
npm run build
git push

After approval and final passing evidence, the integration owner merges the pull request. Preserve focused commits with Create a merge commit when available. Delete the remote feature branch only after GitHub confirms the merge.

Every contributor synchronizes:

Synchronize accepted Stage 3 main
git switch main
git pull --ff-only
git status
git rev-parse HEAD
git rev-parse origin/main
npm ci
npm test
npm run typecheck
npm run lint
npm run build

Clone into a new empty folder outside all current working copies:

Verify Stage 3 recovery
git clone REPOSITORY-URL delivery-board-stage-3-check
cd delivery-board-stage-3-check
npm ci
npm test
npm run typecheck
npm run lint
npm run build

Start the API and preview in separate terminals. Verify direct health, complete collection, valid filter, invalid filter, cold client load, one valid client URL filter, one status update, one known detail, one unknown route, and one stopped-API retry. Stop both processes and confirm git status remains clean.

Record the final remote main commit and fresh-clone result in the verification document and Teams submission.

Assistance 1 — Prepare a reviewable connected branch

Stop local processes, make the branch clean, list focused commits, run the full automated gate, record current runtime evidence, push, and put the API contract, client states, evidence, limits, and review focus in the pull request.

Assistance 2 — Turn a review observation into evidence

Separate condition → expected contract → actual result → consequence → chosen action → focused retest. Confirm the observation before editing and respond with evidence when the correct result is to keep the current implementation.

Assistance 3 — Close the stage without losing history

Approval → compare with remote main → merge current main when required → repeat checks → push → merge commit → confirm GitHub result → synchronize all working copies → fresh clone → repeat two-process smoke checks → record final commit.

Checkpoint: The reviewed API connection is the recoverable main baseline

What now works
Independent review covers API, client, and source-or-test behavior; every finding has a response; focused history reaches remote main; all working copies are synchronized; and a fresh clone reproduces the verified two-process application.
Files changed
Private GitHub pull request, README.md, docs/stage-3-verification.md, Remote and local main history, Fresh clone, Teams submission evidence
What remains
Complete the self-check and submission, then keep the clean main baseline for cross-platform design work.
Next action
Copy the repository URL, merged pull-request URL, final remote main commit, verification summary, role evidence, and limits into the Teams submission.
If it does not work
Compare GitHub merge state, remote main, local main, lockfile install, automated gate, direct API checks, and connected preview before creating any Stage 4 branch.

Self-check

Complete these checks against the required result.

  1. Confirm that work continued in the existing private Delivery Board repository and did not create a second product history.
  2. Confirm that feature/express-api began from accepted Stage 2 main and preserves separate server-foundation, API-development, and API-consumption commits.
  3. Confirm that the branch author, reviewer, and integration owner are named and that author and reviewer are different people.
  4. Point to at least six fictional server records with unique valid IDs, nonempty text, unique labels within each record, and at least two items in each status.
  5. Confirm that the client fixture remains deleted and the Express seed is the only runtime collection fixture.
  6. Point to the Express application, listener, query parser, store, seed, API adapter, App state, route pages, action components, and test setup and state what each owns.
  7. Confirm that the store copies its input and returned values and that each API test receives independent state.
  8. Request health, complete collection, one known item, one missing item, one valid update, one invalid update, and one unmatched API path and confirm each contract.
  9. Request planned, active, and done status filters and confirm that every returned record matches the selected value.
  10. Request empty, unsupported, and repeated status filters and confirm 400 plus INVALID_STATUS_FILTER without a store change.
  11. Confirm that query parsing begins from the actual Express query shape and uses no assertion or cast to create WorkStatus.
  12. Send malformed and oversized JSON and confirm distinct 400 and 413 error contracts.
  13. Confirm that API responses use JSON, no-store, stable safe errors, and no X-Powered-By header.
  14. Run all twelve API contract tests and confirm that no test uses the normal port or depends on another test.
  15. Run the controlled invalid-query mutation, confirm the focused intended failure, restore the parser, and rerun the suite.
  16. Confirm that every client URL is relative and only Vite configuration names the local Express target.
  17. Trace a collection response from unknown JSON through envelope, exact keys, field values, uniqueness checks, copied values, and accepted React state.
  18. Trace a status action through pending identity, disabled buttons, request, validated returned item, state replacement, feedback, and focus.
  19. Stop Express during an update and confirm that the last accepted item remains, feedback is focused, and the action becomes available again.
  20. Stop Express before initial load, start it, activate retry without reloading, and confirm loading followed by success.
  21. Confirm that aborted or obsolete collection results cannot replace the current request result.
  22. Run all twelve client contracts without a live API and confirm that each test names a user-visible or transport-boundary result.
  23. Run the controlled client parser or premature-update mutation, confirm the focused intended failure, restore source, and rerun the suite.
  24. Run npm test, typecheck, lint, build, and git diff --check from the committed dependency graph.
  25. Verify direct API evidence separately from proxied client evidence.
  26. Verify the complete development process pair and built-preview process pair, including stopped-process recovery and server restart reset.
  27. Use pointer, Tab, Shift+Tab, Enter, Space, and native select keys and confirm visible focus through success and failure paths.
  28. Verify one stable main, one page h1, semantic controls, live or alert semantics, no color-only meaning, AA contrast, 320 pixels, 200 percent zoom, wrapping, no overflow, and no unexpected Console output.
  29. Read README and docs/stage-3-verification.md and confirm contracts, processes, test counts, mutations, browser evidence, PHP transfer, limits, tested commit, and Stage 4 handoff are current.
  30. Confirm that the pull request states outcome, routes, client states, history, evidence, limits, review focus, and evidence locations.
  31. Confirm that review contains one API observation, one connected-client observation, and one source-or-test observation without an invented defect.
  32. Confirm that every review item has an author decision, focused verification, and complete rerun when source changed.
  33. Confirm that the approved pull request is merged with focused history preserved and every contributor has clean synchronized main.
  34. Run the fresh-clone install, tests, typecheck, lint, build, direct API smoke path, and connected browser smoke path without editing source.
  35. Confirm that Teams identifies the repository, merged pull request, final remote main commit, contributors, roles, evidence, limits, and private reflection.

The Stage 3 review uses observable evidence from the required path:

Area Weight Evidence
API design and validation 25% Written contracts, route and middleware order, query and body validation, status and error choices, store boundaries, memory lifetime, and direct HTTP evidence
Client integration and state 20% Relative API boundary, response validation, explicit load and mutation states, retry, obsolete-result protection, accepted server representation, and failure recovery
Automated tests and quality gates 20% Twelve API plus twelve client contracts, isolation, semantic or transport-level assertions, two sensitivity proofs, typecheck, lint, and build
Accessibility and real-runtime behavior 15% Two process pairs, direct routes, keyboard, focus, semantics, contrast, 320 pixels, zoom, wrapping, overflow, restart, and Console evidence
Collaboration and feedback 10% Focused history, complete pull request, independent API, client, and source-or-test observations, responses, approval, and safe integration
Documentation and recovery 10% Accurate README, Stage 3 verification record, PHP transfer, limits, final commit, fresh-clone recovery, and cross-platform handoff

Optional extensions do not affect whether the required assignment is complete. Assessment uses the stable definition of done above.

Checkpoint sections provide orientation, targeted hints, and ordered subgoals. Open the deeper support below when a partial structure or full reference path will help you resume.

Assistance 4 — Review a partial Stage 3 responsibility map
Partial Stage 3 responsibility map
server/
app.ts Express settings, middleware, routes, errors
index.ts PORT validation and local listener
data/initial-work-items.ts fictional server seed
store/work-item-store.ts copied in-memory collection operations
validation/status-update.ts request-body narrowing
validation/status-filter.ts optional query narrowing
app.test.ts API contract tests
src/
api/work-items-api.ts fetch, JSON parsing, response validation
api/work-items-api.test.ts transport and response contracts
App.tsx collection request and accepted state
App.test.tsx routed load, retry, state, and failure behavior
components/ list and pending actions
pages/ routes, derived filters, feedback, focus
test/setup.ts client DOM test reset
docs/stage-3-verification.md evidence, review, recovery, handoff
README.md contributor process and contract reference
vite.config.ts local relative /api proxy

Use this order when several failures appear:

  1. Restore a clean known branch state.
  2. Run isolated API and client tests.
  3. Run typecheck, lint, and build.
  4. Start Express and verify direct health.
  5. Verify direct collection and update contracts.
  6. Start Vite and inspect the proxied request.
  7. Trace response parsing and accepted client state.
  8. Verify interaction, feedback, and focus.
  9. Verify built assets and responsive behavior.
  10. Reconcile documentation and review evidence.

Keep one active problem. Record unrelated ideas under Later without expanding required scope.

Assistance 5 — Review the complete guided Stage 3 reference routeExample solution

The three lessons contain the guided reference baseline:

  1. Run TypeScript on the server with Node and Express — runtime and process model, health route, configuration validation, application and listener split, direct HTTP evidence, and PHP comparison.
  2. Develop, validate, and test a JSON API — server seed and store, body validation, four routes, stable errors, application factory, Supertest isolation, and eight API tests.
  3. Connect a React application to an API — relative proxy, fetch adapter, response validation, explicit client states, abort or ignore cleanup, server-backed updates, injected tests, two-process verification, and client fixture removal.

The complete required flow is:

Complete Stage 3 trust and data flow
external request input
→ Express middleware and route
→ runtime parser
→ copied in-memory store operation
→ deliberate HTTP status and JSON
→ relative Vite-proxied client request
→ response body as unknown
→ client envelope and item parser
→ accepted React state
→ route and derived interface
→ user action
→ validated PATCH response
→ accepted replacement, feedback, and focus

The assignment-specific work remains required:

  • adapt the seed to six or more records;
  • write and implement the optional status-query contract;
  • expand to twelve API and twelve client contracts;
  • complete both sensitivity proofs;
  • run direct, development, and preview matrices;
  • update README and the Stage 3 verification record;
  • obtain independent review and respond to it;
  • merge and synchronize main; and
  • verify a fresh clone with both processes.

Reference use does not replace evidence or independent review. When reference source and current installed packages disagree, use the written product contract, current official documentation, tests, and installed type information to decide the result.

Stop only at a working boundary: after the 24-row evidence map is committed, after the adapted API and twelve API tests pass, after all twelve client contracts pass, after runtime evidence is recorded, after a review response is pushed, or after the approved pull request is merged and every contributor has synchronized main.

Before stopping, add this resume note to docs/stage-3-verification.md or the active pull request:

  • What works: Latest passing automated command, direct API result, and connected browser result.
  • Current branch and commit: Exact branch name and full or short commit ID.
  • Active contract: API or CLIENT ID and expected result.
  • Process state: Express, Vite, preview, and exact stop action.
  • Review state: Draft, ready, changes requested, approved, or merged.
  • What remains: Next unmet requirement, failed check, or unreviewed relationship.
  • Next action: One command, file edit, request, browser path, test, or review response.
  • Required setup: Project folder, installed dependencies, terminal roles, URL, browser route, account, and reviewer availability.

Do not stop with a controlled mutation, .only, .skip, unresolved merge, active project process, unexplained uncommitted file, or ambiguous test failure. The clean accepted Stage 3 main becomes the starting point for cross-platform design.