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

6.5 KiB
Raw Blame History

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

  • Inertia-first: no API-only split — UI served via Inertia page
  • 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.)
  • Webhook + job flow prepared but out-of-scope for this slice (idempotency planned in later features)
  • Image compositing will run in queued jobs in later features (not done in this slice)
  • Cache busting: server returns master_version in metadata for image URL ?v= token
  • 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.phpcell_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:

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.