Chapter 19 Exercises: Full-Stack Application Development


Tier 1: Remember and Understand (Exercises 1-6)

These exercises test your recall and comprehension of full-stack concepts.

Exercise 1: Layer Identification

For each of the following tasks, identify which layer of the full-stack (frontend, backend, or database) is primarily responsible. Some tasks may involve more than one layer — if so, list all involved layers and explain the role of each.

a) Displaying a loading spinner while data is fetched b) Hashing a user's password before storage c) Enforcing a foreign key constraint between tasks and users d) Converting snake_case API responses to camelCase for JavaScript e) Setting the HttpOnly flag on an authentication cookie f) Creating an index on the email column for faster lookups

Exercise 2: CORS Comprehension

Explain in your own words why the following scenario fails:

  • A React app running at http://localhost:5173 makes a fetch() request to http://localhost:8000/api/tasks.
  • The FastAPI backend at http://localhost:8000 does not have any CORS middleware configured.
  • The browser console shows: Access to fetch at 'http://localhost:8000/api/tasks' from origin 'http://localhost:5173' has been blocked by CORS policy.

What is the browser protecting against? What is the fix?

Exercise 3: JWT Token Flow

Draw or describe a sequence diagram showing the complete JWT authentication flow for the following scenario:

  1. A user opens the app for the first time
  2. They register with username, email, and password
  3. They are automatically logged in after registration
  4. They navigate to a protected page that fetches their tasks
  5. After 30 minutes, their token expires
  6. They try to fetch tasks again

Label each step with the HTTP method, URL, request body, response body, and where the token is stored or read from.

Exercise 4: Environment Variable Classification

Classify each of the following configuration values as "safe to commit to version control" or "must be kept secret." For each secret, suggest where it should be stored in a production environment.

a) VITE_API_URL=http://localhost:8000 b) DATABASE_URL=postgresql://admin:s3cur3p@ss@db.example.com:5432/prod c) CORS_ORIGINS=https://myapp.com,https://www.myapp.com d) AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY e) MAX_UPLOAD_SIZE_MB=10 f) SECRET_KEY=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Exercise 5: State Synchronization Scenarios

For each scenario below, recommend the most appropriate state synchronization strategy (fetch on navigation, polling, optimistic update, or real-time WebSocket) and justify your choice:

a) A personal to-do list app used by one person b) A stock trading dashboard showing live prices c) A collaborative document editor where multiple users edit simultaneously d) An e-commerce product page showing remaining inventory e) A social media feed that occasionally shows new posts

Exercise 6: HTTP vs. WebSocket

Explain why a chat application would use WebSockets for message delivery but HTTP for user registration. What characteristics of each feature make one protocol more appropriate than the other?


Tier 2: Apply (Exercises 7-14)

These exercises require you to implement specific full-stack patterns.

Exercise 7: API Client Enhancement

The API client in Section 19.3 throws errors but does not handle specific HTTP status codes differently. Extend the client with the following behavior:

  • On 401 responses, clear the stored token and redirect to the login page
  • On 429 responses (rate limited), wait for the time specified in the Retry-After header and retry the request
  • On 500 responses, show a user-friendly error message ("Something went wrong. Please try again later.")
  • On network errors (fetch throws), show "Unable to connect to server. Check your internet connection."

Write the updated request method in TypeScript.

Exercise 8: Pydantic Schema Design

Design a complete set of Pydantic schemas for a blog post system with the following requirements:

  • A blog post has a title, body, tags (list of strings), status (draft/published), and author
  • There should be separate schemas for: creating a post, updating a post (all fields optional), the API response (includes id, created_at, updated_at, author name), and a list response (includes pagination metadata)
  • The response schemas should use camelCase field names for the frontend
  • Include validation: title must be 1-200 characters, body must be 1-50,000 characters, tags limited to 10 items

Exercise 9: Protected Route with Role Check

