Full-Stack Development Case Studies & Practical Application 4 — Questions and Answers
Question 1: A web app stores session tokens in localStorage. A security audit flags this as a risk. What is the recommended alternative and why?
- Store tokens in a JavaScript variable so they reset on refresh
- Store tokens in HttpOnly cookies so JavaScript cannot access them, mitigating XSS theft (Correct answer)
- Base64-encode tokens before storing in localStorage
- Store tokens in sessionStorage instead
Correct answer: Store tokens in HttpOnly cookies so JavaScript cannot access them, mitigating XSS theft
HttpOnly cookies are inaccessible to JavaScript, so even if XSS occurs, the attacker cannot steal the session token.
Question 2: A startup runs a single PostgreSQL instance. As they scale to 1M users, read queries slow down. They cannot yet afford a full sharding solution. What is the most practical first step?
- Move all data to MongoDB
- Add a read replica and route all SELECT queries to it, keeping writes on the primary (Correct answer)
- Archive old data to S3 and rebuild from scratch
- Increase the PostgreSQL work_mem to 10 GB
Correct answer: Add a read replica and route all SELECT queries to it, keeping writes on the primary
A read replica offloads SELECT load from the primary with minimal operational overhead and no application architecture change.
Question 3: A Next.js e-commerce site has poor Core Web Vitals scores. The Largest Contentful Paint (LCP) is a hero product image. What is the highest-impact fix?
- Lazy-load the hero image with loading='lazy'
- Serve the hero image with a <link rel='preload'> tag and use a modern format like WebP (Correct answer)
- Convert the image to a CSS background-image
- Reduce the image resolution to 100x100 pixels
Correct answer: Serve the hero image with a <link rel='preload'> tag and use a modern format like WebP
Preloading the LCP image combined with a compressed modern format directly reduces the time for the browser to paint the largest element.
Question 4: A GraphQL API allows clients to request deeply nested data (e.g., user → friends → friends → posts → comments). This causes CPU spikes. What protection should be added?
- Disable GraphQL introspection
- Enforce query depth limiting and complexity scoring to reject excessively expensive queries (Correct answer)
- Switch from GraphQL to REST
- Require all queries to be submitted as POST requests
Correct answer: Enforce query depth limiting and complexity scoring to reject excessively expensive queries
Query depth limits and complexity scores prevent clients from crafting exponentially expensive queries that exhaust server resources.
Question 5: A developer pushes a hotfix directly to the main branch to resolve a production incident. The team wants to prevent this in the future. What process change achieves this?
- Require all commits to be GPG-signed
- Enable branch protection rules requiring at least one PR review before merging to main (Correct answer)
- Delete the main branch and use release branches only
- Restrict SSH access to the server
Correct answer: Enable branch protection rules requiring at least one PR review before merging to main
Branch protection rules enforce peer review as a gate, ensuring even urgent fixes get a second pair of eyes before hitting production.
Question 6: A team is designing a system where a user placing an order must also notify inventory and billing services. Which architectural pattern keeps these services decoupled?
- Have the order service call inventory and billing APIs synchronously
- Use an event/message broker so the order service publishes an event and other services subscribe independently (Correct answer)
- Combine all three services into a single service
- Use a shared database table as the communication channel
Correct answer: Use an event/message broker so the order service publishes an event and other services subscribe independently
A message broker decouples publishers from subscribers, allowing each service to evolve independently and fail without blocking others.
Question 7: During load testing, a team finds that their Express.js API drops requests when concurrency exceeds 200. The bottleneck is traced to a blocking bcrypt password hash call in the login route. What is the fix?
- Increase the Node.js cluster size to 200 processes
- Switch to an async bcrypt library (e.g., bcryptjs or argon2 async) so the event loop is not blocked during hashing (Correct answer)
- Cache all password hashes in memory
- Reduce the bcrypt cost factor to 1
Correct answer: Switch to an async bcrypt library (e.g., bcryptjs or argon2 async) so the event loop is not blocked during hashing
Synchronous cryptographic operations block the Node.js event loop; using async variants offloads the work and keeps the server responsive.
A web app stores session tokens in localStorage.
A security audit flags this as a risk.
What is the recommended alternative and why?