bulk commit changes!

This commit is contained in:
2026-02-13 02:32:06 -05:00
parent c8f98c54c9
commit bf4a40f533
152 changed files with 2210 additions and 19 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-13

View File

@@ -0,0 +1,88 @@
## Context
`frontend/index.html` currently renders the hero CTA as an external redirect (`window.open(item.source_url)`), and modal sizing is constrained by `max-w-2xl` with `max-h-[90vh]`. TL;DR content does not expose a dedicated loading placeholder, and hero badges can lose readability over bright images. On the backend, `backend/news_service.py` already performs keyword extraction and provider fallback, but defaults remain too generic (`"news technology"`) and do not explicitly prioritize AI-topic fallback behavior.
## Goals / Non-Goals
**Goals:**
- Keep users on-site by making the hero primary CTA open the existing TL;DR modal flow.
- Ensure `LATEST` and relative timestamp remain legible over all hero images in light/dark themes.
- Increase modal usable area (width and near-full-height scrolling behavior) without breaking mobile usability.
- Add a small horizontal shimmer placeholder for TL;DR bullets while modal content initializes.
- Improve image relevance with stronger AI-focused keyword fallback and deterministic generic AI-image fallback when lookup fails.
**Non-Goals:**
- Rebuilding the full feed card architecture.
- Replacing existing provider integrations or adding new third-party image providers.
- Introducing backend sentiment ML models.
- Reworking scheduler or ingestion cadence.
## Decisions
### Decision: Reuse existing modal interaction path for hero CTA
**Decision:** Wire hero CTA to the same `openSummary(item)` behavior used by feed cards.
**Rationale:**
- Reuses existing event tracking and modal rendering logic.
- Avoids duplicate interaction models and reduces regression risk.
**Alternatives considered:**
- Add a second hero-only modal implementation: rejected due to duplicate UI state and maintenance cost.
### Decision: Enforce readability with layered overlay + contrast-safe tokens
**Decision:** Strengthen hero overlay and badge/text color tokens so metadata remains visible independent of image luminance.
**Rationale:**
- Solves visibility issues without image preprocessing.
- Keeps responsive behavior in CSS instead of JS image analysis.
**Alternatives considered:**
- Dynamic luminance detection per image: rejected as unnecessary complexity for current scope.
### Decision: Expand modal dimensions with responsive constraints
**Decision:** Use a wider desktop container (minimum half viewport intent) while preserving mobile full-width behavior and near-full-height scrolling.
**Rationale:**
- Improves readability for summary blocks and TL;DR bullets.
- Keeps accessibility of close controls and keyboard escape path.
**Alternatives considered:**
- Full-screen modal only: rejected due to excessive visual disruption on desktop.
### Decision: Treat TL;DR loading as explicit skeleton state
**Decision:** Add a low-height horizontal shimmer placeholder visible when TL;DR is not yet available.
**Rationale:**
- Reduces perceived latency ambiguity.
- Matches existing skeleton design language already used for images/cards.
### Decision: Improve fallback query semantics for AI-news image retrieval
**Decision:** Enhance keyword fallback to AI-focused defaults (`ai machine learning deep learning`) and add explicit generic AI image fallback contract.
**Rationale:**
- Reduces irrelevant imagery when topic extraction is weak or providers return noisy results.
- Keeps behavior deterministic and testable.
## Risks / Trade-offs
- **[Risk] Wider modal may crowd smaller laptops** -> Mitigation: use responsive width caps with mobile-first breakpoints and overflow handling.
- **[Risk] Hero overlay could darken images too much** -> Mitigation: tune gradient opacity and preserve theme-specific token overrides.
- **[Risk] Fallback image monotony if providers fail frequently** -> Mitigation: keep provider chain first; generic AI fallback only as terminal fallback.
- **[Trade-off] Stronger AI default keywords may reduce non-AI niche relevance** -> Mitigation: apply defaults only when extracted keywords are insufficient.
## Migration Plan
1. Update hero CTA and hero readability styles in `frontend/index.html`.
2. Update modal sizing and TL;DR shimmer loading state in `frontend/index.html`.
3. Update backend keyword fallback and generic AI image fallback behavior in `backend/news_service.py`.
4. Verify behavior manually on desktop/mobile and run relevant checks.
Rollback:
- Revert hero CTA to external link behavior.
- Revert modal class and shimmer additions.
- Revert keyword/default fallback updates in image pipeline.
## Open Questions
- Should generic AI fallback be local static asset only, or deterministic remote URL with local optimization?
- Do we need separate fallback keyword sets per language now, or keep English-focused defaults in this change?

View File

@@ -0,0 +1,27 @@
## Why
The current UX for the homepage hero and summary modal still has high-friction behavior and readability issues, and image relevance is still inconsistent for AI news topics. Fixing these now improves retention, trust, and content quality without changing the core product flow.
## What Changes
- Change hero primary CTA behavior to open the in-site TL;DR summary flow instead of immediately sending users off-site.
- Improve hero readability over images so `LATEST` and relative time metadata remain visible across themes and screen sizes.
- Increase modal width and adjust modal height behavior so long content can use near full-height viewport scrolling.
- Add a short horizontal shimmer placeholder for TL;DR bullet content while summary details are loading.
- Strengthen image relevance by extracting better keywords from news text, adding AI-topic default keywords, and using a generic AI fallback image when providers fail.
## Capabilities
### New Capabilities
- `hero-summary-entry-and-readability`: Define hero CTA in-site summary entry behavior and image-overlay readability requirements for badges, timestamps, headline, and summary text.
- `modal-layout-and-loading-feedback`: Define modal sizing/overflow behavior and TL;DR loading placeholders for clearer perceived loading state.
- `news-image-relevance-and-fallbacks`: Define keyword extraction quality, default AI keyword fallback rules, and generic AI image fallback behavior when no relevant image is found.
### Modified Capabilities
- None.
## Impact
- **Frontend/UI:** `frontend/index.html` (hero CTA wiring, hero overlay/readability styles, modal width/height classes, TL;DR loading skeleton state).
- **Backend/Image Pipeline:** `backend/news_service.py` (keyword extraction and provider fallback behavior for summary images).
- **Assets/Config:** generic AI fallback image path/asset contract and related docs may be updated.

