--- description: "Task list for Public Grid Viewer (vertical slice)" --- # Tasks: Public Grid Viewer + Live Selection **Input**: Design docs from `specs/001-public-grid-viewer/` (spec.md, plan.md) ## Phase 1: Setup (Shared Infrastructure) - [ ] T001 [P] Create config/pixel_grid.php in config/pixel_grid.php (defines `cell_size`, `price_per_cell`, `master_path`) - [ ] T002 [P] Add sample master image to storage/app/public/master/master.png and ensure `php artisan storage:link` (path: storage/app/public/master/master.png) - [ ] T003 [P] Create lightweight `MasterImage` model at app/Models/MasterImage.php and optional migration at database/migrations/*_create_master_images_table.php - [ ] T004 [P] Add `PublicGridController` skeleton at app/Http/Controllers/PublicGridController.php and route placeholder in routes/web.php - [X] T001 [P] Create config/pixel_grid.php in config/pixel_grid.php (defines `cell_size`, `price_per_cell`, `master_path`) - [X] T002 [P] Add sample master image to storage/app/public/master/master.png and ensure `php artisan storage:link` (path: storage/app/public/master/master.png) - [X] T003 [P] Create lightweight `MasterImage` model at app/Models/MasterImage.php and optional migration at database/migrations/*_create_master_images_table.php - [X] T004 [P] Add `PublicGridController` skeleton at app/Http/Controllers/PublicGridController.php and route placeholder in routes/web.php --- ## Phase 2: Foundational API (Blocking prerequisites) - [ ] T005 [P] [US1] Implement `GET /api/grid/meta` in app/Http/Controllers/PublicGridController.php; route in routes/web.php — returns `{ master_image_url, master_version, cell_size }` - [ ] T006 [P] [US1] Implement `GET /api/grid/price` in app/Http/Controllers/PublicGridController.php — returns `{ price_per_cell }` (read from config/pixel_grid.php) - [ ] T007 [P] [US1] Implement `GET /api/grid/availability` in app/Http/Controllers/PublicGridController.php — returns list of occupied `{cell_x,cell_y}` (MVP: empty array) - [ ] T008 [P] Add rate-limiting middleware to sensitive endpoints (routes/web.php or RouteServiceProvider) - [ ] T009 [P] [US1] Add Pest tests: tests/Feature/PublicGridMetaTest.php and tests/Feature/PriceCalculationTest.php verifying endpoints and JSON schema - [X] T005 [P] [US1] Implement `GET /api/grid/meta` in app/Http/Controllers/PublicGridController.php; route in routes/web.php — returns `{ master_image_url, master_version, cell_size }` - [X] T006 [P] [US1] Implement `GET /api/grid/price` in app/Http/Controllers/PublicGridController.php — returns `{ price_per_cell }` (read from config/pixel_grid.php) - [X] T007 [P] [US1] Implement `GET /api/grid/availability` in app/Http/Controllers/PublicGridController.php — returns list of occupied `{cell_x,cell_y}` (MVP: empty array) - [X] T008 [P] Add rate-limiting middleware to sensitive endpoints (routes/web.php or RouteServiceProvider) - [X] T009 [P] [US1] Add Pest tests: tests/Feature/PublicGridMetaTest.php and tests/Feature/PriceCalculationTest.php verifying endpoints and JSON schema --- ## Phase 3: User Story 1 - Public viewer + Live selection (Priority: P1) 🎯 MVP **Goal**: Interactive public page with pan/zoom, canvas grid, rectangle selection, sidebar price preview, and upload preview modal (no persistence) **Independent Test**: Load the Inertia page, make selections on desktop and mobile; verify cell count and `cell_count × price_per_cell` displayed equals expected value from `config/pixel_grid.php`. - [ ] T010 [US1] Create Inertia page at resources/js/Pages/PublicGrid/Index.vue and wire route to `PublicGridController@show` - [ ] T011 [US1] Implement `resources/js/components/GridCanvas.vue` using Konva or Canvas API (pan/zoom, grid draw, hit-testing mapped to cell units) - [ ] T012 [US1] Implement `resources/js/components/SelectionSidebar.vue` (shows cell count, queries `/api/grid/price`, shows total price, CTA opens modal) - [ ] T013 [US1] Implement `resources/js/components/UploadModal.vue` with client-side image selection and preview composited into selection rectangle - [ ] T014 [US1] Wire mobile touch handlers in `GridCanvas.vue` (pinch to zoom, drag to pan, touch selection) and test on iPhone viewport - [ ] T015 [P] [US1] Add client-side clamp/validation: selection clamped to image bounds and max selection size enforced in GridCanvas.vue - [X] T010 [US1] Create Inertia page at resources/js/Pages/PublicGrid/Index.vue and wire route to `PublicGridController@show` - [X] T011 [US1] Implement `resources/js/components/GridCanvas.vue` using Konva or Canvas API (pan/zoom, grid draw, hit-testing mapped to cell units) - [X] T012 [US1] Implement `resources/js/components/SelectionSidebar.vue` (shows cell count, queries `/api/grid/price`, shows total price, CTA opens modal) - [X] T013 [US1] Implement `resources/js/components/UploadModal.vue` with client-side image selection and preview composited into selection rectangle - [X] T014 [US1] Wire mobile touch handlers in `GridCanvas.vue` (pinch to zoom, drag to pan, touch selection) and test on iPhone viewport - [X] T015 [P] [US1] Add client-side clamp/validation: selection clamped to image bounds and max selection size enforced in GridCanvas.vue --- ## Phase 4: Tests & QA - [ ] T016 [US1] Add selection math feature test at tests/Feature/SelectionMathTest.php verifying client/server cell mapping (can be unit or integration with mocked cell_size) - [ ] T017 [P] Create manual QA checklist at specs/001-public-grid-viewer/checklists/qa.md (mobile interactions, selection precision, upload preview) - [X] T016 [US1] Add selection math feature test at tests/Feature/SelectionMathTest.php verifying client/server cell mapping (can be unit or integration with mocked cell_size) - [ ] T017 [P] Create manual QA checklist at specs/001-public-grid-viewer/checklists/qa.md (mobile interactions, selection precision, upload preview) --- ## Phase 5: Polish & Cross-Cutting Concerns - [ ] T018 [P] Add quickstart file specs/001-public-grid-viewer/quickstart.md with local dev steps - [ ] T019 [P] Add design decision doc at docs/decisions/001-public-grid-viewer.md explaining canvas choice and DB-locking deferral - [ ] T020 [P] Run `vendor/bin/pint` / code style checks and ensure tests pass locally - [ ] T018 [P] Add quickstart file specs/001-public-grid-viewer/quickstart.md with local dev steps - [ ] T019 [P] Add design decision doc at docs/decisions/001-public-grid-viewer.md explaining canvas choice and DB-locking deferral - [ ] T020 [P] Run `vendor/bin/pint` / code style checks and ensure tests pass locally --- ## Dependencies & Execution Order - Setup (Phase 1) must complete before Foundational (Phase 2) — Phase 1 tasks can be parallelized. - Foundational (Phase 2) blocks User Story implementation — once T005..T009 pass, frontend work can begin. - User Story tasks (Phase 3) depend on Foundational APIs (T005/T006) but UI components T011/T012 can be scaffolded in parallel and stub the API during development. ## User Story Task Counts - Total tasks: 20 - Tasks for US1: 9 (T005-T007, T009, T010-T015, T016) ## Parallel Opportunities - Phase 1 tasks T001-T004 are parallelizable ([P]). - Endpoint implementations T005-T007 and T008 rate-limiting can be parallelized across backend devs. - Frontend components T011-T013 can be implemented in parallel by different developers. ## Independent Test Criteria (per story) - US1: Selection precision verified by tests/Feature/SelectionMathTest.php and manual mobile QA; price display uses server `price_per_cell` (T006) — independent of payments. ## Suggested MVP scope - Deliver Phases 1–3 for an internal demo: `PublicGrid` page with working selection and price preview (no persistence). This is the recommended MVP. ## Implementation Strategy 1. Implement Phase 1 & Phase 2 backend endpoints and tests (T001-T009). 2. Scaffold frontend pages and components (T010-T013) using mocked API responses. 3. Replace mocks with real endpoints and complete mobile handlers (T014-T015). 4. Run tests, perform QA, and add docs (T016-T019). *** *** End File