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>
102 lines
4.0 KiB
YAML
102 lines
4.0 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Reklamator Landing Page API
|
|
version: 1.0.0
|
|
description: Product selection landing page contract for feature 002-product-list
|
|
|
|
paths:
|
|
/:
|
|
get:
|
|
summary: Landing page - list active products
|
|
description: |
|
|
Display a landing page showing all active products available for feedback submission.
|
|
Products are sorted alphabetically by name (case-insensitive), with product_id as tiebreaker.
|
|
operationId: getLandingPage
|
|
tags:
|
|
- Landing Page
|
|
responses:
|
|
'200':
|
|
description: HTML page with product list or empty state message
|
|
content:
|
|
text/html:
|
|
schema:
|
|
type: string
|
|
description: Server-rendered HTML page
|
|
examples:
|
|
with_products:
|
|
summary: Multiple active products displayed
|
|
value: |
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head><title>Select a Product</title></head>
|
|
<body>
|
|
<h1>Select a Product for Feedback</h1>
|
|
<ul>
|
|
<li>
|
|
<a href="/submit/acme-app">Acme Application</a>
|
|
<p>Enterprise resource planning system</p>
|
|
</li>
|
|
<li>
|
|
<a href="/submit/beta-service">Beta Service</a>
|
|
<p>Cloud infrastructure platform</p>
|
|
</li>
|
|
</ul>
|
|
</body>
|
|
</html>
|
|
|
|
no_products:
|
|
summary: No active products (empty state)
|
|
value: |
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head><title>Select a Product</title></head>
|
|
<body>
|
|
<h1>Select a Product for Feedback</h1>
|
|
<p>No products are currently accepting feedback. Please check back later.</p>
|
|
</body>
|
|
</html>
|
|
|
|
product_without_description:
|
|
summary: Product without description (no placeholder text)
|
|
value: |
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head><title>Select a Product</title></head>
|
|
<body>
|
|
<h1>Select a Product for Feedback</h1>
|
|
<ul>
|
|
<li>
|
|
<a href="/submit/simple-app">Simple App</a>
|
|
</li>
|
|
</ul>
|
|
</body>
|
|
</html>
|
|
|
|
components:
|
|
schemas:
|
|
# No request/response schemas needed (HTML rendering)
|
|
# Product data comes from file-based storage, not API request body
|
|
|
|
# Contract Test Scenarios
|
|
# These scenarios should be covered in tests/contract/test_landing_routes.py:
|
|
#
|
|
# 1. GET / with active products → 200 OK with product list HTML
|
|
# 2. GET / with no active products → 200 OK with empty state message
|
|
# 3. GET / with mixed active/archived → 200 OK showing only active
|
|
# 4. GET / verifies alphabetical sorting (name, then product_id)
|
|
# 5. GET / excludes products with missing submission_url_slug
|
|
# 6. GET / properly escapes product names (XSS prevention)
|
|
# 7. GET / displays descriptions when present
|
|
# 8. GET / omits description placeholder when missing
|
|
# 9. GET / accessible to anonymous users
|
|
# 10. GET / accessible to authenticated users (same behavior)
|
|
|
|
# Success Criteria Validation:
|
|
# - SC-001: Page contains clickable links to /submit/{slug}
|
|
# - SC-002: Response time <1s for up to 100 products
|
|
# - SC-004: Existing /submit/{slug} routes still functional (backwards compatibility)
|
|
# - SC-005: Empty state message displayed when no active products
|
|
# - SC-006: HTML escaping prevents XSS (test with <script> in product name)
|
|
# - SC-007: No JavaScript in response (server-side rendered only)
|
|
# - SC-008: Visual separation via HTML list structure
|