Completed planning phases 0 and 1 for simple landing page feature. ## Plan Overview: **Approach**: Minimal addition to existing Flask app - reuse Product model, add one route, one template. No new dependencies or complexity. **Constitution Check**: ✅ All 5 principles satisfied - Specification-first development (spec.md complete) - Test-first discipline (TDD workflow defined) - Independent user stories (3 stories, all independently testable) - Simplicity (reuses existing Flask/Jinja2/Product architecture) - Documentation as code (all artifacts in specs/002-product-list/) ## Artifacts Created: ### Phase 0: Research (research.md) - Reuses infrastructure from feature 001 (Flask, Jinja2, file storage) - Single new decision: Product.load_active() method for filtering/sorting - Performance analysis: <100ms for 100 products (well under 1s target) ### Phase 1: Design & Contracts - **data-model.md**: Documents Product model extension (load_active method) - **contracts/landing-page.yaml**: OpenAPI contract for GET / route - **quickstart.md**: Developer implementation guide with: - Step-by-step implementation checklist - Code snippets for route, template, tests - TDD workflow (write tests → verify fail → implement → pass) - Manual verification checklist ### Agent Context - Updated CLAUDE.md with feature technologies (no new tech added) ## Implementation Summary: **New Files** (to be created): - app/routes/landing.py - Landing page route handler - app/templates/landing/index.html - Product list template - tests/contract/test_landing_routes.py - Contract tests (6 scenarios) - tests/integration/test_landing_flow.py - User journey test **Modified Files**: - app/models/product.py - Add load_active() class method - app/__init__.py - Register landing blueprint ## Key Technical Decisions: 1. **Filtering**: status=='active' AND submission_url_slug exists 2. **Sorting**: Alphabetical by name (case-insensitive), then product_id 3. **Empty State**: "No products are currently accepting feedback" message 4. **XSS Prevention**: Jinja2 auto-escaping (no manual escaping needed) 5. **Performance**: File I/O sufficient (<1s for 100 products, no caching) ## Next Steps: 1. Run /speckit.tasks to generate tasks.md 2. Run /speckit.implement to execute TDD workflow 3. Verify all tests pass 4. Manual verification checklist 5. Create pull request 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7.7 KiB
Implementation Plan: Product Selection Landing Page
Branch: 002-product-list | Date: 2025-10-17 | Spec: spec.md
Summary
Add a landing page at root URL (/) that lists all active products, enabling visitors to discover and select products for feedback submission. This removes the barrier of requiring users to know direct product URLs.
Technical approach: Add new Flask route, reuse existing Product model, create simple HTML template with server-side rendering. No new dependencies needed.
Technical Context
Language/Version: Python 3.11+ Primary Dependencies: Flask 3.0+, Jinja2 (built-in) Storage: File-based (data/products/*/config.yaml - existing) Testing: pytest + pytest-flask (existing) Target Platform: Linux server (existing deployment) Project Type: Web application (Flask backend with server-side rendering) Performance Goals: <1 second page load for up to 100 products Constraints: Server-side rendering only (no JavaScript), minimal CSS (no frameworks) Scale/Scope: Simple single-page addition to existing Flask app
Constitution Check
GATE: Must pass before Phase 0 research.
Principle I: Specification-First Development
✅ PASS - Complete specification exists at spec.md with prioritized user stories, functional requirements, and success criteria.
Principle II: Test-First Discipline
✅ PASS - Implementation will follow TDD: contract tests → integration tests → implementation.
Principle III: Independent User Stories
✅ PASS - All 3 user stories (P1: Browse/Select, P2: Status visibility, P3: Direct nav) are independently testable and deliverable.
Principle IV: Simplicity & Justification
✅ PASS - Feature reuses existing architecture (Flask routes, Product model, Jinja2 templates). No new abstractions, dependencies, or complexity added.
Principle V: Documentation as Code
✅ PASS - Specification, plan, and implementation artifacts maintained in specs/002-product-list/ with version control.
Constitution Status: ✅ All principles satisfied. No violations to justify.
Project Structure
Documentation (this feature)
specs/002-product-list/
├── spec.md # Feature specification (complete)
├── plan.md # This file
├── research.md # Phase 0 - Technical research (minimal - reuses 001)
├── data-model.md # Phase 1 - Data model (reference to existing Product)
├── contracts/ # Phase 1 - API contract (GET / route)
│ └── landing-page.yaml
├── quickstart.md # Phase 1 - Developer quickstart
└── tasks.md # Phase 2 - Task breakdown (/speckit.tasks)
Source Code (repository root)
app/
├── models/
│ └── product.py # Existing - no changes needed
├── routes/
│ └── landing.py # NEW - landing page route
└── templates/
└── landing/
└── index.html # NEW - product list template
tests/
├── contract/
│ └── test_landing_routes.py # NEW - contract tests for GET /
└── integration/
└── test_landing_flow.py # NEW - end-to-end user journey tests
Structure Decision: Reuse existing Flask application structure. Landing page is a simple addition: one new route file, one new template, and corresponding tests. Follows established patterns from feature 001.
Complexity Tracking
No violations - table not needed.
All complexity requirements from Constitution Principle IV are satisfied:
- No additional abstraction layers
- No new dependencies
- No new design patterns
- Reuses existing Flask/Jinja2/Product architecture
Phase 0: Research
Research Scope
Since this feature builds on existing infrastructure from 001-build-an-application, minimal research is needed. Key questions already answered:
- Product data access: Resolved in 001 - Product.load_all() method exists
- Template rendering: Resolved in 001 - Jinja2 with server-side rendering
- Route patterns: Resolved in 001 - Flask blueprints for organization
- Sorting implementation: Python built-in sorted() with key function
New Technical Decisions
Only one new decision needed for this feature:
Product List Retrieval & Sorting
- Decision: Extend existing Product model with
load_active()class method - Rationale: Centralizes "active products only" logic, enables reuse
- Sorting: Python's
sorted()withkey=lambda p: (p.name.lower(), p.product_id) - Performance: File I/O for 100 products ~10-50ms (acceptable for <1s target)
Output: research.md (minimal - references 001, documents sorting decision)
Phase 1: Design & Contracts
Data Model
Entities: Reuse existing Product model from 001-build-an-application
Extension needed:
# app/models/product.py - add class method
@classmethod
def load_active(cls):
"""Load all active products, sorted alphabetically by name then product_id"""
all_products = cls.load_all()
active = [p for p in all_products if p.status == 'active' and p.submission_url_slug]
return sorted(active, key=lambda p: (p.name.lower(), p.product_id))
Output: data-model.md (references existing Product entity, documents extension)
API Contracts
New Route: GET /
Contract:
# contracts/landing-page.yaml
paths:
/:
get:
summary: Landing page - list active products
operationId: getLandingPage
responses:
'200':
description: HTML page with product list
content:
text/html:
schema:
type: string
examples:
with_products:
summary: Multiple active products
value: |
<html>
<h1>Select a Product</h1>
<ul>
<li><a href="/submit/product-a">Product A</a> - Description</li>
<li><a href="/submit/product-b">Product B</a></li>
</ul>
</html>
no_products:
summary: No active products
value: |
<html>
<p>No products are currently accepting feedback.</p>
</html>
Output: contracts/landing-page.yaml
Developer Quickstart
Key implementation points for developers:
- Route: app/routes/landing.py with
@app.route('/') - Template: app/templates/landing/index.html - loop over products
- XSS Prevention: Use Jinja2 auto-escaping for product names/descriptions
- Empty State: Check
if productsto show appropriate message - Logging: Log landing page access with product count
Output: quickstart.md
Agent Context Update
Run: .specify/scripts/bash/update-agent-context.sh claude
Expected update: No new technologies added (reuses Flask, Jinja2, Python 3.11+)
Output: Updated .claude.md or equivalent agent context file
Phase 2: Task Generation
Not executed by /speckit.plan - run /speckit.tasks next.
Expected task structure:
- Contract tests for GET / (various scenarios)
- Integration test for user journey
- Implement Product.load_active() method
- Implement landing route
- Create landing template
- Add logging
- Manual verification
Output: tasks.md (generated by /speckit.tasks command)
Next Steps
- ✅ Phase 0 complete: Generate research.md
- ✅ Phase 1 complete: Generate data-model.md, contracts/, quickstart.md
- ⏭️ Run
/speckit.tasksto generate tasks.md - ⏭️ Run
/speckit.implementto execute tasks
Branch: 002-product-list Plan: /home/markus/workspace/reklamator/specs/002-product-list/plan.md