This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Umami pageview tracking
|
||||
When Umami is enabled by configuration, the site MUST load Umami tracking on all indexable pages and MUST record pageviews.
|
||||
|
||||
When Umami is disabled or not configured, the site MUST still function and MUST NOT error in the browser due to missing analytics.
|
||||
|
||||
#### Scenario: Umami enabled
|
||||
- **WHEN** Umami is enabled by configuration
|
||||
- **THEN** the site includes the Umami script on `/`, `/videos`, `/podcast`, and `/about`
|
||||
|
||||
#### Scenario: Umami disabled
|
||||
- **WHEN** Umami is not configured
|
||||
- **THEN** the site renders normally and no analytics script is required
|
||||
|
||||
### Requirement: Custom event tracking
|
||||
When Umami is enabled, the site MUST support custom event emission for:
|
||||
- `cta_click`
|
||||
- `outbound_click`
|
||||
|
||||
Each emitted event MUST include enough properties to segment reports by platform and placement when applicable.
|
||||
|
||||
#### Scenario: Emit outbound click event
|
||||
- **WHEN** a user clicks a non-CTA outbound link from the homepage
|
||||
- **THEN** the system emits an `outbound_click` event with a property identifying the destination domain
|
||||
|
||||
### Requirement: Environment configuration
|
||||
The site MUST support configuration of Umami parameters (at minimum: website ID and script URL) without requiring code changes.
|
||||
|
||||
#### Scenario: Configure Umami via environment
|
||||
- **WHEN** Umami configuration values are provided via environment or config file
|
||||
- **THEN** the site uses those values to initialize analytics without modifying source code
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Reusable CTA component
|
||||
The site MUST implement CTAs as a reusable component that can render at least the following actions:
|
||||
- YouTube subscribe action (linking to the channel)
|
||||
- Instagram follow action (linking to the profile)
|
||||
- Podcast listen action (linking to a designated destination)
|
||||
|
||||
Each CTA MUST be configurable with:
|
||||
- `platform` (`youtube`, `instagram`, `podcast`)
|
||||
- `placement` (e.g., `hero`, `module_header`, `footer`)
|
||||
- destination `url`
|
||||
|
||||
#### Scenario: Rendering a YouTube subscribe CTA
|
||||
- **WHEN** the homepage includes a CTA with `platform: youtube`
|
||||
- **THEN** the site renders a visible action that links to the configured YouTube channel destination URL
|
||||
|
||||
### Requirement: Trackable outbound links
|
||||
CTA outbound links MUST support appending UTM parameters so traffic can be attributed in downstream analytics.
|
||||
|
||||
#### Scenario: UTM parameters applied
|
||||
- **WHEN** a CTA is configured with UTM parameters
|
||||
- **THEN** the rendered outbound link includes the UTM query parameters in its URL
|
||||
|
||||
### Requirement: CTA click event emission
|
||||
CTA clicks MUST emit an analytics event with at least:
|
||||
- event name `cta_click`
|
||||
- `platform`
|
||||
- `placement`
|
||||
- `target` (destination URL or a stable identifier)
|
||||
|
||||
#### Scenario: User clicks CTA
|
||||
- **WHEN** a user clicks an Instagram follow CTA in the hero placement
|
||||
- **THEN** the system emits a `cta_click` event with `platform=instagram` and `placement=hero`
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Homepage modules and ordering
|
||||
The homepage MUST render distinct content modules that include:
|
||||
- newest content
|
||||
- high-performing videos
|
||||
- channel/podcast highlights
|
||||
- prominent conversion CTAs
|
||||
|
||||
The homepage MUST render modules in a deterministic order configured by the site (not dependent on network timing).
|
||||
|
||||
#### Scenario: Homepage render with available data
|
||||
- **WHEN** content data is available in the cache
|
||||
- **THEN** the homepage renders the newest module and the high-performing videos module in the configured order
|
||||
|
||||
### Requirement: Newest content module
|
||||
The system MUST compute a "newest" feed across sources by sorting normalized items by `publishedAt` descending.
|
||||
|
||||
The system MUST support filtering and limiting the number of items displayed for the newest module.
|
||||
|
||||
#### Scenario: Mixed-source newest list
|
||||
- **WHEN** the cached dataset contains YouTube, Instagram, and podcast items with different publish dates
|
||||
- **THEN** the newest module lists items ordered by `publishedAt` descending regardless of source
|
||||
|
||||
### Requirement: High-performing YouTube videos module
|
||||
When `metrics.views` is available for YouTube items, the system MUST compute "high-performing" videos by ranking videos by `metrics.views` (descending) with an optional manual override list.
|
||||
|
||||
When `metrics.views` is not available, the system MUST render the high-performing module using a manual curated list and MUST NOT fail the page render.
|
||||
|
||||
#### Scenario: Views-based ranking available
|
||||
- **WHEN** YouTube items include `metrics.views`
|
||||
- **THEN** the high-performing module shows videos ranked by views, unless a manual override list is configured
|
||||
|
||||
#### Scenario: Views-based ranking unavailable
|
||||
- **WHEN** YouTube items do not include `metrics.views`
|
||||
- **THEN** the high-performing module renders using a manual curated list and the page still loads successfully
|
||||
|
||||
### Requirement: Graceful empty and error states
|
||||
If a module has no content to display, the homepage MUST render a non-broken empty state for that module and MUST still render the rest of the page.
|
||||
|
||||
#### Scenario: No Instagram items available
|
||||
- **WHEN** the cached dataset contains no Instagram items
|
||||
- **THEN** the Instagram-related module renders an empty state and the homepage still renders other modules
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Indexable pages
|
||||
The site MUST provide indexable HTML pages for:
|
||||
- home (`/`)
|
||||
- videos (`/videos`)
|
||||
- podcast (`/podcast`)
|
||||
- about (`/about`)
|
||||
|
||||
These pages MUST be server-rendered or statically generated HTML suitable for search engine crawling (not client-rendered only).
|
||||
|
||||
#### Scenario: Crawling the home page
|
||||
- **WHEN** a crawler requests `/`
|
||||
- **THEN** the server returns an HTML document containing the homepage content modules and metadata
|
||||
|
||||
### Requirement: Metadata and canonical URLs
|
||||
Each indexable page MUST define:
|
||||
- a document title
|
||||
- a meta description
|
||||
- a canonical URL
|
||||
|
||||
#### Scenario: Page metadata is present
|
||||
- **WHEN** a crawler requests `/videos`
|
||||
- **THEN** the HTML contains a `<title>`, a meta description, and a canonical URL for `/videos`
|
||||
|
||||
### Requirement: Social sharing cards
|
||||
The site MUST provide Open Graph and Twitter card metadata for indexable pages so shared links render a preview.
|
||||
|
||||
#### Scenario: Sharing the home page
|
||||
- **WHEN** a social crawler requests `/`
|
||||
- **THEN** the response includes Open Graph and Twitter card tags with a title, description, and image when available
|
||||
|
||||
### Requirement: Sitemap and robots
|
||||
The site MUST provide:
|
||||
- `sitemap.xml` enumerating indexable pages
|
||||
- `robots.txt` that allows indexing of indexable pages
|
||||
|
||||
#### Scenario: Sitemap is available
|
||||
- **WHEN** a crawler requests `/sitemap.xml`
|
||||
- **THEN** the server returns an XML sitemap listing `/`, `/videos`, `/podcast`, and `/about`
|
||||
|
||||
### Requirement: Structured data
|
||||
The site MUST support structured data (JSON-LD) for Video and Podcast content when detail pages exist, and MUST ensure the JSON-LD is valid JSON.
|
||||
|
||||
#### Scenario: Video structured data present
|
||||
- **WHEN** a video detail page exists and is requested
|
||||
- **THEN** the HTML includes JSON-LD describing the video using a recognized schema type
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Normalized content items
|
||||
The system MUST normalize all ingested items (YouTube videos, Instagram posts, podcast episodes) into a single internal schema so the website can render them consistently.
|
||||
|
||||
The normalized item MUST include at minimum:
|
||||
- `id` (stable within its source)
|
||||
- `source` (`youtube`, `instagram`, or `podcast`)
|
||||
- `url`
|
||||
- `title`
|
||||
- `publishedAt` (ISO-8601)
|
||||
- `thumbnailUrl` (optional)
|
||||
|
||||
#### Scenario: Normalizing a YouTube video
|
||||
- **WHEN** the system ingests a YouTube video item
|
||||
- **THEN** it produces a normalized item containing `id`, `source: youtube`, `url`, `title`, and `publishedAt`
|
||||
|
||||
#### Scenario: Normalizing a podcast episode
|
||||
- **WHEN** the system ingests a podcast RSS episode
|
||||
- **THEN** it produces a normalized item containing `id`, `source: podcast`, `url`, `title`, and `publishedAt`
|
||||
|
||||
### Requirement: YouTube ingestion with stats when available
|
||||
The system MUST support ingesting YouTube videos for channel `youtube.com/santhoshj`.
|
||||
|
||||
When a YouTube API key is configured, the system MUST ingest video metadata and MUST ingest view count (and MAY ingest likes/comments if available) so "high-performing" can be computed.
|
||||
|
||||
When no YouTube API key is configured, the system MUST still ingest latest videos using a non-authenticated mechanism (for example, channel RSS) but MUST omit performance stats.
|
||||
|
||||
#### Scenario: API key configured
|
||||
- **WHEN** a YouTube API key is configured
|
||||
- **THEN** the system ingests video metadata and includes `metrics.views` for each ingested video when available from the API
|
||||
|
||||
#### Scenario: No API key configured
|
||||
- **WHEN** no YouTube API key is configured
|
||||
- **THEN** the system ingests latest videos and does not require `metrics.views` to be present
|
||||
|
||||
### Requirement: Podcast RSS ingestion
|
||||
The system MUST ingest the Irregular Mind podcast RSS feed and produce normalized items representing podcast episodes.
|
||||
|
||||
#### Scenario: RSS feed fetch succeeds
|
||||
- **WHEN** the system fetches the podcast RSS feed successfully
|
||||
- **THEN** it produces one normalized item per episode with `source: podcast`
|
||||
|
||||
### Requirement: Instagram content support via embed-first approach
|
||||
The system MUST support representing Instagram posts for `@santhoshjanan` in the site content surface.
|
||||
|
||||
If API-based ingestion is not configured/available, the system MUST support an embed-first representation where the normalized item contains a `url` to the Instagram post and any additional embed metadata needed by the renderer.
|
||||
|
||||
#### Scenario: Embed-first mode
|
||||
- **WHEN** Instagram API ingestion is not configured
|
||||
- **THEN** the system provides normalized Instagram items that contain a public post `url` suitable for embedding
|
||||
|
||||
### Requirement: Refresh and caching
|
||||
The system MUST cache the latest successful ingestion output and MUST serve the cached data to the site renderer.
|
||||
|
||||
The system MUST support periodic refresh on a schedule (at minimum daily) and MUST support a manual refresh trigger.
|
||||
|
||||
On ingestion failure, the system MUST continue serving the most recent cached data.
|
||||
|
||||
#### Scenario: Scheduled refresh fails
|
||||
- **WHEN** a scheduled refresh run fails to fetch one or more sources
|
||||
- **THEN** the site continues to use the most recent successfully cached dataset
|
||||
|
||||
#### Scenario: Manual refresh requested
|
||||
- **WHEN** a manual refresh is triggered
|
||||
- **THEN** the system attempts ingestion immediately and updates the cache if ingestion succeeds
|
||||
|
||||
Reference in New Issue
Block a user