View File

@@ -0,0 +1,27 @@
## ADDED Requirements
### Requirement: Hero primary action opens in-site TL;DR summary
The homepage hero primary CTA SHALL open the in-site summary modal for the hero article instead of navigating off-site.
#### Scenario: Hero CTA opens summary modal
- **WHEN** a user clicks the hero primary CTA
- **THEN** the system opens the summary modal for the current hero article
- **AND** no external navigation is triggered by that CTA
### Requirement: Hero source link remains available as secondary action
The hero section SHALL keep an explicit secondary source-link action for external navigation.
#### Scenario: Source link navigates externally
- **WHEN** a user clicks the hero source link
- **THEN** the system opens the article source URL in a new tab
### Requirement: Hero metadata readability over images
Hero metadata (`LATEST`, relative time, headline, and summary) SHALL remain visually legible across bright and dark images on desktop and mobile.
#### Scenario: Bright image background
- **WHEN** the hero image contains bright regions under metadata text
- **THEN** overlay and text styles preserve readable contrast for metadata and headline blocks
#### Scenario: Mobile viewport readability
- **WHEN** the hero renders on a mobile viewport
- **THEN** metadata and title remain readable without overlapping controls or clipping

View File

@@ -0,0 +1,33 @@
## ADDED Requirements
### Requirement: Modal width supports comfortable desktop reading
The summary modal SHALL render with a desktop width that is approximately half of viewport width or larger when space allows, while remaining responsive on small screens.
#### Scenario: Desktop width expansion
- **WHEN** the modal opens on desktop viewport widths
- **THEN** the modal content area renders wider than the previous narrow baseline
- **AND** text blocks are readable without excessive line wrapping
#### Scenario: Mobile responsiveness
- **WHEN** the modal opens on small mobile viewport widths
- **THEN** modal width remains fully usable without horizontal overflow
### Requirement: Modal height supports near-full viewport scrolling
The summary modal SHALL use near full-height viewport behavior when content overflows.
#### Scenario: Overflowing summary content
- **WHEN** summary content exceeds modal viewport height
- **THEN** modal body remains scrollable with close controls accessible
- **AND** modal container uses near full viewport height constraints
### Requirement: TL;DR loading placeholder is explicit
The modal SHALL show a horizontal shimmer placeholder for TL;DR content while TL;DR bullets are not yet available.
#### Scenario: TL;DR pending state
- **WHEN** the summary modal is open and TL;DR bullet data is pending
- **THEN** the system displays a low-height horizontal shimmer placeholder
#### Scenario: TL;DR loaded state
- **WHEN** TL;DR bullet data becomes available
- **THEN** shimmer placeholder is removed
- **AND** TL;DR bullet list is rendered

View File

@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: Image query fallback uses AI-focused defaults
When extracted image keywords are insufficient, the system SHALL use AI-focused default fallback terms.
#### Scenario: Empty keyword extraction
- **WHEN** keyword extraction yields no usable topic keywords
- **THEN** the system uses default fallback terms including AI-domain keywords (for example `ai`, `machine learning`, `deep learning`)
### Requirement: Generic AI image fallback is guaranteed
If provider lookups fail to return a usable summary image, the system SHALL use a generic AI-themed fallback image.
#### Scenario: Provider chain failure
- **WHEN** all configured image providers return no usable image
- **THEN** the system assigns a generic AI fallback image URL/path for summary image
### Requirement: Fallback behavior remains context-aware first
The system SHALL attempt context-aware keyword retrieval before any generic fallback image is selected.
#### Scenario: Context-aware attempt precedes fallback
- **WHEN** summary image selection runs for a news item
- **THEN** the system first attempts provider queries from extracted context-aware keywords
- **AND** only falls back to generic AI image if these attempts fail

View File

@@ -0,0 +1,29 @@
## 1. Hero UX Fixes
- [x] 1.1 Update hero primary CTA in `frontend/index.html` to open the in-site summary modal for the hero item.
- [x] 1.2 Keep hero source link as a secondary external action and preserve tracking events.
- [x] 1.3 Strengthen hero overlay and metadata styles so `LATEST` and relative time remain readable across image brightness levels.
## 2. Modal Layout Improvements
- [x] 2.1 Increase modal width for desktop while keeping mobile-safe responsive behavior.
- [x] 2.2 Update modal height/overflow behavior to support near full-height scrolling for long content.
- [x] 2.3 Verify close controls and keyboard escape behavior remain intact after sizing changes.
## 3. TL;DR Loading Feedback
- [x] 3.1 Add a dedicated horizontal shimmer placeholder for TL;DR content while modal summary data is initializing.
- [x] 3.2 Hide the TL;DR shimmer placeholder when TL;DR bullets are available and render the bullet list.
## 4. Image Relevance and Fallback
- [x] 4.1 Update keyword fallback logic in `backend/news_service.py` to use AI-focused default terms when extracted keywords are insufficient.
- [x] 4.2 Add explicit generic AI summary-image fallback behavior when provider chain returns no usable image.
- [x] 4.3 Ensure context-aware keyword/provider attempts always run before generic AI fallback selection.
## 5. Validation
- [x] 5.1 Verify hero CTA opens summary modal instead of navigating away.
- [x] 5.2 Verify modal sizing on desktop/mobile and long-content scrolling behavior.
- [x] 5.3 Verify TL;DR shimmer appears during pending state and disappears after load.
- [x] 5.4 Verify generic AI fallback image is used when provider chain fails.

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-13

View File