Extend the ProtectedRoute component from Section 19.5 to support role-based access control. The component should:

  • Accept a requiredRole prop (e.g., "admin", "editor", "viewer")
  • Check the user's role from the auth context
  • Redirect to a "not authorized" page if the user is authenticated but lacks the required role
  • Redirect to the login page if the user is not authenticated at all

Write both the React component and the corresponding backend dependency that checks roles.

Exercise 10: File Upload with Preview

Create a React component that extends the file upload from Section 19.6 with:

  • Image preview before upload (using URL.createObjectURL)
  • Drag-and-drop support
  • A progress bar showing upload percentage
  • The ability to cancel an in-progress upload
  • Support for uploading multiple files simultaneously

Write the complete component in TypeScript.

Exercise 11: Database Migration Script

Write an Alembic migration that adds a profile_picture_url column to the users table and a tags column (as a PostgreSQL ARRAY type) to the tasks table. Include both the upgrade and downgrade functions. Then write the corresponding updates to the SQLAlchemy models and Pydantic schemas.

Exercise 12: Docker Compose Enhancement

Extend the Docker Compose configuration from Section 19.8 to include:

  • A Redis service for caching and session storage
  • An Nginx reverse proxy that serves the frontend and proxies API requests
  • Health checks for each service
  • A named network so services can communicate by hostname
  • Volume mounts for development hot-reloading

Write the complete docker-compose.yml file.

Exercise 13: Error Boundary Component

Create a React error boundary component that catches runtime errors in child components and:

  • Displays a user-friendly error message instead of a blank screen
  • Includes a "Try Again" button that re-renders the failed component
  • Sends the error details to a /api/errors endpoint on the backend for logging
  • Shows a different message in development vs. production (stack trace in dev, generic message in prod)

Exercise 14: API Rate Limiting

Implement rate limiting middleware for your FastAPI backend that:

  • Limits each authenticated user to 100 requests per minute
  • Limits unauthenticated requests to 20 per minute by IP address
  • Returns a 429 status code with a Retry-After header when the limit is exceeded
  • Stores rate limit counters in memory (for simplicity) or Redis (for production)
  • Excludes health check endpoints from rate limiting

Write the middleware and show how to apply it to the FastAPI app.


Tier 3: Analyze (Exercises 15-20)

These exercises require you to break down problems and evaluate approaches.

Exercise 15: Architecture Comparison

You are building a project management tool similar to Trello. Compare these two architectures:

Architecture A: Monolithic FastAPI backend serving a React SPA, with PostgreSQL database, deployed on a single server with Nginx.

Architecture B: Separate microservices (auth service, task service, notification service) communicating via a message queue, React SPA hosted on a CDN, PostgreSQL for each service, deployed on Kubernetes.

For each architecture, analyze: a) Development speed for a team of 2 developers b) Operational complexity c) Scaling characteristics d) Cost at 100 users vs. 10,000 users vs. 1,000,000 users e) Fault isolation (what happens when one component fails)

Which would you recommend for a startup MVP and why?

Exercise 16: Authentication Strategy Analysis

Compare these three authentication strategies for a full-stack application:

a) JWT stored in localStorage b) JWT stored in an httpOnly cookie c) Session-based authentication with server-side session storage

For each, analyze: security against XSS, security against CSRF, scalability across multiple servers, ease of implementation, mobile app compatibility, and token revocation capability.

Exercise 17: State Management Audit

Given the following React component, identify all state management issues and propose fixes:

function TaskDashboard() {
    const [tasks, setTasks] = useState([]);
    const [user, setUser] = useState(null);

    useEffect(() => {
        fetch('http://localhost:8000/api/tasks')
            .then(r => r.json())
            .then(setTasks);
        fetch('http://localhost:8000/api/auth/me')
            .then(r => r.json())
            .then(setUser);
    }, []);

    const deleteTask = (id) => {
        fetch(`http://localhost:8000/api/tasks/${id}`, { method: 'DELETE' });
        setTasks(tasks.filter(t => t.id !== id));
    };

    return (
        <div>
            <h1>Welcome, {user.username}</h1>
            {tasks.map(task => (
                <div key={task.id}>
                    {task.title}
                    <button onClick={() => deleteTask(task.id)}>Delete</button>
                </div>
            ))}
        </div>
    );
}

