Step 1: Configure caching
Caching is a delivery architecture, not an optimization you add at the end. Different content types need different caching strategies.
Static assets (JavaScript bundles, CSS files, images with hashed filenames): these never change once deployed. A new deploy creates new files with new hashes. Set Cache-Control: public, max-age=31536000, immutable -- the browser caches them for a year and never re-fetches. The "immutable" directive tells the browser not to even check if the file changed.
SSG pages (About, Visit, History): these change only when you deploy. Set Cache-Control: public, s-maxage=86400, stale-while-revalidate=43200 -- the CDN caches them for 24 hours and serves stale content while revalidating in the background after that.
Authenticated member pages: never cache at the CDN. Set Cache-Control: no-store, no-cache, must-revalidate. If a member page is cached at the CDN, another user might see it -- that's not a performance issue, that's a security breach.
Direct Claude to configure these headers in the Next.js middleware or response handlers. Each route type gets its own caching strategy.
Step 2: Verify caching behavior
Open Chrome DevTools, go to the Network tab, and check the response headers for each route type.
Load the About page. Check the Cache-Control header. It should show the SSG caching values.
Load a static asset (a JavaScript bundle). Check the header. It should show immutable with a year-long max-age.
Load the members dashboard (while logged in). Check the header. It should show no-store, no-cache.
Now open a private/incognito window and load the same pages. This simulates a fresh visitor with no cache. The SSG pages should load from the CDN (check the response headers for CDN indicators). The member pages should redirect to login.
A misconfigured cache header passes all functional tests. The site works correctly in development, where caching is typically disabled. The problem only appears in production, where the CDN serves cached content to the wrong people.
Step 3: Run Lighthouse performance
Run a Lighthouse performance audit.
The numbers here are a consequence of the architecture decisions you made in Unit 2. SSG pages should show excellent First Contentful Paint and Largest Contentful Paint because the content was pre-built. The collection SSR page should show good numbers if the Suspense boundaries are working -- the shell loads fast while the data streams in. The members area (CSR) will show slower initial metrics because JavaScript has to load before anything renders.
If the numbers aren't where you expected, the architecture decisions and the results are connected. A slow SSG page means something is wrong with the CDN configuration. A slow SSR page means the server-side rendering is doing too much work. A slow CSR page with high Total Blocking Time means too much JavaScript is being sent to the browser.
Step 4: Document the decisions
Write an architecture decision document. Include:
- The rendering strategy for each route type and why
- The caching strategy for each content type and why
- The Suspense boundary placements and why
- The auth enforcement approach (server-side middleware) and why
This document is for the next developer who works on this site. Without it, someone changes a cache header because "it seemed wrong" and breaks member page privacy. Someone changes a server component to a client component because "it was easier" and kills the collection page performance.
The decisions aren't obvious from the code. The rendering strategy looks like route configuration. The caching headers look like response headers. Only the documentation explains why those choices were made and what breaks if they change.
Step 5: Deploy
Deploy to production. Then verify:
- Run the full test suite in production mode
- Verify OAuth callbacks work with the production URL (update the callback URLs in your OAuth provider)
- Load the site on your phone (or use DevTools device emulation with 3G throttling)
- Verify CDN caching on SSG pages (check response headers)
- Verify member pages are not cached at the CDN
- Verify the Grafana dashboards are receiving production metrics
Step 6: Close the project
Push to GitHub. Write the README with a description of the project, the tech stack, and the architecture decisions.
Send Ivan the production URL along with the Grafana dashboard link.
He responds after two days: "I have shared this with the board and the curatorial team. The collection browsing is excellent. The accessibility -- I tested it myself with a screen reader, following the instructions you provided. It works. The members have been notified and we've had twelve logins in the first day. This meets our standards."
Ivan doesn't say that lightly. He reviews things thoroughly and he doesn't give praise he doesn't mean. "This meets our standards" is the formal approval of a person who cares deeply about his institution's public presence.
Check: Load the deployed site on a phone. Navigate to the collection, search for an artifact, open the detail view. Initial page load under 2 seconds on a 3G connection. Then navigate to a member login -- server redirects if not authenticated.