@@ -0,0 +1,85 @@
## Context
Current operations are concentrated in `backend/cli.py` with a single `force-fetch` command and no unified admin maintenance suite. Operational actions such as archive cleanup, translation regeneration, image refresh, and cache/news reset require manual code/DB operations. Existing backend services already contain reusable primitives: ingestion (`process_and_store_news`), archival helpers (`archive_old_news`, `delete_archived_news`), and translation generation pipelines in `backend/news_service.py`.
## Goals / Non-Goals
**Goals:**
- Introduce an admin command suite that consolidates common maintenance and recovery actions.
- Implement queued image refetch for latest 30 items, sequentially processed with exponential backoff.
- Improve image refresh relevance by combining keyword and mood/sentiment cues with deterministic fallback behavior.
- Provide safe destructive operations (`clear-news`, `clean-archive`, cache clear) with operator guardrails.
- Add translation regeneration and parameterized fetch count command to reduce manual intervention.
**Non-Goals:**
- Replacing the scheduled ingestion model.
- Introducing external queue infrastructure (RabbitMQ/Redis workers) for this phase.
- Redesigning storage models or adding new DB tables unless strictly necessary.
- Building a web-based admin dashboard in this change.
## Decisions
### Decision: Extend existing CLI with subcommands
**Decision:** Expand `backend/cli.py` into a multi-subcommand admin command suite.
**Rationale:**
- Reuses existing deployment/runtime assumptions.
- Keeps operations scriptable via terminal/cron and avoids UI scope expansion.
**Alternatives considered:**
- New standalone admin binary: rejected due to duplicated bootstrapping/runtime checks.
### Decision: Queue image refetch in-process with sequential workers
**Decision:** Build a bounded in-memory queue for latest 30 items and process one-by-one.
**Rationale:**
- Meets rate-limit resilience requirement without new infrastructure.
- Deterministic and easy to monitor in command output.
**Alternatives considered:**
- Parallel refetch workers: rejected due to higher provider throttling risk.
### Decision: Exponential backoff for external image calls
**Decision:** Apply exponential backoff with capped retries for rate-limited or transient failures.
**Rationale:**
- Reduces burst retry amplification.
- Improves success rate under API pressure.
### Decision: Safety-first destructive command ergonomics
**Decision:** Destructive operations require explicit confirmation/flags and support dry-run where meaningful.
**Rationale:**
- Prevents accidental data loss.
- Makes admin actions auditable and predictable.
### Decision: Fetch-N command reuses ingestion pipeline
**Decision:** Add a fetch-count option that drives existing ingestion/fetch flow rather than building a second implementation.
**Rationale:**
- Preserves deduplication/retry logic and minimizes divergence.
## Risks / Trade-offs
- **[Risk] Operator misuse of destructive commands** -> Mitigation: confirmation gate + explicit flags + dry-run.
- **[Risk] Backoff can increase command runtime** -> Mitigation: cap retries and print progress ETA-style output.
- **[Risk] Queue processing interruption mid-run** -> Mitigation: idempotent per-item updates and resumable reruns.
- **[Trade-off] In-process queue is simpler but non-distributed** -> Mitigation: acceptable for admin-invoked maintenance scope.
## Migration Plan
1. Extend CLI parser with admin subcommands and argument validation.
2. Add reusable maintenance handlers (archive clean, cache clear, clear news, rebuild, regenerate translations, fetch-n).
3. Implement queued image-refetch handler with exponential backoff and per-item progress logs.
4. Add safe guards (`--confirm`, optional `--dry-run`) for destructive operations.
5. Document command usage and examples in README.
Rollback:
- Keep existing `force-fetch` path intact.
- Revert new subcommands while preserving unaffected ingestion pipeline.
## Open Questions
- What cache layers are considered in-scope for `clear-cache` (in-memory only vs additional filesystem cache)?
- Should `rebuild-site` chain all maintenance actions or remain a defined subset with explicit steps?
- Should `fetch n` enforce an upper bound to avoid accidental high-cost runs?

View File

@@ -0,0 +1,34 @@
## Why
Operational recovery and maintenance flows are currently fragmented, manual, and risky for site admins during outages or data-quality incidents. We need a reliable admin command surface that supports safe reset/rebuild workflows without requiring ad-hoc scripts.
## What Changes
- Add a unified admin CLI command with maintenance subcommands for common operational tasks.
- Add `refetch-images` mode that processes the latest 30 news items through a queue, one-by-one, with exponential backoff to reduce provider/API rate-limit failures.
- Make image refetch context-aware using article keywords plus mood/sentiment signals to improve image relevance.
- Add archive cleanup command for archived news maintenance.
- Add cache clear command for application cache invalidation.
- Add clear-news command for wiping existing news items.
- Add rebuild-site command to re-run full rebuild workflow.
- Add regenerate-translations command for all supported languages.
- Add fetch command supporting user-provided `n` article count.
- Add guardrails and operator UX improvements (dry-run where applicable, progress output, failure summaries, and safe defaults).
## Capabilities
### New Capabilities
- `admin-maintenance-command-suite`: Defines a single admin command surface with subcommands for refetch images, archive cleanup, cache clear, news clear, rebuild, translation regeneration, and fetch-n workflows.
- `queued-image-refetch-with-backoff`: Defines queue-based image refetch behavior for latest 30 items with sequential processing and exponential backoff for rate-limit resilience.
- `context-aware-image-selection-recovery`: Defines keyword + sentiment/mood-informed image query rules and generic AI fallback behavior for refetch operations.
- `site-admin-safety-and-ergonomics`: Defines operational safeguards and usability requirements (dry-run, confirmation for destructive actions, progress reporting, and actionable error summaries).
### Modified Capabilities
- None.
## Impact
- **Backend/CLI:** new admin command entrypoints and orchestration logic for maintenance workflows.
- **News/Image Pipeline:** image re-fetch and optimization logic, retry/backoff strategy, and relevance heuristics.
- **Data Layer:** archive cleanup, cache invalidation, news-clear, translation regeneration, and controlled fetch-count ingestion operations.
- **Operations:** faster incident recovery, reduced manual intervention, and safer reset/rebuild procedures for admins.

