p08-seo-tweaks
This commit is contained in:
2
openspec/changes/p04-summary/.openspec.yaml
Normal file
2
openspec/changes/p04-summary/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-12
|
||||
95
openspec/changes/p04-summary/design.md
Normal file
95
openspec/changes/p04-summary/design.md
Normal file
@@ -0,0 +1,95 @@
|
||||
## Context
|
||||
|
||||
ClawFort currently stores and displays full headline/summary text from the ingestion pipeline and renders feed content directly in cards/hero. There is no dedicated concise summary format, modal reading experience, or summary-specific analytics lifecycle.
|
||||
|
||||
This change introduces a structured summary artifact per fetched article, with template-driven rendering and event instrumentation.
|
||||
|
||||
Constraints:
|
||||
- Reuse existing Perplexity integration for generation.
|
||||
- Keep source attribution visible and preserved.
|
||||
- Prefer royalty-free image retrieval via MCP integration when available, with deterministic fallback path.
|
||||
- Ensure modal interactions are fully tagged in Umami.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Generate and persist concise summary content at ingestion time.
|
||||
- Persist and return template-compatible summary fields and image metadata.
|
||||
- Present summary in a modal dialog with required visual structure.
|
||||
- Track modal open/close/link-out analytics events consistently.
|
||||
|
||||
**Non-Goals:**
|
||||
- Replacing the existing core feed API model end-to-end.
|
||||
- Building a full long-form article reader.
|
||||
- Introducing user-authored summary editing workflows.
|
||||
- Supporting arbitrary analytics providers beyond current Umami hooks.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Persist structured summary fields alongside article records
|
||||
**Decision:** Store summary artifacts as explicit fields (TL;DR bullets, summary body, citation/source, summary image URL/credit) linked to each article.
|
||||
|
||||
**Rationale:**
|
||||
- Enables deterministic API response shape for modal rendering.
|
||||
- Keeps summary retrieval simple at read time.
|
||||
- Avoids dynamic prompt regeneration during page interactions.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Generate summary on-demand at modal open: rejected due to latency and cost spikes.
|
||||
- Store a single blob markdown string only: rejected due to weaker field-level control and analytics granularity.
|
||||
|
||||
### Decision: Use Perplexity for summary generation with strict output schema
|
||||
**Decision:** Prompt Perplexity to return machine-parseable JSON fields that map directly to the template sections.
|
||||
|
||||
**Rationale:**
|
||||
- Existing Perplexity integration and operational familiarity.
|
||||
- Structured output reduces frontend parsing fragility.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Free-form text generation then regex parsing: rejected as brittle.
|
||||
|
||||
### Decision: Prefer MCP royalty-free image sourcing, fallback to deterministic non-MCP source path
|
||||
**Decision:** When MCP image retrieval integration is configured, use it first; otherwise use a configured royalty-free provider path and fallback placeholder.
|
||||
|
||||
**Rationale:**
|
||||
- Satisfies preference for MCP leverage while preserving reliability.
|
||||
- Maintains legal/licensing constraints and avoids blocked ingestion.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Hard dependency on MCP only: rejected due to availability/runtime coupling risk.
|
||||
|
||||
### Decision: Add modal-specific analytics event contract
|
||||
**Decision:** Define and emit explicit Umami events for summary modal open, close, and source link-out clicks.
|
||||
|
||||
**Rationale:**
|
||||
- Makes summary engagement measurable independently of feed interactions.
|
||||
- Prevents implicit/ambiguous event interpretation.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Reusing existing generic card click events only: rejected due to insufficient modal-level observability.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Risk] Summary generation adds ingest latency** -> Mitigation: bounded retries and skip/fallback behavior.
|
||||
- **[Risk] Provider output schema drift breaks parser** -> Mitigation: strict validation + fallback summary text behavior.
|
||||
- **[Risk] Royalty-free image selection may be semantically weak** -> Mitigation: relevance prompt constraints and placeholder fallback.
|
||||
- **[Trade-off] Additional stored fields increase row size** -> Mitigation: concise field limits and optional archival policy alignment.
|
||||
- **[Risk] Event overcount from repeated modal toggles** -> Mitigation: standardize open/close trigger boundaries and dedupe rules in frontend logic.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add summary/image metadata fields or related model for persisted summary artifacts.
|
||||
2. Extend ingestion flow to generate structured summary + citation via Perplexity.
|
||||
3. Integrate royalty-free image retrieval with MCP-preferred flow and fallback.
|
||||
4. Extend API payloads to return summary-modal-ready data.
|
||||
5. Implement frontend modal rendering with exact template and analytics tags.
|
||||
6. Validate event tagging correctness and rendering fallback behavior.
|
||||
|
||||
Rollback:
|
||||
- Disable modal entrypoint and return existing feed behavior while retaining stored summary data.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should TL;DR bullet count be fixed (for example 3) or provider-adaptive within a bounded range?
|
||||
- Should summary modal open be card-click only or have an explicit "Read Summary" CTA in each card?
|
||||
- Which royalty-free provider is preferred default when MCP is unavailable?
|
||||
37
openspec/changes/p04-summary/proposal.md
Normal file
37
openspec/changes/p04-summary/proposal.md
Normal file
@@ -0,0 +1,37 @@
|
||||
## Why
|
||||
|
||||
Users need a quick, concise view of fetched news without reading long article text. Adding a TL;DR summary flow improves scan speed, reading experience, and engagement while keeping source transparency.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **New Capabilities:**
|
||||
- Generate concise article summaries via Perplexity when news is fetched.
|
||||
- Store structured summary content in the database using the required display template.
|
||||
- Fetch and attach an appropriate royalty-free image for each summarized article.
|
||||
- Render summary content in a modal dialog from the landing page.
|
||||
- Add Umami event tagging for modal opens, closes, and source link-outs.
|
||||
- **Backend:**
|
||||
- Extend ingestion to call Perplexity summary generation and persist summary output.
|
||||
- Integrate royalty-free image sourcing (prefer MCP path when available).
|
||||
- **Frontend:**
|
||||
- Add summary modal UI and interaction flow.
|
||||
- Add event tracking for all required user actions in the modal.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `article-tldr-summary`: Generate and persist concise TL;DR + summary content per fetched article using Perplexity.
|
||||
- `summary-modal-experience`: Display summary content in a modal dialog using the standardized template format.
|
||||
- `royalty-free-image-enrichment`: Attach appropriate royalty-free images for summarized articles, leveraging MCP integration when available.
|
||||
- `summary-analytics-tagging`: Track summary modal opens, closes, and external source link-outs via Umami event tags.
|
||||
|
||||
### Modified Capabilities
|
||||
- None.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Code:** Ingestion pipeline, storage model/schema, API response payloads, and frontend modal interactions will be updated.
|
||||
- **APIs:** Existing news payloads will include summary/template-ready fields and image metadata.
|
||||
- **Dependencies:** Reuses Perplexity; may add/enable royalty-free image provider integration (including MCP route if available).
|
||||
- **Infrastructure:** No major topology change expected.
|
||||
- **Data:** Database will store summary artifacts and associated image/source metadata.
|
||||
@@ -0,0 +1,22 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: System generates structured TL;DR summary for each fetched article
|
||||
The system SHALL generate a concise summary artifact for each newly fetched article using Perplexity during ingestion.
|
||||
|
||||
#### Scenario: Successful summary generation
|
||||
- **WHEN** a new article is accepted in ingestion
|
||||
- **THEN** the system generates TL;DR bullet points and a concise summary body
|
||||
- **AND** output is persisted in a structured, template-compatible format
|
||||
|
||||
#### Scenario: Summary generation fallback
|
||||
- **WHEN** summary generation fails for an article
|
||||
- **THEN** ingestion continues without failing the entire cycle
|
||||
- **AND** the article remains available with existing non-summary content
|
||||
|
||||
### Requirement: Summary storage includes citation and source context
|
||||
The system SHALL persist source/citation information needed to render summary provenance.
|
||||
|
||||
#### Scenario: Persist source and citation metadata
|
||||
- **WHEN** summary content is stored
|
||||
- **THEN** associated source/citation fields are stored with the article summary artifact
|
||||
- **AND** response payloads can render a "Source and Citation" section
|
||||
@@ -0,0 +1,22 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: System enriches summaries with appropriate royalty-free images
|
||||
The system SHALL attach an appropriate royalty-free image to each summarized article.
|
||||
|
||||
#### Scenario: Successful royalty-free image retrieval
|
||||
- **WHEN** summary generation succeeds for an article
|
||||
- **THEN** the system retrieves an appropriate royalty-free image for that article context
|
||||
- **AND** stores image URL and attribution metadata for rendering
|
||||
|
||||
#### Scenario: MCP-preferred retrieval path
|
||||
- **WHEN** MCP image integration is available in runtime
|
||||
- **THEN** the system uses MCP-based retrieval as the preferred image sourcing path
|
||||
- **AND** falls back to configured non-MCP royalty-free source path when MCP retrieval fails or is unavailable
|
||||
|
||||
### Requirement: Image retrieval failures do not block article availability
|
||||
The system SHALL remain resilient when image sourcing fails.
|
||||
|
||||
#### Scenario: Image fallback behavior
|
||||
- **WHEN** no suitable royalty-free image can be retrieved
|
||||
- **THEN** the article summary remains available for modal display
|
||||
- **AND** UI uses configured placeholder/fallback image behavior
|
||||
@@ -0,0 +1,22 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Modal interactions are tagged for analytics
|
||||
The system SHALL emit Umami analytics events for summary modal open and close actions.
|
||||
|
||||
#### Scenario: Modal open event tagging
|
||||
- **WHEN** a user opens the summary modal
|
||||
- **THEN** the system emits a modal-open Umami event
|
||||
- **AND** event payload includes article context identifier
|
||||
|
||||
#### Scenario: Modal close event tagging
|
||||
- **WHEN** a user closes the summary modal
|
||||
- **THEN** the system emits a modal-close Umami event
|
||||
- **AND** event payload includes article context identifier when available
|
||||
|
||||
### Requirement: Source link-out interactions are tagged for analytics
|
||||
The system SHALL emit Umami analytics events for source/citation link-outs from summary modal.
|
||||
|
||||
#### Scenario: Source link-out event tagging
|
||||
- **WHEN** a user clicks source/citation link in summary modal
|
||||
- **THEN** the system emits a link-out Umami event before or at navigation trigger
|
||||
- **AND** event includes source URL or source identifier metadata
|
||||
@@ -0,0 +1,22 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Summary is rendered in a modal dialog using standard template
|
||||
The system SHALL render article summary content in a modal dialog using the required structure.
|
||||
|
||||
#### Scenario: Open summary modal
|
||||
- **WHEN** a user triggers summary view for an article
|
||||
- **THEN** a modal dialog opens and displays content in this order: relevant image, TL;DR bullets, summary body, source and citation, and "Powered by Perplexity"
|
||||
- **AND** modal content corresponds to the selected article
|
||||
|
||||
#### Scenario: Close summary modal
|
||||
- **WHEN** a user closes the modal via close control or backdrop interaction
|
||||
- **THEN** the modal is dismissed cleanly
|
||||
- **AND** user returns to previous feed context without page navigation
|
||||
|
||||
### Requirement: Modal content preserves source link-out behavior
|
||||
The system SHALL provide source link-outs from the summary modal.
|
||||
|
||||
#### Scenario: Source link-out from modal
|
||||
- **WHEN** a user clicks source/citation link in the modal
|
||||
- **THEN** the original source opens in a new tab/window
|
||||
- **AND** modal behavior remains stable for continued browsing
|
||||
46
openspec/changes/p04-summary/tasks.md
Normal file
46
openspec/changes/p04-summary/tasks.md
Normal file
@@ -0,0 +1,46 @@
|
||||
## 1. Summary Data Model and Persistence
|
||||
|
||||
- [x] 1.1 Add persisted summary fields for TL;DR bullets, summary body, source/citation, and summary image metadata
|
||||
- [x] 1.2 Update database initialization/migration path for summary-related storage changes
|
||||
- [x] 1.3 Add repository read/write helpers for structured summary artifact fields
|
||||
|
||||
## 2. Ingestion-Time Summary Generation
|
||||
|
||||
- [x] 2.1 Extend ingestion flow to request structured TL;DR + summary output from Perplexity for each fetched article
|
||||
- [x] 2.2 Implement strict parser/validator for summary output schema used by the frontend template
|
||||
- [x] 2.3 Persist generated summary artifacts with article records during the same ingestion cycle
|
||||
- [x] 2.4 Add graceful fallback behavior when summary generation fails without blocking article availability
|
||||
|
||||
## 3. Royalty-Free Image Enrichment
|
||||
|
||||
- [x] 3.1 Implement royalty-free image retrieval for summarized articles with relevance constraints
|
||||
- [x] 3.2 Prefer MCP-based image retrieval path when available
|
||||
- [x] 3.3 Implement deterministic non-MCP fallback image path and placeholder behavior
|
||||
- [x] 3.4 Persist image attribution/licensing metadata required for compliant display
|
||||
|
||||
## 4. API Delivery for Summary Modal
|
||||
|
||||
- [x] 4.1 Extend API response payloads to include summary-modal-ready fields
|
||||
- [x] 4.2 Ensure API payload contract maps directly to required template sections
|
||||
- [x] 4.3 Preserve source and citation link-out data in API responses
|
||||
|
||||
## 5. Frontend Summary Modal Experience
|
||||
|
||||
- [x] 5.1 Implement summary modal dialog component in landing page flow
|
||||
- [x] 5.2 Render modal using required order: image, TL;DR bullets, summary, source/citation, Powered by Perplexity
|
||||
- [x] 5.3 Add article-level trigger to open summary modal from feed interactions
|
||||
- [x] 5.4 Implement robust modal close behavior (close control + backdrop interaction)
|
||||
|
||||
## 6. Analytics Event Tagging
|
||||
|
||||
- [x] 6.1 Emit Umami event on summary modal open with article context
|
||||
- [x] 6.2 Emit Umami event on summary modal close with article context when available
|
||||
- [x] 6.3 Emit Umami event on source/citation link-out from modal with source metadata
|
||||
- [x] 6.4 Validate event naming and payload consistency across repeated interactions
|
||||
|
||||
## 7. Validation and Documentation
|
||||
|
||||
- [x] 7.1 Validate end-to-end summary generation, persistence, and modal rendering for new articles
|
||||
- [x] 7.2 Validate fallback behavior for summary/image retrieval failures
|
||||
- [x] 7.3 Validate source/citation visibility and external link behavior in modal
|
||||
- [x] 7.4 Update README with summary modal feature behavior and analytics event contract
|
||||
2
openspec/changes/p05-no-ownership/.openspec.yaml
Normal file
2
openspec/changes/p05-no-ownership/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-12
|
||||
65
openspec/changes/p05-no-ownership/design.md
Normal file
65
openspec/changes/p05-no-ownership/design.md
Normal file
@@ -0,0 +1,65 @@
|
||||
## Context
|
||||
|
||||
ClawFort currently has a single-page news experience and no dedicated policy/disclaimer documents accessible from primary navigation. This creates ambiguity around authorship, verification, and acceptable use expectations.
|
||||
|
||||
This change introduces lightweight policy pages and footer navigation updates without changing core data flows or APIs.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Add visible footer links for Terms of Use and Attribution.
|
||||
- Add dedicated pages with explicit non-ownership and AI-generation disclosures.
|
||||
- Add clear risk language that content is unverified and users act at their own risk.
|
||||
|
||||
**Non-Goals:**
|
||||
- Implementing full legal-policy versioning workflows.
|
||||
- User-specific policy acceptance tracking.
|
||||
- Backend auth/session changes.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Serve policy pages as static frontend documents
|
||||
**Decision:** Implement `terms.html` and `attribution.html` as static pages in the frontend directory.
|
||||
|
||||
**Rationale:**
|
||||
- Lowest complexity for current architecture.
|
||||
- Policy content is mostly static and does not require dynamic API data.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Backend-rendered templates: rejected due to unnecessary server complexity.
|
||||
|
||||
### Decision: Add persistent footer links on main page and policy pages
|
||||
**Decision:** Footer includes links on landing page and reciprocal navigation from policy pages back to home.
|
||||
|
||||
**Rationale:**
|
||||
- Improves discoverability and prevents navigation dead ends.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Header-only links: rejected due to crowded header and lower policy discoverability.
|
||||
|
||||
### Decision: Keep disclaimer wording explicit and prominent
|
||||
**Decision:** Use direct language in page body and heading hierarchy emphasizing AI generation, non-ownership, and use-at-own-risk boundaries.
|
||||
|
||||
**Rationale:**
|
||||
- Meets intent of legal disclosure and user expectation setting.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Compact single-line disclaimers: rejected as insufficiently clear.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Risk] Disclaimer copy may still be interpreted differently by jurisdictions** -> Mitigation: keep language clear and easily editable in static pages.
|
||||
- **[Trade-off] Static pages require redeploy for copy updates** -> Mitigation: isolate content in dedicated files for quick revision.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add static policy pages under frontend.
|
||||
2. Add footer links in the main page and cross-links in policy pages.
|
||||
3. Validate page serving and navigation in local runtime.
|
||||
|
||||
Rollback:
|
||||
- Remove policy pages and footer links; no data migration required.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should policy pages include effective-date/version metadata in this phase?
|
||||
26
openspec/changes/p05-no-ownership/proposal.md
Normal file
26
openspec/changes/p05-no-ownership/proposal.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## Why
|
||||
|
||||
The site needs explicit legal/disclaimer pages so users understand content ownership boundaries and reliability limits. Adding these now reduces misuse risk and sets clear expectations for AI-generated, unverified information.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add two footer links: **Terms of Use** and **Attribution**.
|
||||
- Create an **Attribution** page with clear disclosure that content is AI-generated and not authored/verified by the site owner.
|
||||
- Create a **Terms of Use** page stating users must use the information at their own risk because it is not independently verified.
|
||||
- Ensure footer links are visible and route correctly from the landing page.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `footer-policy-links`: Add footer navigation entries for Terms of Use and Attribution pages.
|
||||
- `attribution-disclaimer-page`: Provide a dedicated attribution/disclaimer page with explicit AI-generation and non-ownership statements.
|
||||
- `terms-of-use-risk-disclosure`: Provide a terms page that clearly states unverified information and user-at-own-risk usage.
|
||||
|
||||
### Modified Capabilities
|
||||
- None.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Frontend/UI:** Footer layout and navigation updated; two new legal/disclaimer pages added.
|
||||
- **Routing/Serving:** Backend/static serving may need routes for new pages if not purely static-linked.
|
||||
- **Content/Policy:** Adds formal disclaimer language for authorship, verification, and usage risk.
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Attribution page discloses AI generation and non-ownership
|
||||
The system SHALL provide an Attribution page with explicit statements that content is AI-generated and not personally authored by the site owner.
|
||||
|
||||
#### Scenario: Attribution page title and disclosure content
|
||||
- **WHEN** a user opens the Attribution page
|
||||
- **THEN** the page title clearly indicates attribution/disclaimer purpose
|
||||
- **AND** the body states that content is AI-generated and not generated by the owner as an individual
|
||||
|
||||
#### Scenario: Attribution page includes non-involvement statement
|
||||
- **WHEN** a user reads the Attribution page
|
||||
- **THEN** the page explicitly states owner non-involvement in generated content claims
|
||||
- **AND** wording is presented in primary readable content area
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Footer exposes policy navigation links
|
||||
The system SHALL display footer links for Terms of Use and Attribution on the landing page.
|
||||
|
||||
#### Scenario: Footer links visible on landing page
|
||||
- **WHEN** a user loads the main page
|
||||
- **THEN** the footer includes links labeled "Terms of Use" and "Attribution"
|
||||
- **AND** links are visually distinguishable and keyboard focusable
|
||||
|
||||
#### Scenario: Footer links navigate correctly
|
||||
- **WHEN** a user activates either policy link
|
||||
- **THEN** the browser navigates to the corresponding policy page
|
||||
- **AND** navigation succeeds without API dependency
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Terms page states unverified-content risk
|
||||
The system SHALL provide a Terms of Use page that states information is unverified and use is at the user’s own risk.
|
||||
|
||||
#### Scenario: Terms page risk statement visible
|
||||
- **WHEN** a user opens the Terms of Use page
|
||||
- **THEN** the page includes clear at-own-risk usage language
|
||||
- **AND** the page states information is not independently verified
|
||||
|
||||
#### Scenario: Terms page references source uncertainty
|
||||
- **WHEN** a user reads terms details
|
||||
- **THEN** the page explains content is surfaced from external/AI-generated sources
|
||||
- **AND** users are informed responsibility remains with their own decisions
|
||||
24
openspec/changes/p05-no-ownership/tasks.md
Normal file
24
openspec/changes/p05-no-ownership/tasks.md
Normal file
@@ -0,0 +1,24 @@
|
||||
## 1. Footer Policy Navigation
|
||||
|
||||
- [x] 1.1 Add Terms of Use and Attribution links to primary footer
|
||||
- [x] 1.2 Ensure policy links are keyboard focusable and readable on all breakpoints
|
||||
|
||||
## 2. Attribution Page Content
|
||||
|
||||
- [x] 2.1 Create attribution page with explicit AI-generated and non-ownership disclosure title/content
|
||||
- [x] 2.2 Add statement clarifying owner non-involvement in generated content claims
|
||||
|
||||
## 3. Terms of Use Risk Disclosure
|
||||
|
||||
- [x] 3.1 Create Terms of Use page with unverified-content and use-at-own-risk statements
|
||||
- [x] 3.2 Add language that users remain responsible for downstream use decisions
|
||||
|
||||
## 4. Routing and Page Serving
|
||||
|
||||
- [x] 4.1 Wire policy page routes/serving behavior from current frontend/backend structure
|
||||
- [x] 4.2 Add return navigation between home and policy pages
|
||||
|
||||
## 5. Validation and Documentation
|
||||
|
||||
- [x] 5.1 Validate footer link navigation and policy page rendering on desktop/mobile
|
||||
- [x] 5.2 Update README or docs with policy page locations and purpose
|
||||
2
openspec/changes/p06-theming/.openspec.yaml
Normal file
2
openspec/changes/p06-theming/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-12
|
||||
68
openspec/changes/p06-theming/design.md
Normal file
68
openspec/changes/p06-theming/design.md
Normal file
@@ -0,0 +1,68 @@
|
||||
## Context
|
||||
|
||||
The current UI defaults to dark presentation and lacks a global theme control. Users with different preference and accessibility needs cannot choose light/system/high-contrast alternatives.
|
||||
|
||||
This change introduces an icon-based theme switcher and persistent client-side preference restoration.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Add a header theme switcher with system, light, dark, and high-contrast options.
|
||||
- Apply theme choice globally with minimal visual regression.
|
||||
- Persist preference in localStorage with cookie fallback.
|
||||
- Restore returning-user choice; default to system when unset.
|
||||
|
||||
**Non-Goals:**
|
||||
- Server-side profile theme persistence.
|
||||
- Theme-specific content changes.
|
||||
- Full design-system rewrite.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Centralize theme state on `document.documentElement`
|
||||
**Decision:** Set a root theme attribute/class and drive color tokens from CSS variables.
|
||||
|
||||
**Rationale:**
|
||||
- Single source of truth for whole page styling.
|
||||
- Works with existing Tailwind utility classes via custom CSS variable bridge.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Component-level theming flags: rejected due to drift and maintenance overhead.
|
||||
|
||||
### Decision: Keep system mode dynamic via `prefers-color-scheme`
|
||||
**Decision:** For `system`, listen to media query changes and update resolved theme automatically.
|
||||
|
||||
**Rationale:**
|
||||
- Matches user OS preference behavior.
|
||||
|
||||
**Alternatives considered:**
|
||||
- One-time system snapshot: rejected as surprising for users changing OS theme at runtime.
|
||||
|
||||
### Decision: Use icon-only options with accessible labels
|
||||
**Decision:** Theme controls are icon buttons with ARIA labels and visible selected state.
|
||||
|
||||
**Rationale:**
|
||||
- Meets UX requirement while preserving accessibility.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Text dropdown: rejected due to explicit icon requirement.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Risk] Existing hardcoded color classes may not adapt perfectly** -> Mitigation: prioritize core surfaces/text and progressively map remaining variants.
|
||||
- **[Risk] High-contrast mode may expose layout artifacts** -> Mitigation: audit focus outlines, borders, and semantic contrast first.
|
||||
- **[Trade-off] Additional JS for persistence and media listeners** -> Mitigation: keep logic modular and lightweight.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add theme tokens and root theme resolver.
|
||||
2. Implement icon switcher in header and state persistence.
|
||||
3. Wire system preference listener and fallback behavior.
|
||||
4. Validate across refresh/returning sessions and responsive breakpoints.
|
||||
|
||||
Rollback:
|
||||
- Remove theme switcher and resolver, revert to existing dark-default classes.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should high-contrast mode align with OS `prefers-contrast` in a later phase?
|
||||
29
openspec/changes/p06-theming/proposal.md
Normal file
29
openspec/changes/p06-theming/proposal.md
Normal file
@@ -0,0 +1,29 @@
|
||||
## Why
|
||||
|
||||
The current UI is locked to dark presentation, which does not match all user preferences or accessibility needs. Adding multi-theme support now improves usability and lets returning users keep a consistent visual experience.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add a theme switcher in the top-right header area.
|
||||
- Support four theme modes: **system**, **light**, **dark**, and **high-contrast**.
|
||||
- Render theme options as icons (not text-only controls).
|
||||
- Persist selected theme in client storage with **localStorage as primary** and **cookie fallback**.
|
||||
- Restore persisted theme for returning users.
|
||||
- Use **system** as default when no prior selection exists.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `theme-switcher-control`: Provide an icon-based theme switcher in the header with system/light/dark/high-contrast options.
|
||||
- `theme-preference-persistence`: Persist and restore user-selected theme using localStorage first, with cookie fallback.
|
||||
- `theme-default-system`: Apply system theme automatically when no saved preference exists.
|
||||
|
||||
### Modified Capabilities
|
||||
- None.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Frontend/UI:** Header controls and global styling system updated for four theme modes.
|
||||
- **State management:** Client-side preference state handling added for theme selection and restoration.
|
||||
- **Accessibility:** High-contrast option improves readability for users needing stronger contrast.
|
||||
- **APIs/Backend:** No required backend API changes expected.
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: System theme is default when no preference exists
|
||||
The system SHALL default to system theme behavior if no persisted theme preference is found.
|
||||
|
||||
#### Scenario: No saved preference on first visit
|
||||
- **WHEN** a user visits the site with no stored theme value
|
||||
- **THEN** the UI resolves theme from system color-scheme preference
|
||||
- **AND** switcher indicates system mode as active
|
||||
|
||||
#### Scenario: Persisted preference overrides system default
|
||||
- **WHEN** a user has an existing stored theme preference
|
||||
- **THEN** stored preference is applied instead of system mode
|
||||
- **AND** user-selected theme remains stable across reloads
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Theme choice persists across sessions
|
||||
The system SHALL persist user-selected theme with localStorage as primary storage and cookie fallback when localStorage is unavailable.
|
||||
|
||||
#### Scenario: Persist theme in localStorage
|
||||
- **WHEN** localStorage is available and user selects a theme
|
||||
- **THEN** selected theme is saved in localStorage
|
||||
- **AND** stored value is used on next visit in same browser
|
||||
|
||||
#### Scenario: Cookie fallback persistence
|
||||
- **WHEN** localStorage is unavailable or blocked
|
||||
- **THEN** selected theme is saved in cookie storage
|
||||
- **AND** cookie value is used to restore theme on return visit
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Header provides icon-based theme switcher
|
||||
The system SHALL display a theme switcher in the top-right header area with icon controls for system, light, dark, and high-contrast modes.
|
||||
|
||||
#### Scenario: Theme options visible as icons
|
||||
- **WHEN** a user views the header
|
||||
- **THEN** all four theme options are represented by distinct icons
|
||||
- **AND** each option is keyboard-accessible and screen-reader labeled
|
||||
|
||||
#### Scenario: Theme selection applies immediately
|
||||
- **WHEN** a user selects a theme option
|
||||
- **THEN** the page updates visual theme without full page reload
|
||||
- **AND** selected option has a visible active state
|
||||
26
openspec/changes/p06-theming/tasks.md
Normal file
26
openspec/changes/p06-theming/tasks.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## 1. Theme Foundation
|
||||
|
||||
- [x] 1.1 Define root-level theme state model for system, light, dark, and high-contrast
|
||||
- [x] 1.2 Add CSS token/variable mapping so all theme modes can be resolved consistently
|
||||
|
||||
## 2. Theme Switcher UI
|
||||
|
||||
- [x] 2.1 Add icon-based theme switcher control to top-right header area
|
||||
- [x] 2.2 Provide accessible labels and active-state indication for each icon option
|
||||
|
||||
## 3. Theme Preference Persistence
|
||||
|
||||
- [x] 3.1 Persist selected theme in localStorage when available
|
||||
- [x] 3.2 Implement cookie fallback persistence when localStorage is unavailable
|
||||
- [x] 3.3 Restore persisted preference for returning users
|
||||
|
||||
## 4. System Default Behavior
|
||||
|
||||
- [x] 4.1 Apply system mode when no persisted preference exists
|
||||
- [x] 4.2 Ensure saved user preference overrides system default on subsequent visits
|
||||
|
||||
## 5. Validation and Documentation
|
||||
|
||||
- [x] 5.1 Validate theme switching and persistence across refreshes and browser restarts
|
||||
- [x] 5.2 Validate icon controls with keyboard navigation and screen reader labels
|
||||
- [x] 5.3 Update README/docs with theme options and persistence behavior
|
||||
2
openspec/changes/p07-tech-robustness/.openspec.yaml
Normal file
2
openspec/changes/p07-tech-robustness/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-12
|
||||
71
openspec/changes/p07-tech-robustness/design.md
Normal file
71
openspec/changes/p07-tech-robustness/design.md
Normal file
@@ -0,0 +1,71 @@
|
||||
## Context
|
||||
|
||||
The current one-page application has strong feature velocity but uneven robustness across viewport sizes and accessibility states. It also initializes analytics without an explicit user consent gate, which creates compliance and trust risks in stricter jurisdictions.
|
||||
|
||||
This change introduces responsive hardening, WCAG 2.2 AA baseline conformance, and explicit cookie-consent-controlled tracking behavior.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Ensure key UI flows work consistently across mobile, tablet, and desktop.
|
||||
- Bring critical interactions and content presentation to WCAG 2.2 AA expectations.
|
||||
- Add consent UI and persist consent state in cookies (with local state sync).
|
||||
- Gate analytics script/event execution behind consent.
|
||||
|
||||
**Non-Goals:**
|
||||
- Full legal-policy framework beyond consent capture basics.
|
||||
- Rebuilding the full visual system from scratch.
|
||||
- Country-specific geo-personalized consent variants in this phase.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Define responsive guarantees around existing breakpoints and interaction surfaces
|
||||
**Decision:** Formalize requirements for hero, feed cards, modal/dialog interactions, and header controls across common breakpoints and orientations.
|
||||
|
||||
**Rationale:**
|
||||
- Targets user-visible breakage points first.
|
||||
- Reduces regression risk while keeping implementation incremental.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Pixel-perfect per-device tailoring: rejected due to maintenance cost.
|
||||
|
||||
### Decision: Prioritize WCAG 2.2 AA for core paths and controls
|
||||
**Decision:** Apply compliance to keyboard navigation, focus indicators, contrast, semantic labels, and non-text alternatives in primary user journeys.
|
||||
|
||||
**Rationale:**
|
||||
- Maximizes accessibility impact where users spend time.
|
||||
- Keeps scope realistic for immediate hardening.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Attempting broad AAA alignment: rejected as out-of-scope for this phase.
|
||||
|
||||
### Decision: Gate analytics on explicit consent and persist choice in cookie
|
||||
**Decision:** Tracking initializes only after user consent; cookie stores consent state and optional local state mirrors for fast frontend read.
|
||||
|
||||
**Rationale:**
|
||||
- Aligns with safer consent posture and user transparency.
|
||||
- Supports returning-user behavior without backend session coupling.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Always-on tracking with notice-only banner: rejected for compliance risk.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Risk] Responsive fixes can introduce visual drift across existing sections** -> Mitigation: validate at target breakpoints and keep changes token-based.
|
||||
- **[Risk] Accessibility remediations may require widespread class/markup changes** -> Mitigation: focus first on critical interactions and reuse shared utility patterns.
|
||||
- **[Trade-off] Consent gating can reduce analytics volume** -> Mitigation: explicit consent messaging and friction-minimized accept flow.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add responsive and accessibility acceptance criteria for key components.
|
||||
2. Implement consent banner, persistence logic, and analytics gating.
|
||||
3. Refine UI semantics/focus/contrast and test keyboard-only navigation.
|
||||
4. Validate across viewport matrix and accessibility checklist.
|
||||
|
||||
Rollback:
|
||||
- Disable consent gate logic and revert to prior analytics init path while retaining non-breaking responsive/accessibility improvements.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should consent expiration/renewal interval be introduced in this phase or follow-up?
|
||||
- Should consent state include analytics-only granularity now, or remain a single accepted state?
|
||||
27
openspec/changes/p07-tech-robustness/proposal.md
Normal file
27
openspec/changes/p07-tech-robustness/proposal.md
Normal file
@@ -0,0 +1,27 @@
|
||||
## Why
|
||||
|
||||
The product needs stronger technical quality and trust signals across devices and accessibility contexts. Improving responsiveness, WCAG 2.2 AA conformance, and compliant consent handling reduces usability risk and supports broader adoption.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Make the site fully device-agnostic and responsive across mobile, tablet, and desktop breakpoints.
|
||||
- Bring key user flows to WCAG 2.2 AA standards (contrast, focus visibility, keyboard navigation, semantics, and non-text content).
|
||||
- Add a cookie consent banner with clear consent messaging and persistence.
|
||||
- Record consent in browser cookies (with local state sync where applicable) and apply analytics only after consent is given.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `responsive-device-agnostic-layout`: Ensure core pages/components adapt reliably across viewport sizes and input modes.
|
||||
- `wcag-2-2-aa-accessibility`: Enforce WCAG 2.2 AA requirements for interactive and content-rendering paths.
|
||||
- `cookie-consent-tracking-gate`: Provide consent capture and persistence for analytics/tracking behavior.
|
||||
|
||||
### Modified Capabilities
|
||||
- None.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Frontend/UI:** Layout, spacing, typography, and interaction behavior updated for responsive and accessible presentation.
|
||||
- **Accessibility:** ARIA semantics, keyboard focus flow, and contrast/focus treatments refined.
|
||||
- **Analytics/Consent:** Consent banner and tracking gate logic added; cookie persistence introduced.
|
||||
- **QA/Validation:** Accessibility and responsiveness verification scope expands (manual + automated checks where available).
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Consent banner captures and persists tracking consent
|
||||
The system SHALL display a cookie consent banner and persist user consent decision in cookies before enabling analytics tracking.
|
||||
|
||||
#### Scenario: Consent capture and persistence
|
||||
- **WHEN** a user interacts with the consent banner and accepts
|
||||
- **THEN** consent state is stored in a cookie
|
||||
- **AND** stored consent is honored on subsequent visits
|
||||
|
||||
#### Scenario: Tracking gated by consent
|
||||
- **WHEN** consent has not been granted
|
||||
- **THEN** analytics/tracking scripts and events do not execute
|
||||
- **AND** tracking begins only after consent state indicates acceptance
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Core layout is device-agnostic and responsive
|
||||
The system SHALL render key surfaces (header, hero, feed, modal, footer) responsively across mobile, tablet, and desktop viewports.
|
||||
|
||||
#### Scenario: Mobile layout behavior
|
||||
- **WHEN** a user opens the site on a mobile viewport
|
||||
- **THEN** content remains readable without horizontal overflow
|
||||
- **AND** interactive controls remain reachable and usable
|
||||
|
||||
#### Scenario: Desktop and tablet adaptation
|
||||
- **WHEN** a user opens the site on tablet or desktop viewports
|
||||
- **THEN** layout reflows according to breakpoint design rules
|
||||
- **AND** no key content or controls are clipped
|
||||
@@ -0,0 +1,14 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Core user flows comply with WCAG 2.2 AA baseline
|
||||
The system SHALL meet WCAG 2.2 AA accessibility requirements for primary interactions and content presentation.
|
||||
|
||||
#### Scenario: Keyboard-only interaction flow
|
||||
- **WHEN** a keyboard-only user navigates the page
|
||||
- **THEN** all primary interactive elements are reachable and operable
|
||||
- **AND** visible focus indication is present at each step
|
||||
|
||||
#### Scenario: Contrast and non-text alternatives
|
||||
- **WHEN** users consume text and non-text UI content
|
||||
- **THEN** color contrast meets AA thresholds for relevant text and controls
|
||||
- **AND** meaningful images and controls include accessible labels/alternatives
|
||||
28
openspec/changes/p07-tech-robustness/tasks.md
Normal file
28
openspec/changes/p07-tech-robustness/tasks.md
Normal file
@@ -0,0 +1,28 @@
|
||||
## 1. Responsive Hardening
|
||||
|
||||
- [x] 1.1 Audit and fix layout breakpoints for header, hero, feed cards, modal, and footer
|
||||
- [x] 1.2 Ensure no horizontal overflow or clipped controls on supported viewport sizes
|
||||
|
||||
## 2. WCAG 2.2 AA Accessibility Baseline
|
||||
|
||||
- [x] 2.1 Implement/verify keyboard operability for primary controls and dialogs
|
||||
- [x] 2.2 Add/verify visible focus indicators and semantic labels for interactive elements
|
||||
- [x] 2.3 Improve contrast and non-text alternatives to meet AA expectations on core flows
|
||||
|
||||
## 3. Cookie Consent and Tracking Gate
|
||||
|
||||
- [x] 3.1 Implement consent banner UI with explicit analytics consent action
|
||||
- [x] 3.2 Persist consent state in cookies and synchronize frontend state
|
||||
- [x] 3.3 Gate analytics script/event initialization until consent is granted
|
||||
|
||||
## 4. Returning User Consent Behavior
|
||||
|
||||
- [x] 4.1 Restore prior consent state from cookie on returning visits
|
||||
- [x] 4.2 Ensure tracking remains disabled without stored accepted consent
|
||||
|
||||
## 5. Verification and Documentation
|
||||
|
||||
- [x] 5.1 Validate responsive behavior on mobile/tablet/desktop matrices
|
||||
- [x] 5.2 Run accessibility checks and manual keyboard-only walkthrough for critical journeys
|
||||
- [x] 5.3 Validate consent gating and analytics behavior before/after acceptance
|
||||
- [x] 5.4 Update README/docs with accessibility and consent behavior notes
|
||||
2
openspec/changes/p08-seo-tweaks/.openspec.yaml
Normal file
2
openspec/changes/p08-seo-tweaks/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-13
|
||||
91
openspec/changes/p08-seo-tweaks/design.md
Normal file
91
openspec/changes/p08-seo-tweaks/design.md
Normal file
@@ -0,0 +1,91 @@
|
||||
## Context
|
||||
|
||||
ClawFort serves a static, client-rendered news experience backed by FastAPI endpoints and scheduled content refresh. The change introduces explicit technical requirements for crawlability, structured data quality, and delivery speed so SEO behavior is reliable across homepage, article cards, and static policy pages.
|
||||
|
||||
Current implementation already includes foundational metadata and partial performance behavior, but requirements are not yet codified in change specs. This design defines an implementation approach that keeps existing architecture (FastAPI + static frontend) while formalizing output guarantees required by search engines and validators.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Define a deterministic metadata contract for homepage and static pages (description, canonical, robots, Open Graph, Twitter card fields).
|
||||
- Define structured-data output for homepage (`Newspaper`) and every rendered news item (`NewsArticle`) with stable required properties.
|
||||
- Define response-delivery expectations for compression and cache policy plus front-end media loading behavior.
|
||||
- Keep requirements implementable in the current stack without introducing heavyweight infrastructure.
|
||||
|
||||
**Non-Goals:**
|
||||
- Full SSR migration or framework replacement.
|
||||
- Introduction of external CDN, edge workers, or managed caching tiers.
|
||||
- Reworking editorial/news-fetch business logic.
|
||||
- Rich-result optimization for types outside this scope (e.g., FAQ, VideoObject, LiveBlogPosting).
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Keep JSON-LD generation in the existing page runtime contract
|
||||
**Decision:** Define structured data as JSON-LD embedded in `index.html`, populated from the same article data model used by hero/feed rendering.
|
||||
|
||||
**Rationale:**
|
||||
- Avoids duplication between UI content and structured data.
|
||||
- Preserves current architecture and deployment flow.
|
||||
- Supports homepage-wide `@graph` output containing `Newspaper` and multiple `NewsArticle` nodes.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Server-side rendered JSON-LD via template engine: rejected due to architectural drift and migration overhead.
|
||||
- Microdata-only tagging: rejected because JSON-LD is simpler to maintain and validate for this use case.
|
||||
|
||||
### Decision: Use standards-aligned required field baseline for `NewsArticle`
|
||||
**Decision:** Require each `NewsArticle` node to include stable core fields: headline, description, image, datePublished, dateModified, url/mainEntityOfPage, inLanguage, publisher, and author.
|
||||
|
||||
**Rationale:**
|
||||
- Produces predictable, testable output.
|
||||
- Reduces schema validation regressions from partial payloads.
|
||||
- Aligns with common crawler expectations for article entities.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Minimal schema with only headline/url: rejected due to weak semantic value and poorer validation confidence.
|
||||
|
||||
### Decision: Enforce lightweight HTTP performance controls in-app
|
||||
**Decision:** Treat transport optimization as explicit requirements using in-app compression middleware and response cache headers by route class (static assets, APIs, HTML pages).
|
||||
|
||||
**Rationale:**
|
||||
- High impact with minimal infrastructure changes.
|
||||
- Testable directly in integration checks.
|
||||
- Works in current deployment topology.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Delegate entirely to reverse proxy/CDN: rejected because this repository currently controls delivery behavior directly.
|
||||
|
||||
### Decision: Standardize lazy media loading behavior with shimmer placeholders
|
||||
**Decision:** Define lazy-loading requirements for non-critical images and require shimmer placeholder states until image load/error resolution.
|
||||
|
||||
**Rationale:**
|
||||
- Improves perceived performance and consistency.
|
||||
- Helps reduce layout instability when paired with explicit image dimensions.
|
||||
- Fits existing UI loading pattern.
|
||||
|
||||
**Alternatives considered:**
|
||||
- Skeleton-only page-level placeholders: rejected because item-level shimmer provides better visual continuity.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Risk] Dynamic metadata timing for client-rendered content** -> Mitigation: require baseline static metadata defaults and deterministic runtime replacement after hero/article payload availability.
|
||||
- **[Risk] Overly aggressive cache behavior could stale fresh news** -> Mitigation: short API max-age with stale-while-revalidate; separate longer static asset policy.
|
||||
- **[Trade-off] Strict validation vs. framework directives in markup** -> Mitigation: define standards-compatible output goals and track exceptions where framework attributes are unavoidable.
|
||||
- **[Trade-off] More metadata fields increase maintenance** -> Mitigation: centralize field mapping helpers and require parity with article model fields.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Implement and verify metadata/structured-data contracts on homepage and news-card rendering paths.
|
||||
2. Add/verify response compression and route-level cache directives in backend delivery layer.
|
||||
3. Align image loading UX requirements (lazy + shimmer + explicit dimensions) across hero/feed/modal contexts.
|
||||
4. Validate output with schema and HTML validation tooling, then fix conformance gaps.
|
||||
5. Document acceptance checks and rollback approach.
|
||||
|
||||
Rollback:
|
||||
- Revert SEO/performance-specific frontend/backend changes to prior baseline while retaining unaffected feature behavior.
|
||||
- Remove schema additions and route cache directives if they introduce regressions.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should policy pages (`/terms`, `/attribution`) share a stricter noindex strategy or remain indexable by default?
|
||||
- Should canonical URLs include hash anchors for in-page article cards or stay route-level canonical only?
|
||||
- Do we require locale-specific `og:locale`/alternate tags in this phase or defer to a follow-up i18n SEO change?
|
||||
28
openspec/changes/p08-seo-tweaks/proposal.md
Normal file
28
openspec/changes/p08-seo-tweaks/proposal.md
Normal file
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
ClawFort currently lacks a formal SEO and structured-data specification, which limits discoverability and consistency for search crawlers. Defining this now ensures the news experience is indexable, standards-oriented, and performance-focused as the content footprint grows.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add search-focused metadata requirements for the main page and policy pages (description, canonical, robots, social preview tags).
|
||||
- Define structured data requirements so the home page is represented as `Newspaper` and each news item is represented as `NewsArticle`.
|
||||
- Establish performance requirements for transport and caching behavior (HTTP compression and cache directives) plus front-end loading behavior.
|
||||
- Define UX and rendering requirements for image lazy loading with shimmer placeholders and smooth scrolling.
|
||||
- Require markup and interaction patterns that are compatible with strict standards validation goals.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `seo-meta-and-social-tags`: Standardize meta, canonical, robots, and social preview tags for key public pages.
|
||||
- `news-structured-data`: Provide machine-readable `Newspaper` and `NewsArticle` structured data for homepage and article entries.
|
||||
- `delivery-and-rendering-performance`: Define response compression/caching and client-side loading behavior for faster page delivery.
|
||||
|
||||
### Modified Capabilities
|
||||
- None.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Frontend/UI:** `frontend/index.html` and static policy pages gain SEO metadata, structured-data hooks, and loading-state behavior requirements.
|
||||
- **Backend/API Delivery:** `backend/main.py` response middleware/headers are affected by compression and cache policy expectations.
|
||||
- **Quality/Validation:** Standards conformance and SEO validation become explicit acceptance criteria for this change.
|
||||
- **Operations:** Performance posture depends on HTTP behavior and deploy/runtime configuration alignment.
|
||||
@@ -0,0 +1,35 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: HTTP delivery applies compression and cache policy
|
||||
The system SHALL apply transport-level compression and explicit cache directives for static assets, API responses, and public HTML routes.
|
||||
|
||||
#### Scenario: Compressed responses are available for eligible payloads
|
||||
- **WHEN** a client requests compressible content that exceeds the compression threshold
|
||||
- **THEN** the response is served with gzip compression
|
||||
- **AND** response headers advertise the selected content encoding
|
||||
|
||||
#### Scenario: Route classes receive deterministic cache-control directives
|
||||
- **WHEN** clients request static assets, API responses, or HTML page routes
|
||||
- **THEN** each route class returns a cache policy aligned to its freshness requirements
|
||||
- **AND** cache directives are explicit and testable from response headers
|
||||
|
||||
### Requirement: Media rendering optimizes perceived loading performance
|
||||
The system SHALL lazy-load non-critical images and render shimmer placeholders until image load completion or fallback resolution.
|
||||
|
||||
#### Scenario: Feed and modal images lazy-load with placeholders
|
||||
- **WHEN** feed or modal images have not completed loading
|
||||
- **THEN** a shimmer placeholder is visible for the pending image region
|
||||
- **AND** the placeholder is removed after load or fallback error handling completes
|
||||
|
||||
#### Scenario: Image rendering reduces layout shift risk
|
||||
- **WHEN** article images are rendered in hero, feed, or modal contexts
|
||||
- **THEN** image elements include explicit dimensions and async decoding hints
|
||||
- **AND** layout remains stable while content loads
|
||||
|
||||
### Requirement: Smooth scrolling behavior is consistently enabled
|
||||
The system SHALL provide smooth scrolling behavior for in-page navigation and user-initiated scroll interactions.
|
||||
|
||||
#### Scenario: In-page navigation uses smooth scrolling
|
||||
- **WHEN** users navigate to in-page anchors or equivalent interactions
|
||||
- **THEN** scrolling transitions occur smoothly rather than jumping abruptly
|
||||
- **AND** behavior is consistent across supported breakpoints
|
||||
@@ -0,0 +1,27 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Homepage publishes Newspaper structured data
|
||||
The system SHALL expose a valid JSON-LD entity of type `Newspaper` on the homepage.
|
||||
|
||||
#### Scenario: Newspaper entity is emitted on homepage
|
||||
- **WHEN** the homepage HTML is rendered
|
||||
- **THEN** a JSON-LD script block includes an entity with `@type` set to `Newspaper`
|
||||
- **AND** the entity includes stable publisher and site identity fields
|
||||
|
||||
#### Scenario: Newspaper entity remains language-aware
|
||||
- **WHEN** homepage content is rendered in a selected language
|
||||
- **THEN** the structured data includes language context for the active locale
|
||||
- **AND** language output stays consistent with visible content language
|
||||
|
||||
### Requirement: Each rendered news item publishes NewsArticle structured data
|
||||
The system SHALL expose a valid JSON-LD entity of type `NewsArticle` for each rendered news item in hero and feed contexts.
|
||||
|
||||
#### Scenario: NewsArticle entities include required semantic fields
|
||||
- **WHEN** news items are present on the homepage
|
||||
- **THEN** each `NewsArticle` entity includes headline, description, image, publication dates, and URL fields
|
||||
- **AND** publisher and author context are present for each item
|
||||
|
||||
#### Scenario: Structured data avoids duplicate article entities
|
||||
- **WHEN** article data appears across hero and feed sections
|
||||
- **THEN** structured-data output deduplicates entities for the same article URL
|
||||
- **AND** only one canonical semantic entry remains for each unique article
|
||||
@@ -0,0 +1,27 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Core SEO metadata is present on public pages
|
||||
The system SHALL expose standards-compliant SEO metadata on the homepage and policy pages, including description, robots, canonical URL, and social preview metadata.
|
||||
|
||||
#### Scenario: Homepage metadata baseline exists
|
||||
- **WHEN** a crawler or browser loads the homepage
|
||||
- **THEN** the document includes `description`, `robots`, and canonical metadata
|
||||
- **AND** Open Graph and Twitter card metadata fields are present with non-empty values
|
||||
|
||||
#### Scenario: Policy pages include indexable metadata
|
||||
- **WHEN** a crawler loads `/terms` or `/attribution`
|
||||
- **THEN** the page includes page-specific `title` and `description` metadata
|
||||
- **AND** Open Graph and Twitter card metadata are present for link previews
|
||||
|
||||
### Requirement: Canonical and preview metadata remain deterministic
|
||||
The system SHALL keep canonical and preview metadata deterministic for each route to avoid conflicting crawler signals.
|
||||
|
||||
#### Scenario: Canonical URL reflects active route
|
||||
- **WHEN** metadata is rendered for a public route
|
||||
- **THEN** exactly one canonical link is emitted for that route
|
||||
- **AND** canonical metadata does not point to unrelated routes
|
||||
|
||||
#### Scenario: Social preview tags map to current page context
|
||||
- **WHEN** the page metadata is generated or updated
|
||||
- **THEN** `og:title`, `og:description`, and corresponding Twitter fields reflect the current page context
|
||||
- **AND** preview image fields resolve to a valid absolute URL
|
||||
34
openspec/changes/p08-seo-tweaks/tasks.md
Normal file
34
openspec/changes/p08-seo-tweaks/tasks.md
Normal file
@@ -0,0 +1,34 @@
|
||||
## 1. SEO Metadata and Social Tags
|
||||
|
||||
- [x] 1.1 Ensure homepage and policy pages expose required `title`, `description`, `robots`, and canonical metadata.
|
||||
- [x] 1.2 Ensure Open Graph and Twitter metadata fields are present and mapped to current page context.
|
||||
- [x] 1.3 Add verification checks for deterministic canonical URLs and valid absolute social image URLs.
|
||||
|
||||
## 2. Structured Data (Newspaper and NewsArticle)
|
||||
|
||||
- [x] 2.1 Implement and verify homepage `Newspaper` JSON-LD output with publisher/site identity fields.
|
||||
- [x] 2.2 Implement and verify `NewsArticle` JSON-LD output for hero and feed items using required semantic fields.
|
||||
- [x] 2.3 Add deduplication logic so repeated hero/feed references emit one semantic entity per article URL.
|
||||
|
||||
## 3. Delivery and Caching Performance
|
||||
|
||||
- [x] 3.1 Apply and validate gzip compression for eligible responses.
|
||||
- [x] 3.2 Apply and validate explicit cache-control policies for static assets, APIs, and HTML routes.
|
||||
- [x] 3.3 Verify route-level header behavior with repeatable checks and document expected header values.
|
||||
|
||||
## 4. Rendering Performance and UX
|
||||
|
||||
- [x] 4.1 Ensure non-critical images use lazy loading with explicit dimensions and async decoding hints.
|
||||
- [x] 4.2 Ensure shimmer placeholders are visible until image load or fallback completion in feed and modal contexts.
|
||||
- [x] 4.3 Ensure smooth scrolling behavior remains consistent for in-page navigation interactions.
|
||||
|
||||
## 5. Validation and Acceptance
|
||||
|
||||
- [x] 5.1 Validate structured data output for `Newspaper` and `NewsArticle` entities against schema expectations.
|
||||
- [x] 5.2 Validate HTML/metadata output against project validation goals and resolve conformance gaps.
|
||||
- [x] 5.3 Execute regression checks for homepage rendering, article card behavior, and policy page metadata.
|
||||
|
||||
## 6. Documentation
|
||||
|
||||
- [x] 6.1 Document SEO/structured-data contracts and performance header expectations in project docs.
|
||||
- [x] 6.2 Document verification steps so future changes can re-run SEO and performance acceptance checks.
|
||||
2
openspec/changes/p09-image-choices/.openspec.yaml
Normal file
2
openspec/changes/p09-image-choices/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-13
|
||||
Reference in New Issue
Block a user