List at least eight issues covering error handling, authentication, hardcoded values, race conditions, and user experience.

Exercise 18: Performance Bottleneck Analysis

A full-stack application is experiencing slow page loads. The task list page takes 4 seconds to become interactive. The performance profile shows:

  • DNS resolution: 50ms
  • TLS handshake: 100ms
  • HTML download: 200ms
  • JavaScript bundle download: 1,500ms
  • JavaScript parse and execute: 800ms
  • API call to /api/tasks: 900ms
  • Rendering task list: 350ms

For each bottleneck, suggest a specific optimization. Prioritize the optimizations by expected impact and implementation effort.

Exercise 19: Security Review

Review the following authentication endpoint and identify all security vulnerabilities:

@router.post("/login")
async def login(email: str, password: str):
    user = db.execute(
        f"SELECT * FROM users WHERE email = '{email}'"
    ).fetchone()

    if user and user.password == password:
        token = jwt.encode(
            {"user_id": user.id},
            "secret123",
            algorithm="HS256"
        )
        return {"token": token, "user": dict(user)}

List every vulnerability, explain the risk, and provide the corrected code.

Exercise 20: Data Flow Trace

Trace the complete data flow for the following user action in a task management app: "User drags a task from the 'in-progress' column to the 'done' column."

For each step, specify: - What component/function/endpoint is involved - What data is sent or received - What validation occurs - What happens if something fails at that step

Cover: drag event handler, optimistic UI update, API request, backend validation, database update, WebSocket broadcast, other clients receiving the update.


Tier 4: Evaluate (Exercises 21-26)

These exercises require judgment and trade-off analysis.

Exercise 21: Technology Selection

A client asks you to build a real-time collaborative whiteboard application. They expect up to 50 concurrent users editing the same canvas. Evaluate the following technology stack choices and recommend a combination:

  • Frontend: React, Svelte, or Vue
  • Backend: FastAPI, Node.js/Express, or Elixir/Phoenix
  • Database: PostgreSQL, MongoDB, or Redis
  • Real-time: WebSockets, Server-Sent Events, or WebRTC

Justify each choice based on the application's specific requirements. Discuss what would change if the expected concurrency increased to 5,000 users.

Exercise 22: Migration Strategy

You have a working prototype built as a single FastAPI application serving both HTML templates and API endpoints. The client now wants a React frontend. Evaluate these two migration strategies:

Strategy A: Rewrite the frontend entirely in React, keeping the existing API endpoints. Deploy both side by side, gradually redirecting users to the new React app.

Strategy B: Incrementally replace HTML templates with React components, embedding them in the existing templates using a micro-frontend approach.

For each strategy, evaluate: risk level, development time, user disruption, testing complexity, and long-term maintainability.

Exercise 23: Caching Strategy Evaluation

A full-stack e-commerce application has the following data access patterns:

  • Product catalog: Read 10,000 times per minute, updated 5 times per day
  • User shopping cart: Read 100 times per minute per user, updated frequently
  • Order history: Read 10 times per day per user, rarely updated
  • Inventory count: Read 1,000 times per minute, updated on every order

For each data type, evaluate whether caching is appropriate and, if so, where in the stack the cache should live (browser cache, CDN, API-level cache with Redis, database query cache). Specify cache duration and invalidation strategy.

Exercise 24: Deployment Platform Comparison

Compare these deployment options for a FastAPI + React + PostgreSQL application:

a) AWS (EC2 + RDS + S3 + CloudFront) b) Railway / Render (managed platform) c) Self-hosted VPS (DigitalOcean droplet with Docker) d) Vercel (frontend) + Railway (backend) + Supabase (database)

Evaluate each on: cost for a small project (100 users), cost at scale (100,000 users), operational complexity, deployment speed, vendor lock-in risk, and available AI tooling support.