View File

@@ -0,0 +1,32 @@
## ADDED Requirements
### Requirement: Unified admin command surface
The system SHALL provide a single admin CLI command family exposing maintenance subcommands.
#### Scenario: Subcommand discovery
- **WHEN** an operator runs the admin command help output
- **THEN** available subcommands include refetch-images, clean-archive, clear-cache, clear-news, rebuild-site, regenerate-translations, and fetch
### Requirement: Fetch command supports configurable article count
The admin fetch command SHALL support an operator-provided article count parameter.
#### Scenario: Fetch with explicit count
- **WHEN** an operator invokes fetch with `n=25`
- **THEN** the command executes ingestion targeting the requested count
- **AND** prints completion summary including processed/stored counts
### Requirement: Translation regeneration command
The system SHALL provide a command to regenerate translations for existing articles.
#### Scenario: Regenerate translations run
- **WHEN** an operator runs regenerate-translations
- **THEN** the system attempts translation regeneration for supported languages
- **AND** outputs success/failure totals
### Requirement: Rebuild site command
The system SHALL provide a rebuild-site command that executes the defined rebuild workflow.
#### Scenario: Rebuild execution
- **WHEN** an operator runs rebuild-site
- **THEN** the system executes the documented rebuild steps in deterministic order
- **AND** prints a final success/failure summary

View File

@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: Context-aware image query generation
Image refetch SHALL construct provider queries from article context including keywords and mood/sentiment cues.
#### Scenario: Context-enriched query
- **WHEN** a queued article is processed for image refetch
- **THEN** the system derives query terms from article headline/summary content
- **AND** includes mood/sentiment-informed cues to improve relevance
### Requirement: AI-domain fallback keywords
When context extraction is insufficient, the system SHALL use AI-domain fallback keywords.
#### Scenario: Empty or weak context extraction
- **WHEN** extracted context terms are empty or below quality threshold
- **THEN** the system applies fallback terms such as `ai`, `machine learning`, `deep learning`
### Requirement: Generic AI fallback image on terminal failure
If no usable provider image is returned, the system SHALL assign a generic AI fallback image.
#### Scenario: Provider chain exhaustion
- **WHEN** all provider attempts fail or return unusable images
- **THEN** the system stores a generic AI fallback image for the article

View File

@@ -0,0 +1,33 @@
## ADDED Requirements
### Requirement: Latest-30 queue construction
The refetch-images command SHALL enqueue up to the latest 30 news items for processing.
#### Scenario: Queue population
- **WHEN** refetch-images is started
- **THEN** the command loads recent news items
- **AND** enqueues at most 30 items ordered from newest to oldest
### Requirement: Sequential processing
The image refetch queue SHALL be processed one item at a time.
#### Scenario: Single-item worker behavior
- **WHEN** queue processing runs
- **THEN** only one queued item is processed concurrently
- **AND** next item starts only after current item completes/fails
### Requirement: Exponential backoff on transient failures
The queue processor SHALL retry transient image-provider failures using exponential backoff.
#### Scenario: Rate-limited provider response
- **WHEN** provider call returns rate-limit or transient error
- **THEN** command retries with exponential delay between attempts
- **AND** stops retrying after configured max attempts
### Requirement: Progress and completion reporting
The command SHALL emit operator-readable progress and final summary output.
#### Scenario: Queue progress output
- **WHEN** queue processing is in progress
- **THEN** the command prints per-item progress (processed/succeeded/failed)
- **AND** prints final totals on completion

View File

@@ -0,0 +1,25 @@
## ADDED Requirements
### Requirement: Confirmation guard for destructive commands
Destructive admin commands SHALL require explicit confirmation before execution.
#### Scenario: Missing confirmation flag
- **WHEN** an operator runs clear-news or clean-archive without required confirmation
- **THEN** the command exits without applying destructive changes
- **AND** prints guidance for explicit confirmation usage
### Requirement: Dry-run support where applicable
Maintenance commands SHALL provide dry-run mode for previewing effects where feasible.
#### Scenario: Dry-run preview
- **WHEN** an operator invokes a command with dry-run mode
- **THEN** the command reports intended actions and affected counts
- **AND** persists no data changes
### Requirement: Actionable failure summaries
Admin commands SHALL output actionable errors and final status summaries.
#### Scenario: Partial failure reporting
- **WHEN** a maintenance command partially fails
- **THEN** output includes succeeded/failed counts
- **AND** includes actionable next-step guidance

View File

@@ -0,0 +1,41 @@
## 1. Admin CLI Foundation
- [x] 1.1 Extend `backend/cli.py` parser with an admin maintenance command group and subcommands.
- [x] 1.2 Add argument validation for subcommands including `fetch --count n`.
- [x] 1.3 Keep existing `force-fetch` command behavior intact.
## 2. Queue-Based Image Refetch
- [x] 2.1 Implement latest-30 article selection query for refetch queue.
- [x] 2.2 Implement in-process sequential queue worker for refetch-images.
- [x] 2.3 Add exponential backoff retry logic for transient/rate-limit provider failures.
- [x] 2.4 Add per-item progress logging and final queue summary output.
## 3. Context-Aware Image Recovery
- [x] 3.1 Add context-aware query generation using article keywords plus mood/sentiment cues.
- [x] 3.2 Add AI-domain fallback keyword set when extracted context is weak.
- [x] 3.3 Add explicit generic AI fallback image assignment for terminal provider failure.
- [x] 3.4 Ensure refetched images are optimized and persisted using existing image pipeline contracts.
## 4. Maintenance Operations
- [x] 4.1 Implement clean-archive command using existing archival repository helpers.
- [x] 4.2 Implement clear-cache command for configured cache layers in scope.
- [x] 4.3 Implement clear-news command for non-archived and/or configured scope items.
- [x] 4.4 Implement rebuild-site command to execute defined rebuild sequence.
- [x] 4.5 Implement regenerate-translations command across supported languages.
- [x] 4.6 Implement fetch command with configurable article count.
## 5. Safety and Operator UX
- [x] 5.1 Add explicit confirmation requirement for destructive commands.
- [x] 5.2 Add dry-run support for commands where preview is feasible.
- [x] 5.3 Standardize command output format for success/failure totals and next-step hints.
## 6. Documentation and Validation
- [x] 6.1 Update README command documentation with examples for each new subcommand.
- [x] 6.2 Add operational guardrail notes (confirmation, dry-run, backoff behavior).
- [x] 6.3 Validate command help output and argument handling.
- [x] 6.4 Run end-to-end manual checks for refetch-images queue behavior and failure recovery output.

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-13

