Module: Full Stack
Full Stack·152·6 MIN READ

152: Full-Stack Interview Review

TOPICS COVERED: Full-Stack Interview Review

Learning objective

Explain the complete application from browser interaction through React state, HTTP, Express, authentication, MongoDB, and the response rendered back to the user.

End-to-end review

Trace one authenticated task update:

  1. React renders TaskScreen from the explicit authStatus state; this project does not require React Router.
  2. A labeled controlled input or checkbox validates the draft for user feedback.
  3. The shared api.updateTask() service sends an authenticated request with credentials: "include".
  4. Express authenticates the session and validates the body.
  5. The service applies an ownership-aware MongoDB update.
  6. The API returns a stable response contract.
  7. React replaces the matching task with the server response; this project uses functional useState setters, not a query cache.
  8. React renders the new state and exposes useful feedback, clearing the row's pending state.

At every boundary identify the input, trust level, expected output, failure mode, and evidence to inspect.

The actual course stack is React state and Effects, one Fetch API service, Express 5, Mongoose, MongoDB, and express-session with connect-mongo. React Router, a form library, TanStack Query, and server actions are valid alternatives, but they are not hidden dependencies of this project. If you choose one, update the lifecycle and test plan instead of describing behavior the code does not have.

Practical assessment

Complete these exercises without looking at the previous answer until you have written your own design.

Debugging task

The browser reports a successful PATCH, but the task appears unchanged after refresh. Investigate in this order:

  1. Confirm the request method, URL, credentials, body, and response status in Network tools.
  2. Confirm the server parsed the body and selected the expected route.
  3. Confirm authentication identified the expected account.
  4. Confirm the update filter includes both task ID and owner.
  5. Confirm the database update matched and modified a document.
  6. Confirm the response serializer returned the updated representation.
  7. Confirm the client invalidated or updated the correct query key.
  8. Add a regression test at the boundary where the defect occurred.

API design task

Design the contract for PATCH /api/tasks/:id, matching the final project:

  • Define accepted fields and reject unknown fields.
  • Decide whether an empty patch is valid.
  • Use the established 400 VALIDATION_ERROR for malformed or semantically invalid input; do not invent 422 for this project.
  • Specify 401, 403, 404, 409, and 500 behavior.
  • Return a stable success envelope and a safe error envelope.
  • State whether the operation is retry-safe and how conflicting updates are handled.

Testing task

Write a test matrix containing:

  • unauthenticated access;
  • another user's task ID;
  • malformed JSON;
  • invalid field types;
  • an empty patch;
  • a successful update;
  • a missing record;
  • a database failure;
  • a stale client cache after mutation;
  • keyboard and screen-reader-visible success and failure feedback.

For every test, name the initial condition, action, observable result, and test boundary.

System-design task

Explain how the application would change if task updates became slow or expensive. Discuss asynchronous processing, 202 Accepted, polling or server-sent updates, idempotency, user-visible pending state, retry behavior, and how the durable database remains authoritative.

For the current synchronous API, a successful PATCH is 200 { data: Task } and the UI keeps the old row until that response arrives. A future 202 design must add a job status contract and an idempotency key; do not claim the present api.updateTask() supports either one.

Security review

Identify the trust boundaries between browser, API, session cookie, validation layer, service logic, and database. Demonstrate why each of these is insufficient by itself:

  • hiding a route in React;
  • validating only in the browser;
  • trusting an ID from the URL;
  • trusting an owner field from the request body;
  • returning raw database errors;
  • treating CORS as authorization.

Project retrospective

Record three decisions made during the project, one rejected alternative for each, and the evidence that would cause you to revisit the decision. Include one bug, its root cause, the regression test, and the prevention measure. A strong interview answer explains the boundary and tradeoff, not only the library name.

Interview questions

  1. Where does authorization happen, and why can it not live only in React?

  2. How would you prevent stale client data after a mutation?

  3. What should the API return for invalid input, missing data, and unauthorized access?

  4. How would you debug a request that succeeds in the browser but does not persist?

  5. Which parts of the system would you test together and which in isolation?

  6. Where are the unit, integration, contract, and E2E boundaries in this project?

  7. How would you distinguish a stub, spy, and mock, and what would you use here?

  8. What release gates and smoke tests would you require before production?

  9. Which signals would you inspect during an incident, and when would you roll back?

Final reference rule

Prefer the smallest design that preserves correct data flow, explicit failure behavior, accessibility, security, and maintainability. Explain tradeoffs instead of naming libraries as solutions by themselves.

Official references

Interview answer bank

Reconciliation: React compares element type and sibling keys, then commits required host changes. Stable domain IDs preserve row identity; index/random keys can move state or remount rows.

Error boundaries and Suspense: boundaries isolate render failures; Suspense coordinates pending rendering. Neither catches every event/API error, authenticates a user, or replaces a cache.

Node: JavaScript executes on the event-loop thread while I/O can use OS/libuv facilities. CPU and sync work block peers; streams require backpressure; shutdown drains work and closes pools with a deadline.

Mongo and SQL: model from access patterns and invariants. Explain aggregation, compound indexes with executionStats, transactions only for cross-document invariants, replication lag, and why SQL constraints/joins may be the better fit.

Security and testing: validate at the server boundary, authorize in the resource query, escape output, deploy CSP, defend CSRF, constrain SSRF, parameterize database operations, rate-limit expensive actions, and keep secrets outside the client. Unit-test pure logic, component-test accessible behavior, contract-test HTTP shape, integration-test real boundaries, and reserve E2E for critical journeys.

Final case study: Bob submits Alice's task ID. Trace session authentication, typed body validation, { _id, owner: bob } authorization, non-revealing 404, unchanged database, safe envelope, client alert, and a regression test. This is stronger than saying “the route is protected.”

Interview answer template: “I test each risk at its cheapest trustworthy boundary. Pure validation is a unit/property-test candidate; React states use accessible component tests; the API shape gets a contract test; Express plus the repository gets integration coverage; and Playwright covers register/create/refresh/logout and the two-user denial journey. CI runs these on the tested commit, a preview smoke test checks health and disposable persistence, and production is monitored by request rate, errors, latency, readiness, and dependency health. If smoke or agreed thresholds fail, I roll back the immutable artifact, verify recovery, and then add the regression test.”