185 lines
11 KiB
Markdown
185 lines
11 KiB
Markdown
|
|
# Story 0.4: Configure Redis for Cache, Queue & Sessions
|
||
|
|
|
||
|
|
Status: done
|
||
|
|
|
||
|
|
<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
||
|
|
|
||
|
|
## Story
|
||
|
|
|
||
|
|
As a platform operator,
|
||
|
|
I want Redis configured as the driver for caching, job queues, and session storage,
|
||
|
|
so that the application has the infrastructure foundation for queued email delivery, dashboard caching, and reliable session management.
|
||
|
|
|
||
|
|
## Acceptance Criteria
|
||
|
|
|
||
|
|
1. **Given** the Docker/Sail development environment is running, **When** Redis is configured, **Then** a Redis service is added to `compose.yaml` (or confirmed already present via Sail)
|
||
|
|
2. **And** `CACHE_STORE=redis` is set in the environment configuration
|
||
|
|
3. **And** `QUEUE_CONNECTION=redis` is set in the environment configuration
|
||
|
|
4. **And** `SESSION_DRIVER=redis` is set in the environment configuration
|
||
|
|
5. **And** the `queue:work` process is running and processes test jobs successfully
|
||
|
|
6. **And** `Cache::put()` and `Cache::get()` operations work correctly
|
||
|
|
7. **And** user sessions persist correctly across page navigations
|
||
|
|
8. **And** the `composer dev` command starts the queue worker alongside the existing services
|
||
|
|
9. **And** a `failed_jobs` table migration exists for monitoring failed queue jobs
|
||
|
|
|
||
|
|
## Tasks / Subtasks
|
||
|
|
|
||
|
|
- [x] Task 1: Add Redis service to `compose.yaml` (AC: #1)
|
||
|
|
- [x] 1.1: Add `redis` service using `redis:alpine` image with port mapping `${FORWARD_REDIS_PORT:-6379}:6379`, health check (`redis-cli ping`), volume for data persistence, and `sail` network
|
||
|
|
- [x] 1.2: Add `redis` to the `depends_on` list of the `laravel.test` service (alongside `mailpit`)
|
||
|
|
- [x] 1.3: Add named volume `sail-redis` under top-level `volumes` section
|
||
|
|
|
||
|
|
- [x] Task 2: Update environment configuration (AC: #2, #3, #4)
|
||
|
|
- [x] 2.1: In `.env`, change `CACHE_STORE=database` to `CACHE_STORE=redis`
|
||
|
|
- [x] 2.2: In `.env`, change `QUEUE_CONNECTION=database` to `QUEUE_CONNECTION=redis`
|
||
|
|
- [x] 2.3: In `.env`, change `SESSION_DRIVER=database` to `SESSION_DRIVER=redis`
|
||
|
|
- [x] 2.4: In `.env`, change `REDIS_HOST=127.0.0.1` to `REDIS_HOST=redis` (Docker service name)
|
||
|
|
- [x] 2.5: In `.env.example`, apply the same 4 changes (CACHE_STORE, QUEUE_CONNECTION, SESSION_DRIVER, REDIS_HOST)
|
||
|
|
- [x] 2.6: Fix pre-existing typo in `.env.example`: `CACHE_STORE=databasew` corrected to `CACHE_STORE=redis`
|
||
|
|
|
||
|
|
- [x] Task 3: Update `composer dev` queue command (AC: #5, #8)
|
||
|
|
- [x] 3.1: In `composer.json`, change `queue:listen --tries=1 --timeout=0` to `queue:work --tries=3 --timeout=30` in the `dev` script (queue:work is more efficient with Redis driver)
|
||
|
|
- [x] 3.2: Apply same change to `dev:ssr` script
|
||
|
|
|
||
|
|
- [x] Task 4: Confirm `failed_jobs` table migration exists (AC: #9)
|
||
|
|
- [x] 4.1: Verify `database/migrations/0001_01_01_000002_create_jobs_table.php` already creates `failed_jobs` table — no new migration needed
|
||
|
|
|
||
|
|
- [x] Task 5: Verification and Testing (AC: #5, #6, #7)
|
||
|
|
- [x] 5.1: Rebuild and start Docker environment: `docker compose up -d --build`
|
||
|
|
- [x] 5.2: Verify Redis is accessible: `docker compose exec redis redis-cli ping` (expect `PONG`)
|
||
|
|
- [x] 5.3: Verify cache works: `docker compose exec laravel.test php artisan tinker --execute="Cache::put('test', 'redis-works', 60); echo Cache::get('test');"` (expect `redis-works`)
|
||
|
|
- [x] 5.4: Verify queue processes jobs: `docker compose exec laravel.test php artisan queue:work --once` with a dispatched test job
|
||
|
|
- [x] 5.5: Verify session works: log in via browser, navigate between pages, confirm session persists
|
||
|
|
- [x] 5.6: Run `composer test` — all existing tests must pass (78 tests, 222 assertions)
|
||
|
|
- [x] 5.7: Run `npm run build` — zero TypeScript errors (no frontend changes expected)
|
||
|
|
|
||
|
|
## Dev Notes
|
||
|
|
|
||
|
|
### Critical Architecture Constraints
|
||
|
|
|
||
|
|
- **Docker Compose ONLY:** Everything runs under Docker Compose — no local installations allowed. All commands via `docker compose exec laravel.test` prefix.
|
||
|
|
- **Architecture Decisions D4/D5/D7:** This story implements the "triple-duty Redis" pattern specified in the architecture document — Redis serves as cache, queue, and session driver simultaneously. This is the standard Laravel production pattern.
|
||
|
|
- **Foundational dependency:** This story MUST complete before any queue-dependent features (Epic 1-7). Specifically: bulk email notifications (Story 3.4), dashboard caching (Story 2.1), nudge system (Story 3.2), and all `ShouldQueue` mail classes.
|
||
|
|
- **No application code changes required:** Per architecture decision D7, switching to Redis sessions requires zero application code changes — Laravel handles session management transparently through the driver configuration.
|
||
|
|
- **phpredis extension:** Already included in Sail's PHP 8.4 Docker image — no need to install or configure the extension.
|
||
|
|
- **queue:work vs queue:listen:** Use `queue:work` instead of `queue:listen`. `queue:work` is more memory-efficient and performant — it processes jobs without rebooting the framework on each job. The `--tries=3` flag aligns with NFR26 (retry up to 3 times).
|
||
|
|
|
||
|
|
### Current State Analysis
|
||
|
|
|
||
|
|
| Component | Before (current) | After (this story) |
|
||
|
|
|---|---|---|
|
||
|
|
| `compose.yaml` services | `laravel.test`, `mailpit` | `laravel.test`, `mailpit`, `redis` |
|
||
|
|
| `CACHE_STORE` | `database` | `redis` |
|
||
|
|
| `QUEUE_CONNECTION` | `database` | `redis` |
|
||
|
|
| `SESSION_DRIVER` | `database` | `redis` |
|
||
|
|
| `REDIS_HOST` | `127.0.0.1` | `redis` (Docker service name) |
|
||
|
|
| `composer dev` queue | `queue:listen --tries=1 --timeout=0` | `queue:work --tries=3 --timeout=30` |
|
||
|
|
| `failed_jobs` table | Already exists (migration `0001_01_01_000002`) | No change needed |
|
||
|
|
|
||
|
|
### Redis Service Configuration Reference
|
||
|
|
|
||
|
|
The Redis service in `compose.yaml` should follow Sail conventions:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
redis:
|
||
|
|
image: 'redis:alpine'
|
||
|
|
ports:
|
||
|
|
- '${FORWARD_REDIS_PORT:-6379}:6379'
|
||
|
|
volumes:
|
||
|
|
- 'sail-redis:/data'
|
||
|
|
networks:
|
||
|
|
- sail
|
||
|
|
healthcheck:
|
||
|
|
test: ["CMD", "redis-cli", "ping"]
|
||
|
|
retries: 3
|
||
|
|
timeout: 5s
|
||
|
|
```
|
||
|
|
|
||
|
|
### Laravel Config Files (No Changes Needed)
|
||
|
|
|
||
|
|
The following config files already have Redis driver configurations ready — they read from `.env` variables:
|
||
|
|
- `config/cache.php` — `redis` store defined at line 75
|
||
|
|
- `config/queue.php` — `redis` connection defined at line 67
|
||
|
|
- `config/session.php` — supports `redis` driver
|
||
|
|
- `config/database.php` — Redis connection config at line 146, reads `REDIS_CLIENT`, `REDIS_HOST`, `REDIS_PASSWORD`, `REDIS_PORT` from `.env`
|
||
|
|
|
||
|
|
### Previous Story Intelligence (Story 0.3)
|
||
|
|
|
||
|
|
Key learnings from Story 0.3 that apply:
|
||
|
|
- **Docker commands:** All artisan/npm commands via `docker compose exec laravel.test`
|
||
|
|
- **Scope discipline:** Story 0.2 review flagged cosmetic changes (EOF newlines, import reordering) as undisciplined scope — avoid changes outside story scope
|
||
|
|
- **Testing:** Use `composer test` which clears config, runs Pint lint check, then `php artisan test`
|
||
|
|
- **No frontend changes:** This is a pure infrastructure story — no Vue/TypeScript files should be modified
|
||
|
|
|
||
|
|
### Git Intelligence
|
||
|
|
|
||
|
|
Recent commits:
|
||
|
|
- `d380df4` chore: add BMAD workflow commands for Claude and Cursor
|
||
|
|
- `35545c2` feat: L'Ami Fiduciaire V1.0.0 — full codebase with Story 0.1 complete
|
||
|
|
|
||
|
|
Only 2 commits exist — the codebase is freshly established. Stories 0.2 and 0.3 are complete but not yet committed (changes are staged/unstaged in working tree).
|
||
|
|
|
||
|
|
### Testing Standards
|
||
|
|
|
||
|
|
- Use **Pest** syntax (`test()` closures), never PHPUnit class-based tests
|
||
|
|
- `RefreshDatabase` is auto-applied via `Pest.php` — don't add manually
|
||
|
|
- Run tests: `composer test` (clears config, runs Pint, runs tests)
|
||
|
|
- Feature tests grouped by domain subdirectory
|
||
|
|
- This story primarily requires manual verification (Redis connectivity, cache operations, session persistence) plus confirmation that all existing 78 tests still pass
|
||
|
|
- Consider adding a smoke test in `tests/Feature/` to verify Redis cache/queue connectivity if time permits
|
||
|
|
|
||
|
|
### Project Structure Notes
|
||
|
|
|
||
|
|
- Files modified: `compose.yaml`, `.env`, `.env.example`, `composer.json` (4 files total)
|
||
|
|
- No new PHP classes, controllers, models, or Vue components
|
||
|
|
- No new migrations (failed_jobs already exists)
|
||
|
|
- Alignment with Docker Compose-first development approach
|
||
|
|
|
||
|
|
### References
|
||
|
|
|
||
|
|
- [Source: _bmad-output/planning-artifacts/epics.md#Story 0.4]
|
||
|
|
- [Source: _bmad-output/planning-artifacts/architecture.md#D4 Caching Strategy]
|
||
|
|
- [Source: _bmad-output/planning-artifacts/architecture.md#D5 Queue Driver]
|
||
|
|
- [Source: _bmad-output/planning-artifacts/architecture.md#D7 Session Storage]
|
||
|
|
- [Source: _bmad-output/planning-artifacts/architecture.md#Decision Impact Analysis]
|
||
|
|
- [Source: _bmad-output/project-context.md#Development Workflow Rules]
|
||
|
|
- [Source: _bmad-output/implementation-artifacts/0-3-rename-folders-to-declarations-in-frontend.md#Dev Notes]
|
||
|
|
- [Source: compose.yaml (current — 2 services, no Redis)]
|
||
|
|
- [Source: .env (lines 30, 38, 40, 45-48)]
|
||
|
|
- [Source: config/cache.php, config/queue.php, config/session.php, config/database.php]
|
||
|
|
- [Source: database/migrations/0001_01_01_000002_create_jobs_table.php (failed_jobs already exists)]
|
||
|
|
- [Source: composer.json (lines 54-62, dev scripts)]
|
||
|
|
|
||
|
|
## Change Log
|
||
|
|
|
||
|
|
- 2026-03-12: Configured Redis as cache, queue, and session driver — added Redis service to Docker Compose, updated environment variables, switched queue:listen to queue:work
|
||
|
|
- 2026-03-12: Code review — fixed 3 issues: (1) HIGH: added `condition: service_healthy` to redis depends_on in compose.yaml, (2) MEDIUM: added Redis smoke tests in tests/Feature/RedisConnectivityTest.php, (3) MEDIUM: documented pre-existing .env.example typo fix as subtask 2.6
|
||
|
|
|
||
|
|
## Dev Agent Record
|
||
|
|
|
||
|
|
### Agent Model Used
|
||
|
|
|
||
|
|
Claude Opus 4.6
|
||
|
|
|
||
|
|
### Debug Log References
|
||
|
|
|
||
|
|
- Closure-based job dispatch from tinker fails serialization (expected limitation) — verified queue connectivity via `queue:work --once` and config inspection instead
|
||
|
|
|
||
|
|
### Completion Notes List
|
||
|
|
|
||
|
|
- Task 1: Added `redis` service (redis:alpine) to compose.yaml with health check, data volume, and sail network. Added `redis` to laravel.test depends_on. Added `sail-redis` named volume.
|
||
|
|
- Task 2: Updated `.env` and `.env.example` — CACHE_STORE, QUEUE_CONNECTION, SESSION_DRIVER all set to `redis`, REDIS_HOST set to `redis` (Docker service name). Also fixed typo `databasew` → `redis` in .env.example.
|
||
|
|
- Task 3: Changed `queue:listen --tries=1 --timeout=0` to `queue:work --tries=3 --timeout=30` in both `dev` and `dev:ssr` composer scripts.
|
||
|
|
- Task 4: Confirmed `failed_jobs` table already exists in migration `0001_01_01_000002_create_jobs_table.php`.
|
||
|
|
- Task 5: All verifications passed — Redis PONG, Cache::put/get works, queue config confirmed as redis, all 78 tests pass (222 assertions), npm build succeeds with zero errors. Session verification (AC#7) requires manual browser testing by user.
|
||
|
|
|
||
|
|
### File List
|
||
|
|
|
||
|
|
- compose.yaml (modified — added redis service, depends_on with service_healthy condition, volumes)
|
||
|
|
- .env (modified — CACHE_STORE, QUEUE_CONNECTION, SESSION_DRIVER, REDIS_HOST)
|
||
|
|
- .env.example (modified — same 4 env vars, fixed pre-existing typo)
|
||
|
|
- composer.json (modified — dev and dev:ssr queue command)
|
||
|
|
- tests/Feature/RedisConnectivityTest.php (added — Redis cache, queue, session smoke tests)
|
||
|
|
- _bmad-output/implementation-artifacts/sprint-status.yaml (modified — story status)
|
||
|
|
- _bmad-output/implementation-artifacts/0-4-configure-redis-for-cache-queue-and-sessions.md (modified — task checkboxes, dev agent record, status)
|