View File

@@ -0,0 +1,23 @@
## Why
Current Umami event payloads for CTA clicks and summary modal interactions include only `article_id`, which makes analysis harder when reviewing dashboards and raw events. Adding human-readable article context improves analyst speed and reduces lookup friction.
## What Changes
- Add `article_title` to CTA-click event payloads so click analytics can be understood without cross-referencing IDs.
- Add `article_title` to summary modal open/close event payloads in addition to existing `article_id` context.
- Keep existing event names and current fields intact for backward compatibility.
## Capabilities
### New Capabilities
- None.
### Modified Capabilities
- `hero-display`: Update analytics tracking requirement so CTA click events include both `article_id` and `article_title`.
- `summary-analytics-tagging`: Update modal open/close analytics requirements so payload includes `article_title` with existing article context identifier.
## Impact
- **Frontend analytics wiring:** `frontend/index.html` event payload construction for hero/feed CTA clicks and summary modal open/close events.
- **Analytics consumers:** Umami dashboards and downstream event analysis gain readable article context while preserving existing identifiers.

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-13

View File

@@ -0,0 +1,36 @@
## Purpose
Canonical specification for admin-maintenance-command-suite requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Unified admin command surface
The system SHALL provide a single admin CLI command family exposing maintenance subcommands.
#### Scenario: Subcommand discovery
- **WHEN** an operator runs the admin command help output
- **THEN** available subcommands include refetch-images, clean-archive, clear-cache, clear-news, rebuild-site, regenerate-translations, and fetch
### Requirement: Fetch command supports configurable article count
The admin fetch command SHALL support an operator-provided article count parameter.
#### Scenario: Fetch with explicit count
- **WHEN** an operator invokes fetch with `n=25`
- **THEN** the command executes ingestion targeting the requested count
- **AND** prints completion summary including processed/stored counts
### Requirement: Translation regeneration command
The system SHALL provide a command to regenerate translations for existing articles.
#### Scenario: Regenerate translations run
- **WHEN** an operator runs regenerate-translations
- **THEN** the system attempts translation regeneration for supported languages
- **AND** outputs success/failure totals
### Requirement: Rebuild site command
The system SHALL provide a rebuild-site command that executes the defined rebuild workflow.
#### Scenario: Rebuild execution
- **WHEN** an operator runs rebuild-site
- **THEN** the system executes the documented rebuild steps in deterministic order
- **AND** prints a final success/failure summary

View File

@@ -0,0 +1,26 @@
## Purpose
Canonical specification for article-tldr-summary requirements synced from OpenSpec change deltas.
## 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

View File

@@ -0,0 +1,31 @@
## Purpose
Canonical specification for article-translations-ml-tm requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: System generates Tamil and Malayalam translations at article creation time
The system SHALL generate Tamil (`ta`) and Malayalam (`ml`) translations for each newly created article during ingestion.
#### Scenario: Translation generation for new article
- **WHEN** a new source article is accepted for storage
- **THEN** the system requests Tamil and Malayalam translations for headline and summary
- **AND** translation generation occurs in the same ingestion flow for that article
#### Scenario: Translation failure fallback
- **WHEN** translation generation fails for one or both target languages
- **THEN** the system stores the base article in English
- **AND** marks missing translations as unavailable without failing the whole ingestion cycle
### Requirement: System stores translation variants linked to the same article
The system SHALL persist language-specific translated content as translation items associated with the base article.
#### Scenario: Persist linked translations
- **WHEN** Tamil and Malayalam translations are generated successfully
- **THEN** the system stores them as language-specific content variants linked to the base article identifier
- **AND** translation records remain queryable by language code
#### Scenario: No duplicate translation variants per language
- **WHEN** translation storage is attempted for an article-language pair that already exists
- **THEN** the system avoids creating duplicate translation items for the same language
- **AND** preserves one authoritative translation variant per article per language in this phase

View File

@@ -0,0 +1,18 @@
## Purpose
Canonical specification for attribution-disclaimer-page requirements synced from OpenSpec change deltas.
## 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

View File

