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

94 lines
3.4 KiB
Markdown
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
3. Create `rsx:ssr_fpc:create` command (copy from `rsx:debug`)
4. Create Playwright script `generate-static-cache.js` in command's resource directory
5. Implement exclusive lock `GENERATE_STATIC_CACHE` in Playwright script
6. Strip GET parameters from URL before rendering
7. Handle redirect interception (manual redirect mode)
8. Capture response: DOM + headers OR redirect location
9. Generate cache structure with 30-char ETag (SHA1 of build_key + URL + content)
### Phase 3: Storage Layer
10. Implement Redis cache with key format: `ssr_fpc:{build_key}:{sha1(url)}`
11. Store JSON: `{url, code, page_dom/redirect, build_key, etag, generated_at}`
12. Add comprehensive error logging to `storage/logs/ssr-fpc-errors.log`
### Phase 4: Runtime Integration
13. Update `Session::__is_fpc_client()` with header check: `X-RSpade-FPC-Client: 1`
14. Add header to Playwright script
15. Create `#[Static_Page]` attribute stub in `.vscode/attribute-stubs.php`
16. 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
17. Create `rsx:ssr_fpc:reset` command (flush Redis `ssr_fpc:*` keys)
18. Add config to `config/rsx.php`:
```php
'ssr_fpc' => [
'enabled' => env('SSR_FPC_ENABLED', false),
'generation_timeout' => 30000, // ms
]
```
### Phase 6: Documentation
19. 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
20. Test simple static page generation and serving
21. Test redirect caching and serving
22. Test ETag validation (304 responses)
23. Test authenticated user bypass
24. 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