Adds landing page at root URL (/) that displays all active products with links to feedback submission forms. This replaces the requirement for users to know direct product URLs. Changes: - Added Product.load_active() method to filter and sort active products alphabetically - Created landing route blueprint with error handling and structured logging - Registered landing blueprint in app factory, replacing old index route - Created landing page template with product list and empty state - Added comprehensive contract tests (6 tests) covering active products, filtering, sorting, XSS prevention - Added integration test for complete user flow from landing page to submission form All 7 tests pass. User Story 1 (P1 - MVP) complete. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9.6 KiB
Tasks: Product Selection Landing Page
Input: Design documents from /home/markus/workspace/reklamator/specs/002-product-list/
Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/landing-page.yaml
Organization: Tasks are grouped by user story to enable independent implementation and testing of each story.
Format: [ID] [P?] [Story] Description
- [P]: Can run in parallel (different files, no dependencies)
- [Story]: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions
Path Conventions
- Web application structure:
app/,tests/at repository root - Following existing Flask structure from feature 001
Phase 1: Setup (Shared Infrastructure)
Purpose: No new setup needed - feature reuses existing Flask infrastructure
This phase is empty - all infrastructure from feature 001 is reused
Phase 2: Foundational (Blocking Prerequisites)
Purpose: Core Product model extension needed by all user stories
⚠️ CRITICAL: User Story 1 depends on this extension
- T001 [US1] Extend Product model with load_active() class method in app/models/product.py
Checkpoint: Product.load_active() method ready - User Story 1 implementation can begin
Phase 3: User Story 1 - Browse and Select Product (Priority: P1) 🎯 MVP
Goal: Enable visitors to discover products via landing page at / and navigate to submission forms
Independent Test: Visit /, see active products listed, click a product link, verify redirect to /submit/{slug}
Tests for User Story 1 (TDD - Write FIRST, ensure FAIL)
- T002 [P] [US1] Contract test: GET / with active products returns 200 with product list HTML in tests/contract/test_landing_routes.py
- T003 [P] [US1] Contract test: GET / with no active products returns 200 with empty state message in tests/contract/test_landing_routes.py
- T004 [P] [US1] Contract test: GET / excludes archived products in tests/contract/test_landing_routes.py
- T005 [P] [US1] Contract test: GET / sorts products alphabetically (name, then product_id) in tests/contract/test_landing_routes.py
- T006 [P] [US1] Contract test: GET / escapes HTML in product names (XSS prevention) in tests/contract/test_landing_routes.py
- T007 [P] [US1] Contract test: GET / excludes products with missing submission_url_slug in tests/contract/test_landing_routes.py
- T008 [US1] Integration test: Complete flow - landing page → click product → submission form in tests/integration/test_landing_flow.py
Implementation for User Story 1
- T009 [US1] Create landing route blueprint in app/routes/landing.py
- T010 [US1] Register landing blueprint in app/__init__.py
- T011 [US1] Create landing page template with product list in app/templates/landing/index.html
- T012 [US1] Add logging for landing page access in app/routes/landing.py
- T013 [US1] Verify all tests pass for User Story 1
Checkpoint: User Story 1 complete and independently testable. MVP ready for demo/deploy.
Phase 4: User Story 2 - See Product Availability Status (Priority: P2)
Goal: Ensure only active products are visible (archived products excluded)
Independent Test: Create products with status 'active' and 'archived', verify only active products appear on landing page
Status: This functionality is already implemented in User Story 1 via the Product.load_active() filtering logic. No additional tasks needed.
Verification: Test T004 already validates this behavior.
Phase 5: User Story 3 - Direct Navigation with Known Product (Priority: P3)
Goal: Maintain backwards compatibility - direct /submit/{slug} URLs continue to work
Independent Test: Navigate directly to /submit/{slug}, verify submission form loads (no landing page interference)
Status: This is backwards compatibility verification only. No new implementation needed - existing submission routes are unchanged.
Verification for User Story 3
- T014 [US3] Manual test: Verify direct URL
/submit/{slug}still works without landing page interference - T015 [US3] Manual test: Verify alphabetical sorting helps users find products efficiently on landing page
Checkpoint: Backwards compatibility confirmed. All 3 user stories validated.
Phase 6: Polish & Cross-Cutting Concerns
Purpose: Final validations and quality checks
- T016 [P] Manual verification: Visit
/with 0 active products - see empty state message - T017 [P] Manual verification: Visit
/with 1 active product - see single product listed - T018 [P] Manual verification: Visit
/with 10+ active products - verify alphabetical order - T019 [P] Manual verification: Check product with no description - verify no placeholder text shown
- T020 [P] Manual verification: Check product with long name - verify proper text wrapping
- T021 [P] Manual verification: Access
/as anonymous user - page accessible - T022 [P] Manual verification: Access
/as authenticated user - same page shown (no redirect) - T023 [P] Manual verification: View page source - confirm no JavaScript present
- T024 [P] Performance verification: Load landing page with 100 products - confirm <1 second load time
- T025 Commit all changes with descriptive message
Dependencies & Execution Order
Phase Dependencies
- Setup (Phase 1): Empty - no setup needed
- Foundational (Phase 2): T001 must complete before User Story 1 - BLOCKS US1
- User Story 1 (Phase 3): Depends on T001 completion - Core MVP
- User Story 2 (Phase 4): Already implemented in US1 - No additional work
- User Story 3 (Phase 5): Manual verification only - Depends on US1
- Polish (Phase 6): Depends on US1 completion
Task Dependencies
Foundational:
- T001: No dependencies - can start immediately
User Story 1 (BLOCKS: T009-T013 depend on T001):
- T002-T008: Tests can all run in parallel [P] - write FIRST
- T009: Depends on T001 (needs Product.load_active method)
- T010: Depends on T009 (needs blueprint to register)
- T011: Can run parallel with T009 [P] conceptually, but blueprint needed for testing
- T012: Depends on T009 (logging in route handler)
- T013: Depends on T002-T012 (final validation)
User Story 3:
- T014-T015: Can run in parallel [P] - manual tests
Polish:
- T016-T024: Can all run in parallel [P] - independent manual checks
- T025: Depends on all previous tasks
Parallel Opportunities
Tests (Phase 3): Launch T002, T003, T004, T005, T006, T007 together (all in same file, different test functions)
Manual Verification (Phase 6): Launch T016-T024 together (independent checks)
Parallel Example: User Story 1
# Launch all contract tests together (write FIRST):
Task: "Contract test: GET / with active products in tests/contract/test_landing_routes.py"
Task: "Contract test: GET / with no products in tests/contract/test_landing_routes.py"
Task: "Contract test: GET / excludes archived in tests/contract/test_landing_routes.py"
Task: "Contract test: GET / sorts alphabetically in tests/contract/test_landing_routes.py"
Task: "Contract test: GET / XSS prevention in tests/contract/test_landing_routes.py"
Task: "Contract test: GET / excludes missing slug in tests/contract/test_landing_routes.py"
# Then implement in sequence:
Task: "Create landing route blueprint in app/routes/landing.py"
Task: "Register blueprint in app/__init__.py"
Task: "Create template in app/templates/landing/index.html"
Implementation Strategy
MVP First (User Story 1 Only)
- Complete T001: Extend Product model (Foundational)
- Complete T002-T008: Write all tests, verify they FAIL
- Complete T009-T012: Implement landing page
- Complete T013: Verify all tests PASS
- STOP and VALIDATE: User Story 1 is independently testable MVP
- Ready for demo/deploy
Incremental Delivery
- Foundation (T001) → Product.load_active() ready
- User Story 1 (T002-T013) → Test independently → Deploy (MVP!)
- User Story 2 → Already complete (filtering in US1)
- User Story 3 (T014-T015) → Verify backwards compatibility
- Polish (T016-T025) → Final quality checks
Single Developer Strategy
Execute tasks in numeric order (T001 → T025):
- T001: Extend model
- T002-T008: Write tests (all should FAIL)
- T009-T012: Implement feature
- T013: Verify tests PASS
- T014-T015: Manual backwards compatibility checks
- T016-T024: Manual quality checks
- T025: Commit
Notes
- TDD Discipline (Constitution Principle II): Tests T002-T008 MUST be written BEFORE T009-T012 implementation
- [P] tasks: Can run in parallel (different test functions or independent manual checks)
- [US1/US2/US3] labels: Map task to specific user story for traceability
- File paths: All paths use existing Flask structure from feature 001
- Simplicity: Only 25 tasks total - feature reuses existing infrastructure
- Independent Stories: US1 is core MVP, US2 already satisfied by US1, US3 is verification only
- Manual tests: T014-T024 are manual verification tasks (quickstart.md has detailed checklist)
Task Count Summary
- Total Tasks: 25
- Foundational: 1 task (T001)
- User Story 1: 12 tasks (T002-T013) - 7 tests, 5 implementation
- User Story 2: 0 tasks (functionality in US1)
- User Story 3: 2 tasks (T014-T015) - manual verification
- Polish: 10 tasks (T016-T025) - 9 manual checks, 1 commit
Parallel Opportunities:
- Tests: 7 tests can be written in parallel (T002-T007, T008)
- Manual verification: 9 checks can run in parallel (T016-T024)
MVP Scope: Tasks T001-T013 deliver complete User Story 1 (core product selection feature)