@@ -0,0 +1,47 @@
## Purpose
Canonical specification for containerized-deployment requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Containerized deployment
The system SHALL run entirely within Docker containers with all dependencies included.
#### Scenario: Single container build
- **WHEN** building the Docker image
- **THEN** the Dockerfile SHALL include Python runtime, Node.js (for Tailwind if needed), and all application code
- **AND** expose port 8000 for web traffic
#### Scenario: Environment configuration
- **WHEN** running the container
- **THEN** the system SHALL read PERPLEXITY_API_KEY from environment variables
- **AND** fail to start if the key is missing or invalid
- **AND** support optional configuration for retention days (default: 30)
- **AND** support optional IMAGE_QUALITY for image compression (default: 85)
- **AND** support optional OPENROUTER_API_KEY for fallback LLM provider
- **AND** support optional UMAMI_SCRIPT_URL and UMAMI_WEBSITE_ID for analytics
#### Scenario: Data persistence
- **WHEN** the container restarts
- **THEN** the SQLite database SHALL persist via Docker volume mount
- **AND** news data SHALL remain intact across restarts
### Requirement: Responsive single-page design
The system SHALL provide a stunning, responsive one-page website with ClawFort branding.
#### Scenario: Brand consistency
- **WHEN** viewing the website
- **THEN** the design SHALL feature ClawFort branding (logo, colors, typography)
- **AND** maintain visual consistency across all sections
#### Scenario: Responsive layout
- **WHEN** viewing on mobile, tablet, or desktop
- **THEN** the layout SHALL adapt appropriately
- **AND** the hero block SHALL resize proportionally
- **AND** the news feed SHALL use appropriate column layouts
#### Scenario: Performance
- **WHEN** loading the page
- **THEN** initial page load SHALL complete within 2 seconds
- **AND** images SHALL lazy load outside viewport
- **AND** JavaScript bundle SHALL be under 100KB gzipped

View File

@@ -0,0 +1,27 @@
## Purpose
Canonical specification for context-aware-image-selection-recovery requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Context-aware image query generation
Image refetch SHALL construct provider queries from article context including keywords and mood/sentiment cues.
#### Scenario: Context-enriched query
- **WHEN** a queued article is processed for image refetch
- **THEN** the system derives query terms from article headline/summary content
- **AND** includes mood/sentiment-informed cues to improve relevance
### Requirement: AI-domain fallback keywords
When context extraction is insufficient, the system SHALL use AI-domain fallback keywords.
#### Scenario: Empty or weak context extraction
- **WHEN** extracted context terms are empty or below quality threshold
- **THEN** the system applies fallback terms such as `ai`, `machine learning`, `deep learning`
### Requirement: Generic AI fallback image on terminal failure
If no usable provider image is returned, the system SHALL assign a generic AI fallback image.
#### Scenario: Provider chain exhaustion
- **WHEN** all provider attempts fail or return unusable images
- **THEN** the system stores a generic AI fallback image for the article

View File

@@ -0,0 +1,18 @@
## Purpose
Canonical specification for cookie-consent-tracking-gate requirements synced from OpenSpec change deltas.
## 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

View File

@@ -0,0 +1,39 @@
## Purpose
Canonical specification for delivery-and-rendering-performance requirements synced from OpenSpec change deltas.
## 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

View File

@@ -0,0 +1,31 @@
## Purpose
Canonical specification for fetch-run-reporting requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Command reports run outcome to operator
The system SHALL present operator-facing output that describes whether the forced run succeeded or failed.
#### Scenario: Successful run reporting
- **WHEN** a forced fetch command completes without fatal errors
- **THEN** the command output includes a success indication
- **AND** includes the number of items stored in that run
#### Scenario: Failed run reporting
- **WHEN** a forced fetch command encounters a fatal execution error
- **THEN** the command output includes a failure indication
- **AND** includes actionable error details for operator diagnosis
### Requirement: Command exposes automation-friendly exit semantics
The system SHALL return deterministic process exit codes for command success and failure.
#### Scenario: Exit code on success
- **WHEN** the force-fetch command execution completes successfully
- **THEN** the process exits with code 0
- **AND** automation tooling can treat the run as successful
#### Scenario: Exit code on fatal failure
- **WHEN** the force-fetch command execution fails fatally
- **THEN** the process exits with a non-zero code
- **AND** automation tooling can detect the failure state

View File

@@ -0,0 +1,18 @@
## Purpose
Canonical specification for footer-policy-links requirements synced from OpenSpec change deltas.
## 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

View File

@@ -0,0 +1,31 @@
## Purpose
Canonical specification for force-fetch-command requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Operator can trigger immediate news fetch via Python command
The system SHALL provide a Python command that triggers one immediate news aggregation run outside of the hourly scheduler.
#### Scenario: Successful forced fetch invocation
- **WHEN** an operator runs the documented force-fetch command with valid runtime configuration
- **THEN** the system executes one full fetch cycle using the existing aggregation pipeline
- **AND** the command terminates after the run completes
#### Scenario: Command does not reconfigure scheduler
- **WHEN** an operator runs the force-fetch command while the service scheduler exists
- **THEN** the command performs a one-off run only
- **AND** scheduler job definitions and cadence remain unchanged
### Requirement: Forced fetch reuses existing aggregation behavior
The system SHALL use the same retry, fallback, deduplication, image processing, and persistence logic as scheduled fetch runs.
#### Scenario: Retry and fallback parity
- **WHEN** the primary news provider request fails during a forced run
- **THEN** the system applies the configured retry behavior
- **AND** uses the configured fallback provider path if available
#### Scenario: Deduplication parity
- **WHEN** fetched headlines match existing duplicate rules
- **THEN** duplicate items are skipped according to existing deduplication policy
- **AND** only eligible items are persisted

View File