Exercise 25: Error Handling Philosophy

Two developers on your team disagree about error handling in a full-stack app:

Developer A: "Every API error should return a structured JSON response with an error code, message, and field-level errors. The frontend should parse these and show specific error messages for each field."

Developer B: "Keep it simple. Return HTTP status codes and a single error message string. The frontend shows a toast notification with the message. Field-level validation happens entirely on the frontend."

Evaluate both approaches. Under what circumstances is each approach better? Propose a compromise that takes the best of both.

Exercise 26: Monorepo vs. Polyrepo

Your team of six developers is building a full-stack application with a React frontend, a FastAPI backend, a background job processor, and a mobile app (React Native). Evaluate monorepo vs. polyrepo (separate repositories for each component) for:

a) Code sharing between frontend and mobile app b) CI/CD pipeline complexity c) Code review workflow d) Dependency management e) Onboarding new developers f) Deploying individual components independently


Tier 5: Create (Exercises 27-30)

These exercises require you to build complete features or systems.

Exercise 27: Notification System

Design and implement a full-stack notification system for a task management app:

Backend: - A Notification model with fields: id, user_id, type (task_assigned, task_completed, comment_added), message, is_read, created_at - API endpoints: GET /api/notifications (with pagination and unread filter), PATCH /api/notifications/{id}/read, PATCH /api/notifications/read-all - WebSocket integration to push new notifications in real-time - A utility function that other endpoints can call to create notifications (e.g., when a task is assigned)

Frontend: - A notification bell icon in the header showing unread count - A dropdown panel showing recent notifications - Mark-as-read on click - Mark-all-as-read button - Real-time updates via WebSocket (new notifications appear without refreshing)

Write complete, working code for both backend and frontend.

Exercise 28: Search Feature

Build a full-stack search feature for a content management system:

Backend: - Full-text search across article titles, bodies, and tags using PostgreSQL's tsvector and tsquery - Search endpoint with pagination, highlighting of matched terms, and relevance sorting - Search suggestions endpoint that returns matching titles as the user types (debounced) - Filter by category, date range, and author

Frontend: - Search bar with autocomplete suggestions (debounced to avoid excessive API calls) - Search results page with highlighted matching text - Faceted filtering UI (category checkboxes, date range picker) - URL-based search state (search query and filters reflected in the URL for shareability)

Write the complete implementation.

Exercise 29: Admin Dashboard

Build a full-stack admin dashboard for a multi-user application:

Backend: - Admin-only middleware that checks user role - Endpoints for: user management (list, disable, change role), application statistics (total users, active users, tasks created per day), and system health (database connectivity, memory usage) - Data aggregation queries using SQLAlchemy

Frontend: - Dashboard page with charts (use a charting library of your choice) showing user growth and activity - User management table with search, pagination, and action buttons (disable account, change role) - Protected admin routes that only admin users can access - Responsive layout that works on desktop and tablet

Write the complete implementation with AI-assistance prompts annotated at each step.

Exercise 30: Full-Stack Feature From Scratch

Choose one of the following features and build it end to end, from database schema to frontend UI:

Option A: Kanban Board — Drag-and-drop task board with columns (To Do, In Progress, Review, Done). Tasks can be dragged between columns and reordered within columns. Changes persist to the database and sync in real-time to other users viewing the same board.

Option B: Activity Feed — A timeline showing all actions taken in the application (task created, task completed, comment added, user joined). Support filtering by action type and user. Include relative timestamps ("2 minutes ago") and infinite scroll pagination.

Option C: Team Workspaces — Multi-tenant support where users can create and join workspaces. Each workspace has its own tasks, members, and settings. Users can switch between workspaces. Include invitation via email link.

For whichever option you choose, write: 1. The database models and migration 2. The API endpoints with Pydantic schemas 3. The React components with state management 4. Integration tests for the API 5. A deployment configuration (Docker Compose or similar)

Document your AI prompts at each step and note where the AI's output needed correction.