ramadanproject/specs/001-public-grid-viewer/plan.md
Ahmed Darrazi 45a147253c
Some checks failed
tests / ci (push) Failing after 6m13s
linter / quality (pull_request) Failing after 58s
linter / quality (push) Failing after 1m19s
tests / ci (pull_request) Failing after 5m28s
feat(public-grid): add QA, quickstart, decision docs; scheduler docs; ignore files; tasks updates; run pint
2026-01-03 04:56:12 +01:00

130 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Implementation Plan: Public Grid Viewer + Live Selection
Branch: `001-public-grid-viewer` | Date: 2026-01-03 | Spec: specs/001-public-grid-viewer/spec.md
Summary
Deliver a vertical slice that proves the core UI/value: a public page that
loads the master image, supports pan/zoom, a performant canvas-based grid,
rectangle selection, a sidebar showing cell count and server-provided
`price_per_cell`, and a modal for client-side upload preview. No checkout,
orders, or rendering Jobs are created in this slice.
Technical Context
Language/Version: PHP ^8.2 (Laravel 12)
Primary Dependencies: laravel/framework ^12, inertiajs/inertia-laravel ^2, vue 3, @inertiajs/vue3
Storage: Laravel Storage (local for dev, S3-ready via Storage driver)
Testing: Pest (pestphp/pest)
Target Platform: Web (Linux production), local dev via Sail / macOS
Project Type: Single Laravel web application (Inertia SPA)
Performance Goals: Public page loads master image + metadata within ~2000ms on 4G for MVP
Constraints: Avoid DOM explosion — use canvas/Konva for grid rendering
Constitution Check (REQUIRED)
Impact area(s): ☑ Public UX ☐ Payments ☐ Locking/Reservations ☐ Rendering/Compositing ☐ Upload/Security
Compliance Checklist
- [x] Inertia-first: no API-only split — UI served via Inertia page
- [x] Server is source of truth for `price_per_cell` (endpoint provides value)
- [ ] No double booking enforced at DB level: DEVIATION for this slice — reservations are out-of-scope; availability API is a stub. DB locking will be implemented in a follow-up feature. (Mitigation: UI shows availability overlay only; spec documents DB requirements.)
- [x] Webhook + job flow prepared but out-of-scope for this slice (idempotency planned in later features)
- [x] Image compositing will run in queued jobs in later features (not done in this slice)
- [x] Cache busting: server returns `master_version` in metadata for image URL `?v=` token
- [x] Upload validation rules: modal is client-only preview in this slice; server-side validation planned later
Decision log:
- Deviation: DB-level prevention of double booking is deferred.
- Rationale: vertical slice focuses on UI and public performance; locking requires order lifecycle and payment flow.
- Mitigation: availability endpoint will be implemented as a stub returning occupied cells later; tasks call out DB-level locking for follow-up.
Project Structure (selected)
Use the existing Laravel app layout. New/modified files for this feature:
- Backend
- `routes/web.php` — add route for public grid page
- `app/Http/Controllers/PublicGridController.php` — serves Inertia page and endpoints
- `config/pixel_grid.php``cell_size`, `price_per_cell`, `master_path`
- `database/migrations/*_create_master_images_table.php` (optional seed for master image)
- `app/Models/MasterImage.php` (lightweight model)
- `routes/api.php` (or small GET endpoints under web with `->name('api.*')`):
- `GET /api/grid/meta` → returns `master_image_url`, `master_version`, `cell_size`
- `GET /api/grid/price` → returns `price_per_cell`
- `GET /api/grid/availability` → returns list of occupied `{cell_x,cell_y}` (MVP: empty)
- Frontend
- `resources/js/Pages/PublicGrid/Index.vue` (Inertia page)
- `resources/js/components/GridCanvas.vue` (Konva/canvas wrapper + hit-testing)
- `resources/js/components/SelectionSidebar.vue` (cell count, price, CTA)
- `resources/js/components/UploadModal.vue` (client preview only)
- Tests
- `tests/Feature/PublicGridMetaTest.php` (meta endpoints)
- `tests/Feature/PriceCalculationTest.php`
Structure Decision: Keep everything inside the single Laravel app to use Inertia and Wayfinder where helpful; frontend code goes into `resources/js/Pages` and `resources/js/components` per project conventions.
Phase Plan & Tasks
Phase 1 — Setup (1-2 days)
- T001 Add `config/pixel_grid.php` with `cell_size` and `price_per_cell`.
- T002 Add sample master image to `storage/app/public/master/master.png` and a migration/seed to populate `master_images` if desired.
- T003 Add routes and `PublicGridController` skeleton.
Phase 2 — Foundational API (1 day)
- T010 Implement `GET /api/grid/meta` returning `{ master_image_url, master_version, cell_size }`.
- T011 Implement `GET /api/grid/price` returning `{ price_per_cell }`.
- T012 Implement `GET /api/grid/availability` returning empty set (stub) and wire rate-limiting middleware.
- T013 Add Pest feature tests for these endpoints (`PublicGridMetaTest`, `PriceCalculationTest`).
Phase 3 — Frontend Vertical Slice (3-5 days)
- T020 Create Inertia page `PublicGrid/Index.vue` and route.
- T021 Implement `GridCanvas.vue` using Konva or native canvas for grid overlay, pan/zoom, and rectangle selection. Ensure hit-testing uses cell units.
- T022 Implement `SelectionSidebar.vue` that queries `/api/grid/price` and computes `cell_count × price_per_cell` for display.
- T023 Implement `UploadModal.vue` for client-side image selection and preview composited into selection rectangle.
- T024 Wire mobile touch handlers (pinch to zoom, drag to pan, drag to select) and test on iPhone viewport.
Phase 4 — Tests & QA (1-2 days)
- T030 Add feature tests verifying price endpoint, meta endpoint, and selection cell math (server-provided `cell_size`).
- T031 Manual QA checklist for mobile pinch/drag and selection precision.
Phase 5 — Polish & Docs (1 day)
- T040 Add `specs/001-public-grid-viewer/quickstart.md` with local dev steps.
- T041 Add a short `/docs/decisions/001-public-grid-viewer.md` noting the canvas choice and DB-locking deferral.
Complexity Tracking
No constitution violations required for this slice except the deliberate deferral of DB-level locking. This is documented above and in the spec.
Deliverables
- Inertia page: `resources/js/Pages/PublicGrid/Index.vue`
- Canvas component: `resources/js/components/GridCanvas.vue`
- API endpoints: `GET /api/grid/meta`, `/api/grid/price`, `/api/grid/availability`
- Tests: `tests/Feature/PublicGridMetaTest.php`, `tests/Feature/PriceCalculationTest.php`
- Spec updates: `specs/001-public-grid-viewer/spec.md` (done)
Next Steps (how I can help)
- I can implement Phase 1+2 now: add config, controller and the three endpoints plus tests.
- Or I can scaffold the frontend Inertia page and the `GridCanvas.vue` component next.
Local run commands to verify:
```bash
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate --force
npm install
npm run dev
php artisan serve
```
Estimated total: 610 developer days (split: backend 2 days, frontend 47 days, QA 1 day). Adjust based on review/iterations.
***