@@ -0,0 +1,57 @@
## Purpose
Canonical specification for hero-display requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Hero block display
The system SHALL display the most recent news item as a featured hero block with full attribution.
#### Scenario: Hero rendering
- **WHEN** the page loads
- **THEN** the hero block SHALL display the latest news headline, summary, and featured image
- **AND** show source attribution (e.g., "Via: TechCrunch")
- **AND** show image credit (e.g., "Image: DALL-E")
#### Scenario: Hero update
- **WHEN** new news is fetched hourly
- **THEN** the hero block SHALL automatically update to show the newest item
- **AND** the previous hero item SHALL move to the news feed
### Requirement: Infinite scroll news feed
The system SHALL display news items in reverse chronological order with infinite scroll pagination.
#### Scenario: Initial load
- **WHEN** the page first loads
- **THEN** the system SHALL display the 10 most recent non-archived news items
- **AND** exclude the hero item from the feed
#### Scenario: Infinite scroll
- **WHEN** the user scrolls to the bottom of the feed
- **THEN** the system SHALL fetch the next 10 news items via API
- **AND** append them to the feed without page reload
- **AND** show a loading indicator during fetch
#### Scenario: End of feed
- **WHEN** all non-archived news items have been loaded
- **THEN** the system SHALL display "No more news" message
- **AND** disable further scroll triggers
### Requirement: News attribution display
The system SHALL clearly attribute all news content and images to their sources.
#### Scenario: Source attribution
- **WHEN** displaying any news item
- **THEN** the system SHALL show the original source name and link
- **AND** display image credit if available
#### Scenario: Perplexity attribution
- **WHEN** displaying aggregated content
- **THEN** the system SHALL include "Powered by Perplexity" in the footer
#### Scenario: Analytics tracking
- **WHEN** Umami analytics is configured via `UMAMI_SCRIPT_URL` and `UMAMI_WEBSITE_ID`
- **THEN** the system SHALL inject Umami tracking script into page head
- **AND** track page view events on initial load
- **AND** track scroll depth events (25%, 50%, 75%, 100%)
- **AND** track CTA click events (news item clicks, source link clicks)

View File

@@ -0,0 +1,31 @@
## Purpose
Canonical specification for hero-summary-entry-and-readability requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Hero primary action opens in-site TL;DR summary
The homepage hero primary CTA SHALL open the in-site summary modal for the hero article instead of navigating off-site.
#### Scenario: Hero CTA opens summary modal
- **WHEN** a user clicks the hero primary CTA
- **THEN** the system opens the summary modal for the current hero article
- **AND** no external navigation is triggered by that CTA
### Requirement: Hero source link remains available as secondary action
The hero section SHALL keep an explicit secondary source-link action for external navigation.
#### Scenario: Source link navigates externally
- **WHEN** a user clicks the hero source link
- **THEN** the system opens the article source URL in a new tab
### Requirement: Hero metadata readability over images
Hero metadata (`LATEST`, relative time, headline, and summary) SHALL remain visually legible across bright and dark images on desktop and mobile.
#### Scenario: Bright image background
- **WHEN** the hero image contains bright regions under metadata text
- **THEN** overlay and text styles preserve readable contrast for metadata and headline blocks
#### Scenario: Mobile viewport readability
- **WHEN** the hero renders on a mobile viewport
- **THEN** metadata and title remain readable without overlapping controls or clipping

View File

@@ -0,0 +1,63 @@
## Purpose
Canonical specification for image-provider-fallback-chain requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Configurable provider priority
The system SHALL support configuring image provider order via `ROYALTY_IMAGE_PROVIDERS` environment variable.
#### Scenario: Custom provider order
- **WHEN** `ROYALTY_IMAGE_PROVIDERS=unsplash,pexels,pixabay,wikimedia,picsum`
- **THEN** system tries providers in order: Unsplash → Pexels → Pixabay → Wikimedia → Picsum
#### Scenario: Default provider order
- **WHEN** `ROYALTY_IMAGE_PROVIDERS` is not set or empty
- **THEN** system uses default order: `pixabay,unsplash,pexels,wikimedia,picsum`
#### Scenario: Single provider configured
- **WHEN** `ROYALTY_IMAGE_PROVIDERS=pexels`
- **THEN** system only tries Pexels provider
- **AND** returns `(None, None)` if Pexels fails or is not configured
### Requirement: Sequential fallback execution
The system SHALL try providers sequentially until one returns a valid image.
#### Scenario: First provider succeeds
- **WHEN** provider chain is `pixabay,unsplash,pexels` AND Pixabay returns valid image
- **THEN** system returns Pixabay image immediately
- **AND** does NOT call Unsplash or Pexels APIs
#### Scenario: First provider fails, second succeeds
- **WHEN** provider chain is `pixabay,unsplash,pexels` AND Pixabay returns no results AND Unsplash returns valid image
- **THEN** system returns Unsplash image
- **AND** does NOT call Pexels API
#### Scenario: All providers fail
- **WHEN** all configured providers return `(None, None)`
- **THEN** system returns `(None, None)` as final result
- **AND** caller handles fallback to article image or placeholder
### Requirement: MCP endpoint override
The existing `ROYALTY_IMAGE_MCP_ENDPOINT` SHALL take priority over the provider chain when configured.
#### Scenario: MCP endpoint configured
- **WHEN** `ROYALTY_IMAGE_MCP_ENDPOINT` is set to valid URL
- **THEN** system tries MCP endpoint first before provider chain
- **AND** falls back to provider chain only if MCP endpoint fails
#### Scenario: MCP endpoint not configured
- **WHEN** `ROYALTY_IMAGE_MCP_ENDPOINT` is empty or unset
- **THEN** system skips MCP endpoint and proceeds directly to provider chain
### Requirement: Provider skip on missing credentials
Providers without required API keys SHALL be skipped silently.
#### Scenario: Skip unconfigured provider
- **WHEN** provider chain includes `pixabay` AND `PIXABAY_API_KEY` is not set
- **THEN** Pixabay is skipped without error
- **AND** chain continues to next provider
#### Scenario: All providers skipped
- **WHEN** no providers in chain have valid API keys configured
- **THEN** system falls back to Wikimedia (no key required) or Picsum (always available)

View File

