Files
rspade_system/FPC_IMPLEMENTATION_PLAN.md
root f6fac6c4bc Fix bin/publish: copy docs.dist from project root
Fix bin/publish: use correct .env path for rspade_system
Fix bin/publish script: prevent grep exit code 1 from terminating script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-21 02:08:33 +00:00

3.4 KiB
Executable File

SSR Full Page Cache (FPC) Implementation Plan

Overview

Server-side rendered static page caching system using Playwright + Redis. Routes marked with #[Static_Page] auto-generate and serve pre-rendered HTML to unauthenticated users.

Implementation Order

Phase 1: Foundation & Research

  1. Study rsx:debug command and Playwright script structure
  2. Understand current Dispatch.php flow and route attribute processing

Phase 2: Core Commands

  1. Create rsx:ssr_fpc:create command (copy from rsx:debug)
  2. Create Playwright script generate-static-cache.js in command's resource directory
  3. Implement exclusive lock GENERATE_STATIC_CACHE in Playwright script
  4. Strip GET parameters from URL before rendering
  5. Handle redirect interception (manual redirect mode)
  6. Capture response: DOM + headers OR redirect location
  7. Generate cache structure with 30-char ETag (SHA1 of build_key + URL + content)

Phase 3: Storage Layer

  1. Implement Redis cache with key format: ssr_fpc:{build_key}:{sha1(url)}
  2. Store JSON: {url, code, page_dom/redirect, build_key, etag, generated_at}
  3. Add comprehensive error logging to storage/logs/ssr-fpc-errors.log

Phase 4: Runtime Integration

  1. Update Session::__is_fpc_client() with header check: X-RSpade-FPC-Client: 1
  2. Add header to Playwright script
  3. Create #[Static_Page] attribute stub in .vscode/attribute-stubs.php
  4. Modify Dispatch.php to:
    • Check for #[Static_Page] attribute
    • Verify !Session::is_active() (unauthenticated only)
    • Skip FPC if Session::__is_fpc_client() is true
    • Check Redis cache, generate if missing (fatal on failure)
    • Validate ETag for 304 responses
    • Serve with proper cache headers (0s dev, 5min prod)

Phase 5: Management & Config

  1. Create rsx:ssr_fpc:reset command (flush Redis ssr_fpc:* keys)
  2. Add config to config/rsx.php:
'ssr_fpc' => [
    'enabled' => env('SSR_FPC_ENABLED', false),
    'generation_timeout' => 30000, // ms
]

Phase 6: Documentation

  1. Create app/RSpade/man/ssr_fpc.txt with:
    • Purpose and usage
    • Attribute syntax
    • Cache lifecycle
    • Bypass headers
    • Future roadmap (sitemap, parallelization, external service, shared secret)
    • Security considerations

Phase 7: Testing

  1. Test simple static page generation and serving
  2. Test redirect caching and serving
  3. Test ETag validation (304 responses)
  4. Test authenticated user bypass
  5. Test cache invalidation on build_key change

Key Technical Decisions

Redis Cache Key

Format: ssr_fpc:{build_key}:{sha1(request_path)}

  • Auto-invalidates on deployment (build_key changes)
  • URL hash prevents key collisions
  • GET params stripped before hashing

ETag

First 30 chars of SHA1(build_key + url + content)

FPC Client Header

X-RSpade-FPC-Client: 1

Session Check

Session::is_active() (not RsxAuth::check())

Redirect Handling

Cache first 302, don't follow

Cache TTL

Indefinite (Redis LRU handles eviction)

Future Roadmap (Not in Initial Implementation)

  • Option for rsx:ssr_fpc:create --from-sitemap rather than a specific url
  • Shared, private, automatic key for the fpc runner, so the fpc headers are only recognized by the server itself
    • The same should be done for rsx:debug
  • External service to generate the fpc renderings
  • Parallelization
  • Programmatic cache reset for things like updating cms or blog posts