@@ -0,0 +1,75 @@
## Purpose
Canonical specification for image-query-refinement requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Keyword extraction from headline
The system SHALL extract relevant keywords from article headlines for image search.
#### Scenario: Extract keywords from standard headline
- **WHEN** headline is "OpenAI Announces GPT-5 with Revolutionary Reasoning Capabilities"
- **THEN** extracted query is "OpenAI GPT-5 Revolutionary Reasoning"
- **AND** stop words like "Announces", "with", "Capabilities" are removed
#### Scenario: Handle short headline
- **WHEN** headline is "AI Breakthrough"
- **THEN** extracted query is "AI Breakthrough"
- **AND** no keywords are removed (headline too short)
#### Scenario: Handle headline with special characters
- **WHEN** headline is "Tesla's Self-Driving AI: 99.9% Accuracy Achieved!"
- **THEN** extracted query is "Tesla Self-Driving AI Accuracy"
- **AND** special characters like apostrophes, colons, and punctuation are normalized
### Requirement: Stop word removal
The system SHALL remove common English stop words from search queries.
#### Scenario: Remove articles and prepositions
- **WHEN** headline is "The Future of AI in the Healthcare Industry"
- **THEN** extracted query is "Future AI Healthcare Industry"
- **AND** "The", "of", "in", "the" are removed
#### Scenario: Preserve technical terms
- **WHEN** headline is "How Machine Learning Models Learn from Data"
- **THEN** extracted query is "Machine Learning Models Learn Data"
- **AND** technical terms "Machine", "Learning", "Models" are preserved
### Requirement: Query length limit
The system SHALL limit search query length to optimize API results.
#### Scenario: Truncate long query
- **WHEN** extracted keywords exceed 10 words
- **THEN** query is limited to first 5 most significant keywords
- **AND** remaining keywords are dropped
#### Scenario: Preserve short query
- **WHEN** extracted keywords are 5 words or fewer
- **THEN** all keywords are included in query
- **AND** no truncation occurs
### Requirement: URL-safe query encoding
The system SHALL URL-encode queries before sending to provider APIs.
#### Scenario: Encode spaces and special characters
- **WHEN** query is "AI Machine Learning"
- **THEN** encoded query is "AI+Machine+Learning" or "AI%20Machine%20Learning"
- **AND** query is safe for HTTP GET parameters
#### Scenario: Handle Unicode characters
- **WHEN** query contains Unicode like "AI für Deutschland"
- **THEN** Unicode characters are properly percent-encoded
- **AND** API request succeeds without encoding errors
### Requirement: Empty query handling
The system SHALL handle edge cases where no keywords can be extracted.
#### Scenario: Headline with only stop words
- **WHEN** headline is "The and a or but"
- **THEN** system uses fallback query "news technology"
- **AND** image search proceeds with generic query
#### Scenario: Empty headline
- **WHEN** headline is empty string or whitespace only
- **THEN** system uses fallback query "news technology"
- **AND** image search proceeds with generic query

View File

@@ -0,0 +1,31 @@
## Purpose
Canonical specification for language-aware-content-delivery requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: API supports language-aware content retrieval
The system SHALL support language-aware content delivery for hero and feed reads using selected language input.
#### Scenario: Language-specific latest article response
- **WHEN** a client requests latest article data with a supported language selection
- **THEN** the system returns headline and summary in the selected language when available
- **AND** includes the corresponding base article metadata and media attribution
#### Scenario: Language-specific paginated feed response
- **WHEN** a client requests paginated feed data with a supported language selection
- **THEN** the system returns each feed item's headline and summary in the selected language when available
- **AND** preserves existing pagination behavior and ordering semantics
### Requirement: Language fallback to English is deterministic
The system SHALL return English source content when the requested translation is unavailable.
#### Scenario: Missing translation fallback
- **WHEN** a client requests Tamil or Malayalam content for an article lacking that translation
- **THEN** the system returns the English headline and summary for that article
- **AND** response shape remains consistent with language-aware responses
#### Scenario: Unsupported language handling
- **WHEN** a client requests a language outside supported values (`en`, `ta`, `ml`)
- **THEN** the system applies the defined default language behavior for this phase
- **AND** avoids breaking existing consumers of news endpoints

View File

@@ -0,0 +1,31 @@
## Purpose
Canonical specification for language-preference-persistence requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Landing page provides language selector
The system SHALL display a language selector on the landing page that allows switching between English, Tamil, and Malayalam content views.
#### Scenario: User selects language from landing page
- **WHEN** a user chooses Tamil or Malayalam from the language selector
- **THEN** hero and feed content update to requested language-aware rendering
- **AND** subsequent API requests use the selected language context
#### Scenario: User switches back to English
- **WHEN** a user selects English in the language selector
- **THEN** content renders in English
- **AND** language state updates immediately in the frontend view
### Requirement: User language preference is persisted and restored
The system SHALL persist selected language preference in client-side storage and restore it for returning users.
#### Scenario: Persist language selection
- **WHEN** a user selects a supported language on the landing page
- **THEN** the selected language code is stored in local storage or a client cookie
- **AND** the persisted value is used as preferred language for future visits on the same browser
#### Scenario: Restore preference on return visit
- **WHEN** a returning user opens the landing page
- **THEN** the system reads persisted language preference from client storage
- **AND** initializes the UI and content requests with that language by default

View File

@@ -0,0 +1,26 @@
## Purpose
Canonical specification for manual-fetch-recovery requirements synced from OpenSpec change deltas.
## Requirements
### Requirement: Manual command supports bootstrap and recovery workflows
The system SHALL allow operators to run the forced fetch command during first-time setup and after failed scheduled cycles.
#### Scenario: Bootstrap content population
- **WHEN** the system is newly deployed and contains no current news items
- **THEN** an operator can run the force-fetch command immediately
- **AND** the command attempts to populate the dataset without waiting for the next hourly schedule
#### Scenario: Recovery after failed scheduled fetch
- **WHEN** a prior scheduled fetch cycle failed or produced incomplete results
- **THEN** an operator can run the force-fetch command on demand
- **AND** the system performs a fresh one-off fetch attempt
### Requirement: Repeated manual runs remain operationally safe
The system SHALL support repeated operator-triggered runs without corrupting data integrity.
#### Scenario: Repeated invocation in same day
- **WHEN** an operator runs the force-fetch command multiple times within the same day
- **THEN** existing deduplication behavior prevents duplicate persistence for matching items
- **AND** each command run completes with explicit run status output

Some files were not shown because too many files have changed in this diff Show More