demo output artifacts

This commit is contained in:
Brian Madison
2025-05-21 20:24:31 -05:00
parent dcc2858873
commit 3a840b6362
24 changed files with 2998 additions and 3 deletions

View File

@@ -1 +1,13 @@
New demo output coming soon.
A simple project run through the Web Gemini BMad Agent - all artifacts from a single chat session (split up into smaller files with the sharding task)
- The [Project Brief](./v3-output-demo-files/project-brief.md) was first collaborated on and created with the Analyst
- The first [PRD Draft](./v3-output-demo-files/prd.draft.md) was created with the PM
- The [Architecture](./v3-output-demo-files/architecture.md) was created and then we worked on some design artifacts. The architect conversation lead to changes in the PRD reflected later.
Design Artifacts with the Design Architect:
- [UX UI Spec](./v3-output-demo-files/ux-ui-spec.md)
- [V0 1 Shot UI Prompt](./v3-output-demo-files/v0-prompt.md)
- [Front End Architecture](./v3-output-demo-files/front-end-architecture.md)
Then the updated PRD with fixed Expic and Stories after running the PO Checklist. The PO took all changes from the architect and design architect and worked them back into the updated [PRD Final](./v3-output-demo-files/prd.md)

View File

@@ -0,0 +1,34 @@
# API Reference
## External APIs Consumed
**1. Algolia Hacker News Search API**
* **Base URL:** `http://hn.algolia.com/api/v1/`
* **Authentication:** None.
* **Endpoints Used:**
* `GET /search_by_date?tags=story&hitsPerPage={N}` (For top posts)
* `GET /items/{POST_ID}` (For comments/post details)
* **Key Data Extracted:** Post title, article URL, HN link, HN Post ID, author, points, creation timestamp; Comment text, author, creation timestamp.
**2. Play.ai PlayNote API**
* **Base URL:** `https://api.play.ai/api/v1/`
* **Authentication:** Headers: `Authorization: Bearer <PLAY_AI_BEARER_TOKEN>`, `X-USER-ID: <PLAY_AI_USER_ID>`.
* **Endpoints Used:**
* `POST /playnotes` (Submit job)
* Request: `application/json` with `sourceText`, `title`, voice params (from env vars: `PLAY_AI_VOICE1_ID`, `PLAY_AI_VOICE1_NAME`, `PLAY_AI_VOICE2_ID`, `PLAY_AI_VOICE2_NAME`), style (`PLAY_AI_STYLE`).
* Response: JSON with `jobId`.
* `GET /playnote/{jobId}` (Poll status)
* Response: JSON with `status`, `audioUrl` (if completed).
## Internal APIs Provided (by backend for frontend)
* **Base URL Path Prefix:** `/v1` (Full URL from `NEXT_PUBLIC_BACKEND_API_URL`).
* **Authentication:** Requires "Frontend Read API Key" via `x-api-key` header for GET endpoints. A separate "Admin Action API Key" for trigger endpoint.
* **Endpoints:**
* **`GET /status`**: Health/status check. Response: `{"message": "BMad Daily Digest Backend is operational.", "timestamp": "..."}`.
* **`GET /episodes`**: Lists episodes. Response: `{ "episodes": [EpisodeListItem, ...] }`.
* **`GET /episodes/{episodeId}`**: Episode details. Response: `EpisodeDetail` object.
* **`POST /jobs/daily-digest/trigger`**: (Admin Key) Triggers daily pipeline. Response: `{"message": "...", "executionArn": "..."}`.
* **Common Errors:** 401 Unauthorized, 404 Not Found, 500 Internal Server Error.

View File

@@ -0,0 +1,571 @@
# BMad Daily Digest Architecture Document
**Version:** 0.1
**Date:** May 20, 2025
**Author:** Fred (Architect) & User
## Table of Contents
1. Introduction / Preamble
2. Technical Summary
3. High-Level Overview
* Backend Architectural Style
* Frontend Architectural Style
* Repository Structure
* Primary Data Flow & User Interaction (Conceptual)
* System Context Diagram (Conceptual)
4. Architectural / Design Patterns Adopted
5. Component View
* Backend Components
* Frontend Components
* External Services
* Component Interaction Diagram (Conceptual Backend Focus)
6. Project Structure
* Backend Repository (`bmad-daily-digest-backend`)
* Frontend Repository (`bmad-daily-digest-frontend`)
* Notes
7. API Reference
* External APIs Consumed
* Internal APIs Provided
8. Data Models
* Core Application Entities / Domain Objects
* API Payload Schemas (Internal API)
* Database Schemas (AWS DynamoDB)
9. Core Workflow / Sequence Diagrams
* Daily Automated Podcast Generation Pipeline (Backend)
* Frontend User Requesting and Playing an Episode
10. Definitive Tech Stack Selections
11. Infrastructure and Deployment Overview
12. Error Handling Strategy
13. Coding Standards (Backend: `bmad-daily-digest-backend`)
* Detailed Language & Framework Conventions (TypeScript/Node.js - Backend Focus)
14. Overall Testing Strategy
15. Security Best Practices
16. Key Reference Documents
17. Change Log
18. Prompt for Design Architect (Jane) - To Produce Frontend Architecture Document
-----
## 1\. Introduction / Preamble
This document outlines the overall project architecture for "BMad Daily Digest," including backend systems, frontend deployment infrastructure, shared services considerations, and non-UI specific concerns. Its primary goal is to serve as the guiding architectural blueprint for AI-driven development and human developers, ensuring consistency and adherence to chosen patterns and technologies as defined in the Product Requirements Document (PRD v0.1) and UI/UX Specification (v0.1).
**Relationship to Frontend Architecture:**
The frontend application (Next.js) will have its own detailed frontend architecture considerations (component structure, state management, etc.) which will be detailed in a separate Frontend Architecture Document (to be created by the Design Architect, Jane, based on a prompt at the end of this document). This overall Architecture Document will define the backend services the frontend consumes, the infrastructure for hosting the frontend (S3/CloudFront), and ensure alignment on shared technology choices (like TypeScript) and API contracts. The "Definitive Tech Stack Selections" section herein is the single source of truth for all major technology choices across the project.
## 2\. Technical Summary
"BMad Daily Digest" is a serverless application designed to automatically produce a daily audio podcast summarizing top Hacker News posts. The backend, built with TypeScript on Node.js 22 and deployed as AWS Lambda functions, will fetch data from the Algolia HN API, scrape linked articles, process content, and use the Play.ai API for audio generation (with job status managed by AWS Step Functions polling). Podcast metadata will be stored in DynamoDB, and audio files in S3. All backend infrastructure will be managed via AWS CDK within its own repository.
The frontend will be a Next.js (React, TypeScript) application, styled with Tailwind CSS and shadcn/ui to an "80s retro CRT terminal" aesthetic, kickstarted by an AI UI generation tool. It will be a statically exported site hosted on AWS S3 and delivered globally via AWS CloudFront, with its infrastructure also managed by a separate AWS CDK application within its own repository. The frontend will consume data from the backend via an AWS API Gateway secured with API Keys. The entire system aims for cost-efficiency, leveraging AWS free-tier services where possible.
## 3\. High-Level Overview
The "BMad Daily Digest" system is architected as a decoupled, serverless application designed for automated daily content aggregation and audio generation, with a statically generated frontend for content consumption.
* **Backend Architectural Style:** The backend employs a **serverless, event-driven architecture** leveraging AWS Lambda functions for discrete processing tasks. These tasks are orchestrated by AWS Step Functions to manage the daily content pipeline, including interactions with external services. An API layer is provided via AWS API Gateway for frontend consumption.
* **Frontend Architectural Style:** The frontend is a **statically generated site (SSG)** built with Next.js. This approach maximizes performance, security, and cost-effectiveness by serving pre-built files from AWS S3 via CloudFront.
* **Repository Structure:** The project utilizes a **polyrepo structure** with two primary repositories:
* `bmad-daily-digest-backend`: Housing all backend TypeScript code, AWS CDK for backend infrastructure, Lambda functions, Step Function definitions, etc.
* `bmad-daily-digest-frontend`: Housing the Next.js TypeScript application, UI components, styling, and its dedicated AWS CDK application for S3/CloudFront infrastructure.
* **Primary Data Flow & User Interaction (Conceptual):**
1. **Daily Automated Pipeline (Backend):**
* An Amazon EventBridge Scheduler rule triggers an AWS Step Function state machine daily.
* The Step Function orchestrates a sequence of AWS Lambda functions to:
* Fetch top posts and comments from the Algolia HN API (identifying repeats).
* Scrape and extract content from linked external article URLs (for new posts or if scraping previously failed).
* Aggregate and format the text content (handling new posts, updates, scrape failures, truncation).
* Submit the formatted text to the Play.ai PlayNote API, receiving a `jobId`.
* Poll the Play.ai API (using the `jobId`) for podcast generation status until completion or failure.
* Upon completion, download the generated MP3 audio from Play.ai.
* Store the MP3 file in a designated S3 bucket.
* Store episode metadata (including the S3 audio link, source HN post details, etc.) in a DynamoDB table and update HN post processing states.
2. **User Consumption (Frontend):**
* The user accesses the "BMad Daily Digest" Next.js web application served via AWS CloudFront from an S3 bucket.
* The frontend application makes API calls (via `axios`) to an AWS API Gateway endpoint (secured with an API Key).
* API Gateway routes these requests to specific AWS Lambda functions that query the DynamoDB table to retrieve episode lists and details.
* The frontend renders the information and provides an HTML5 audio player to stream/play the MP3 from its S3/CloudFront URL.
**System Context Diagram (Conceptual):**
```mermaid
graph TD
A[User] -->|Views & Interacts via Browser| B(Frontend Application\nNext.js on S3/CloudFront);
B -->|Fetches Episode Data (HTTPS, API Key)| C(Backend API\nAPI Gateway + Lambda);
C -->|Reads/Writes| D(Episode Metadata\nDynamoDB);
B -->|Streams Audio| E(Podcast Audio Files\nS3 via CloudFront);
F[Daily Scheduler\nEventBridge] -->|Triggers| G(Orchestration Service\nAWS Step Functions);
G -->|Invokes| H(Data Collection Lambdas\n- Fetch HN via Algolia\n- Scrape Articles);
H -->|Calls| I[Algolia HN API];
H -->|Scrapes| J[External Article Websites];
G -->|Invokes| K(Content Processing Lambda);
G -->|Invokes| L(Play.ai Interaction Lambdas\n- Submit Job\n- Poll Status);
L -->|Calls / Gets Status| M[Play.ai PlayNote API];
G -->|Invokes| N(Storage Lambdas\n- Store Audio to S3\n- Store Metadata to DynamoDB);
N -->|Writes| E;
N -->|Writes| D;
M -->|Returns Audio URL| L;
```
## 4\. Architectural / Design Patterns Adopted
The following key architectural and design patterns have been chosen for this project:
* **Serverless Architecture:** Entire backend on AWS Lambda, API Gateway, S3, DynamoDB, Step Functions. Rationale: Minimized operations, auto-scaling, pay-per-use, cost-efficiency.
* **Event-Driven Architecture:** Daily pipeline initiated by EventBridge Scheduler; Step Functions orchestrate based on state changes. Rationale: Decoupled components, reactive system for automation.
* **Microservices-like Approach (Backend Lambda Functions):** Each Lambda handles a specific, well-defined task. Rationale: Modularity, independent scalability, easier testing/maintenance.
* **Static Site Generation (SSG) for Frontend:** Next.js frontend exported as static files, hosted on S3/CloudFront. Rationale: Optimal performance, security, scalability, lower hosting costs.
* **Infrastructure as Code (IaC):** AWS CDK in TypeScript for all AWS infrastructure in both repositories. Rationale: Repeatable, version-controlled, automated provisioning.
* **Polling Pattern (External Job Status):** AWS Step Functions implement a polling loop for Play.ai job status. Rationale: Reliable tracking of asynchronous third-party jobs, based on Play.ai docs.
* **Orchestration Pattern (AWS Step Functions):** End-to-end daily backend pipeline managed by a Step Functions state machine. Rationale: Robust workflow automation, state management, error handling for multi-step processes.
## 5\. Component View
The system is divided into distinct backend and frontend components.
**Backend Components (`bmad-daily-digest-backend` repository):**
1. **Daily Workflow Orchestrator (AWS Step Functions state machine):** Manages the end-to-end daily pipeline.
2. **HN Data Fetcher Service (AWS Lambda):** Fetches HN posts/comments (Algolia), identifies repeats (via DynamoDB).
3. **Article Scraping Service (AWS Lambda):** Scrapes/extracts content from external article URLs, handles fallbacks.
4. **Content Formatting Service (AWS Lambda):** Aggregates and formats text payload for Play.ai.
5. **Play.ai Interaction Service (AWS Lambda functions, orchestrated by Polling Step Function):** Submits job to Play.ai, polls for status.
6. **Podcast Storage Service (AWS Lambda):** Downloads audio from Play.ai, stores to S3.
7. **Metadata Persistence Service (AWS Lambda & DynamoDB Tables):** Manages episode and HN post processing state metadata in DynamoDB.
8. **Backend API Service (AWS API Gateway + AWS Lambda functions):** Exposes endpoints for frontend (episode lists/details).
**Frontend Components (`bmad-daily-digest-frontend` repository):**
1. **Next.js Web Application (Static Site on S3/CloudFront):** Renders UI, handles navigation.
2. **Frontend API Client Service (TypeScript module):** Encapsulates communication with the Backend API Service.
**External Services:** Algolia HN Search API, Play.ai PlayNote API, Various External Article Websites.
**Component Interaction Diagram (Conceptual Backend Focus):**
```mermaid
graph LR
subgraph Frontend Application Space
F_App[Next.js App on S3/CloudFront]
F_APIClient[Frontend API Client]
F_App --> F_APIClient
end
subgraph Backend API Space
APIGW[API Gateway]
API_L[Backend API Lambdas]
APIGW --> API_L
end
subgraph Backend Daily Pipeline Space
Scheduler[EventBridge Scheduler] --> Orchestrator[Step Functions Orchestrator]
Orchestrator --> HNFetcher[HN Data Fetcher Lambda]
HNFetcher -->|Reads/Writes Post Status| DDB
HNFetcher --> Algolia[Algolia HN API]
Orchestrator --> ArticleScraper[Article Scraper Lambda]
ArticleScraper --> ExtWebsites[External Article Websites]
Orchestrator --> ContentFormatter[Content Formatter Lambda]
Orchestrator --> PlayAISubmit[Play.ai Submit Lambda]
PlayAISubmit --> PlayAI_API[Play.ai PlayNote API]
subgraph Polling_SF[Play.ai Polling (Step Functions)]
direction LR
PollTask[Poll Status Lambda] --> PlayAI_API
end
Orchestrator --> Polling_SF
Orchestrator --> PodcastStorage[Podcast Storage Lambda]
PodcastStorage --> PlayAI_API
PodcastStorage --> S3Store[S3 Audio Storage]
Orchestrator --> MetadataService[Metadata Persistence Lambda]
MetadataService --> DDB[DynamoDB Episode/Post Metadata]
end
F_APIClient --> APIGW
API_L --> DDB
classDef external fill:#ddd,stroke:#333,stroke-width:2px;
class Algolia,ExtWebsites,PlayAI_API external;
```
## 6\. Project Structure
The project utilizes a polyrepo structure with separate backend and frontend repositories, each with its own CDK application.
**1. Backend Repository (`bmad-daily-digest-backend`)**
Organized by features within `src/`, using `dash-case` for folders and files (e.g., `src/features/content-ingestion/hn-fetcher-service.ts`).
```plaintext
bmad-daily-digest-backend/
├── .github/
├── cdk/
│ ├── bin/
│ ├── lib/ # Backend Stack, Step Function definitions
│ └── test/
├── src/
│ ├── features/
│ │ ├── dailyJobOrchestrator/ # Main Step Function trigger/definition support
│ │ ├── hnContentPipeline/ # Services for Algolia, scraping, formatting
│ │ ├── playAiIntegration/ # Services for Play.ai submit & polling Lambda logic
│ │ ├── podcastPersistence/ # Services for S3 & DynamoDB storage
│ │ └── publicApi/ # Handlers for API Gateway (status, episodes)
│ ├── shared/
│ │ ├── utils/
│ │ ├── types/
│ │ └── services/ # Optional shared low-level AWS SDK wrappers
├── tests/ # Unit/Integration tests, mirroring src/features/
│ └── features/
... (root config files: .env.example, .eslintrc.js, .gitignore, .prettierrc.js, jest.config.js, package.json, README.md, tsconfig.json)
```
*Key Directories: `cdk/` for IaC, `src/features/` for modular backend logic, `src/shared/` for reusable code, `tests/` for Jest tests.*
**2. Frontend Repository (`bmad-daily-digest-frontend`)**
Aligns with V0.dev generated Next.js App Router structure, using `dash-case` for custom files/folders where applicable.
```plaintext
bmad-daily-digest-frontend/
├── .github/
├── app/
│ ├── (pages)/
│ │ ├── episodes/
│ │ │ ├── page.tsx # List page
│ │ │ └── [episode-id]/
│ │ │ └── page.tsx # Detail page
│ │ └── about/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── globals.css
├── components/
│ ├── ui/ # shadcn/ui based components
│ └── domain/ # Custom composite components (e.g., episode-card)
├── cdk/ # AWS CDK application for frontend infra (S3, CloudFront)
│ ├── bin/
│ └── lib/
├── hooks/
├── lib/
│ ├── types.ts
│ ├── utils.ts
│ └── api-client.ts # Backend API communication
├── public/
├── tests/ # Jest & RTL tests
... (root config files: .env.local.example, .eslintrc.js, components.json, next.config.mjs, package.json, tailwind.config.ts, tsconfig.json)
```
*Key Directories: `app/` for Next.js routes, `components/` for UI, `cdk/` for frontend IaC, `lib/` for utilities and `api-client.ts`.*
## 7\. API Reference
### External APIs Consumed
**1. Algolia Hacker News Search API**
* **Base URL:** `http://hn.algolia.com/api/v1/`
* **Authentication:** None.
* **Endpoints Used:**
* `GET /search_by_date?tags=story&hitsPerPage={N}` (For top posts)
* `GET /items/{POST_ID}` (For comments/post details)
* **Key Data Extracted:** Post title, article URL, HN link, HN Post ID, author, points, creation timestamp; Comment text, author, creation timestamp.
**2. Play.ai PlayNote API**
* **Base URL:** `https://api.play.ai/api/v1/`
* **Authentication:** Headers: `Authorization: Bearer <PLAY_AI_BEARER_TOKEN>`, `X-USER-ID: <PLAY_AI_USER_ID>`.
* **Endpoints Used:**
* `POST /playnotes` (Submit job)
* Request: `application/json` with `sourceText`, `title`, voice params (from env vars: `PLAY_AI_VOICE1_ID`, `PLAY_AI_VOICE1_NAME`, `PLAY_AI_VOICE2_ID`, `PLAY_AI_VOICE2_NAME`), style (`PLAY_AI_STYLE`).
* Response: JSON with `jobId`.
* `GET /playnote/{jobId}` (Poll status)
* Response: JSON with `status`, `audioUrl` (if completed).
### Internal APIs Provided (by backend for frontend)
* **Base URL Path Prefix:** `/v1` (Full URL from `NEXT_PUBLIC_BACKEND_API_URL`).
* **Authentication:** Requires "Frontend Read API Key" via `x-api-key` header for GET endpoints. A separate "Admin Action API Key" for trigger endpoint.
* **Endpoints:**
* **`GET /status`**: Health/status check. Response: `{"message": "BMad Daily Digest Backend is operational.", "timestamp": "..."}`.
* **`GET /episodes`**: Lists episodes. Response: `{ "episodes": [EpisodeListItem, ...] }`.
* **`GET /episodes/{episodeId}`**: Episode details. Response: `EpisodeDetail` object.
* **`POST /jobs/daily-digest/trigger`**: (Admin Key) Triggers daily pipeline. Response: `{"message": "...", "executionArn": "..."}`.
* **Common Errors:** 401 Unauthorized, 404 Not Found, 500 Internal Server Error.
## 8\. Data Models
### Core Application Entities
**a. Episode**
* Attributes: `episodeId` (PK, UUID), `publicationDate` (YYYY-MM-DD), `episodeNumber` (Number), `podcastGeneratedTitle` (String), `audioS3Bucket` (String), `audioS3Key` (String), `audioUrl` (String, derived for API), `playAiJobId` (String), `playAiSourceAudioUrl` (String), `sourceHNPosts` (List of `SourceHNPost`), `status` (String: "PROCESSING", "PUBLISHED", "FAILED"), `createdAt` (ISO Timestamp), `updatedAt` (ISO Timestamp).
**b. SourceHNPost (object within `Episode.sourceHNPosts`)**
* Attributes: `hnPostId` (String), `title` (String), `originalArticleUrl` (String), `hnLink` (String), `isUpdateStatus` (Boolean), `oldRank` (Number, Optional), `lastCommentFetchTimestamp` (Number, Unix Timestamp), `articleScrapingFailed` (Boolean), `articleTitleFromScrape` (String, Optional).
**c. HackerNewsPostProcessState (DynamoDB Table)**
* Attributes: `hnPostId` (PK, String), `originalArticleUrl` (String), `articleTitleFromScrape` (String, Optional), `lastSuccessfullyScrapedTimestamp` (Number, Optional), `lastCommentFetchTimestamp` (Number, Optional), `firstProcessedDate` (YYYY-MM-DD), `lastProcessedDate` (YYYY-MM-DD), `lastKnownRank` (Number, Optional).
### API Payload Schemas (Internal API)
**a. `EpisodeListItem` (for `GET /episodes`)**
* `episodeId`, `publicationDate`, `episodeNumber`, `podcastGeneratedTitle`.
**b. `EpisodeDetail` (for `GET /episodes/{episodeId}`)**
* `episodeId`, `publicationDate`, `episodeNumber`, `podcastGeneratedTitle`, `audioUrl`, `sourceHNPosts` (list of `SourceHNPostDetail` containing `hnPostId`, `title`, `originalArticleUrl`, `hnLink`, `isUpdateStatus`, `oldRank`), `playAiJobId` (optional), `playAiSourceAudioUrl` (optional), `createdAt`.
### Database Schemas (AWS DynamoDB)
**a. `BmadDailyDigestEpisodes` Table**
* PK: `episodeId` (String).
* Attributes: As per `Episode` entity.
* GSI Example (`PublicationDateIndex`): PK: `status`, SK: `publicationDate`.
* Billing: PAY\_PER\_REQUEST.
**b. `HackerNewsPostProcessState` Table**
* PK: `hnPostId` (String).
* Attributes: As per `HackerNewsPostProcessState` entity.
* Billing: PAY\_PER\_REQUEST.
## 9\. Core Workflow / Sequence Diagrams
### 1\. Daily Automated Podcast Generation Pipeline (Backend)
*(Mermaid diagram as previously shown, detailing EventBridge -\> Step Functions -\> Lambdas -\> Algolia/External Sites/Play.ai -\> S3/DynamoDB).*
```mermaid
sequenceDiagram
participant Sched as Scheduler (EventBridge)
participant Orch as Orchestrator (Step Functions)
participant HNF as HN Data Fetcher Lambda
participant Algolia as Algolia HN API
participant ASL as Article Scraper Lambda
participant EAS as External Article Sites
participant CFL as Content Formatter Lambda
participant PSubL as Play.ai Submit Lambda
participant PlayAI as Play.ai API
participant PStatL as Play.ai Status Poller Lambda
participant PSL as Podcast Storage Lambda
participant S3 as S3 Audio Storage
participant MPL as Metadata Persistence Lambda
participant DDB as DynamoDB (Episodes & HNPostState)
Sched->>Orch: Trigger Daily Workflow
activate Orch
Orch->>HNF: Start: Fetch HN Posts
activate HNF
HNF->>Algolia: Request top N posts
Algolia-->>HNF: Return HN post list
HNF->>DDB: Query HNPostProcessState for repeat status & lastCommentFetchTimestamp
DDB-->>HNF: Return status
HNF-->>Orch: HN Posts Data (with repeat status)
deactivate HNF
Orch->>ASL: For each NEW HN Post: Scrape Article (URL)
activate ASL
ASL->>EAS: Fetch article HTML
EAS-->>ASL: Return HTML
ASL-->>Orch: Scraped Article Content / Scrape Failure+Fallback Flag
deactivate ASL
Orch->>HNF: For each HN Post: Fetch Comments (HN Post ID, isRepeat, lastCommentFetchTimestamp, articleScrapedFailedFlag)
activate HNF
HNF->>Algolia: Request comments for Post ID
Algolia-->>HNF: Return comments
HNF->>DDB: Update HNPostProcessState (lastCommentFetchTimestamp)
DDB-->>HNF: Confirm update
HNF-->>Orch: Selected Comments
deactivate HNF
Orch->>CFL: Format Content for Play.ai (HN Posts, Articles, Comments)
activate CFL
CFL-->>Orch: Formatted Text Payload
deactivate CFL
Orch->>PSubL: Submit to Play.ai (Formatted Text)
activate PSubL
PSubL->>PlayAI: POST /playnotes (text, voice params, auth)
PlayAI-->>PSubL: Return { jobId }
PSubL-->>Orch: Play.ai Job ID
deactivate PSubL
loop Poll for Completion (managed by Orchestrator/Step Functions)
Orch->>Orch: Wait (e.g., M minutes)
Orch->>PStatL: Check Status (Job ID)
activate PStatL
PStatL->>PlayAI: GET /playnote/{jobId} (auth)
PlayAI-->>PStatL: Return { status, audioUrl? }
PStatL-->>Orch: Job Status & audioUrl (if completed)
deactivate PStatL
alt Job Completed
Orch->>PSL: Store Podcast (audioUrl, jobId, episode context)
activate PSL
PSL->>PlayAI: GET audio from audioUrl
PlayAI-->>PSL: Audio Stream/File
PSL->>S3: Upload MP3
S3-->>PSL: Confirm S3 Upload (s3Key, s3Bucket)
PSL-->>Orch: S3 Location
deactivate PSL
Orch->>MPL: Persist Episode Metadata (S3 loc, HN sources, etc.)
activate MPL
MPL->>DDB: Save Episode Item & Update HNPostProcessState (lastProcessedDate)
DDB-->>MPL: Confirm save
MPL-->>Orch: Success
deactivate MPL
else Job Failed or Timeout
Orch->>Orch: Log Error, Terminate Sub-Workflow for this job
end
end
deactivate Orch
```
### 2\. Frontend User Requesting and Playing an Episode
*(Mermaid diagram as previously shown, detailing User -\> Next.js App -\> API Gateway/Lambda -\> DynamoDB, and User -\> Next.js App -\> S3/CloudFront for audio).*
```mermaid
sequenceDiagram
participant User as User (Browser)
participant FE_App as Frontend App (Next.js on CloudFront/S3)
participant BE_API as Backend API (API Gateway)
participant API_L as API Lambda
participant DDB as DynamoDB (Episode Metadata)
participant Audio_S3 as Audio Storage (S3 via CloudFront)
User->>FE_App: Requests page (e.g., /episodes or /episodes/{id})
activate FE_App
FE_App->>BE_API: GET /v1/episodes (or /v1/episodes/{id}) (includes API Key)
activate BE_API
BE_API->>API_L: Invoke Lambda with request data
activate API_L
API_L->>DDB: Query for episode(s) metadata
activate DDB
DDB-->>API_L: Return episode data
deactivate DDB
API_L-->>BE_API: Return formatted episode data
deactivate API_L
BE_API-->>FE_App: Return API response (JSON)
deactivate BE_API
FE_App->>FE_App: Render page with episode data (list or detail)
FE_App-->>User: Display page
deactivate FE_App
alt User on Episode Detail Page & Clicks Play
User->>FE_App: Clicks play on HTML5 Audio Player
activate FE_App
Note over FE_App, Audio_S3: Player's src attribute is set to CloudFront URL for audio file in S3.
FE_App->>Audio_S3: Browser requests audio file via CloudFront URL
activate Audio_S3
Audio_S3-->>FE_App: Stream/Return audio file
deactivate Audio_S3
FE_App-->>User: Plays audio
deactivate FE_App
end
```
## 10\. Definitive Tech Stack Selections
| Category | Technology | Version / Details | Description / Purpose | Justification (Optional) |
| :------------------- | :----------------------------- | :------------------------------------- | :------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------- |
| **Languages** | TypeScript | Latest stable (e.g., 5.x) | Primary language for backend and frontend. | Consistency, strong typing. |
| **Runtime** | Node.js | 22.x | Server-side environment for backend & Next.js. | User preference, performance. |
| **Frameworks (Frontend)** | Next.js (with React) | Latest stable (e.g., 14.x) | Frontend web application framework. | User preference, SSG, DX. |
| **Frameworks (Backend)** | AWS Lambda (Node.js runtime) | N/A | Execution environment for serverless functions. | Serverless architecture. |
| | AWS Step Functions | N/A | Orchestration of backend workflows. | Robust state management, retries. |
| **Databases** | AWS DynamoDB | N/A | NoSQL database for metadata. | Scalability, serverless, free-tier. |
| **Cloud Platform** | AWS | N/A | Primary cloud provider. | Comprehensive services, serverless. |
| **Cloud Services** | AWS Lambda, API Gateway, S3, CloudFront, EventBridge Scheduler, CloudWatch, IAM, ACM | N/A | Core services for application hosting and operation. | Standard AWS serverless stack. |
| **Infrastructure as Code (IaC)** | AWS CDK (TypeScript) | v2.x Latest stable | Defining cloud infrastructure. | User preference, TypeScript, repeatability. |
| **UI Libraries (Frontend)** | Tailwind CSS | Latest stable (e.g., 3.x) | Utility-first CSS framework. | User preference, customization. |
| | shadcn/ui | Latest stable | Accessible UI components. | User preference, base for themed components. |
| **HTTP Client (Backend)** | axios | Latest stable | Making HTTP requests from backend. | User preference, feature-rich. |
| **SDKs / Core Libraries (Backend)** | AWS SDK for JavaScript/TypeScript | v3.x (Latest stable) | Programmatic interaction with AWS services. | Official AWS SDK, modular. |
| **Scraping / Content Extraction** | Cheerio | Latest stable | Server-side HTML parsing. | Efficient for static HTML. |
| | @mozilla/readability (JS port) | Latest stable | Extracting primary readable article content. | Key for isolating main content. |
| | Playwright (or Puppeteer) | Latest stable | Browser automation (if required for dynamic content). | Handles dynamic sites; use judiciously. |
| **Bundling (Backend)**| esbuild | Latest stable | Bundling TypeScript Lambda functions. | User preference, speed. |
| **Logging (Backend)** | Pino | Latest stable | Structured, low-overhead logging. | Better observability, JSON logs for CloudWatch. |
| **Testing (Backend)**| Jest, ESLint, Prettier | Latest stable | Unit/integration testing, linting, formatting. | Code quality, consistency. |
| **Testing (Frontend)**| Jest, React Testing Library, ESLint, Prettier | Latest stable | Unit/component testing, linting, formatting. | Code quality, consistency. |
| **CI/CD** | GitHub Actions | N/A | Automation of build, test, quality checks. | Integration with GitHub. |
| **External APIs** | Algolia HN Search API, Play.ai PlayNote API | v1 (for both) | Data sources and audio generation. | Core to product functionality. |
*Note: "Latest stable" versions should be pinned to specific versions in `package.json` files during development.*
## 11\. Infrastructure and Deployment Overview
* **Cloud Provider:** AWS.
* **Core Services Used:** Lambda, API Gateway (HTTP API), S3, DynamoDB (On-Demand), Step Functions, EventBridge Scheduler, CloudFront, CloudWatch, IAM, ACM (if custom domain).
* **IaC:** AWS CDK (TypeScript), with separate CDK apps in backend and frontend polyrepos.
* **Deployment Strategy (MVP):** CI (GitHub Actions) for build/test/lint. CDK deployment (initially manual or CI-scripted) to a single AWS environment.
* **Environments (MVP):** Local Development; Single Deployed MVP Environment (e.g., "dev" acting as initial production).
* **Rollback Strategy (MVP):** CDK stack rollback, Lambda/S3 versioning, DynamoDB PITR.
## 12\. Error Handling Strategy
* **General Approach:** Custom `Error` classes hierarchy. Promises reject with `Error` objects.
* **Logging:** Pino for structured JSON logs to CloudWatch. Standard levels (DEBUG, INFO, WARN, ERROR, CRITICAL). Contextual info (AWS Request ID, business IDs). No sensitive data in logs.
* **Specific Patterns:**
* **External API Calls (`axios`):** Timeouts, retries (e.g., `axios-retry`), wrap errors in custom types.
* **Internal Errors:** Custom error types, detailed server-side logging.
* **API Gateway Responses:** Translate internal errors to appropriate HTTP errors (4xx, 500) with generic client messages.
* **Workflow (Step Functions):** Error handling, retries, catch blocks for states. Failed executions logged.
* **Data Consistency:** Lambdas handle partial failures gracefully. Step Functions manage overall workflow state.
## 13\. Coding Standards (Backend: `bmad-daily-digest-backend`)
**Scope:** Applies to `bmad-daily-digest-backend`. Frontend standards are separate.
* **Primary Language:** TypeScript (Node.js 22).
* **Style:** ESLint, Prettier.
* **Naming:** Variables/Functions: `camelCase`. Constants: `UPPER_SNAKE_CASE`. Classes/Interfaces/Types/Enums: `PascalCase`. Files/Folders: `dash-case` (e.g., `episode-service.ts`, `content-ingestion/`).
* **Structure:** Feature-based (`src/features/feature-name/`).
* **Tests:** Unit/integration tests co-located (`*.test.ts`). E2E tests (if any for backend API) in root `tests/e2e/`.
* **Async:** `async`/`await` for Promises.
* **Types:** `strict: true`. No `any` without justification. JSDoc for exported items. Inline comments for clarity.
* **Dependencies:** `npm` with `package-lock.json`. Pin versions or use tilde (`~`).
* **Detailed Conventions:** Immutability preferred. Functional constructs for stateless logic, classes for stateful services/entities. Custom errors. Strict null checks. ESModules. Pino for logging (structured JSON, levels, context, no secrets). Lambda best practices (lean handlers, env vars, optimize size). `axios` with timeouts. AWS SDK v3 modular imports. Avoid common anti-patterns (deep nesting, large functions, `@ts-ignore`, hardcoded secrets, unhandled promises).
## 14\. Overall Testing Strategy
* **Tools:** Jest, React Testing Library (frontend), ESLint, Prettier, GitHub Actions.
* **Unit Tests:** Isolate functions/methods/components. Mock dependencies. Co-located. Developer responsibility.
* **Integration Tests (Backend/Frontend):** Test interactions between internal components with external systems mocked (AWS SDK clients, third-party APIs).
* **End-to-End (E2E) Tests (MVP):**
* Backend API: Automated test for "Hello World"/status. Test daily job trigger verifies DDB/S3 output.
* Frontend UI: Key user flows tested manually for MVP. (Playwright deferred to post-MVP).
* **Coverage:** Guideline \>80% unit test coverage for critical logic. Quality over quantity. Measured by Jest.
* **Mocking:** Jest's built-in system. `axios-mock-adapter` if needed.
* **Test Data:** Inline mocks or small fixtures for unit/integration.
## 15\. Security Best Practices
* **Input Validation:** API Gateway basic validation; Zod for detailed payload validation in Lambdas.
* **Output Encoding:** Next.js/React handles XSS for frontend rendering. Backend API is JSON.
* **Secrets Management:** Lambda environment variables via CDK (from local gitignored `.env` for MVP setup). No hardcoding. Pino redaction for logs if needed.
* **Dependency Security:** `npm audit` in CI. Promptly address high/critical vulnerabilities.
* **Authentication/Authorization:** API Gateway API Keys (Frontend Read Key, Admin Action Key). IAM roles with least privilege for service-to-service.
* **Principle of Least Privilege (IAM):** Minimal permissions for all IAM roles (Lambdas, Step Functions, CDK).
* **API Security:** HTTPS enforced by API Gateway/CloudFront. Basic rate limiting on API Gateway. Frontend uses HTTP security headers (via CloudFront/Next.js).
* **Error Disclosure:** Generic errors to client, detailed logs server-side.
* **Infrastructure Security:** S3 bucket access restricted (CloudFront OAC/OAI).
* **Post-MVP:** Consider SAST/DAST, penetration testing.
* **Adherence:** AWS Well-Architected Framework - Security Pillar.
## 16\. Key Reference Documents
1. **Product Requirements Document (PRD) - BMad Daily Digest** (Version: 0.1)
2. **UI/UX Specification - BMad Daily Digest** (Version: 0.1)
3. **Algolia Hacker News Search API Documentation** (`https://hn.algolia.com/api`)
4. **Play.ai PlayNote API Documentation** (`https://docs.play.ai/api-reference/playnote/post`)
## 17\. Change Log
| Version | Date | Author | Summary of Changes |
| :------ | :----------- | :----------------------- | :---------------------------------------------------------------------------------------------------------------- |
| 0.1 | May 20, 2025 | Fred (Architect) & User | Initial draft of the Architecture Document based on PRD v0.1 and UI/UX Spec v0.1. |

View File

@@ -0,0 +1,8 @@
# Change Log
> This document is a granulated shard from the main "PRD.md" focusing on "Change Log".
| Change | Date | Version | Description | Author |
| :----------------------------------------------------------- | :------------ | :------ | :--------------------------------------------------------------------------------------------------------- | :------------------------------- |
| Initial PRD draft and MVP scope definition. | May 20, 2025 | 0.1 | Created initial PRD based on Project Brief and discussions on goals, requirements, and Epics/Stories (shells). | John (PM) & User |
| Architectural refinements incorporated into Story ACs. | May 20, 2025 | 0.2 | Updated ACs for Stories 2.1 and 3.1 based on System Architecture Document feedback from Fred (Architect). | Sarah (PO) & User |

View File

@@ -0,0 +1,90 @@
# Component View
The system is divided into distinct backend and frontend components.
## Backend Components (`bmad-daily-digest-backend` repository)
1. **Daily Workflow Orchestrator (AWS Step Functions state machine):** Manages the end-to-end daily pipeline.
2. **HN Data Fetcher Service (AWS Lambda):** Fetches HN posts/comments (Algolia), identifies repeats (via DynamoDB).
3. **Article Scraping Service (AWS Lambda):** Scrapes/extracts content from external article URLs, handles fallbacks.
4. **Content Formatting Service (AWS Lambda):** Aggregates and formats text payload for Play.ai.
5. **Play.ai Interaction Service (AWS Lambda functions, orchestrated by Polling Step Function):** Submits job to Play.ai, polls for status.
6. **Podcast Storage Service (AWS Lambda):** Downloads audio from Play.ai, stores to S3.
7. **Metadata Persistence Service (AWS Lambda & DynamoDB Tables):** Manages episode and HN post processing state metadata in DynamoDB.
8. **Backend API Service (AWS API Gateway + AWS Lambda functions):** Exposes endpoints for frontend (episode lists/details).
## Frontend Components (`bmad-daily-digest-frontend` repository)
1. **Next.js Web Application (Static Site on S3/CloudFront):** Renders UI, handles navigation.
2. **Frontend API Client Service (TypeScript module):** Encapsulates communication with the Backend API Service.
## External Services
- Algolia HN Search API
- Play.ai PlayNote API
- Various External Article Websites
## Component Interaction Diagram (Conceptual Backend Focus)
```mermaid
graph LR
subgraph Frontend Application Space
F_App[Next.js App on S3/CloudFront]
F_APIClient[Frontend API Client]
F_App --> F_APIClient
end
subgraph Backend API Space
APIGW[API Gateway]
API_L[Backend API Lambdas]
APIGW --> API_L
end
subgraph Backend Daily Pipeline Space
Scheduler[EventBridge Scheduler] --> Orchestrator[Step Functions Orchestrator]
Orchestrator --> HNFetcher[HN Data Fetcher Lambda]
HNFetcher -->|Reads/Writes Post Status| DDB
HNFetcher --> Algolia[Algolia HN API]
Orchestrator --> ArticleScraper[Article Scraper Lambda]
ArticleScraper --> ExtWebsites[External Article Websites]
Orchestrator --> ContentFormatter[Content Formatter Lambda]
Orchestrator --> PlayAISubmit[Play.ai Submit Lambda]
PlayAISubmit --> PlayAI_API[Play.ai PlayNote API]
subgraph Polling_SF[Play.ai Polling (Step Functions)]
direction LR
PollTask[Poll Status Lambda] --> PlayAI_API
end
Orchestrator --> Polling_SF
Orchestrator --> PodcastStorage[Podcast Storage Lambda]
PodcastStorage --> PlayAI_API
PodcastStorage --> S3Store[S3 Audio Storage]
Orchestrator --> MetadataService[Metadata Persistence Lambda]
MetadataService --> DDB[DynamoDB Episode/Post Metadata]
end
F_APIClient --> APIGW
API_L --> DDB
classDef external fill:#ddd,stroke:#333,stroke-width:2px;
class Algolia,ExtWebsites,PlayAI_API external;
```
## Architectural / Design Patterns Adopted
The following key architectural and design patterns have been chosen for this project:
* **Serverless Architecture:** Entire backend on AWS Lambda, API Gateway, S3, DynamoDB, Step Functions. Rationale: Minimized operations, auto-scaling, pay-per-use, cost-efficiency.
* **Event-Driven Architecture:** Daily pipeline initiated by EventBridge Scheduler; Step Functions orchestrate based on state changes. Rationale: Decoupled components, reactive system for automation.
* **Microservices-like Approach (Backend Lambda Functions):** Each Lambda handles a specific, well-defined task. Rationale: Modularity, independent scalability, easier testing/maintenance.
* **Static Site Generation (SSG) for Frontend:** Next.js frontend exported as static files, hosted on S3/CloudFront. Rationale: Optimal performance, security, scalability, lower hosting costs.
* **Infrastructure as Code (IaC):** AWS CDK in TypeScript for all AWS infrastructure in both repositories. Rationale: Repeatable, version-controlled, automated provisioning.
* **Polling Pattern (External Job Status):** AWS Step Functions implement a polling loop for Play.ai job status. Rationale: Reliable tracking of asynchronous third-party jobs, based on Play.ai docs.
* **Orchestration Pattern (AWS Step Functions):** End-to-end daily backend pipeline managed by a Step Functions state machine. Rationale: Robust workflow automation, state management, error handling for multi-step processes.

View File

@@ -0,0 +1,40 @@
# Data Models
## Core Application Entities
**a. Episode**
* Attributes: `episodeId` (PK, UUID), `publicationDate` (YYYY-MM-DD), `episodeNumber` (Number), `podcastGeneratedTitle` (String), `audioS3Bucket` (String), `audioS3Key` (String), `audioUrl` (String, derived for API), `playAiJobId` (String), `playAiSourceAudioUrl` (String), `sourceHNPosts` (List of `SourceHNPost`), `status` (String: "PROCESSING", "PUBLISHED", "FAILED"), `createdAt` (ISO Timestamp), `updatedAt` (ISO Timestamp).
**b. SourceHNPost (object within `Episode.sourceHNPosts`)**
* Attributes: `hnPostId` (String), `title` (String), `originalArticleUrl` (String), `hnLink` (String), `isUpdateStatus` (Boolean), `oldRank` (Number, Optional), `lastCommentFetchTimestamp` (Number, Unix Timestamp), `articleScrapingFailed` (Boolean), `articleTitleFromScrape` (String, Optional).
**c. HackerNewsPostProcessState (DynamoDB Table)**
* Attributes: `hnPostId` (PK, String), `originalArticleUrl` (String), `articleTitleFromScrape` (String, Optional), `lastSuccessfullyScrapedTimestamp` (Number, Optional), `lastCommentFetchTimestamp` (Number, Optional), `firstProcessedDate` (YYYY-MM-DD), `lastProcessedDate` (YYYY-MM-DD), `lastKnownRank` (Number, Optional).
## API Payload Schemas (Internal API)
**a. `EpisodeListItem` (for `GET /episodes`)**
* `episodeId`, `publicationDate`, `episodeNumber`, `podcastGeneratedTitle`.
**b. `EpisodeDetail` (for `GET /episodes/{episodeId}`)**
* `episodeId`, `publicationDate`, `episodeNumber`, `podcastGeneratedTitle`, `audioUrl`, `sourceHNPosts` (list of `SourceHNPostDetail` containing `hnPostId`, `title`, `originalArticleUrl`, `hnLink`, `isUpdateStatus`, `oldRank`), `playAiJobId` (optional), `playAiSourceAudioUrl` (optional), `createdAt`.
## Database Schemas (AWS DynamoDB)
**a. `BmadDailyDigestEpisodes` Table**
* PK: `episodeId` (String).
* Attributes: As per `Episode` entity.
* GSI Example (`PublicationDateIndex`): PK: `status`, SK: `publicationDate`.
* Billing: PAY\_PER\_REQUEST.
**b. `HackerNewsPostProcessState` Table**
* PK: `hnPostId` (String).
* Attributes: As per `HackerNewsPostProcessState` entity.
* Billing: PAY\_PER\_REQUEST.

View File

@@ -0,0 +1,19 @@
# Environment Variables Documentation
The BMad Daily Digest application uses various environment variables for configuration settings. These variables are referenced throughout the architecture document, particularly in the sections about API interactions with external services.
## Backend Environment Variables
### Play.ai API Configuration
- `PLAY_AI_BEARER_TOKEN`: Authentication token for Play.ai API
- `PLAY_AI_USER_ID`: User ID for Play.ai API
- `PLAY_AI_VOICE1_ID`: ID for primary voice used in podcast
- `PLAY_AI_VOICE1_NAME`: Name of primary voice
- `PLAY_AI_VOICE2_ID`: ID for secondary voice used in podcast
- `PLAY_AI_VOICE2_NAME`: Name of secondary voice
- `PLAY_AI_STYLE`: Style parameter for the Play.ai API
### Frontend API Configuration
- `NEXT_PUBLIC_BACKEND_API_URL`: URL to access the backend API
Note: The environment variables are managed through AWS Lambda environment variables via CDK (from local gitignored `.env` for MVP setup).

View File

@@ -0,0 +1,77 @@
# Epic 1: Backend Foundation, Tooling & "Hello World" API
**Goal:** To establish the core backend project infrastructure in its dedicated repository, including robust development tooling and initial AWS CDK setup for essential services. By the end of this epic:
1. A simple "hello world" API endpoint (AWS API Gateway + Lambda) **must** be deployed and testable via `curl`, returning a dynamic message.
2. The backend project **must** have ESLint, Prettier, Jest (unit testing), and esbuild (TypeScript bundling) configured and operational.
3. Basic unit tests **must** exist for the "hello world" Lambda function.
4. Code formatting and linting checks **should** be integrated into a pre-commit hook and/or a basic CI pipeline stub.
## User Stories
**Story 1.1: Initialize Backend Project using TS-TEMPLATE-STARTER**
* **User Story Statement:** As a Developer, I want to create the `bmad-daily-digest-backend` Git repository and initialize it using the existing `TS-TEMPLATE-STARTER`, ensuring all foundational tooling (TypeScript, Node.js 22, ESLint, Prettier, Jest, esbuild) is correctly configured and operational for this specific project, so that I have a high-quality, standardized development environment ready for application logic.
* **Acceptance Criteria (ACs):**
1. A new, private Git repository named `bmad-daily-digest-backend` **must** be created on GitHub.
2. The contents of the `TS-TEMPLATE-STARTER` project **must** be copied/cloned into this new repository.
3. `package.json` **must** be updated (project name, version, description).
4. Project dependencies **must** be installable.
5. TypeScript setup (`tsconfig.json`) **must** be verified for Node.js 22, esbuild compatibility; project **must** compile.
6. ESLint and Prettier configurations **must** be operational; lint/format scripts **must** execute successfully.
7. Jest configuration **must** be operational; test scripts **must** execute successfully with any starter example tests.
8. Irrelevant generic demo code from starter **should** be removed. `index.ts`/`index.test.ts` can remain as placeholders.
9. A standard `.gitignore` and an updated project `README.md` **must** be present.
**Story 1.2: Pre-commit Hook Implementation**
* **User Story Statement:** As a Developer, I want pre-commit hooks automatically enforced in the `bmad-daily-digest-backend` repository, so that code quality standards (like linting and formatting) are checked and applied to staged files before any code is committed, thereby maintaining codebase consistency and reducing trivial errors.
* **Acceptance Criteria (ACs):**
1. A pre-commit hook tool (e.g., Husky) **must** be installed and configured.
2. A tool for running linters/formatters on staged files (e.g., `lint-staged`) **must** be installed and configured.
3. Pre-commit hook **must** trigger `lint-staged` on staged `.ts` files.
4. `lint-staged` **must** be configured to run ESLint (`--fix`) and Prettier (`--write`).
5. Attempting to commit files with auto-fixable issues **must** result in fixes applied and successful commit.
6. Attempting to commit files with non-auto-fixable linting errors **must** abort the commit with error messages.
7. Committing clean files **must** proceed without issues.
**Story 1.3: "Hello World" Lambda Function Implementation & Unit Tests**
* **User Story Statement:** As a Developer, I need a simple "Hello World" AWS Lambda function implemented in TypeScript within the `bmad-daily-digest-backend` project. This function, when invoked, should return a dynamic greeting message including the current date and time, and it must be accompanied by comprehensive Jest unit tests, so that our basic serverless compute functionality, testing setup, and TypeScript bundling are validated.
* **Acceptance Criteria (ACs):**
1. A `src/features/publicApi/statusHandler.ts` file (or similar according to final backend structure) **must** contain the Lambda handler.
2. Handler **must** be AWS Lambda compatible (event, context, Promise response).
3. Successful execution **must** return JSON: `statusCode: 200`, body with `message: "Hello from BMad Daily Digest Backend, today is [current_date] at [current_time]."`.
4. Date and time in message **must** be dynamic.
5. A corresponding Jest unit test file (e.g., `src/features/publicApi/statusHandler.test.ts`) **must** be created.
6. Unit tests **must** verify: 200 status, valid JSON body, expected `message` field, "Hello from..." prefix, dynamic date/time portion (use mocked `Date`).
7. All unit tests **must** pass.
8. esbuild configuration **must** correctly bundle the handler.
**Story 1.4: AWS CDK Setup for "Hello World" API (Lambda & API Gateway)**
* **User Story Statement:** As a Developer, I want to define the necessary AWS infrastructure (Lambda function and API Gateway endpoint) for the "Hello World" service using AWS CDK (Cloud Development Kit) in TypeScript, so that the infrastructure is version-controlled, repeatable, and can be deployed programmatically.
* **Acceptance Criteria (ACs):**
1. AWS CDK (v2) **must** be a development dependency.
2. CDK app structure **must** be initialized (e.g., in `cdk/`).
3. A new CDK stack (e.g., `BmadDailyDigestBackendStack`) **must** be defined in TypeScript.
4. CDK stack **must** define an AWS Lambda resource for the "Hello World" function (Node.js 22, bundled code reference, handler entry point, basic IAM role for CloudWatch logs, free-tier conscious settings).
5. CDK stack **must** define an AWS API Gateway (HTTP API preferred) with a route (e.g., `GET /status` or `GET /hello`) triggering the Lambda, secured with the "Frontend Read API Key".
6. CDK stack **must** be synthesizable (`cdk synth`) without errors.
7. CDK code **must** adhere to project ESLint/Prettier standards.
8. Mechanism for passing Lambda environment variables via CDK **must** be in place.
**Story 1.5: "Hello World" API Deployment & Manual Invocation Test**
* **User Story Statement:** As a Developer, I need to deploy the "Hello World" API (defined in AWS CDK) to an AWS environment and successfully invoke its endpoint using a tool like `curl` (including the API Key), so that I can verify the end-to-end deployment process and confirm the basic API is operational in the cloud.
* **Acceptance Criteria (ACs):**
1. The AWS CDK stack for "Hello World" API **must** deploy successfully to a designated AWS account/region.
2. The API Gateway endpoint URL for the `/status` (or `/hello`) route **must** be retrievable post-deployment.
3. A `GET` request to the deployed endpoint, including the correct `x-api-key` header, **must** receive a response.
4. HTTP response status **must** be 200 OK.
5. Response body **must** be JSON containing the expected dynamic "Hello..." message.
6. Basic Lambda invocation logs **must** be visible in AWS CloudWatch Logs.
**Story 1.6: Basic CI/CD Pipeline Stub with Quality Gates**
* **User Story Statement:** As a Developer, I need a basic Continuous Integration (CI) pipeline established for the `bmad-daily-digest-backend` repository, so that code quality checks (linting, formatting, unit tests) and the build process are automated upon code pushes and pull requests, ensuring early feedback and maintaining codebase health.
* **Acceptance Criteria (ACs):**
1. A CI workflow file (e.g., GitHub Actions in `.github/workflows/main.yml`) **must** be created.
2. Pipeline **must** trigger on pushes to `main` and PRs targeting `main`.
3. Pipeline **must** include steps for: checkout, Node.js 22 setup, dependency install, ESLint check, Prettier format check, Jest unit tests, esbuild bundle.
4. Pipeline **must** fail if any lint, format, test, or bundle step fails.
5. A successful CI run on the `main` branch **must** be demonstrated.
6. CI pipeline for MVP **does not** need to perform AWS deployment.

View File

@@ -0,0 +1,119 @@
# Epic 2: Automated Content Ingestion & Podcast Generation Pipeline
**Goal:** To implement the complete automated daily workflow within the backend. This includes fetching Hacker News post data, scraping and extracting content from linked external articles, aggregating and formatting text, submitting it to Play.ai, managing job status via polling, and retrieving/storing the final audio file and associated metadata. This epic delivers the core value proposition of generating the daily audio content and making it ready for consumption via an API.
## User Stories
**Story 2.1: AWS CDK Extension for Epic 2 Resources**
* **User Story Statement:** As a Developer, I need to extend the existing AWS CDK stack within the `bmad-daily-digest-backend` project to define and provision all new AWS resources required for the content ingestion and podcast generation pipeline—including the `BmadDailyDigestEpisodes` DynamoDB table (with GSI), the `HackerNewsPostProcessState` DynamoDB table, an S3 bucket for audio storage, and the AWS Step Functions state machine for orchestrating the Play.ai job status polling—so that all backend infrastructure for this epic is managed as code and ready for the application logic.
* **Acceptance Criteria (ACs):**
1. The existing AWS CDK application (from Epic 1) **must** be extended.
2. The `BmadDailyDigestEpisodes` DynamoDB table resource **must** be defined in CDK as specified in the System Architecture Document's "Data Models" section (with `episodeId` PK, key attributes like `publicationDate`, `episodeNumber`, `podcastGeneratedTitle`, `audioS3Key`, `audioS3Bucket`, `playAiJobId`, `playAiSourceAudioUrl`, `sourceHNPosts` list, `status`, `createdAt`, `updatedAt`), including a GSI for chronological sorting (e.g., PK `status`, SK `publicationDate`), and PAY_PER_REQUEST billing.
3. The `HackerNewsPostProcessState` DynamoDB table resource **must** be defined in CDK as specified in the System Architecture Document's "Data Models" section (with `hnPostId` PK and attributes like `lastCommentFetchTimestamp`, `lastSuccessfullyScrapedTimestamp`, `lastKnownRank`), and PAY_PER_REQUEST billing.
4. An S3 bucket resource (e.g., `bmad-daily-digest-audio-{unique-suffix}`) **must** be defined via CDK for audio storage, with private access by default.
5. An AWS Step Functions state machine resource **must** be defined via CDK to manage the Play.ai job status polling workflow (as detailed in Story 2.6).
6. Necessary IAM roles and permissions for Lambda functions within this epic to interact with DynamoDB, S3, Step Functions, CloudWatch Logs **must** be defined via CDK, adhering to least privilege.
7. The updated CDK stack **must** synthesize (`cdk synth`) and deploy (`cdk deploy`) successfully.
8. All new CDK code **must** adhere to project ESLint/Prettier standards.
**Story 2.2: Fetch Top Hacker News Posts & Identify Repeats**
* **User Story Statement:** As the System, I need to reliably fetch the top N (configurable, e.g., 10) current Hacker News posts daily using the Algolia HN API, including their essential metadata. I also need to identify if each fetched post has been processed in a recent digest by checking against the `HackerNewsPostProcessState` table, so that I have an accurate list of stories and their status (new or repeat) to begin generating the daily digest.
* **Acceptance Criteria (ACs):**
1. A `hackerNewsService.ts` function **must** fetch top N HN posts (stories only) via `axios` from Algolia API (configurable `HN_POSTS_COUNT`).
2. Extracted metadata per post: Title, Article URL, HN Post URL, HN Post ID (`objectID`), Author, Points, Creation timestamp.
3. For each post, the function **must** query the `HackerNewsPostProcessState` DynamoDB table to determine its `isUpdateStatus` (true if `lastSuccessfullyScrapedTimestamp` and `lastCommentFetchTimestamp` indicate prior full processing) and retrieve `lastCommentFetchTimestamp` and `lastKnownRank` if available.
4. Function **must** return an array of HN post objects with metadata, `isUpdateStatus`, `lastCommentFetchTimestamp`, and `lastKnownRank`.
5. Error handling for Algolia/DynamoDB calls **must** be implemented and logged.
6. Unit tests (Jest) **must** verify API calls, data extraction, repeat identification (mocked DDB), and error handling. All tests **must** pass.
**Story 2.3: Article Content Scraping & Extraction (Conditional)**
* **User Story Statement:** As the System, for each Hacker News post identified as *new* (or for which article scraping previously failed and is being retried), I need to robustly fetch its HTML content from the linked article URL and extract the primary textual content and title using libraries like Cheerio and Mozilla Readability. If scraping fails, a fallback mechanism must be triggered.
* **Acceptance Criteria (ACs):**
1. An `articleScraperService.ts` function **must** accept an article URL and `isUpdateStatus`.
2. If `isUpdateStatus` is true (article already successfully scraped and stored, though we are not storing full articles long term - this implies we have the article data available from a previous step if it's a repeat post where we don't re-scrape), scraping **must** be skipped. (For MVP, if it's a repeat post, we assume we don't need to re-scrape the article itself, only comments, as per user feedback. This story focuses on *new* scrapes or retries of failed scrapes).
3. If a new scrape is needed: use `axios` (timeout, User-Agent) to fetch HTML.
4. Use `Mozilla Readability` (JS port) and/or `Cheerio` to extract main article text and title.
5. Return `{ success: true, title: string, content: string }` on success.
6. If scraping fails: log failure, return `{ success: false, error: string, fallbackNeeded: true }`.
7. No specific "polite" inter-article scraping delays for MVP.
8. Unit tests (Jest) **must** mock `axios`, test successful extraction, skip logic for non-applicable cases, and failure/fallback scenarios. All tests **must** pass.
**Story 2.4: Fetch Hacker News Comments (Conditional Logic)**
* **User Story Statement:** As the System, I need to fetch comments for each selected Hacker News post using the Algolia HN API, adjusting the strategy to fetch up to N comments for new posts, only new comments since last fetch for repeat posts, or up to 3N comments if article scraping failed.
* **Acceptance Criteria (ACs):**
1. `hackerNewsService.ts` **must** be extended to fetch comments for an HN Post ID, accepting `isUpdateStatus`, `lastCommentFetchTimestamp` (from `HackerNewsPostProcessState`), and `articleScrapingFailed` flags.
2. Use `axios` to call Algolia HN API item endpoint.
3. **Comment Fetching Logic:**
* If `articleScrapingFailed`: Fetch up to 3 * `HN_COMMENTS_COUNT_PER_POST` available comments.
* If `isUpdateStatus`: Fetch all comments, then filter client-side for comments with `created_at_i` > `lastCommentFetchTimestamp`. Select up to `HN_COMMENTS_COUNT_PER_POST` of these *new* comments.
* Else (new post, successful scrape): Fetch up to `HN_COMMENTS_COUNT_PER_POST`.
4. For selected comments, extract plain text (HTML stripped), author, creation timestamp.
5. Return array of comment objects; empty if none. An updated `lastCommentFetchTimestamp` (max `created_at_i` of fetched comments for this post) should be available for updating `HackerNewsPostProcessState`.
6. Error handling and logging for API calls.
7. Unit tests (Jest) **must** mock `axios` and verify all conditional fetching logic, comment selection/filtering, data extraction, and error handling. All tests **must** pass.
**Story 2.5: Content Aggregation and Formatting for Play.ai**
* **User Story Statement:** As the System, I need to aggregate the collected Hacker News post data (titles), associated article content (full, truncated, or fallback summary), and comments (new, updated, or extended sets) for all top stories, and format this combined text according to the specified structure for the play.ai PlayNote API, including special phrasing for different post types (new, update, scrape-failed) and configurable article truncation.
* **Acceptance Criteria (ACs):**
1. A `contentFormatterService.ts` **must** be implemented.
2. Inputs: Array of processed HN post objects (with metadata, statuses, content, comments).
3. Output: A single string.
4. String starts: "It's a top 10 countdown for [Current Date]".
5. Posts sequenced in reverse rank order.
6. **Formatting (new post):** "Story [Rank] - [Article Title]. [Full/Truncated Article Text]. Comments Section. [Number] comments follow. Comment 1: [Text]..."
7. **Formatting (repeat post):** "Story [Rank] (previously Rank [OldRank] yesterday) - [Article Title]. We're bringing you new comments on this popular story. Comments Section. [Number] new comments follow. Comment 1: [Text]..."
8. **Formatting (scrape-failed post):** "Story [Rank] - [Article Title]. We couldn't retrieve the full article, but here's a summary if available and the latest comments. [Optional HN Summary]. Comments Section. [Number] comments follow. Comment 1: [Text]..."
9. **Article Truncation:** If `MAX_ARTICLE_LENGTH` (env var) set and article exceeds, truncate aiming to preserve intro/conclusion.
10. Graceful handling for missing parts.
11. Unit tests (Jest) verify all formatting, truncation, data merging, error handling. All tests **must** pass.
**Story 2.6 (REVISED): Implement Podcast Generation Status Polling via Play.ai API**
* **User Story Statement:** As the System, after submitting a podcast generation job to Play.ai and receiving a `jobId`, I need an AWS Step Function state machine to periodically poll the Play.ai API for the status of this specific job, continuing until the job is reported as "completed" or "failed" (or a configurable max duration/attempts limit is reached), so the system can reliably determine when the podcast audio is ready or if an error occurred.
* **Acceptance Criteria (ACs):**
1. The AWS Step Function state machine (CDK defined in Story 2.1) **must** manage the polling workflow.
2. Input: `jobId`.
3. States: Invoke Poller Lambda (calls Play.ai status GET endpoint with `axios`), Wait (configurable `POLLING_INTERVAL_MINUTES`), Choice (evaluates status: "processing", "completed", "failed").
4. Loop if "processing". Stop if "completed" or "failed".
5. Max polling duration/attempts (configurable env vars `MAX_POLLING_DURATION_MINUTES`, `MAX_POLLING_ATTEMPTS`) **must** be enforced, treating expiry as failure.
6. If "completed": extract `audioUrl`, trigger next step (Story 2.8 process) with data.
7. If "failed"/"timeout": log event, record failure (e.g., update episode status in DDB via a Lambda), terminate.
8. Poller Lambda handles API errors gracefully.
9. Unit tests for Poller Lambda logic; Step Function definition tested (locally if possible, or via AWS console tests). All tests **must** pass.
**Story 2.7: Submit Content to Play.ai PlayNote API & Initiate Podcast Generation**
* **User Story Statement:** As the System, I need to securely submit the aggregated and formatted text content (using `sourceText`) to the play.ai PlayNote API via an `application/json` request to initiate the podcast generation process, and I must capture the `jobId` returned by Play.ai, so that this `jobId` can be passed to the status polling mechanism (Step Function).
* **Acceptance Criteria (ACs):**
1. A `playAiService.ts` function **must** handle submission.
2. Input: formatted text (from Story 2.5).
3. Use `axios` for `POST` to Play.ai endpoint (e.g., `https://api.play.ai/api/v1/playnotes`).
4. Request `Content-Type: application/json`.
5. JSON body: `sourceText`, and configurable `title`, `voiceId1`, `name1` (default "Angelo"), `voiceId2`, `name2` (default "Deedee"), `styleGuidance` (default "podcast") from env vars.
6. Headers: `Authorization: Bearer <PLAY_AI_BEARER_TOKEN>`, `X-USER-ID: <PLAY_AI_USER_ID>` (from env vars).
7. No `webHookUrl` sent.
8. On success: extract `jobId`, log it, initiate polling Step Function (Story 2.6) with `jobId` and other context (like internal `episodeId`).
9. Error handling for API submission; log and flag failure.
10. Unit tests (Jest) mock `axios`, verify API call, auth, payload, `jobId` extraction, Step Function initiation (mocked), error handling. All tests **must** pass.
**Story 2.8: Retrieve, Store Generated Podcast Audio & Persist Episode Metadata**
* **User Story Statement:** As the System, once the podcast generation status polling (Story 2.6) indicates a Play.ai job is "completed," I need to download the generated audio file from the provided `audioUrl`, store this file in our designated S3 bucket, and then save/update all relevant metadata for the episode (including S3 audio location, `episodeNumber`, `podcastGeneratedTitle`, `playAiSourceAudioUrl`, and source HN post information including their `lastCommentFetchTimestamp`) into our DynamoDB tables (`BmadDailyDigestEpisodes` and `HackerNewsPostProcessState`), so that the daily digest is fully processed, archived, and ready for access.
* **Acceptance Criteria (ACs):**
1. A `podcastStorageService.ts` function **must** be triggered by Step Function (Story 2.6) on "completed" status, receiving `audioUrl`, Play.ai `jobId`, and original context (like internal `episodeId`, list of source HN posts with their metadata and processing status).
2. Use `axios` to download audio from `audioUrl`.
3. Upload audio to S3 bucket (from Story 2.1), using key (e.g., `YYYY/MM/DD/episodeId.mp3`).
4. Prepare `Episode` metadata for `BmadDailyDigestEpisodes` table: `episodeId` (UUID), `publicationDate` (YYYY-MM-DD), `episodeNumber` (sequential logic, TBD), `podcastGeneratedTitle` (from Play.ai or constructed), `audioS3Bucket`, `audioS3Key`, `playAiJobId`, `playAiSourceAudioUrl`, `sourceHNPosts` (array of objects: `{ hnPostId, title, originalArticleUrl, hnLink, isUpdateStatus, oldRank, articleScrapingFailed }`), `status: "Published"`, `createdAt`, `updatedAt`.
5. For each `hnPostId` in `sourceHNPosts`, update its corresponding item in the `HackerNewsPostProcessState` table with the `lastCommentFetchTimestamp` (current time or max comment time from this run), `lastProcessedDate` (current date), and `lastKnownRank`. If `articleScrapingFailed` was false for this run, update `lastSuccessfullyScrapedTimestamp`.
6. Save `Episode` metadata to `BmadDailyDigestEpisodes` DynamoDB table.
7. Error handling for download, S3 upload, DDB writes; failure should result in episode `status: "Failed"`.
8. Unit tests (Jest) mock `axios`, AWS SDK (S3, DynamoDB); verify data handling, storage, metadata construction for both tables, errors. All tests **must** pass.
**Story 2.9: Daily Workflow Orchestration & Scheduling**
* **User Story Statement:** As the System Administrator, I need the entire daily backend workflow (Stories 2.2 through 2.8) to be fully orchestrated by the primary AWS Step Function state machine and automatically scheduled to run once per day using Amazon EventBridge Scheduler, ensuring it handles re-runs for the same day by overwriting/starting over (for MVP), so that "BMad Daily Digest" episodes are produced consistently and reliably.
* **Acceptance Criteria (ACs):**
1. The primary AWS Step Function state machine **must** orchestrate the sequence: Fetch HN Posts & Identify Repeats (2.2); For each post: conditionally Scrape Article (2.3) & Fetch Comments (2.4); then Aggregate & Format Content (2.5); then Submit to Play.ai & get `jobId` (2.7); then initiate/manage Polling (2.6 using `jobId`); on "completed" polling, trigger Retrieve & Store Audio/Metadata (2.8).
2. State machine **must** manage data flow (inputs/outputs) between steps correctly.
3. Overall workflow error handling: critical step failure marks state machine execution as "Failed" and logs comprehensively. Steps use retries for transient errors.
4. **Idempotency (MVP):** Re-running for the same `publicationDate` **must** re-process and effectively overwrite previous data for that date.
5. Amazon EventBridge Scheduler rule (CDK defined) **must** trigger the main Step Function daily at 12:00 UTC (default, configurable via `DAILY_JOB_SCHEDULE_UTC_CRON`).
6. Successful end-to-end run **must** be demonstrated (e.g., processing sample data through the pipeline).
7. Step Function execution history **must** provide a clear audit trail of steps and data.
8. Unit tests for any new orchestrator-specific Lambda functions (if any not covered). All tests **must** pass.

View File

@@ -0,0 +1,83 @@
# Epic 3: Web Application MVP & Podcast Consumption
**Goal:** To set up the frontend project in its dedicated repository and develop and deploy the Next.js frontend application MVP, enabling users to consume the "BMad Daily Digest." This includes initial project setup (AI-assisted UI kickstart from `bmad-daily-digest-ui` scaffold), pages for listing and detailing episodes, an about page, and deployment.
## User Stories
**Story 3.1: Frontend Project Repository & Initial UI Setup (AI-Assisted)**
* **User Story Statement:** As a Developer, I need to establish the `bmad-daily-digest-frontend` Git repository with a new Next.js (TypeScript, Node.js 22) project, using the provided `bmad-daily-digest-ui` V0 scaffold as the base. This setup must include all foundational tooling (ESLint, Prettier, Jest with React Testing Library, a basic CI stub), and an initial AWS CDK application structure, ensuring the "80s retro CRT terminal" aesthetic (with Tailwind CSS and shadcn/ui) is operational, so that a high-quality, styled, and standardized frontend development environment is ready.
* **Acceptance Criteria (ACs):**
1. A new, private Git repository `bmad-daily-digest-frontend` **must** be created on GitHub.
2. The `bmad-daily-digest-ui` V0 scaffold project files **must** be used as the initial codebase in this repository.
3. `package.json` **must** be updated (project name, version, description).
4. Project dependencies **must** be installable.
5. TypeScript (`tsconfig.json`), Next.js (`next.config.mjs`), Tailwind (`tailwind.config.ts`), ESLint, Prettier, Jest configurations from the scaffold **must** be verified and operational.
6. The application **must** build successfully (`npm run build`) with the scaffolded UI.
7. A basic CI pipeline stub (GitHub Actions) for lint, format check, test, build **must** be created.
8. A standard `.gitignore` and an updated `README.md` **must** be present.
9. An initial AWS CDK application structure **must** be created within a `cdk/` directory in this repository, ready for defining frontend-specific infrastructure (S3, CloudFront in Story 3.6).
**Story 3.2: Frontend API Service Layer for Backend Communication**
* **User Story Statement:** As a Frontend Developer, I need a dedicated and well-typed API service layer (e.g., `lib/api-client.ts`) within the Next.js frontend application to manage all HTTP communication with the "BMad Daily Digest" backend API (for fetching episode lists and specific episode details), so that UI components can cleanly and securely consume backend data with robust error handling.
* **Acceptance Criteria (ACs):**
1. A TypeScript module `lib/api-client.ts` (or similar) **must** encapsulate backend API interactions.
2. Functions **must** exist for: `getEpisodes(): Promise<EpisodeListItem[]>` and `getEpisodeDetails(episodeId: string): Promise<EpisodeDetail | null>`.
3. `axios` (or native `Workspace` with a wrapper if preferred for frontend) **must** be used for HTTP requests.
4. Backend API base URL (`NEXT_PUBLIC_BACKEND_API_URL`) and Frontend Read API Key (`NEXT_PUBLIC_FRONTEND_API_KEY`) **must** be configurable via public environment variables and used in requests.
5. TypeScript interfaces (`EpisodeListItem`, `EpisodeDetail`, `SourceHNPostDetail` from `lib/types.ts`) for API response data **must** be defined/used, matching backend API.
6. API functions **must** correctly parse JSON responses and transform data into defined interfaces.
7. Error handling (network errors, non-2xx responses from backend) **must** be implemented, providing clear error information/objects.
8. Unit tests (Jest) **must** mock the HTTP client and verify API calls, data parsing/transformation, and error handling. All tests **must** pass.
**Story 3.3: Episode List Page Implementation**
* **User Story Statement:** As a Busy Tech Executive, I want to view a responsive "Episode List Page" (based on `app/(pages)/episodes/page.tsx` from the scaffold) that clearly displays all available "BMad Daily Digest" episodes in reverse chronological order, showing the episode number, publication date, and podcast title for each, using themed components like `episode-card.tsx`, so that I can quickly find and select an episode.
* **Acceptance Criteria (ACs):**
1. The existing `app/(pages)/episodes/page.tsx` (or equivalent main list page from scaffold) **must** be updated.
2. It **must** use the API service layer (Story 3.2) to fetch episodes.
3. A themed loading state (e.g., using `loading-state.tsx`) **must** be shown.
4. A themed error message (e.g., using `error-state.tsx`) **must** be shown if fetching fails.
5. A "No episodes available yet" message **must** be shown for an empty list.
6. Episodes **must** be listed in reverse chronological order.
7. Each list item, potentially using a modified `episode-card.tsx` component, **must** display "Episode [EpisodeNumber]: [PublicationDate] - [PodcastGeneratedTitle]".
8. Each item **must** link to the Episode Detail Page for that episode using its `episodeId`.
9. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
10. The page **must** be responsive.
11. Unit/integration tests (Jest with RTL) **must** cover all states, data display, order, and navigation. All tests **must** pass.
**Story 3.4: Episode Detail Page Implementation**
* **User Story Statement:** As a Busy Tech Executive, after selecting an episode, I want to navigate to a responsive "Episode Detail Page" (based on `app/(pages)/episodes/[episodeId]/page.tsx`/page.tsx] from the scaffold) that features an embedded HTML5 audio player, displays the episode title/date/number, a list of the Hacker News stories covered (using components like `story-item.tsx`), and provides clear links to the original articles and HN discussions, so I can listen and explore sources.
* **Acceptance Criteria (ACs):**
1. The dynamic route page `app/(pages)/episodes/[episodeId]/page.tsx` **must** be implemented.
2. It **must** accept `episodeId` from the URL.
3. It **must** use the API service layer (Story 3.2) to fetch episode details.
4. Loading and error states **must** be handled and displayed with themed components.
5. If data found, **must** display: `podcastGeneratedTitle`, `publicationDate`, `episodeNumber`.
6. An embedded HTML5 audio player (`<audio controls>`) **must** play the podcast using the public `audioUrl` from the episode details.
7. A list of included Hacker News stories (from `sourceHNPosts`) **must** be displayed, potentially using a `story-item.tsx` component for each.
8. For each HN story: its title, a link to `originalArticleUrl` (new tab), and a link to `hnLink` (new tab) **must** be displayed.
9. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
10. The page **must** be responsive.
11. Unit/integration tests (Jest with RTL) **must** cover all states, rendering of details, player, links. All tests **must** pass.
**Story 3.5: "About" Page Implementation**
* **User Story Statement:** As a User, I want to access a minimalist, responsive "About Page" (based on `app/(pages)/about/page.tsx` from the scaffold) that clearly explains "BMad Daily Digest," its purpose, and how it works, styled consistently, so I can understand the service.
* **Acceptance Criteria (ACs):**
1. The `app/(pages)/about/page.tsx` component **must** be implemented.
2. It **must** display static informational content (Placeholder: "BMad Daily Digest provides a daily audio summary of top Hacker News discussions for busy tech professionals, generated using AI. Our mission is to keep you informed, efficiently. All content is curated and processed to deliver key insights in an easily digestible audio format, presented with a unique retro-tech vibe.").
3. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
4. The page **must** be responsive.
5. A link to "About Page" **must** be accessible from site navigation (e.g., via `header.tsx` or `footer.tsx`).
6. Unit tests (Jest with RTL) for rendering static content. All tests **must** pass.
**Story 3.6: Frontend Deployment to S3 & CloudFront via CDK**
* **User Story Statement:** As a Developer, I need the Next.js frontend application to be configured for static export (or an equivalent static-first deployment model) and have its AWS infrastructure (S3 for hosting, CloudFront for CDN and HTTPS) defined and managed via its own AWS CDK application within the frontend repository. This setup should automate the build and deployment of the static site, making the "BMad Daily Digest" web application publicly accessible, performant, and cost-effective.
* **Acceptance Criteria (ACs):**
1. Next.js app **must** be configured for static export suitable for S3/CloudFront.
2. The AWS CDK app within `bmad-daily-digest-frontend/cdk/` (from Story 3.1) **must** define the S3 bucket and CloudFront distribution.
3. CDK stack **must** define: S3 bucket (static web hosting), CloudFront distribution (S3 origin, HTTPS via default CloudFront domain or ACM cert for custom domain if specified for MVP, caching, OAC/OAI).
4. A `package.json` build script **must** generate the static output.
5. The CDK deployment process (`cdk deploy` run via CI or manually for MVP) **must** include steps/hooks to build the Next.js app and sync static files to S3.
6. Application **must** be accessible via its CloudFront URL.
7. All MVP functionalities **must** be operational on the deployed site.
8. HTTPS **must** be enforced.
9. CDK code **must** meet project standards.

View File

@@ -0,0 +1,320 @@
# BMad Daily Digest Frontend Architecture Document
**Version:** 0.1
**Date:** May 20, 2025
**Author:** Jane (Design Architect) & User
## Table of Contents
1. Introduction
2. Overall Frontend Philosophy & Patterns
3. Detailed Frontend Directory Structure
4. Component Breakdown & Implementation Details
- Component Naming & Organization
- Template for Component Specification
- Example Key Custom Component: `EpisodeCard`
5. State Management In-Depth
6. API Interaction Layer (`lib/api-client.ts`)
7. Routing Strategy
8. Build, Bundling, and Deployment
9. Frontend Testing Strategy
10. Accessibility (AX) Implementation Details
11. Performance Considerations
12. Internationalization (i18n) and Localization (l10n) Strategy
13. Feature Flag Management
14. Frontend Security Considerations
15. Browser Support and Progressive Enhancement
16. Change Log
---
## 1\. Introduction
This document details the technical architecture specifically for the frontend of "BMad Daily Digest." It complements the main "BMad Daily Digest" System Architecture Document (v0.1) and the UI/UX Specification (v0.1). This document builds upon the foundational decisions (e.g., overall tech stack, CI/CD, primary testing tools) defined in the System Architecture Document and the visual/UX direction from the UI/UX Specification. The initial frontend structure has been scaffolded using an AI UI generation tool (V0.dev), and this document outlines how that scaffold will be developed into the full MVP application.
- **Link to Main System Architecture Document (REQUIRED):** `docs/architecture.md` (Conceptual path, refers to the doc created by Fred).
- **Link to UI/UX Specification (REQUIRED):** `docs/ui-ux-specification.md` (Conceptual path, refers to the doc we created).
- **Link to Primary Design Files (Figma, Sketch, etc.):** As per UI/UX Spec, detailed visual mockups in separate design files are not planned for MVP. Design is derived from UI/UX Spec and this document.
- **Link to Deployed Storybook / Component Showcase:** Not an initial deliverable for MVP. May evolve post-MVP.
- **Link to Frontend Source Code Repository:** `bmad-daily-digest-frontend` (GitHub).
## 2\. Overall Frontend Philosophy & Patterns
The frontend for "BMad Daily Digest" aims for a unique user experience based on an "80s retro CRT terminal" aesthetic, while being efficient, responsive, and maintainable.
- **Framework & Core Libraries:** Next.js (vLatest stable, e.g., 14.x, using App Router) with React (vLatest stable, e.g., 18.x) and TypeScript. These are derived from the "Definitive Tech Stack Selections" in the System Architecture Document.
- **Component Architecture:**
- Leverage **shadcn/ui** components as a base for building accessible and customizable UI elements.
- These components will be heavily themed using **Tailwind CSS** to match the "80s retro CRT terminal" style.
- Custom components (like `EpisodeCard`, `StoryItem` from the V0 scaffold) will be developed for application-specific needs, following a presentational/container pattern where appropriate, though for many Next.js App Router components, data fetching will be co-located or handled by Server Components if applicable to the static export strategy.
- **State Management Strategy (MVP):**
- Primarily **local component state** (`useState`, `useReducer`) for UI-specific logic.
- **React Context API** for simple, shared state if needed across a limited part of the component tree (e.g., `ThemeProvider` from V0 scaffold).
- No complex global state management library (like Redux or Zustand) is planned for the MVP, as the application's state needs are currently simple (fetching and displaying data). This can be reassessed post-MVP if complexity grows.
- **Data Flow:** Client-side data fetching via the API Interaction Layer (`lib/api-client.ts`) which communicates with the backend API. Next.js App Router conventions for data fetching in pages/components will be used (e.g., `async` Server Components, or `useEffect` in Client Components for data fetching).
- **Styling Approach:**
- **Tailwind CSS:** Primary utility-first framework for all styling. Configuration in `tailwind.config.ts`.
- **Global Styles:** Base styles, CSS variable definitions for the theme (e.g., glowing green color, retro fonts), and Tailwind base/components/utilities in `app/globals.css`.
- The "80s retro CRT terminal" aesthetic (dark mode, glowing green text, monospaced/pixel fonts) is paramount.
- **Key Design Patterns Used:**
- Server Components & Client Components (Next.js App Router).
- Custom Hooks (e.g., `use-mobile.tsx`, `use-toast.ts` from V0 scaffold) for reusable logic.
- Composition over inheritance for UI components.
## 3\. Detailed Frontend Directory Structure
The project structure is based on the initial V0.dev scaffold for `bmad-daily-digest-frontend` and standard Next.js App Router conventions. The `cdk/` directory is added for managing frontend-specific AWS infrastructure.
```plaintext
bmad-daily-digest-frontend/
├── .github/ # GitHub Actions for CI/CD
│ └── workflows/
│ └── main.yml
├── app/ # Next.js App Router
│ ├── (pages)/ # Route group for main pages (as per V0 screenshot)
│ │ ├── episodes/ # Route group for episodes
│ │ │ ├── page.tsx # List Page (e.g., /episodes or /)
│ │ │ └── [episode-id]/ # Dynamic route for episode detail
│ │ │ └── page.tsx # Detail Page (e.g., /episodes/123)
│ │ └── about/
│ │ └── page.tsx # About Page (e.g., /about)
│ ├── globals.css # Global styles, Tailwind base
│ └── layout.tsx # Root layout, includes ThemeProvider
├── components/ # UI components
│ ├── ui/ # Base UI elements (likely shadcn/ui based, themed)
│ ├── episode-card.tsx # Custom component for episode list items
│ ├── error-state.tsx # Component for displaying error states
│ ├── footer.tsx # Footer component
│ ├── header.tsx # Header component with navigation
│ ├── loading-state.tsx # Component for displaying loading states
│ └── story-item.tsx # Component for HN story items on detail page
├── cdk/ # AWS CDK application for frontend infra (S3, CloudFront)
│ ├── bin/ # CDK app entry point
│ └── lib/ # CDK stack definitions
├── hooks/ # Custom React Hooks
│ ├── use-mobile.tsx
│ └── use-toast.ts
├── lib/ # Utility functions, types, API client
│ ├── data.ts # Initial V0 mock data (TO BE REMOVED/REPLACED)
│ ├── types.ts # Frontend-specific TypeScript types (e.g., API responses)
│ ├── utils.ts # Utility functions
│ └── api-client.ts # NEW: Service for backend API communication
├── public/ # Static assets (e.g., favicons, images if any)
├── styles/ # Additional global styles or CSS modules (if any)
├── .env.local.example # Example environment variables
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── components.json # shadcn/ui configuration
├── jest.config.js
├── next-env.d.ts
├── next.config.mjs # Next.js configuration
├── package.json
├── package-lock.json
├── postcss.config.js # For Tailwind CSS
├── README.md
├── tailwind.config.ts
└── tsconfig.json
```
**Key Directory Descriptions:**
- `app/`: Core Next.js App Router directory for pages, layouts, and global styles. The `(pages)` group organizes user-facing routes.
- `components/`: Contains reusable React components, with `ui/` for base shadcn/ui elements (customized for the theme) and other files for application-specific composite components (e.g., `episode-card.tsx`).
- `cdk/`: Houses the AWS CDK application for defining and deploying the frontend's S3 bucket and CloudFront distribution.
- `hooks/`: For custom React Hooks providing reusable stateful logic.
- `lib/`: For shared utilities (`utils.ts`), TypeScript type definitions (`types.ts`), and crucially, the `api-client.ts` which will encapsulate all communication with the backend. The initial `data.ts` (mock data from V0) will be phased out as `api-client.ts` is implemented.
- Root configuration files (`next.config.mjs`, `tailwind.config.ts`, `tsconfig.json`, etc.) manage the Next.js, Tailwind, and TypeScript settings.
## 4\. Component Breakdown & Implementation Details
Components will be developed adhering to React best practices and Next.js App Router conventions (Server and Client Components). The V0 scaffold provides a good starting point for several components (`episode-card.tsx`, `header.tsx`, etc.) which will be refined and made dynamic.
### a. Component Naming & Organization
- **Naming Convention:** `PascalCase` for component file names and component names themselves (e.g., `EpisodeCard.tsx`, `LoadingState.tsx`). Folder names for components (if grouping) will be `dash-case`.
- **Organization:** Shared, primitive UI elements (heavily themed shadcn/ui components) in `components/ui/`. More complex, domain-specific components directly under `components/` (e.g., `EpisodeCard.tsx`) or grouped into feature-specific subdirectories if the application grows significantly post-MVP.
### b. Template for Component Specification
_(This template should be used when defining new significant components or detailing existing ones that require complex logic or props. For many simple V0-generated presentational components, this level of formal spec might be overkill for MVP if their structure is clear from the code and UI/UX spec)._
#### Component: `{ComponentName}` (e.g., `EpisodeCard`, `StoryItem`)
- **Purpose:** {Briefly describe what this component does and its role.}
- **Source File(s):** {e.g., `components/episode-card.tsx`}
- **Visual Reference from UI/UX Spec:** {Link to relevant section/description in UI/UX Spec or conceptual layout.}
- **Props (Properties):**
| Prop Name | Type | Required? | Default Value | Description |
| :-------------- | :------------------------ | :-------- | :------------ | :---------------------------------------- |
| `{propName}` | `{type}` | Yes/No | N/A | {Description, constraints} |
- **Internal State (if any):**
| State Variable | Type | Initial Value | Description |
| :-------------- | :------- | :------------ | :---------------------------------------- |
| `{stateName}` | `{type}` | `{value}` | {Description} |
- **Key UI Elements / Structure (Conceptual JSX/HTML):** {Describe the primary DOM structure and key elements, especially focusing on thematic styling classes from Tailwind.}
- **Events Handled / Emitted:** {e.g., `onClick` for navigation, custom events.}
- **Actions Triggered (Side Effects):** {e.g., API calls via `apiClient`, state updates.}
- **Styling Notes:** {Key Tailwind classes, specific retro theme applications.}
- **Accessibility Notes:** {ARIA attributes, keyboard navigation specifics.}
### c. Example Key Custom Component: `EpisodeCard.tsx`
_(This is an example of how the template might be briefly applied to an existing V0 component that needs to be made dynamic)._
- **Purpose:** Displays a single episode summary in the Episode List Page, acting as a link to the Episode Detail Page.
- **Source File(s):** `components/episode-card.tsx`
- **Props:**
| Prop Name | Type | Required? | Description |
| :---------------------- | :------------------------------------ | :-------- | :----------------------------------------------- |
| `episode` | `EpisodeListItem` (from `lib/types.ts`) | Yes | Data object for the episode to display. |
- **Key UI Elements / Structure:**
- A clickable root container (e.g., `Link` component from Next.js).
- Displays "Episode `episode.episodeNumber`: `episode.publicationDate` - `episode.podcastGeneratedTitle`" using themed text components.
- Styled with Tailwind to match the "80s retro CRT terminal" aesthetic.
- **Actions Triggered:** Navigates to `/episodes/${episode.episodeId}` on click.
- **Styling Notes:** Uses primary glowing green text on dark background. Clear hover/focus state.
- **Accessibility Notes:** Ensures the entire card is keyboard focusable and clearly indicates it's a link.
## 5\. State Management In-Depth
For the MVP, the state management strategy will be kept simple and align with modern React/Next.js best practices, leveraging built-in capabilities.
- **Chosen Solution(s):**
- **Local Component State (`useState`, `useReducer`):** This will be the primary method for managing UI-specific state within individual components (e.g., dropdown open/close, input field values, loading states for component-specific data fetches).
- **React Context API:** Will be used for sharing simple, global-like state that doesn't change frequently, such as theme information (e.g., the `ThemeProvider` from the V0 scaffold if it manages aspects of the dark mode or retro theme dynamically) or potentially user authentication status if added post-MVP. For MVP, its use will be minimal.
- **URL State:** Next.js App Router's dynamic routes and search parameters will be used to manage state where appropriate (e.g., current `episodeId` in the URL).
- **No Global State Library for MVP:** A dedicated global state management library (e.g., Redux Toolkit, Zustand, Jotai, Zustand) is **not planned for the initial MVP** due to the current simplicity of application-wide state requirements. Data fetching will be handled by components or page-level Server Components, with data passed down via props or managed via React Context if shared across a limited tree. This decision can be revisited post-MVP if state complexity grows.
- **Conventions:**
- Keep state as close as possible to where it's used.
- Lift state up only when necessary for sharing between siblings.
- For data fetched from the API, components will typically manage their own loading/error/data states locally (e.g., using custom hooks that wrap calls to `apiClient.ts`).
## 6\. API Interaction Layer (`lib/api-client.ts`)
This module will encapsulate all communication with the `bmad-daily-digest-backend` API.
- **HTTP Client Setup:**
- Will use the browser's native **`Workspace` API**, wrapped in utility functions within `api-client.ts` for ease of use, error handling, and request/response processing.
- The Backend API Base URL will be sourced from the `NEXT_PUBLIC_BACKEND_API_URL` environment variable.
- The "Frontend Read API Key" (if decided upon for backend API access, as discussed with Fred) will be sourced from `NEXT_PUBLIC_FRONTEND_API_KEY` and included in requests via the `x-api-key` header.
- **Service Functions (examples):**
- `async function getEpisodes(): Promise<EpisodeListItem[]>`: Fetches the list of all episodes.
- `async function getEpisodeDetails(episodeId: string): Promise<EpisodeDetail | null>`: Fetches details for a specific episode.
- These functions will handle constructing request URLs, adding necessary headers (API Key, `Content-Type: application/json` for POST/PUT if any), making the `Workspace` call, parsing JSON responses, and transforming data into the frontend TypeScript types defined in `lib/types.ts`.
- **Error Handling:**
- The `api-client.ts` functions will implement robust error handling for network issues and non-successful HTTP responses from the backend.
- Errors will be processed and returned in a consistent format (e.g., throwing a custom `ApiError` object or returning a result object like `{ data: null, error: { message: string, status?: number } }`) that UI components can easily consume to display appropriate feedback to the user (using `error-state.tsx` component).
- Detailed errors will be logged to the browser console for debugging during development.
- **Data Types:** All request and response payloads will be typed using interfaces defined in `lib/types.ts`, aligning with the backend API's data models.
## 7\. Routing Strategy
Routing will be handled by the **Next.js App Router**, leveraging its file-system based routing conventions.
- **Routing Library:** Next.js App Router (built-in).
- **Route Definitions (MVP):**
| Path Pattern | Page Component File Path (`app/...`) | Protection | Notes |
| :--------------------- | :------------------------------------------ | :------------- | :---------------------------------- |
| `/` or `/episodes` | `(pages)/episodes/page.tsx` | Public | Episode List Page (Homepage) |
| `/episodes/[episodeId]`| `(pages)/episodes/[episodeId]/page.tsx` | Public | Episode Detail Page (Dynamic route) |
| `/about` | `(pages)/about/page.tsx` | Public | About Page |
- **Route Guards / Protection (MVP):** No specific client-side route protection (e.g., auth guards) is required for the MVP, as all content is public. The backend API endpoints used by the frontend are protected by an API Key.
## 8\. Build, Bundling, and Deployment
This section aligns with the "Frontend Deployment to S3 & CloudFront via CDK" (Story 3.6) from the PRD and System Architecture Document.
- **Build Process & Scripts (`package.json`):**
- `"dev": "next dev"`: Starts the Next.js development server.
- `"build": "next build"`: Builds the application for production. For static export, this may be followed by `next export` if using an older Next.js pattern, or newer Next.js versions handle static/hybrid output more directly with the build command for S3/CloudFront compatible deployment. We will aim for a fully static export if all pages support it.
- `"start": "next start"`: Starts a production server (less relevant for pure SSG to S3, but good for local production testing).
- `"lint": "next lint"`
- `"test": "jest"`
- **Environment Configuration Management:**
- Public environment variables (prefixed with `NEXT_PUBLIC_`) like `NEXT_PUBLIC_BACKEND_API_URL` and `NEXT_PUBLIC_FRONTEND_API_KEY` will be managed via `.env.local` (gitignored), `.env.development`, `.env.production` files, and corresponding build-time environment variables in the CI/CD deployment process.
- **Key Bundling Optimizations (largely handled by Next.js):**
- **Code Splitting:** Automatic per-page code splitting by Next.js. Dynamic imports (`next/dynamic` or `React.lazy`) can be used for further component-level splitting if needed post-MVP.
- **Tree Shaking:** Handled by Next.js's underlying Webpack/SWC bundler.
- **Lazy Loading:** Next.js `next/image` component for image lazy loading. `next/dynamic` for component lazy loading.
- **Minification & Compression:** Handled by Next.js production build.
- **Deployment to S3/CloudFront (via Frontend CDK App):**
- The `next build` (and potentially `next export` if using that pattern) output will be synced to an AWS S3 bucket configured for static website hosting.
- An AWS CloudFront distribution will serve the content from S3, providing CDN caching, HTTPS, and custom domain support (post-MVP for custom domain).
- The CDK app in the `bmad-daily-digest-frontend` repository will manage this S3 bucket and CloudFront distribution.
## 9\. Frontend Testing Strategy
This elaborates on the "Overall Testing Strategy" from the System Architecture Document, focusing on frontend specifics. E2E testing with Playwright is post-MVP.
- **Tools:** Jest with React Testing Library (RTL) for unit and component integration tests.
- **Unit Tests:**
- **Scope:** Individual utility functions, custom hooks, and simple presentational components.
- **Focus:** Logic correctness, handling of different inputs/props.
- **Component Tests / UI Integration Tests (using RTL):**
- **Scope:** Testing individual React components or small groups of interacting components in isolation from the full application, but verifying their rendering, interactions, and basic state changes.
- **Focus:** Correct rendering based on props/state, user interactions (clicks, form inputs if any using `@testing-library/user-event`), event emission, accessibility attributes. API calls from components (via `apiClient.ts`) will be mocked.
- **Location:** Co-located with components (e.g., `MyComponent.test.tsx`).
- **Test Coverage:** Aim for meaningful coverage of critical components and logic (\>70-80% as a guideline). Quality over quantity.
- **Mocking:** Jest mocks for API service layer (`apiClient.ts`), Next.js router (`next/router` or `next/navigation`), and any browser APIs not available in JSDOM.
## 10\. Accessibility (AX) Implementation Details
This section details how the AX requirements from the UI/UX Specification will be technically implemented.
- **Semantic HTML:** Prioritize using correct HTML5 elements (e.g., `<nav>`, `<main>`, `<article>`, `<button>`) as provided by Next.js and React, or within custom JSX, to ensure inherent accessibility.
- **ARIA Implementation:** `shadcn/ui` components generally provide good ARIA support out-of-the-box. For any custom components or interactions not covered, appropriate ARIA roles, states, and properties will be added as per WAI-ARIA authoring practices.
- **Keyboard Navigation:** Ensure all interactive elements (links, custom components from shadcn/ui, audio player) are focusable and operable via keyboard. Logical focus order will be maintained. Focus visible styles will adhere to the retro theme (e.g., brighter green outline or block cursor).
- **Focus Management:** For any future modals or dynamic UI changes that might trap focus, proper focus management techniques will be implemented.
- **Contrast & Theming:** The "80s retro CRT terminal" theme (glowing green on dark) requires careful selection of shades to meet WCAG AA contrast ratios for text. This will be verified using accessibility tools during development and testing.
- **Testing Tools for AX:**
- Browser extensions like Axe DevTools or WAVE during development.
- Automated checks using `jest-axe` for component tests where applicable.
- Lighthouse accessibility audits in browser developer tools.
- Manual keyboard navigation and screen reader (e.g., NVDA, VoiceOver) checks for key user flows.
## 11\. Performance Considerations
Frontend performance is key for a good user experience, especially for busy executives.
- **Next.js Optimizations:** Leverage built-in Next.js features:
- Static Site Generation (SSG) for all pages where possible for fastest load times.
- `next/image` for optimized image loading (formats, sizes, lazy loading), though MVP is text-heavy.
- `next/font` for optimized web font loading if custom retro fonts are used.
- Automatic code splitting.
- **Minimizing Re-renders (React):** Use `React.memo` for components that render frequently with the same props. Optimize data structures passed as props. Use `useCallback` and `useMemo` judiciously for expensive computations or to preserve reference equality for props.
- **Bundle Size:** Monitor frontend bundle size. While Next.js optimizes, be mindful of large dependencies. Use dynamic imports for non-critical, large components/libraries if they arise post-MVP.
- **Efficient Data Fetching:** Ensure API calls via `apiClient.ts` are efficient and only fetch necessary data for each view.
- **Debouncing/Throttling:** Not anticipated for MVP core features, but if any real-time input features were added post-MVP (e.g., search), these techniques would be applied.
- **Performance Monitoring Tools:** Browser DevTools (Lighthouse, Performance tab), Next.js build output analysis.
## 12\. Internationalization (i18n) and Localization (l10n) Strategy
- **Not a requirement for MVP.** The application will be developed in English only. This can be revisited post-MVP if there's a need to support other languages.
## 13\. Feature Flag Management
- **Not a requirement for MVP.** No complex feature flagging system will be implemented for the initial release. New features will be released directly.
## 14\. Frontend Security Considerations
Aligns with "Security Best Practices" in the System Architecture Document.
- **XSS Prevention:** Rely on React's JSX auto-escaping. Avoid `dangerouslySetInnerHTML`.
- **API Key Handling:** The `NEXT_PUBLIC_FRONTEND_API_KEY` for accessing the backend API will be embedded in the static build. While "public," it's specific to this frontend and can be rotated if necessary. This key should grant minimal (read-only) privileges on the backend.
- **Third-Party Scripts:** Minimize use for MVP. If any are added (e.g., analytics post-MVP), vet for security and use Subresource Integrity (SRI) if loaded from CDNs.
- **HTTPS:** Enforced by CloudFront.
- **Dependency Vulnerabilities:** `npm audit` in CI.
## 15\. Browser Support and Progressive Enhancement
- **Target Browsers:** Latest 2 stable versions of modern evergreen browsers (Chrome, Firefox, Safari, Edge). Internet Explorer is NOT supported.
- **Polyfill Strategy:** Next.js handles most necessary polyfills based on browser targets and features used. `core-js` might be implicitly included.
- **JavaScript Requirement:** The application is a Next.js (React) Single Page Application and **requires JavaScript to be enabled** for all functionality. No significant progressive enhancement for non-JS environments is planned for MVP.
- **CSS Compatibility:** Use Tailwind CSS with Autoprefixer (handled by Next.js build process) to ensure CSS compatibility with target browsers.
## 16\. Change Log
| Version | Date | Author | Summary of Changes |
| :------ | :----------- | :----------------------------- | :--------------------------------------------------- |
| 0.1 | May 20, 2025 | Jane (Design Architect) & User | Initial draft of the Frontend Architecture Document. |

View File

@@ -0,0 +1,37 @@
# BMad Daily Digest Documentation
Welcome to the BMad Daily Digest documentation index. This page provides links to all project documentation.
## Project Overview & Requirements
- [Product Requirements Document (PRD)](./prd.md)
- [UI/UX Specification](./ux-ui-spec.md)
- [Architecture Overview](./architecture.md)
## Epics & User Stories
- [Epic 1: Backend Foundation](./epic-1.md) - Backend project setup and "Hello World" API
- [Epic 2: Content Ingestion & Podcast Generation](./epic-2.md) - Core data pipeline and podcast creation
- [Epic 3: Web Application & Podcast Consumption](./epic-3.md) - Frontend implementation for end-users
## Technical Documentation
### Backend Architecture
- [API Reference](./api-reference.md) - External and internal API documentation
- [Data Models](./data-models.md) - Core data entities and schemas
- [Component View](./component-view.md) - System components and their interactions
- [Sequence Diagrams](./sequence-diagrams.md) - Core workflows and processes
- [Project Structure](./project-structure.md) - Repository organization
- [Environment Variables](./environment-vars.md) - Configuration settings
### Infrastructure & Operations
- [Technology Stack](./tech-stack.md) - Definitive technology selections
- [Infrastructure and Deployment](./infra-deployment.md) - Deployment architecture
- [Operational Guidelines](./operational-guidelines.md) - Coding standards, testing, error handling, and security
## Reference Materials
- [Key References](./key-references.md) - External documentation and resources
- [Change Log](./change-log.md) - Document version history

View File

@@ -0,0 +1,8 @@
# Infrastructure and Deployment Overview
* **Cloud Provider:** AWS.
* **Core Services Used:** Lambda, API Gateway (HTTP API), S3, DynamoDB (On-Demand), Step Functions, EventBridge Scheduler, CloudFront, CloudWatch, IAM, ACM (if custom domain).
* **IaC:** AWS CDK (TypeScript), with separate CDK apps in backend and frontend polyrepos.
* **Deployment Strategy (MVP):** CI (GitHub Actions) for build/test/lint. CDK deployment (initially manual or CI-scripted) to a single AWS environment.
* **Environments (MVP):** Local Development; Single Deployed MVP Environment (e.g., "dev" acting as initial production).
* **Rollback Strategy (MVP):** CDK stack rollback, Lambda/S3 versioning, DynamoDB PITR.

View File

@@ -0,0 +1,6 @@
# Key Reference Documents
1. **Product Requirements Document (PRD) - BMad Daily Digest** (Version: 0.1)
2. **UI/UX Specification - BMad Daily Digest** (Version: 0.1)
3. **Algolia Hacker News Search API Documentation** (`https://hn.algolia.com/api`)
4. **Play.ai PlayNote API Documentation** (`https://docs.play.ai/api-reference/playnote/post`)

View File

@@ -0,0 +1,52 @@
# Operational Guidelines
## Coding Standards (Backend: `bmad-daily-digest-backend`)
**Scope:** Applies to `bmad-daily-digest-backend`. Frontend standards are separate.
* **Primary Language:** TypeScript (Node.js 22).
* **Style:** ESLint, Prettier.
* **Naming:** Variables/Functions: `camelCase`. Constants: `UPPER_SNAKE_CASE`. Classes/Interfaces/Types/Enums: `PascalCase`. Files/Folders: `dash-case` (e.g., `episode-service.ts`, `content-ingestion/`).
* **Structure:** Feature-based (`src/features/feature-name/`).
* **Tests:** Unit/integration tests co-located (`*.test.ts`). E2E tests (if any for backend API) in root `tests/e2e/`.
* **Async:** `async`/`await` for Promises.
* **Types:** `strict: true`. No `any` without justification. JSDoc for exported items. Inline comments for clarity.
* **Dependencies:** `npm` with `package-lock.json`. Pin versions or use tilde (`~`).
* **Detailed Conventions:** Immutability preferred. Functional constructs for stateless logic, classes for stateful services/entities. Custom errors. Strict null checks. ESModules. Pino for logging (structured JSON, levels, context, no secrets). Lambda best practices (lean handlers, env vars, optimize size). `axios` with timeouts. AWS SDK v3 modular imports. Avoid common anti-patterns (deep nesting, large functions, `@ts-ignore`, hardcoded secrets, unhandled promises).
## Overall Testing Strategy
* **Tools:** Jest, React Testing Library (frontend), ESLint, Prettier, GitHub Actions.
* **Unit Tests:** Isolate functions/methods/components. Mock dependencies. Co-located. Developer responsibility.
* **Integration Tests (Backend/Frontend):** Test interactions between internal components with external systems mocked (AWS SDK clients, third-party APIs).
* **End-to-End (E2E) Tests (MVP):**
* Backend API: Automated test for "Hello World"/status. Test daily job trigger verifies DDB/S3 output.
* Frontend UI: Key user flows tested manually for MVP. (Playwright deferred to post-MVP).
* **Coverage:** Guideline \>80% unit test coverage for critical logic. Quality over quantity. Measured by Jest.
* **Mocking:** Jest's built-in system. `axios-mock-adapter` if needed.
* **Test Data:** Inline mocks or small fixtures for unit/integration.
## Error Handling Strategy
* **General Approach:** Custom `Error` classes hierarchy. Promises reject with `Error` objects.
* **Logging:** Pino for structured JSON logs to CloudWatch. Standard levels (DEBUG, INFO, WARN, ERROR, CRITICAL). Contextual info (AWS Request ID, business IDs). No sensitive data in logs.
* **Specific Patterns:**
* **External API Calls (`axios`):** Timeouts, retries (e.g., `axios-retry`), wrap errors in custom types.
* **Internal Errors:** Custom error types, detailed server-side logging.
* **API Gateway Responses:** Translate internal errors to appropriate HTTP errors (4xx, 500) with generic client messages.
* **Workflow (Step Functions):** Error handling, retries, catch blocks for states. Failed executions logged.
* **Data Consistency:** Lambdas handle partial failures gracefully. Step Functions manage overall workflow state.
## Security Best Practices
* **Input Validation:** API Gateway basic validation; Zod for detailed payload validation in Lambdas.
* **Output Encoding:** Next.js/React handles XSS for frontend rendering. Backend API is JSON.
* **Secrets Management:** Lambda environment variables via CDK (from local gitignored `.env` for MVP setup). No hardcoding. Pino redaction for logs if needed.
* **Dependency Security:** `npm audit` in CI. Promptly address high/critical vulnerabilities.
* **Authentication/Authorization:** API Gateway API Keys (Frontend Read Key, Admin Action Key). IAM roles with least privilege for service-to-service.
* **Principle of Least Privilege (IAM):** Minimal permissions for all IAM roles (Lambdas, Step Functions, CDK).
* **API Security:** HTTPS enforced by API Gateway/CloudFront. Basic rate limiting on API Gateway. Frontend uses HTTP security headers (via CloudFront/Next.js).
* **Error Disclosure:** Generic errors to client, detailed logs server-side.
* **Infrastructure Security:** S3 bucket access restricted (CloudFront OAC/OAI).
* **Post-MVP:** Consider SAST/DAST, penetration testing.
* **Adherence:** AWS Well-Architected Framework - Security Pillar.

View File

@@ -0,0 +1,428 @@
# BMad Daily Digest Product Requirements Document (PRD)
**Version:** 0.1
**Date:** May 20, 2025
**Author:** JohnAI
## 1. Goal, Objective and Context
* **Overall Goal:** To provide busy tech executives with a quick, daily audio digest of top Hacker News posts and discussions, enabling them to stay effortlessly informed.
* **Project Objective (MVP Focus):** To successfully launch the "BMad Daily Digest" by:
* Automating the daily fetching of top 10 Hacker News posts (article metadata and comments via Algolia HN API) and scraping of linked article content.
* Processing this content into a structured format.
* Generating a 2-agent audio podcast using the play.ai PlayNote API.
* Delivering the podcast via a simple Next.js web application (polyrepo structure) with a list of episodes and detail pages including an audio player and links to source materials.
* Operating this process daily, aiming for delivery by a consistent morning hour.
* Adhering to a full TypeScript stack (Node.js 22 for backend), with a Next.js frontend, AWS Lambda backend, DynamoDB, S3, and AWS CDK for IaC, while aiming to stay within AWS free-tier limits where possible.
* **Context/Problem Solved:** Busy tech executives lack the time to thoroughly read Hacker News daily but need to stay updated on key tech discussions, trends, and news for strategic insights. "BMad Daily Digest" solves this by offering a convenient, curated audio summary.
## 2. Functional Requirements (MVP)
**FR1: Content Acquisition**
* The system **must** automatically fetch data for the top 10 (configurable) posts from Hacker News daily.
* For each Hacker News post, the system **must** identify and retrieve:
* The URL of the linked article.
* Key metadata about the Hacker News post (e.g., title, HN link, score, author, HN Post ID).
* The system **must** fetch comments for each identified Hacker News post using the Algolia HN Search API, with logic to handle new vs. repeat posts and scraping failures differently.
* The system **must** attempt to scrape and extract the primary textual content from the linked article URL for each of the top posts (unless it's a repeat post where only new comments are needed).
* This process should aim to isolate the main article body.
* If scraping fails, a fallback using HN title, summary (if available), and increased comments **must** be used.
**FR2: Content Processing and Formatting**
* The system **must** aggregate the extracted/fallback article content and selected comments for the top 10 posts.
* The system **must** process and structure the aggregated text content into a single text file suitable for submission to the play.ai PlayNote API.
* The text file **must** begin with an introductory sentence: "It's a top 10 countdown for [Today'sDate]".
* Content **must** be structured sequentially (e.g., "Story 10 - [details]..."), with special phrasing for repeat posts or posts where article scraping failed.
* Article content may be truncated if `MAX_ARTICLE_LENGTH` is set, preserving intro/conclusion where possible.
**FR3: Podcast Generation**
* The system **must** submit the formatted text content to the play.ai PlayNote API daily using specified voice and style parameters (configurable via environment variables).
* The system **must** capture the `jobId` from Play.ai and use a polling mechanism (e.g., AWS Step Functions) to check for job completion status.
* Upon successful completion, the system **must** retrieve the generated audio podcast file from the Play.ai-provided URL.
* The system **must** store the generated audio file (e.g., on S3) and its associated metadata (including episode number, generated title, S3 location, original Play.ai URL, source HN posts, and processing status) in DynamoDB.
**FR4: Web Application Interface (MVP)**
* The system **must** provide a web application (Next.js, "80s retro CRT terminal" theme with Tailwind CSS & shadcn/ui) with a **List Page** that:
* Displays a chronological list (newest first) of all generated "BMad Daily Digest" episodes, formatted as "Episode [EpisodeNumber]: [PublicationDate] - [PodcastTitle]".
* Allows users to navigate to a Detail Page for each episode.
* The system **must** provide a web application with a **Detail Page** for each episode that:
* Displays the `podcastGeneratedTitle`, `publicationDate`, and `episodeNumber`.
* Includes an embedded HTML5 audio player for the podcast.
* Lists the individual Hacker News stories included, with direct links to the original source article and the Hacker News discussion page.
* The system **must** provide a minimalist **About Page**.
* The web application **must** be responsive.
**FR5: Automation and Scheduling**
* The entire end-to-end backend process **must** be orchestrated (preferably via AWS Step Functions) and automated to run daily, triggered by Amazon EventBridge Scheduler (default 12:00 UTC, configurable).
* For MVP, a re-run of the daily job for the same day **must** overwrite/start over previous data for that day.
## 3. Non-Functional Requirements (MVP)
**a. Performance:**
* **Podcast Generation Time:** The daily process should complete in a timely manner (e.g., target by 8 AM CST/12:00-13:00 UTC, specific completion window TBD based on Play.ai processing).
* **Web Application Load Time:** Pages on the Next.js app should aim for fast load times (e.g., target under 3-5 seconds).
**b. Reliability / Availability:**
* **Daily Process Success Rate:** Target >95% success rate for automated podcast generation without manual intervention.
* **Web Application Uptime:** Target 99.5%+ uptime.
**c. Maintainability:**
* **Code Quality:** Code **must** be well-documented. Internal code comments **should** be used when logic isn't clear from names. All functions **must** have JSDoc-style outer comments. Adherence to defined coding standards (ESLint, Prettier).
* **Configuration Management:** System configurations and secrets **must** be managed via environment variables (`.env` locally, Lambda environment variables when deployed), set manually for MVP.
**d. Usability (Web Application):**
* The web application **must** be intuitive for busy tech executives.
* The audio player **must** be simple and reliable.
* Accessibility: Standard MVP considerations, with particular attention to contrast for the "glowing green on dark" theme, good keyboard navigation, and basic screen reader compatibility.
**e. Security (MVP Focus):**
* **API Key Management:** Keys for Algolia, Play.ai, AWS **must** be stored securely (gitignored `.env` files locally, Lambda environment variables in AWS), not hardcoded.
* **Data Handling:** Scraped content handled responsibly.
**f. Cost Efficiency:**
* AWS service usage **must** aim to stay within free-tier limits where feasible. Play.ai usage is via existing user subscription.
## 4. User Interaction and Design Goals
**a. Overall Vision & Experience:**
* **Look and Feel:** Dark mode UI, "glowing green ASCII/text on a black background" aesthetic (CRT terminal style), "80s retro everything" theme.
* **UI Component Toolkit:** Tailwind CSS and shadcn/ui, customized for the theme. Initial structure/components kickstarted by an AI UI generation tool.
* **User Experience:** Highly efficient, clear navigation, no clutter, prioritizing content readability for busy tech executives.
**b. Key Interaction Paradigms (MVP):**
* View list of digests (reverse chronological), select one for details. No sorting/filtering on list page for MVP.
**c. Core Screens/Views (MVP):**
* **List Page:** Episodes ("Episode [N]: [Date] - [PodcastTitle]").
* **Detail Page:** Episode details, HTML5 audio player, list of source HN stories with links to articles and HN discussions.
* **About Page:** Minimalist, explaining the service, consistent theme.
**d. Accessibility Aspirations (MVP):**
* Standard considerations: good contrast (critical for theme), keyboard navigation, basic screen reader compatibility.
**e. Branding Considerations (High-Level):**
* "80s retro everything" theme is central. Logo/typeface should complement this (e.g., pixel art, retro fonts).
**f. Target Devices/Platforms:**
* Responsive web application, good UX on desktop and mobile.
## 5. Technical Assumptions
**a. Core Technology Stack & Approach:**
* **Full TypeScript Stack:** TypeScript for frontend and backend.
* **Frontend:** Next.js (React), Node.js 22. Styling: Tailwind CSS, shadcn/ui. Hosting: Static site on AWS S3 (via CloudFront).
* **Backend:** Node.js 22, TypeScript. HTTP Client: `axios`. Compute: AWS Lambda. Database: AWS DynamoDB.
* **Infrastructure as Code (IaC):** All AWS infrastructure via AWS CDK.
* **Key External Services/APIs:** Algolia HN Search API (posts/comments), Play.ai PlayNote API (audio gen, user has subscription, polling for status), Custom scraping for articles (TypeScript with Cheerio, Readability.js, potentially Puppeteer/Playwright).
* **Automation:** Daily trigger via Amazon EventBridge Scheduler. Orchestration via AWS Step Functions.
* **Configuration & Secrets:** Environment variables (`.env` local & gitignored, Lambda env vars).
* **Coding Standards:** JSDoc for functions, inline comments for clarity. ESLint, Prettier.
**b. Repository Structure & Service Architecture:**
* **Repository Structure:** Polyrepo (separate Git repositories for `bmad-daily-digest-frontend` and `bmad-daily-digest-backend`).
* **High-Level Service Architecture:** Backend is serverless functions (AWS Lambda) for distinct tasks, orchestrated by Step Functions. API layer via AWS API Gateway to expose backend to frontend.
## 6. Epic Overview
This section details the Epics and their User Stories for the MVP.
**Epic 1: Backend Foundation, Tooling & "Hello World" API**
* **Goal:** To establish the core backend project infrastructure in its dedicated repository, including robust development tooling and initial AWS CDK setup for essential services. By the end of this epic:
1. A simple "hello world" API endpoint (AWS API Gateway + Lambda) **must** be deployed and testable via `curl`, returning a dynamic message.
2. The backend project **must** have ESLint, Prettier, Jest (unit testing), and esbuild (TypeScript bundling) configured and operational.
3. Basic unit tests **must** exist for the "hello world" Lambda function.
4. Code formatting and linting checks **should** be integrated into a pre-commit hook and/or a basic CI pipeline stub.
* **User Stories for Epic 1:**
**Story 1.1: Initialize Backend Project using TS-TEMPLATE-STARTER**
* **User Story Statement:** As a Developer, I want to create the `bmad-daily-digest-backend` Git repository and initialize it using the existing `TS-TEMPLATE-STARTER`, ensuring all foundational tooling (TypeScript, Node.js 22, ESLint, Prettier, Jest, esbuild) is correctly configured and operational for this specific project, so that I have a high-quality, standardized development environment ready for application logic.
* **Acceptance Criteria (ACs):**
1. A new, private Git repository named `bmad-daily-digest-backend` **must** be created on GitHub.
2. The contents of the `TS-TEMPLATE-STARTER` project **must** be copied/cloned into this new repository.
3. `package.json` **must** be updated (project name, version, description).
4. Project dependencies **must** be installable.
5. TypeScript setup (`tsconfig.json`) **must** be verified for Node.js 22, esbuild compatibility; project **must** compile.
6. ESLint and Prettier configurations **must** be operational; lint/format scripts **must** execute successfully.
7. Jest configuration **must** be operational; test scripts **must** execute successfully with any starter example tests.
8. Irrelevant generic demo code from starter **should** be removed. `index.ts`/`index.test.ts` can remain as placeholders.
9. A standard `.gitignore` and an updated project `README.md` **must** be present.
**Story 1.2: Pre-commit Hook Implementation**
* **User Story Statement:** As a Developer, I want pre-commit hooks automatically enforced in the `bmad-daily-digest-backend` repository, so that code quality standards (like linting and formatting) are checked and applied to staged files before any code is committed, thereby maintaining codebase consistency and reducing trivial errors.
* **Acceptance Criteria (ACs):**
1. A pre-commit hook tool (e.g., Husky) **must** be installed and configured.
2. A tool for running linters/formatters on staged files (e.g., `lint-staged`) **must** be installed and configured.
3. Pre-commit hook **must** trigger `lint-staged` on staged `.ts` files.
4. `lint-staged` **must** be configured to run ESLint (`--fix`) and Prettier (`--write`).
5. Attempting to commit files with auto-fixable issues **must** result in fixes applied and successful commit.
6. Attempting to commit files with non-auto-fixable linting errors **must** abort the commit with error messages.
7. Committing clean files **must** proceed without issues.
**Story 1.3: "Hello World" Lambda Function Implementation & Unit Tests**
* **User Story Statement:** As a Developer, I need a simple "Hello World" AWS Lambda function implemented in TypeScript within the `bmad-daily-digest-backend` project. This function, when invoked, should return a dynamic greeting message including the current date and time, and it must be accompanied by comprehensive Jest unit tests, so that our basic serverless compute functionality, testing setup, and TypeScript bundling are validated.
* **Acceptance Criteria (ACs):**
1. A `src/handlers/helloWorldHandler.ts` file (or similar) **must** contain the Lambda handler.
2. Handler **must** be AWS Lambda compatible (event, context, Promise response).
3. Successful execution **must** return JSON: `statusCode: 200`, body with `message: "Hello from BMad Daily Digest Backend, today is [current_date] at [current_time]."`.
4. Date and time in message **must** be dynamic.
5. A corresponding Jest unit test file (e.g., `src/handlers/helloWorldHandler.test.ts`) **must** be created.
6. Unit tests **must** verify: 200 status, valid JSON body, expected `message` field, "Hello from..." prefix, dynamic date/time portion (use mocked `Date`).
7. All unit tests **must** pass.
8. esbuild configuration **must** correctly bundle the handler.
**Story 1.4: AWS CDK Setup for "Hello World" API (Lambda & API Gateway)**
* **User Story Statement:** As a Developer, I want to define the necessary AWS infrastructure (Lambda function and API Gateway endpoint) for the "Hello World" service using AWS CDK (Cloud Development Kit) in TypeScript, so that the infrastructure is version-controlled, repeatable, and can be deployed programmatically.
* **Acceptance Criteria (ACs):**
1. AWS CDK (v2) **must** be a development dependency.
2. CDK app structure **must** be initialized (e.g., in `cdk/` or `infra/`).
3. A new CDK stack (e.g., `BmadDailyDigestBackendStack`) **must** be defined in TypeScript.
4. CDK stack **must** define an AWS Lambda resource for the "Hello World" function (Node.js 22, bundled code reference, handler entry point, basic IAM role for CloudWatch logs, free-tier conscious settings).
5. CDK stack **must** define an AWS API Gateway (HTTP API preferred) with a route (e.g., `GET /hello`) triggering the Lambda.
6. CDK stack **must** be synthesizable (`cdk synth`) without errors.
7. CDK code **must** adhere to project ESLint/Prettier standards.
8. Mechanism for passing Lambda environment variables via CDK (if any needed for "Hello World") **must** be in place.
**Story 1.5: "Hello World" API Deployment & Manual Invocation Test**
* **User Story Statement:** As a Developer, I need to deploy the "Hello World" API (defined in AWS CDK) to an AWS environment and successfully invoke its endpoint using a tool like `curl`, so that I can verify the end-to-end deployment process and confirm the basic API is operational in the cloud.
* **Acceptance Criteria (ACs):**
1. The AWS CDK stack for "Hello World" API **must** deploy successfully to a designated AWS account/region.
2. The API Gateway endpoint URL for `/hello` **must** be retrievable post-deployment.
3. A `GET` request to the deployed `/hello` endpoint **must** receive a response.
4. HTTP response status **must** be 200 OK.
5. Response body **must** be JSON containing the expected dynamic "Hello..." message.
6. Basic Lambda invocation logs **must** be visible in AWS CloudWatch Logs.
**Story 1.6: Basic CI/CD Pipeline Stub with Quality Gates**
* **User Story Statement:** As a Developer, I need a basic Continuous Integration (CI) pipeline established for the `bmad-daily-digest-backend` repository, so that code quality checks (linting, formatting, unit tests) and the build process are automated upon code pushes and pull requests, ensuring early feedback and maintaining codebase health.
* **Acceptance Criteria (ACs):**
1. A CI workflow file (e.g., GitHub Actions in `.github/workflows/main.yml`) **must** be created.
2. Pipeline **must** trigger on pushes to `main` and PRs targeting `main`.
3. Pipeline **must** include steps for: checkout, Node.js 22 setup, dependency install, ESLint check, Prettier format check, Jest unit tests, esbuild bundle.
4. Pipeline **must** fail if any lint, format, test, or bundle step fails.
5. A successful CI run on the `main` branch (with "Hello World" code) **must** be demonstrated.
6. CI pipeline for MVP **does not** need to perform AWS deployment; focus is on quality gates.
---
**Epic 2: Automated Content Ingestion & Podcast Generation Pipeline**
**Goal:** To implement the complete automated daily workflow within the backend. This includes fetching Hacker News post data, scraping and extracting content from linked external articles, aggregating and formatting text, submitting it to Play.ai, managing job status via polling, and retrieving/storing the final audio file and associated metadata. This epic delivers the core value proposition of generating the daily audio content and making it ready for consumption via an API.
**User Stories for Epic 2:**
**Story 2.1: AWS CDK Extension for Epic 2 Resources**
* **User Story Statement:** As a Developer, I need to extend the existing AWS CDK stack within the `bmad-daily-digest-backend` project to define and provision all new AWS resources required for the content ingestion and podcast generation pipeline—including a DynamoDB table for episode and processed post metadata, an S3 bucket for audio storage, and the AWS Step Functions state machine for orchestrating the Play.ai job status polling—so that all backend infrastructure for this epic is managed as code and ready for the application logic.
* **Acceptance Criteria (ACs):**
1. The existing AWS CDK application (from Epic 1) **must** be extended with new resource definitions for Epic 2.
2. A DynamoDB table (e.g., `BmadDailyDigestEpisodes`) **must** be defined via CDK for episode metadata, with `episodeId` (String UUID) as PK, key attributes (`publicationDate`, `episodeNumber`, `podcastGeneratedTitle`, `audioS3Key`, `audioS3Bucket`, `playAiJobId`, `playAiSourceAudioUrl`, `sourceHNPosts` (List of objects: `{ hnPostId, title, originalArticleUrl, hnLink, isUpdateStatus, lastCommentFetchTimestamp, oldRank }`), `status`, `createdAt`), and PAY_PER_REQUEST billing.
3. A DynamoDB table or GSI strategy **must** be defined via CDK to efficiently track processed Hacker News posts (`hnPostId`) and their `lastCommentFetchTimestamp` to support the "new comments only" feature.
4. An S3 bucket (e.g., `bmad-daily-digest-audio-{unique-suffix}`) **must** be defined via CDK for audio storage, with private access.
5. An AWS Step Functions state machine **must** be defined via CDK to manage the Play.ai job status polling workflow (details in Story 2.6).
6. Necessary IAM roles/permissions for Lambdas to interact with DynamoDB, S3, Step Functions, CloudWatch Logs **must** be defined via CDK.
7. The updated CDK stack **must** synthesize (`cdk synth`) and deploy (`cdk deploy`) successfully.
8. All new CDK code **must** adhere to project ESLint/Prettier standards.
**Story 2.2: Fetch Top Hacker News Posts & Identify Repeats**
* **User Story Statement:** As the System, I need to reliably fetch the top N (configurable, e.g., 10) current Hacker News posts daily using the Algolia HN API, including their essential metadata. I also need to identify if each fetched post has been processed in a recent digest by checking against stored data, so that I have an accurate list of stories and their status (new or repeat) to begin generating the daily digest.
* **Acceptance Criteria (ACs):**
1. A `hackerNewsService.ts` function **must** fetch top N HN posts (stories only) via `axios` from Algolia API (configurable `HN_POSTS_COUNT`).
2. Extracted metadata per post: Title, Article URL, HN Post URL, HN Post ID (`objectID`), Author, Points, Creation timestamp.
3. For each post, the function **must** query DynamoDB (see Story 2.1 AC#3) to determine its `isUpdateStatus` (true if recently processed and article scraped) and retrieve `lastCommentFetchTimestamp` and `oldRank` if available.
4. Function **must** return an array of HN post objects with metadata, `isUpdateStatus`, `lastCommentFetchTimestamp`, and `oldRank`.
5. Error handling for Algolia/DynamoDB calls **must** be implemented and logged.
6. Unit tests (Jest) **must** verify API calls, data extraction, repeat identification (mocked DDB), and error handling. All tests **must** pass.
**Story 2.3: Article Content Scraping & Extraction (Conditional)**
* **User Story Statement:** As the System, for each Hacker News post identified as *new* (or for which article scraping previously failed), I need to robustly fetch its HTML content from the linked article URL and extract the primary textual content and title. If scraping fails, a fallback mechanism must be triggered using available HN metadata and signaling the need for increased comments.
* **Acceptance Criteria (ACs):**
1. An `articleScraperService.ts` function **must** accept an article URL and `isUpdateStatus`.
2. If `isUpdateStatus` is true (article already scraped and good), scraping **must** be skipped, and a success status indicating no new scrape needed is returned (or pre-existing content reference).
3. If new scrape needed: use `axios` (timeout, User-Agent) to fetch HTML.
4. Use `Mozilla Readability` (JS port) or similar to extract main article text and title.
5. Return `{ success: true, title: string, content: string, ... }` on success.
6. If scraping fails: log failure, return `{ success: false, error: string, fallbackNeeded: true }`.
7. No "polite" inter-article scraping delays for MVP.
8. Unit tests (Jest) **must** mock `axios`, test successful extraction, skip logic, and failure/fallback scenarios. All tests **must** pass.
**Story 2.4: Fetch Hacker News Comments (Conditional Logic)**
* **User Story Statement:** As the System, I need to fetch comments for each selected Hacker News post using the Algolia HN API, adjusting the strategy based on whether the post is new, a repeat (requiring only new comments), or if its article scraping failed (requiring more comments).
* **Acceptance Criteria (ACs):**
1. `hackerNewsService.ts` **must** be extended to fetch comments for an HN Post ID, accepting `isUpdateStatus`, `lastCommentFetchTimestamp`, and `articleScrapingFailed` flags.
2. Use `axios` to call Algolia HN API item endpoint (`/api/v1/items/[POST_ID]`).
3. **Comment Fetching Logic:**
* If `articleScrapingFailed`: Fetch up to 3x `HN_COMMENTS_COUNT_PER_POST` (configurable, e.g., ~150) available comments (top-level first, then immediate children, by Algolia sort order).
* If `isUpdateStatus` (repeat post): Fetch all comments, then filter client-side for comments with `created_at_i` > `lastCommentFetchTimestamp`. Select up to `HN_COMMENTS_COUNT_PER_POST` of these *new* comments.
* Else (new post, successful scrape): Fetch up to `HN_COMMENTS_COUNT_PER_POST` (configurable, e.g., ~50) available comments.
4. Extract plain text (HTML stripped), author, creation timestamp for selected comments.
5. Return array of comment objects; empty if none.
6. Error handling and logging for API calls.
7. Unit tests (Jest) **must** mock `axios` and verify all conditional fetching logic, comment selection/filtering, data extraction (HTML stripping), and error handling. All tests **must** pass.
**Story 2.5: Content Aggregation and Formatting for Play.ai**
* **User Story Statement:** As the System, I need to aggregate the collected Hacker News post data (titles), associated article content (full, truncated, or fallback summary), and comments (new, updated, or extended sets) for all top stories, and format this combined text according to the specified structure for the play.ai PlayNote API, including special phrasing for different post types (new, update, scrape-failed), so that it's ready for podcast generation.
* **Acceptance Criteria (ACs):**
1. A `contentFormatterService.ts` **must** be implemented.
2. It **must** accept an array of processed HN post objects (containing all necessary metadata, statuses, content, and comments).
3. Output **must** be a single string.
4. String **must** start: "It's a top 10 countdown for [Current Date]".
5. Posts **must** be sequenced in reverse rank order.
6. **Formatting for standard new post:** "Story [Rank] - [Article Title]. [Full/Truncated Article Text]. Comments Section. [Number] comments follow. Comment 1: [Text]. Comment 2: [Text]..."
7. **Formatting for repeat post (update):** "Story [Rank] (previously Rank [OldRank] yesterday) - [Article Title]. We're bringing you new comments on this popular story. Comments Section. [Number] new comments follow. Comment 1: [Text]..."
8. **Formatting for scrape-failed post:** "Story [Rank] - [Article Title]. We couldn't retrieve the full article, but here's a summary if available and the latest comments. [Optional HN Summary]. Comments Section. [Number] comments follow. Comment 1: [Text]..."
9. **Article Truncation:** If `MAX_ARTICLE_LENGTH` (env var) is set and article exceeds, truncate by attempting to preserve beginning and end (or simpler first X / last Y characters for MVP).
10. Graceful handling for missing parts (e.g., "Article content not available," "0 comments follow") **must** be implemented.
11. Unit tests (Jest) **must** verify all formatting variations, truncation, data merging, and error handling. All tests **must** pass.
**Story 2.6 (REVISED): Implement Podcast Generation Status Polling via Play.ai API**
* **User Story Statement:** As the System, after submitting a podcast generation job to Play.ai and receiving a `jobId`, I need an AWS Step Function state machine to periodically poll the Play.ai API for the status of this specific job, continuing until the job is reported as "completed" or "failed" (or a configurable max duration/attempts limit is reached), so the system can reliably determine when the podcast audio is ready or if an error occurred.
* **Acceptance Criteria (ACs):**
1. The AWS Step Function state machine (CDK defined in Story 2.1) **must** manage the polling workflow.
2. Input: `jobId`.
3. States: Invoke Poller Lambda (calls Play.ai status endpoint with `axios`), Wait (configurable `POLLING_INTERVAL_MINUTES`), Choice (evaluates status).
4. Loop if status is "processing".
5. Stop if "completed" or "failed".
6. Max polling duration/attempts (configurable env vars `MAX_POLLING_DURATION_MINUTES`, `MAX_POLLING_ATTEMPTS`) **must** be enforced, treating expiry as failure.
7. If "completed": extract `audioUrl`, trigger next step (Story 2.8 process) with data.
8. If "failed"/"timeout": log event, record failure, terminate.
9. Poller Lambda handles Play.ai API errors gracefully.
10. Unit tests for Poller Lambda; Step Function definition tested. All tests **must** pass.
**Story 2.7: Submit Content to Play.ai PlayNote API & Initiate Podcast Generation**
* **User Story Statement:** As the System, I need to securely submit the aggregated and formatted text content (using `sourceText`) to the play.ai PlayNote API via an `application/json` request to initiate the podcast generation process, and I must capture the `jobId` returned by Play.ai, so that this `jobId` can be passed to the status polling mechanism (Step Function).
* **Acceptance Criteria (ACs):**
1. A `playAiService.ts` function **must** handle submission.
2. Input: formatted text (from Story 2.5).
3. Use `axios` for `POST` to Play.ai endpoint (e.g., `https://api.play.ai/api/v1/playnotes`).
4. Request `Content-Type: application/json`.
5. JSON body: `sourceText`, and configurable `title`, `voiceId1`, `name1`, `voiceId2`, `name2`, `styleGuidance` (from env vars). *Developer to confirm exact field names per Play.ai JSON API for text input.*
6. Headers: `Authorization: Bearer [TOKEN]`, `X-USER-ID: [API_KEY]` (from env vars `PLAY_AI_BEARER_TOKEN`, `PLAY_AI_USER_ID`).
7. No `webHookUrl` sent.
8. On success: extract `jobId`, log it, initiate polling Step Function (Story 2.6) with `jobId`.
9. Error handling for API submission.
10. Unit tests (Jest) mock `axios`, verify API call, auth, payload, `jobId` extraction, Step Function initiation, error handling. All tests **must** pass.
**Story 2.8: Retrieve, Store Generated Podcast Audio & Persist Episode Metadata**
* **User Story Statement:** As the System, once the podcast generation status polling (Story 2.6) indicates a Play.ai job is "completed," I need to download the generated audio file from the provided `audioUrl`, store this file in our designated S3 bucket, and then save all relevant metadata for the episode (including the S3 audio location, `episodeNumber`, `podcastGeneratedTitle`, `playAiSourceAudioUrl`, and source information like `isUpdateStatus` for each HN story, and `lastCommentFetchTimestamp` for each HN post) into our DynamoDB table, so that the daily digest is fully processed, archived, and ready for access.
* **Acceptance Criteria (ACs):**
1. A `podcastStorageService.ts` function **must** be triggered by Step Function (Story 2.6) on "completed" status, receiving `audioUrl`, Play.ai `jobId`, and original context (list of source HN posts with their processing statuses & metadata).
2. Use `axios` to download audio from `audioUrl`.
3. Upload audio to S3 bucket (from Story 2.1), using key (e.g., `YYYY/MM/DD/episodeId.mp3`).
4. Prepare episode metadata: `episodeId` (UUID), `publicationDate` (YYYY-MM-DD), `episodeNumber` (sequential logic), `podcastGeneratedTitle` (from Play.ai or constructed), `audioS3Bucket`, `audioS3Key`, `playAiJobId`, `playAiSourceAudioUrl`, `sourceHNPosts` (array of objects: `{ hnPostId, title, originalArticleUrl, hnLink, isUpdateStatus, lastCommentFetchTimestamp, oldRank }`), `status: "Published"`, `createdAt`.
5. The `lastCommentFetchTimestamp` for each processed `hnPostId` in `sourceHNPosts` **must** be set to the current time (or comment processing time) for future "new comments only" logic.
6. Save metadata to `BmadDailyDigestEpisodes` DynamoDB table.
7. Error handling for download, S3 upload, DDB write; failure sets episode status to "Failed".
8. Unit tests (Jest) mock `axios`, AWS SDK (S3, DynamoDB); verify data handling, storage, metadata, errors. All tests **must** pass.
**Story 2.9: Daily Workflow Orchestration & Scheduling**
* **User Story Statement:** As the System Administrator, I need the entire daily backend workflow (Stories 2.2 through 2.8) to be fully orchestrated by the primary AWS Step Function state machine and automatically scheduled to run once per day using Amazon EventBridge Scheduler, ensuring it handles re-runs for the same day by overwriting/starting over (for MVP), so that "BMad Daily Digest" episodes are produced consistently and reliably.
* **Acceptance Criteria (ACs):**
1. The primary AWS Step Function state machine **must** orchestrate the sequence: Call Lambdas/services for Fetch HN Posts (2.2), then for each post: Scrape Article (2.3) & Fetch Comments (2.4); then Aggregate & Format (2.5); then Submit to Play.ai (2.7 which returns `jobId`); then initiate Polling (2.6 using `jobId`); on "completed" polling, trigger Retrieve & Store Audio/Metadata (2.8).
2. State machine **must** manage data flow between steps.
3. Overall workflow error handling: critical step failure marks state machine execution as "Failed" and logs comprehensively. Individual steps use retries for transient errors.
4. **Idempotency (MVP):** Re-running for the same `publicationDate` **must** re-process and overwrite previous data for that date.
5. Amazon EventBridge Scheduler rule (CDK defined) **must** trigger the main Step Function daily at 12:00 UTC (default, configurable via `DAILY_JOB_SCHEDULE_UTC_CRON`).
6. Successful end-to-end run **must** be demonstrated.
7. Step Function execution history **must** provide a clear audit trail.
8. Unit tests for any new orchestrator-specific Lambda functions. All tests **must** pass.
---
**Epic 3: Web Application MVP & Podcast Consumption**
**Goal:** To set up the frontend project in its dedicated repository and develop and deploy the Next.js frontend application MVP, enabling users to consume the "BMad Daily Digest." This includes initial project setup (AI-assisted UI kickstart), pages for listing and detailing episodes, an about page, and deployment.
**User Stories for Epic 3:**
**Story 3.1: Frontend Project Repository & Initial UI Setup (AI-Assisted)**
* **User Story Statement:** As a Developer, I need to establish the `bmad-daily-digest-frontend` Git repository with a new Next.js (TypeScript, Node.js 22) project. This foundational setup must include essential development tooling (ESLint, Prettier, Jest with React Testing Library, a basic CI stub), and integrate an initial UI structure and core presentational components—kickstarted by an AI UI generation tool—styled with Tailwind CSS and shadcn/ui to embody the "80s retro CRT terminal" aesthetic, so that a high-quality, styled, and standardized frontend development environment is ready for building application features.
* **Acceptance Criteria (ACs):**
1. A new, private Git repository `bmad-daily-digest-frontend` **must** be created on GitHub.
2. A Next.js project (TypeScript, targeting Node.js 22) **must** be initialized.
3. Tooling (ESLint for Next.js/React/TS, Prettier, Jest with React Testing Library) **must** be installed and configured.
4. NPM scripts for lint, format, test, build **must** be in `package.json`.
5. Tailwind CSS and `shadcn/ui` **must** be installed and configured.
6. An initial UI structure (basic page layout, placeholder pages for List, Detail, About) and a few core presentational components (themed buttons, text display) **must** be generated using an agreed-upon AI UI generation tool, targeting the "80s retro CRT terminal" aesthetic.
7. The AI-generated UI code **must** be integrated into the Next.js project.
8. The application **must** build successfully with the initial UI.
9. A basic CI pipeline stub (GitHub Actions) for lint, format check, test, build **must** be created.
10. A standard Next.js `.gitignore` and an updated `README.md` **must** be present.
**Story 3.2: Frontend API Service Layer for Backend Communication**
* **User Story Statement:** As a Frontend Developer, I need a dedicated and well-typed API service layer within the Next.js frontend application to manage all HTTP communication with the "BMad Daily Digest" backend API (for fetching episode lists and specific episode details), so that UI components can cleanly and securely consume backend data with robust error handling.
* **Acceptance Criteria (ACs):**
1. A TypeScript module (e.g., `src/services/apiClient.ts`) **must** encapsulate backend API interactions.
2. Functions **must** exist for: fetching all podcast episodes (e.g., `getEpisodes()`) and fetching details for a single episode by `episodeId` (e.g., `getEpisodeDetails(episodeId)`).
3. `axios` **must** be used for HTTP requests.
4. Backend API base URL **must** be configurable via `NEXT_PUBLIC_BACKEND_API_URL`.
5. TypeScript interfaces (e.g., `EpisodeListItem`, `EpisodeDetail`, `SourceHNStory`) for API response data **must** be defined, matching data structure from backend (Story 2.8).
6. API functions **must** correctly parse JSON responses and transform data into defined frontend interfaces.
7. Error handling (network errors, non-2xx responses) **must** be implemented, providing clear error information.
8. Unit tests (Jest) **must** mock `axios` and verify API calls, data parsing/transformation, and error handling. All tests **must** pass.
**Story 3.3: Episode List Page Implementation**
* **User Story Statement:** As a Busy Tech Executive, I want to view a responsive "Episode List Page" that clearly displays all available "BMad Daily Digest" episodes in reverse chronological order, showing the episode number, publication date, and podcast title for each, so that I can quickly find and select the latest or a specific past episode to listen to.
* **Acceptance Criteria (ACs):**
1. A Next.js page component (e.g., `src/app/page.tsx` or `src/app/episodes/page.tsx`) **must** be created.
2. It **must** use the API service layer (Story 3.2) to fetch episodes.
3. A themed loading state **must** be shown during data fetching.
4. An error message **must** be shown if fetching fails.
5. A "No episodes available yet" message **must** be shown for an empty list.
6. Episodes **must** be listed in reverse chronological order (newest first), based on `publicationDate` or `episodeNumber`.
7. Each list item **must** display "Episode [EpisodeNumber]: [PublicationDate] - [PodcastGeneratedTitle]".
8. Each item **must** link to the Episode Detail Page for that episode using its `episodeId`.
9. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
10. The page **must** be responsive.
11. Unit/integration tests (Jest with RTL) **must** cover loading, error, no episodes, list rendering, data display, order, and navigation. All tests **must** pass.
**Story 3.4: Episode Detail Page Implementation**
* **User Story Statement:** As a Busy Tech Executive, after selecting a podcast episode from the list, I want to be taken to a responsive "Episode Detail Page" where I can easily play the audio using a standard HTML5 player, see a clear breakdown of the Hacker News stories discussed in that episode, and have direct links to explore both the original articles and the Hacker News comment threads, so I can listen to the digest and dive deeper into topics of interest.
* **Acceptance Criteria (ACs):**
1. A Next.js dynamic route page (e.g., `src/app/episodes/[episodeId]/page.tsx`) **must** be created.
2. It **must** accept `episodeId` from the URL.
3. It **must** use the API service layer (Story 3.2) to fetch details for the `episodeId`.
4. Loading and error states **must** be handled.
5. If data is found, it **must** display: `podcastGeneratedTitle`, `publicationDate`, `episodeNumber`.
6. An embedded HTML5 audio player (`<audio controls>`) **must** play the podcast. The `src` **must** be the publicly accessible URL for the audio file (e.g., a CloudFront URL pointing to the S3 object).
7. A list of included Hacker News stories (from the `sourceHNPosts` array in the episode data) **must** be displayed.
8. For each HN story in the list: its title, a link to the `originalArticleUrl` (opening in new tab), and a link to its `hnLink` (opening in new tab) **must** be displayed.
9. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
10. The page **must** be responsive.
11. Unit/integration tests (Jest with RTL) **must** cover loading, error, rendering of all details, player presence, and correct link generation. All tests **must** pass.
**Story 3.5: "About" Page Implementation**
* **User Story Statement:** As a User, I want to access a minimalist, responsive, and consistently styled "About Page" that clearly explains what the "BMad Daily Digest" service is, its core purpose, and how it works at a high level, so that I can quickly understand the value and nature of the service.
* **Acceptance Criteria (ACs):**
1. A Next.js page component (e.g., `src/app/about/page.tsx`) **must** be created.
2. It **must** display static informational content (placeholder text: "BMad Daily Digest provides a daily audio summary of top Hacker News discussions for busy tech professionals, generated using AI.").
3. Content **must** explain: What "BMad Daily Digest" is, its purpose, and a high-level overview of generation.
4. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
5. The page **must** be responsive.
6. A link to the "About Page" **must** be accessible (e.g., in site navigation/footer, specific location defined by Story 3.1's AI-generated layout).
7. Unit tests (Jest with RTL) **must** verify rendering of static content. All tests **must** pass.
**Story 3.6: Frontend Deployment to S3 & CloudFront via CDK**
* **User Story Statement:** As a Developer, I need the Next.js frontend application to be configured for static export (or an equivalent static-first deployment model) and have its AWS infrastructure (S3 for hosting, CloudFront for CDN and HTTPS) defined and managed via AWS CDK. This setup should automate the deployment of the static site, making the "BMad Daily Digest" web application publicly accessible, performant, and cost-effective.
* **Acceptance Criteria (ACs):**
1. The Next.js application **must** be configured for static export suitable for S3/CloudFront hosting.
2. AWS CDK scripts (managed in the `bmad-daily-digest-backend` repo's CDK app for unified IaC, unless Architect advises a separate frontend CDK app) **must** define the frontend S3 bucket and CloudFront distribution.
3. CDK stack **must** define: S3 bucket (static web hosting), CloudFront distribution (S3 origin, HTTPS via default CloudFront domain or ACM cert for custom domain if specified, caching behaviors, OAC/OAI).
4. A `package.json` build script **must** generate the static output (e.g., to `out/`).
5. The CDK deployment process (or related script) **must** include steps to build the Next.js app and sync static files to S3.
6. The application **must** be accessible via its CloudFront URL.
7. All MVP functionalities **must** be operational on the deployed site.
8. HTTPS **must** be enforced.
9. CDK code **must** meet project standards.
## 7. Key Reference Documents
*{This section will be populated later with links to the final PRD, Architecture Document, UI/UX Specification, etc.}*
## 8. Out of Scope Ideas Post MVP
* **Advanced Audio Player Functionality:** Custom controls (skip +/- 15s), playback speed adjustment, remembering playback position.
* **User Accounts & Personalization:** User creation, email subscription management, customizable podcast hosts.
* **Enhanced Content Delivery & Discovery:** Daily email summary, full RSS feed, full podcast transcription on website, search functionality.
* **Expanded Content Sources:** Beyond Hacker News.
* **Community & Feedback:** In-app feedback mechanisms.
## 9. Change Log
| Change | Date | Version | Description | Author |
| :------------------------------------------ | :------------ | :------ | :-------------------------------------------------------------------------- | :------------ |
| Initial PRD draft and MVP scope definition. | May 20, 2025 | 0.1 | Created initial PRD based on Project Brief; defined Epics & detailed Stories. | John (PM) & User |

View File

@@ -0,0 +1,431 @@
# BMad Daily Digest Product Requirements Document (PRD)
**Version:** 0.2
**Date:** May 20, 2025
**Author:** BMad Project Team (John - PM, Fred - Architect, Sarah - PO, User)
## 1. Goal, Objective and Context
* **Overall Goal:** To provide busy tech executives with a quick, daily audio digest of top Hacker News posts and discussions, enabling them to stay effortlessly informed.
* **Project Objective (MVP Focus):** To successfully launch the "BMad Daily Digest" by:
* Automating the daily fetching of top 10 Hacker News posts (article metadata and comments via Algolia HN API) and scraping of linked article content.
* Processing this content into a structured format.
* Generating a 2-agent audio podcast using the play.ai PlayNote API.
* Delivering the podcast via a simple Next.js web application (polyrepo structure) with a list of episodes and detail pages including an audio player and links to source materials.
* Operating this process daily, aiming for delivery by a consistent morning hour.
* Adhering to a full TypeScript stack (Node.js 22 for backend), with a Next.js frontend, AWS Lambda backend, DynamoDB, S3, and AWS CDK for IaC, while aiming to stay within AWS free-tier limits where possible.
* **Context/Problem Solved:** Busy tech executives lack the time to thoroughly read Hacker News daily but need to stay updated on key tech discussions, trends, and news for strategic insights. "BMad Daily Digest" solves this by offering a convenient, curated audio summary.
## 2. Functional Requirements (MVP)
**FR1: Content Acquisition**
* The system **must** automatically fetch data for the top 10 (configurable) posts from Hacker News daily.
* For each Hacker News post, the system **must** identify and retrieve:
* The URL of the linked article.
* Key metadata about the Hacker News post (e.g., title, HN link, score, author, HN Post ID).
* The system **must** fetch comments for each identified Hacker News post using the Algolia HN Search API, with logic to handle new vs. repeat posts and scraping failures differently.
* The system **must** attempt to scrape and extract the primary textual content from the linked article URL for each of the top posts (unless it's a repeat post where only new comments are needed).
* This process should aim to isolate the main article body.
* If scraping fails, a fallback using HN title, summary (if available), and increased comments **must** be used.
**FR2: Content Processing and Formatting**
* The system **must** aggregate the extracted/fallback article content and selected comments for the top 10 posts.
* The system **must** process and structure the aggregated text content into a single text file suitable for submission to the play.ai PlayNote API.
* The text file **must** begin with an introductory sentence: "It's a top 10 countdown for [Today'sDate]".
* Content **must** be structured sequentially (e.g., "Story 10 - [details]..."), with special phrasing for repeat posts or posts where article scraping failed.
* Article content may be truncated if `MAX_ARTICLE_LENGTH` (environment variable) is set, aiming to preserve intro/conclusion where possible.
**FR3: Podcast Generation**
* The system **must** submit the formatted text content to the play.ai PlayNote API daily using specified voice and style parameters (configurable via environment variables).
* The system **must** capture the `jobId` from Play.ai and use a polling mechanism (e.g., AWS Step Functions) to check for job completion status.
* Upon successful completion, the system **must** retrieve the generated audio podcast file from the Play.ai-provided URL.
* The system **must** store the generated audio file (e.g., on S3) and its associated metadata (including episode number, generated title, S3 location, original Play.ai URL, source HN posts, and processing status) in DynamoDB.
**FR4: Web Application Interface (MVP)**
* The system **must** provide a web application (Next.js, "80s retro CRT terminal" theme with Tailwind CSS & shadcn/ui) with a **List Page** that:
* Displays a chronological list (newest first) of all generated "BMad Daily Digest" episodes, formatted as "Episode [EpisodeNumber]: [PublicationDate] - [PodcastTitle]".
* Allows users to navigate to a Detail Page for each episode.
* The system **must** provide a web application with a **Detail Page** for each episode that:
* Displays the `podcastGeneratedTitle`, `publicationDate`, and `episodeNumber`.
* Includes an embedded HTML5 audio player for the podcast.
* Lists the individual Hacker News stories included, with direct links to the original source article and the Hacker News discussion page.
* The system **must** provide a minimalist **About Page**.
* The web application **must** be responsive.
**FR5: Automation and Scheduling**
* The entire end-to-end backend process **must** be orchestrated (preferably via AWS Step Functions) and automated to run daily, triggered by Amazon EventBridge Scheduler (default 12:00 UTC, configurable).
* For MVP, a re-run of the daily job for the same day **must** overwrite/start over previous data for that day.
## 3. Non-Functional Requirements (MVP)
**a. Performance:**
* **Podcast Generation Time:** The daily process should complete in a timely manner (e.g., target by 8 AM CST/12:00-13:00 UTC, specific completion window TBD based on Play.ai processing).
* **Web Application Load Time:** Pages on the Next.js app should aim for fast load times (e.g., target under 3-5 seconds).
**b. Reliability / Availability:**
* **Daily Process Success Rate:** Target >95% success rate for automated podcast generation without manual intervention.
* **Web Application Uptime:** Target 99.5%+ uptime.
**c. Maintainability:**
* **Code Quality:** Code **must** be well-documented. Internal code comments **should** be used when logic isn't clear from names. All functions **must** have JSDoc-style outer comments. Adherence to defined coding standards (ESLint, Prettier).
* **Configuration Management:** System configurations and secrets **must** be managed via environment variables (`.env` locally, Lambda environment variables when deployed), set manually for MVP.
**d. Usability (Web Application):**
* The web application **must** be intuitive for busy tech executives.
* The audio player **must** be simple and reliable.
* Accessibility: Standard MVP considerations, with particular attention to contrast for the "glowing green on dark" theme, good keyboard navigation, and basic screen reader compatibility.
**e. Security (MVP Focus):**
* **API Key Management:** Keys for Algolia, Play.ai, AWS **must** be stored securely (gitignored `.env` files locally, Lambda environment variables in AWS), not hardcoded.
* **Data Handling:** Scraped content handled responsibly.
**f. Cost Efficiency:**
* AWS service usage **must** aim to stay within free-tier limits where feasible. Play.ai usage is via existing user subscription.
## 4. User Interaction and Design Goals
**a. Overall Vision & Experience:**
* **Look and Feel:** Dark mode UI, "glowing green ASCII/text on a black background" aesthetic (CRT terminal style), "80s retro everything" theme.
* **UI Component Toolkit:** Tailwind CSS and shadcn/ui, customized for the theme. Initial structure/components kickstarted by an AI UI generation tool (using the `bmad-daily-digest-ui` V0 scaffold as a base).
* **User Experience:** Highly efficient, clear navigation, no clutter, prioritizing content readability for busy tech executives.
**b. Key Interaction Paradigms (MVP):**
* View list of digests (reverse chronological), select one for details. No sorting/filtering on list page for MVP.
**c. Core Screens/Views (MVP):**
* **List Page:** Episodes ("Episode [N]: [Date] - [PodcastTitle]").
* **Detail Page:** Episode details, HTML5 audio player, list of source HN stories with links to articles and HN discussions.
* **About Page:** Minimalist, explaining the service, consistent theme.
**d. Accessibility Aspirations (MVP):**
* Standard considerations: good contrast (critical for theme), keyboard navigation, basic screen reader compatibility.
**e. Branding Considerations (High-Level):**
* "80s retro everything" theme is central. Logo/typeface should complement this (e.g., pixel art, retro fonts).
**f. Target Devices/Platforms:**
* Responsive web application, good UX on desktop and mobile.
## 5. Technical Assumptions
**a. Core Technology Stack & Approach:**
* **Full TypeScript Stack:** TypeScript for frontend and backend.
* **Frontend:** Next.js (React), Node.js 22. Styling: Tailwind CSS, shadcn/ui. Hosting: Static site on AWS S3 (via CloudFront).
* **Backend:** Node.js 22, TypeScript. HTTP Client: `axios`. Compute: AWS Lambda. Database: AWS DynamoDB.
* **Infrastructure as Code (IaC):** All AWS infrastructure via AWS CDK.
* **Key External Services/APIs:** Algolia HN Search API (posts/comments), Play.ai PlayNote API (audio gen, user has subscription, polling for status), Custom scraping for articles (TypeScript with Cheerio, Readability.js, potentially Puppeteer/Playwright).
* **Automation:** Daily trigger via Amazon EventBridge Scheduler. Orchestration via AWS Step Functions.
* **Configuration & Secrets:** Environment variables (`.env` local & gitignored, Lambda env vars).
* **Coding Standards:** JSDoc for functions, inline comments for clarity. ESLint, Prettier.
**b. Repository Structure & Service Architecture:**
* **Repository Structure:** Polyrepo (separate Git repositories for `bmad-daily-digest-frontend` and `bmad-daily-digest-backend`).
* **High-Level Service Architecture:** Backend is serverless functions (AWS Lambda) for distinct tasks, orchestrated by Step Functions. API layer via AWS API Gateway to expose backend to frontend, secured with API Keys.
## 6. Epic Overview
This section details the Epics and their User Stories for the MVP. Architectural refinements have been incorporated.
**Epic 1: Backend Foundation, Tooling & "Hello World" API**
* **Goal:** To establish the core backend project infrastructure in its dedicated repository, including robust development tooling and initial AWS CDK setup for essential services. By the end of this epic:
1. A simple "hello world" API endpoint (AWS API Gateway + Lambda) **must** be deployed and testable via `curl`, returning a dynamic message.
2. The backend project **must** have ESLint, Prettier, Jest (unit testing), and esbuild (TypeScript bundling) configured and operational.
3. Basic unit tests **must** exist for the "hello world" Lambda function.
4. Code formatting and linting checks **should** be integrated into a pre-commit hook and/or a basic CI pipeline stub.
* **User Stories for Epic 1:**
**Story 1.1: Initialize Backend Project using TS-TEMPLATE-STARTER**
* **User Story Statement:** As a Developer, I want to create the `bmad-daily-digest-backend` Git repository and initialize it using the existing `TS-TEMPLATE-STARTER`, ensuring all foundational tooling (TypeScript, Node.js 22, ESLint, Prettier, Jest, esbuild) is correctly configured and operational for this specific project, so that I have a high-quality, standardized development environment ready for application logic.
* **Acceptance Criteria (ACs):**
1. A new, private Git repository named `bmad-daily-digest-backend` **must** be created on GitHub.
2. The contents of the `TS-TEMPLATE-STARTER` project **must** be copied/cloned into this new repository.
3. `package.json` **must** be updated (project name, version, description).
4. Project dependencies **must** be installable.
5. TypeScript setup (`tsconfig.json`) **must** be verified for Node.js 22, esbuild compatibility; project **must** compile.
6. ESLint and Prettier configurations **must** be operational; lint/format scripts **must** execute successfully.
7. Jest configuration **must** be operational; test scripts **must** execute successfully with any starter example tests.
8. Irrelevant generic demo code from starter **should** be removed. `index.ts`/`index.test.ts` can remain as placeholders.
9. A standard `.gitignore` and an updated project `README.md` **must** be present.
**Story 1.2: Pre-commit Hook Implementation**
* **User Story Statement:** As a Developer, I want pre-commit hooks automatically enforced in the `bmad-daily-digest-backend` repository, so that code quality standards (like linting and formatting) are checked and applied to staged files before any code is committed, thereby maintaining codebase consistency and reducing trivial errors.
* **Acceptance Criteria (ACs):**
1. A pre-commit hook tool (e.g., Husky) **must** be installed and configured.
2. A tool for running linters/formatters on staged files (e.g., `lint-staged`) **must** be installed and configured.
3. Pre-commit hook **must** trigger `lint-staged` on staged `.ts` files.
4. `lint-staged` **must** be configured to run ESLint (`--fix`) and Prettier (`--write`).
5. Attempting to commit files with auto-fixable issues **must** result in fixes applied and successful commit.
6. Attempting to commit files with non-auto-fixable linting errors **must** abort the commit with error messages.
7. Committing clean files **must** proceed without issues.
**Story 1.3: "Hello World" Lambda Function Implementation & Unit Tests**
* **User Story Statement:** As a Developer, I need a simple "Hello World" AWS Lambda function implemented in TypeScript within the `bmad-daily-digest-backend` project. This function, when invoked, should return a dynamic greeting message including the current date and time, and it must be accompanied by comprehensive Jest unit tests, so that our basic serverless compute functionality, testing setup, and TypeScript bundling are validated.
* **Acceptance Criteria (ACs):**
1. A `src/features/publicApi/statusHandler.ts` file (or similar according to final backend structure) **must** contain the Lambda handler.
2. Handler **must** be AWS Lambda compatible (event, context, Promise response).
3. Successful execution **must** return JSON: `statusCode: 200`, body with `message: "Hello from BMad Daily Digest Backend, today is [current_date] at [current_time]."`.
4. Date and time in message **must** be dynamic.
5. A corresponding Jest unit test file (e.g., `src/features/publicApi/statusHandler.test.ts`) **must** be created.
6. Unit tests **must** verify: 200 status, valid JSON body, expected `message` field, "Hello from..." prefix, dynamic date/time portion (use mocked `Date`).
7. All unit tests **must** pass.
8. esbuild configuration **must** correctly bundle the handler.
**Story 1.4: AWS CDK Setup for "Hello World" API (Lambda & API Gateway)**
* **User Story Statement:** As a Developer, I want to define the necessary AWS infrastructure (Lambda function and API Gateway endpoint) for the "Hello World" service using AWS CDK (Cloud Development Kit) in TypeScript, so that the infrastructure is version-controlled, repeatable, and can be deployed programmatically.
* **Acceptance Criteria (ACs):**
1. AWS CDK (v2) **must** be a development dependency.
2. CDK app structure **must** be initialized (e.g., in `cdk/`).
3. A new CDK stack (e.g., `BmadDailyDigestBackendStack`) **must** be defined in TypeScript.
4. CDK stack **must** define an AWS Lambda resource for the "Hello World" function (Node.js 22, bundled code reference, handler entry point, basic IAM role for CloudWatch logs, free-tier conscious settings).
5. CDK stack **must** define an AWS API Gateway (HTTP API preferred) with a route (e.g., `GET /status` or `GET /hello`) triggering the Lambda, secured with the "Frontend Read API Key".
6. CDK stack **must** be synthesizable (`cdk synth`) without errors.
7. CDK code **must** adhere to project ESLint/Prettier standards.
8. Mechanism for passing Lambda environment variables via CDK **must** be in place.
**Story 1.5: "Hello World" API Deployment & Manual Invocation Test**
* **User Story Statement:** As a Developer, I need to deploy the "Hello World" API (defined in AWS CDK) to an AWS environment and successfully invoke its endpoint using a tool like `curl` (including the API Key), so that I can verify the end-to-end deployment process and confirm the basic API is operational in the cloud.
* **Acceptance Criteria (ACs):**
1. The AWS CDK stack for "Hello World" API **must** deploy successfully to a designated AWS account/region.
2. The API Gateway endpoint URL for the `/status` (or `/hello`) route **must** be retrievable post-deployment.
3. A `GET` request to the deployed endpoint, including the correct `x-api-key` header, **must** receive a response.
4. HTTP response status **must** be 200 OK.
5. Response body **must** be JSON containing the expected dynamic "Hello..." message.
6. Basic Lambda invocation logs **must** be visible in AWS CloudWatch Logs.
**Story 1.6: Basic CI/CD Pipeline Stub with Quality Gates**
* **User Story Statement:** As a Developer, I need a basic Continuous Integration (CI) pipeline established for the `bmad-daily-digest-backend` repository, so that code quality checks (linting, formatting, unit tests) and the build process are automated upon code pushes and pull requests, ensuring early feedback and maintaining codebase health.
* **Acceptance Criteria (ACs):**
1. A CI workflow file (e.g., GitHub Actions in `.github/workflows/main.yml`) **must** be created.
2. Pipeline **must** trigger on pushes to `main` and PRs targeting `main`.
3. Pipeline **must** include steps for: checkout, Node.js 22 setup, dependency install, ESLint check, Prettier format check, Jest unit tests, esbuild bundle.
4. Pipeline **must** fail if any lint, format, test, or bundle step fails.
5. A successful CI run on the `main` branch **must** be demonstrated.
6. CI pipeline for MVP **does not** need to perform AWS deployment.
---
**Epic 2: Automated Content Ingestion & Podcast Generation Pipeline**
**Goal:** To implement the complete automated daily workflow within the backend. This includes fetching Hacker News post data, scraping and extracting content from linked external articles, aggregating and formatting text, submitting it to Play.ai, managing job status via polling, and retrieving/storing the final audio file and associated metadata. This epic delivers the core value proposition of generating the daily audio content and making it ready for consumption via an API.
**User Stories for Epic 2:**
**Story 2.1: AWS CDK Extension for Epic 2 Resources**
* **User Story Statement:** As a Developer, I need to extend the existing AWS CDK stack within the `bmad-daily-digest-backend` project to define and provision all new AWS resources required for the content ingestion and podcast generation pipeline—including the `BmadDailyDigestEpisodes` DynamoDB table (with GSI), the `HackerNewsPostProcessState` DynamoDB table, an S3 bucket for audio storage, and the AWS Step Functions state machine for orchestrating the Play.ai job status polling—so that all backend infrastructure for this epic is managed as code and ready for the application logic.
* **Acceptance Criteria (ACs):**
1. The existing AWS CDK application (from Epic 1) **must** be extended.
2. The `BmadDailyDigestEpisodes` DynamoDB table resource **must** be defined in CDK as specified in the System Architecture Document's "Data Models" section (with `episodeId` PK, key attributes like `publicationDate`, `episodeNumber`, `podcastGeneratedTitle`, `audioS3Key`, `audioS3Bucket`, `playAiJobId`, `playAiSourceAudioUrl`, `sourceHNPosts` list, `status`, `createdAt`, `updatedAt`), including a GSI for chronological sorting (e.g., PK `status`, SK `publicationDate`), and PAY_PER_REQUEST billing.
3. The `HackerNewsPostProcessState` DynamoDB table resource **must** be defined in CDK as specified in the System Architecture Document's "Data Models" section (with `hnPostId` PK and attributes like `lastCommentFetchTimestamp`, `lastSuccessfullyScrapedTimestamp`, `lastKnownRank`), and PAY_PER_REQUEST billing.
4. An S3 bucket resource (e.g., `bmad-daily-digest-audio-{unique-suffix}`) **must** be defined via CDK for audio storage, with private access by default.
5. An AWS Step Functions state machine resource **must** be defined via CDK to manage the Play.ai job status polling workflow (as detailed in Story 2.6).
6. Necessary IAM roles and permissions for Lambda functions within this epic to interact with DynamoDB, S3, Step Functions, CloudWatch Logs **must** be defined via CDK, adhering to least privilege.
7. The updated CDK stack **must** synthesize (`cdk synth`) and deploy (`cdk deploy`) successfully.
8. All new CDK code **must** adhere to project ESLint/Prettier standards.
**Story 2.2: Fetch Top Hacker News Posts & Identify Repeats**
* **User Story Statement:** As the System, I need to reliably fetch the top N (configurable, e.g., 10) current Hacker News posts daily using the Algolia HN API, including their essential metadata. I also need to identify if each fetched post has been processed in a recent digest by checking against the `HackerNewsPostProcessState` table, so that I have an accurate list of stories and their status (new or repeat) to begin generating the daily digest.
* **Acceptance Criteria (ACs):**
1. A `hackerNewsService.ts` function **must** fetch top N HN posts (stories only) via `axios` from Algolia API (configurable `HN_POSTS_COUNT`).
2. Extracted metadata per post: Title, Article URL, HN Post URL, HN Post ID (`objectID`), Author, Points, Creation timestamp.
3. For each post, the function **must** query the `HackerNewsPostProcessState` DynamoDB table to determine its `isUpdateStatus` (true if `lastSuccessfullyScrapedTimestamp` and `lastCommentFetchTimestamp` indicate prior full processing) and retrieve `lastCommentFetchTimestamp` and `lastKnownRank` if available.
4. Function **must** return an array of HN post objects with metadata, `isUpdateStatus`, `lastCommentFetchTimestamp`, and `lastKnownRank`.
5. Error handling for Algolia/DynamoDB calls **must** be implemented and logged.
6. Unit tests (Jest) **must** verify API calls, data extraction, repeat identification (mocked DDB), and error handling. All tests **must** pass.
**Story 2.3: Article Content Scraping & Extraction (Conditional)**
* **User Story Statement:** As the System, for each Hacker News post identified as *new* (or for which article scraping previously failed and is being retried), I need to robustly fetch its HTML content from the linked article URL and extract the primary textual content and title using libraries like Cheerio and Mozilla Readability. If scraping fails, a fallback mechanism must be triggered.
* **Acceptance Criteria (ACs):**
1. An `articleScraperService.ts` function **must** accept an article URL and `isUpdateStatus`.
2. If `isUpdateStatus` is true (article already successfully scraped and stored, though we are not storing full articles long term - this implies we have the article data available from a previous step if it's a repeat post where we don't re-scrape), scraping **must** be skipped. (For MVP, if it's a repeat post, we assume we don't need to re-scrape the article itself, only comments, as per user feedback. This story focuses on *new* scrapes or retries of failed scrapes).
3. If a new scrape is needed: use `axios` (timeout, User-Agent) to fetch HTML.
4. Use `Mozilla Readability` (JS port) and/or `Cheerio` to extract main article text and title.
5. Return `{ success: true, title: string, content: string }` on success.
6. If scraping fails: log failure, return `{ success: false, error: string, fallbackNeeded: true }`.
7. No specific "polite" inter-article scraping delays for MVP.
8. Unit tests (Jest) **must** mock `axios`, test successful extraction, skip logic for non-applicable cases, and failure/fallback scenarios. All tests **must** pass.
**Story 2.4: Fetch Hacker News Comments (Conditional Logic)**
* **User Story Statement:** As the System, I need to fetch comments for each selected Hacker News post using the Algolia HN API, adjusting the strategy to fetch up to N comments for new posts, only new comments since last fetch for repeat posts, or up to 3N comments if article scraping failed.
* **Acceptance Criteria (ACs):**
1. `hackerNewsService.ts` **must** be extended to fetch comments for an HN Post ID, accepting `isUpdateStatus`, `lastCommentFetchTimestamp` (from `HackerNewsPostProcessState`), and `articleScrapingFailed` flags.
2. Use `axios` to call Algolia HN API item endpoint.
3. **Comment Fetching Logic:**
* If `articleScrapingFailed`: Fetch up to 3 * `HN_COMMENTS_COUNT_PER_POST` available comments.
* If `isUpdateStatus`: Fetch all comments, then filter client-side for comments with `created_at_i` > `lastCommentFetchTimestamp`. Select up to `HN_COMMENTS_COUNT_PER_POST` of these *new* comments.
* Else (new post, successful scrape): Fetch up to `HN_COMMENTS_COUNT_PER_POST`.
4. For selected comments, extract plain text (HTML stripped), author, creation timestamp.
5. Return array of comment objects; empty if none. An updated `lastCommentFetchTimestamp` (max `created_at_i` of fetched comments for this post) should be available for updating `HackerNewsPostProcessState`.
6. Error handling and logging for API calls.
7. Unit tests (Jest) **must** mock `axios` and verify all conditional fetching logic, comment selection/filtering, data extraction, and error handling. All tests **must** pass.
**Story 2.5: Content Aggregation and Formatting for Play.ai**
* **User Story Statement:** As the System, I need to aggregate the collected Hacker News post data (titles), associated article content (full, truncated, or fallback summary), and comments (new, updated, or extended sets) for all top stories, and format this combined text according to the specified structure for the play.ai PlayNote API, including special phrasing for different post types (new, update, scrape-failed) and configurable article truncation.
* **Acceptance Criteria (ACs):**
1. A `contentFormatterService.ts` **must** be implemented.
2. Inputs: Array of processed HN post objects (with metadata, statuses, content, comments).
3. Output: A single string.
4. String starts: "It's a top 10 countdown for [Current Date]".
5. Posts sequenced in reverse rank order.
6. **Formatting (new post):** "Story [Rank] - [Article Title]. [Full/Truncated Article Text]. Comments Section. [Number] comments follow. Comment 1: [Text]..."
7. **Formatting (repeat post):** "Story [Rank] (previously Rank [OldRank] yesterday) - [Article Title]. We're bringing you new comments on this popular story. Comments Section. [Number] new comments follow. Comment 1: [Text]..."
8. **Formatting (scrape-failed post):** "Story [Rank] - [Article Title]. We couldn't retrieve the full article, but here's a summary if available and the latest comments. [Optional HN Summary]. Comments Section. [Number] comments follow. Comment 1: [Text]..."
9. **Article Truncation:** If `MAX_ARTICLE_LENGTH` (env var) set and article exceeds, truncate aiming to preserve intro/conclusion.
10. Graceful handling for missing parts.
11. Unit tests (Jest) verify all formatting, truncation, data merging, error handling. All tests **must** pass.
**Story 2.6 (REVISED): Implement Podcast Generation Status Polling via Play.ai API**
* **User Story Statement:** As the System, after submitting a podcast generation job to Play.ai and receiving a `jobId`, I need an AWS Step Function state machine to periodically poll the Play.ai API for the status of this specific job, continuing until the job is reported as "completed" or "failed" (or a configurable max duration/attempts limit is reached), so the system can reliably determine when the podcast audio is ready or if an error occurred.
* **Acceptance Criteria (ACs):**
1. The AWS Step Function state machine (CDK defined in Story 2.1) **must** manage the polling workflow.
2. Input: `jobId`.
3. States: Invoke Poller Lambda (calls Play.ai status GET endpoint with `axios`), Wait (configurable `POLLING_INTERVAL_MINUTES`), Choice (evaluates status: "processing", "completed", "failed").
4. Loop if "processing". Stop if "completed" or "failed".
5. Max polling duration/attempts (configurable env vars `MAX_POLLING_DURATION_MINUTES`, `MAX_POLLING_ATTEMPTS`) **must** be enforced, treating expiry as failure.
6. If "completed": extract `audioUrl`, trigger next step (Story 2.8 process) with data.
7. If "failed"/"timeout": log event, record failure (e.g., update episode status in DDB via a Lambda), terminate.
8. Poller Lambda handles API errors gracefully.
9. Unit tests for Poller Lambda logic; Step Function definition tested (locally if possible, or via AWS console tests). All tests **must** pass.
**Story 2.7: Submit Content to Play.ai PlayNote API & Initiate Podcast Generation**
* **User Story Statement:** As the System, I need to securely submit the aggregated and formatted text content (using `sourceText`) to the play.ai PlayNote API via an `application/json` request to initiate the podcast generation process, and I must capture the `jobId` returned by Play.ai, so that this `jobId` can be passed to the status polling mechanism (Step Function).
* **Acceptance Criteria (ACs):**
1. A `playAiService.ts` function **must** handle submission.
2. Input: formatted text (from Story 2.5).
3. Use `axios` for `POST` to Play.ai endpoint (e.g., `https://api.play.ai/api/v1/playnotes`).
4. Request `Content-Type: application/json`.
5. JSON body: `sourceText`, and configurable `title`, `voiceId1`, `name1` (default "Angelo"), `voiceId2`, `name2` (default "Deedee"), `styleGuidance` (default "podcast") from env vars.
6. Headers: `Authorization: Bearer <PLAY_AI_BEARER_TOKEN>`, `X-USER-ID: <PLAY_AI_USER_ID>` (from env vars).
7. No `webHookUrl` sent.
8. On success: extract `jobId`, log it, initiate polling Step Function (Story 2.6) with `jobId` and other context (like internal `episodeId`).
9. Error handling for API submission; log and flag failure.
10. Unit tests (Jest) mock `axios`, verify API call, auth, payload, `jobId` extraction, Step Function initiation (mocked), error handling. All tests **must** pass.
**Story 2.8: Retrieve, Store Generated Podcast Audio & Persist Episode Metadata**
* **User Story Statement:** As the System, once the podcast generation status polling (Story 2.6) indicates a Play.ai job is "completed," I need to download the generated audio file from the provided `audioUrl`, store this file in our designated S3 bucket, and then save/update all relevant metadata for the episode (including S3 audio location, `episodeNumber`, `podcastGeneratedTitle`, `playAiSourceAudioUrl`, and source HN post information including their `lastCommentFetchTimestamp`) into our DynamoDB tables (`BmadDailyDigestEpisodes` and `HackerNewsPostProcessState`), so that the daily digest is fully processed, archived, and ready for access.
* **Acceptance Criteria (ACs):**
1. A `podcastStorageService.ts` function **must** be triggered by Step Function (Story 2.6) on "completed" status, receiving `audioUrl`, Play.ai `jobId`, and original context (like internal `episodeId`, list of source HN posts with their metadata and processing status).
2. Use `axios` to download audio from `audioUrl`.
3. Upload audio to S3 bucket (from Story 2.1), using key (e.g., `YYYY/MM/DD/episodeId.mp3`).
4. Prepare `Episode` metadata for `BmadDailyDigestEpisodes` table: `episodeId` (UUID), `publicationDate` (YYYY-MM-DD), `episodeNumber` (sequential logic, TBD), `podcastGeneratedTitle` (from Play.ai or constructed), `audioS3Bucket`, `audioS3Key`, `playAiJobId`, `playAiSourceAudioUrl`, `sourceHNPosts` (array of objects: `{ hnPostId, title, originalArticleUrl, hnLink, isUpdateStatus, oldRank, articleScrapingFailed }`), `status: "Published"`, `createdAt`, `updatedAt`.
5. For each `hnPostId` in `sourceHNPosts`, update its corresponding item in the `HackerNewsPostProcessState` table with the `lastCommentFetchTimestamp` (current time or max comment time from this run), `lastProcessedDate` (current date), and `lastKnownRank`. If `articleScrapingFailed` was false for this run, update `lastSuccessfullyScrapedTimestamp`.
6. Save `Episode` metadata to `BmadDailyDigestEpisodes` DynamoDB table.
7. Error handling for download, S3 upload, DDB writes; failure should result in episode `status: "Failed"`.
8. Unit tests (Jest) mock `axios`, AWS SDK (S3, DynamoDB); verify data handling, storage, metadata construction for both tables, errors. All tests **must** pass.
**Story 2.9: Daily Workflow Orchestration & Scheduling**
* **User Story Statement:** As the System Administrator, I need the entire daily backend workflow (Stories 2.2 through 2.8) to be fully orchestrated by the primary AWS Step Function state machine and automatically scheduled to run once per day using Amazon EventBridge Scheduler, ensuring it handles re-runs for the same day by overwriting/starting over (for MVP), so that "BMad Daily Digest" episodes are produced consistently and reliably.
* **Acceptance Criteria (ACs):**
1. The primary AWS Step Function state machine **must** orchestrate the sequence: Fetch HN Posts & Identify Repeats (2.2); For each post: conditionally Scrape Article (2.3) & Fetch Comments (2.4); then Aggregate & Format Content (2.5); then Submit to Play.ai & get `jobId` (2.7); then initiate/manage Polling (2.6 using `jobId`); on "completed" polling, trigger Retrieve & Store Audio/Metadata (2.8).
2. State machine **must** manage data flow (inputs/outputs) between steps correctly.
3. Overall workflow error handling: critical step failure marks state machine execution as "Failed" and logs comprehensively. Steps use retries for transient errors.
4. **Idempotency (MVP):** Re-running for the same `publicationDate` **must** re-process and effectively overwrite previous data for that date.
5. Amazon EventBridge Scheduler rule (CDK defined) **must** trigger the main Step Function daily at 12:00 UTC (default, configurable via `DAILY_JOB_SCHEDULE_UTC_CRON`).
6. Successful end-to-end run **must** be demonstrated (e.g., processing sample data through the pipeline).
7. Step Function execution history **must** provide a clear audit trail of steps and data.
8. Unit tests for any new orchestrator-specific Lambda functions (if any not covered). All tests **must** pass.
---
**Epic 3: Web Application MVP & Podcast Consumption**
**Goal:** To set up the frontend project in its dedicated repository and develop and deploy the Next.js frontend application MVP, enabling users to consume the "BMad Daily Digest." This includes initial project setup (AI-assisted UI kickstart from `bmad-daily-digest-ui` scaffold), pages for listing and detailing episodes, an about page, and deployment.
**User Stories for Epic 3:**
**Story 3.1: Frontend Project Repository & Initial UI Setup (AI-Assisted)**
* **User Story Statement:** As a Developer, I need to establish the `bmad-daily-digest-frontend` Git repository with a new Next.js (TypeScript, Node.js 22) project, using the provided `bmad-daily-digest-ui` V0 scaffold as the base. This setup must include all foundational tooling (ESLint, Prettier, Jest with React Testing Library, a basic CI stub), and an initial AWS CDK application structure, ensuring the "80s retro CRT terminal" aesthetic (with Tailwind CSS and shadcn/ui) is operational, so that a high-quality, styled, and standardized frontend development environment is ready.
* **Acceptance Criteria (ACs):**
1. A new, private Git repository `bmad-daily-digest-frontend` **must** be created on GitHub.
2. The `bmad-daily-digest-ui` V0 scaffold project files **must** be used as the initial codebase in this repository.
3. `package.json` **must** be updated (project name, version, description).
4. Project dependencies **must** be installable.
5. TypeScript (`tsconfig.json`), Next.js (`next.config.mjs`), Tailwind (`tailwind.config.ts`), ESLint, Prettier, Jest configurations from the scaffold **must** be verified and operational.
6. The application **must** build successfully (`npm run build`) with the scaffolded UI.
7. A basic CI pipeline stub (GitHub Actions) for lint, format check, test, build **must** be created.
8. A standard `.gitignore` and an updated `README.md` **must** be present.
9. An initial AWS CDK application structure **must** be created within a `cdk/` directory in this repository, ready for defining frontend-specific infrastructure (S3, CloudFront in Story 3.6).
**Story 3.2: Frontend API Service Layer for Backend Communication**
* **User Story Statement:** As a Frontend Developer, I need a dedicated and well-typed API service layer (e.g., `lib/api-client.ts`) within the Next.js frontend application to manage all HTTP communication with the "BMad Daily Digest" backend API (for fetching episode lists and specific episode details), so that UI components can cleanly and securely consume backend data with robust error handling.
* **Acceptance Criteria (ACs):**
1. A TypeScript module `lib/api-client.ts` (or similar) **must** encapsulate backend API interactions.
2. Functions **must** exist for: `getEpisodes(): Promise<EpisodeListItem[]>` and `getEpisodeDetails(episodeId: string): Promise<EpisodeDetail | null>`.
3. `axios` (or native `Workspace` with a wrapper if preferred for frontend) **must** be used for HTTP requests.
4. Backend API base URL (`NEXT_PUBLIC_BACKEND_API_URL`) and Frontend Read API Key (`NEXT_PUBLIC_FRONTEND_API_KEY`) **must** be configurable via public environment variables and used in requests.
5. TypeScript interfaces (`EpisodeListItem`, `EpisodeDetail`, `SourceHNPostDetail` from `lib/types.ts`) for API response data **must** be defined/used, matching backend API.
6. API functions **must** correctly parse JSON responses and transform data into defined interfaces.
7. Error handling (network errors, non-2xx responses from backend) **must** be implemented, providing clear error information/objects.
8. Unit tests (Jest) **must** mock the HTTP client and verify API calls, data parsing/transformation, and error handling. All tests **must** pass.
**Story 3.3: Episode List Page Implementation**
* **User Story Statement:** As a Busy Tech Executive, I want to view a responsive "Episode List Page" (based on `app/(pages)/episodes/page.tsx` from the scaffold) that clearly displays all available "BMad Daily Digest" episodes in reverse chronological order, showing the episode number, publication date, and podcast title for each, using themed components like `episode-card.tsx`, so that I can quickly find and select an episode.
* **Acceptance Criteria (ACs):**
1. The existing `app/(pages)/episodes/page.tsx` (or equivalent main list page from scaffold) **must** be updated.
2. It **must** use the API service layer (Story 3.2) to fetch episodes.
3. A themed loading state (e.g., using `loading-state.tsx`) **must** be shown.
4. A themed error message (e.g., using `error-state.tsx`) **must** be shown if fetching fails.
5. A "No episodes available yet" message **must** be shown for an empty list.
6. Episodes **must** be listed in reverse chronological order.
7. Each list item, potentially using a modified `episode-card.tsx` component, **must** display "Episode [EpisodeNumber]: [PublicationDate] - [PodcastGeneratedTitle]".
8. Each item **must** link to the Episode Detail Page for that episode using its `episodeId`.
9. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
10. The page **must** be responsive.
11. Unit/integration tests (Jest with RTL) **must** cover all states, data display, order, and navigation. All tests **must** pass.
**Story 3.4: Episode Detail Page Implementation**
* **User Story Statement:** As a Busy Tech Executive, after selecting an episode, I want to navigate to a responsive "Episode Detail Page" (based on `app/(pages)/episodes/[episodeId]/page.tsx`/page.tsx] from the scaffold) that features an embedded HTML5 audio player, displays the episode title/date/number, a list of the Hacker News stories covered (using components like `story-item.tsx`), and provides clear links to the original articles and HN discussions, so I can listen and explore sources.
* **Acceptance Criteria (ACs):**
1. The dynamic route page `app/(pages)/episodes/[episodeId]/page.tsx` **must** be implemented.
2. It **must** accept `episodeId` from the URL.
3. It **must** use the API service layer (Story 3.2) to fetch episode details.
4. Loading and error states **must** be handled and displayed with themed components.
5. If data found, **must** display: `podcastGeneratedTitle`, `publicationDate`, `episodeNumber`.
6. An embedded HTML5 audio player (`<audio controls>`) **must** play the podcast using the public `audioUrl` from the episode details.
7. A list of included Hacker News stories (from `sourceHNPosts`) **must** be displayed, potentially using a `story-item.tsx` component for each.
8. For each HN story: its title, a link to `originalArticleUrl` (new tab), and a link to `hnLink` (new tab) **must** be displayed.
9. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
10. The page **must** be responsive.
11. Unit/integration tests (Jest with RTL) **must** cover all states, rendering of details, player, links. All tests **must** pass.
**Story 3.5: "About" Page Implementation**
* **User Story Statement:** As a User, I want to access a minimalist, responsive "About Page" (based on `app/(pages)/about/page.tsx` from the scaffold) that clearly explains "BMad Daily Digest," its purpose, and how it works, styled consistently, so I can understand the service.
* **Acceptance Criteria (ACs):**
1. The `app/(pages)/about/page.tsx` component **must** be implemented.
2. It **must** display static informational content (Placeholder: "BMad Daily Digest provides a daily audio summary of top Hacker News discussions for busy tech professionals, generated using AI. Our mission is to keep you informed, efficiently. All content is curated and processed to deliver key insights in an easily digestible audio format, presented with a unique retro-tech vibe.").
3. Styling **must** adhere to the "80s retro CRT terminal" aesthetic.
4. The page **must** be responsive.
5. A link to "About Page" **must** be accessible from site navigation (e.g., via `header.tsx` or `footer.tsx`).
6. Unit tests (Jest with RTL) for rendering static content. All tests **must** pass.
**Story 3.6: Frontend Deployment to S3 & CloudFront via CDK**
* **User Story Statement:** As a Developer, I need the Next.js frontend application to be configured for static export (or an equivalent static-first deployment model) and have its AWS infrastructure (S3 for hosting, CloudFront for CDN and HTTPS) defined and managed via its own AWS CDK application within the frontend repository. This setup should automate the build and deployment of the static site, making the "BMad Daily Digest" web application publicly accessible, performant, and cost-effective.
* **Acceptance Criteria (ACs):**
1. Next.js app **must** be configured for static export suitable for S3/CloudFront.
2. The AWS CDK app within `bmad-daily-digest-frontend/cdk/` (from Story 3.1) **must** define the S3 bucket and CloudFront distribution.
3. CDK stack **must** define: S3 bucket (static web hosting), CloudFront distribution (S3 origin, HTTPS via default CloudFront domain or ACM cert for custom domain if specified for MVP, caching, OAC/OAI).
4. A `package.json` build script **must** generate the static output.
5. The CDK deployment process (`cdk deploy` run via CI or manually for MVP) **must** include steps/hooks to build the Next.js app and sync static files to S3.
6. Application **must** be accessible via its CloudFront URL.
7. All MVP functionalities **must** be operational on the deployed site.
8. HTTPS **must** be enforced.
9. CDK code **must** meet project standards.
## 7. Key Reference Documents
* Product Requirements Document (PRD) - BMad Daily Digest (This Document, v0.2)
* UI/UX Specification - BMad Daily Digest (v0.1)
* System Architecture Document - BMad Daily Digest (v0.1)
* Frontend Architecture Document - BMad Daily Digest (v0.1)
* Algolia Hacker News Search API Documentation (`https://hn.algolia.com/api`)
* Play.ai PlayNote API Documentation (`https://docs.play.ai/api-reference/playnote/post`)
## 8. Out of Scope Ideas Post MVP
* Advanced Audio Player Functionality (skip +/-, speed control, playback position memory).
* User Accounts & Personalization (account creation, email subscription management, customizable podcast hosts).
* Enhanced Content Delivery & Discovery (Daily Email Summary, Full RSS Feed, Full Podcast Transcription, Search Functionality).
* Expanded Content Sources (beyond Hacker News).
* Community & Feedback (In-app feedback mechanisms).
## 9. Change Log
| Change | Date | Version | Description | Author |
| :----------------------------------------------------------- | :------------ | :------ | :--------------------------------------------------------------------------------------------------------- | :------------------------------- |
| Initial PRD draft and MVP scope definition. | May 20, 2025 | 0.1 | Created initial PRD based on Project Brief and discussions on goals, requirements, and Epics/Stories (shells). | John (PM) & User |
| Architectural refinements incorporated into Story ACs. | May 20, 2025 | 0.2 | Updated ACs for Stories 2.1 and 3.1 based on System Architecture Document feedback from Fred (Architect). | Sarah (PO) & User |

View File

@@ -0,0 +1,101 @@
# Project Brief: BMad Daily Digest
## 1. Introduction / Problem Statement
- **The Core Idea is**: To create a daily podcast, "BMad Daily Digest," by scraping top Hacker News posts and their comments, then using an AI service (play.ai PlayNote) to generate an audio summary with two speakers.
- **The Problem Being Solved is**: Busy professionals, especially in the tech world, find it hard to keep up with important discussions and news on platforms like Hacker News due to time constraints. They need a quick, digestible audio format to stay informed.
## 2. Vision & Goals
- **a. Vision**: To become the go-to daily audio source for busy professionals seeking to stay effortlessly informed on the most relevant and engaging discussions from Hacker News.
- **b. Primary Goals (for MVP)**:
1. Successfully scrape the top 10 Hacker News posts (articles and comments) and generate a coherent text file suitable for the play.ai API daily.
2. Reliably submit the generated text to play.ai PlayNote and receive a 2-agent audio podcast daily.
3. Ensure the produced podcast is easily accessible to a pilot group of users (e.g., via a simple download link or a basic podcast feed).
4. Deliver the daily digest by a consistent time each morning (e.g., by 8 AM local time).
- **c. Success Metrics (Initial Ideas)**:
- Content Accuracy: X% of generated summaries accurately reflect the core topics of the Hacker News posts.
- Production Reliability: Successfully produce a podcast on X out of Y days (e.g., 95% uptime).
- User Feedback (Qualitative): Positive feedback from a small group of initial listeners regarding clarity, usefulness, and audio quality.
- Listenership (Small Scale): Number of downloads/listens by the pilot user group.
## 3. Target Audience / Users
- **Primary Users**: Busy tech executives (e.g., VPs, Directors, C-suite in technology companies).
- **Characteristics**:
- Extremely time-poor with demanding schedules.
- Need to stay informed about technology trends, competitor moves, and industry sentiment for strategic decision-making.
- Likely consume content during commutes, short breaks, or while multitasking.
- Value high-signal, concise, and curated information.
- Familiar with Hacker News but lack the time for in-depth daily reading.
## 4. Key Features / Scope (High-Level Ideas for MVP)
1. **Hacker News Scraper:**
- Automatically fetches the top X (e.g., 10) posts from Hacker News daily.
- Extracts the main article content/summary for each post.
- Extracts a selection of top/relevant comments for each post.
2. **Content Aggregator & Formatter:**
- Combines the scraped article content and comments into a single, structured text file.
- Formats the text in a way that's optimal for the play.ai PlayNote API.
3. **AI Podcast Generation:**
- Submits the formatted text file to the play.ai PlayNote API.
- Retrieves the generated audio file.
4. **Basic Web Application (for MVP delivery):**
- **List Page:** Displays a chronological list of daily "BMad Daily Digest" episodes.
- **Detail Page (per episode):**
- Shows the list of individual Hacker News stories included in that day's digest.
- Provides direct links to the original Hacker News post for each story.
- Provides direct links to the source article for each story.
- Embeds an audio player to play the generated podcast for that day.
5. **Scheduling/Automation:**
- The entire backend process (scrape, format, generate podcast, update application data) runs automatically on a daily schedule.
## 5. Post MVP Features / Scope and Ideas
After the successful launch and validation of the MVP, "BMad Daily Digest" could be enhanced with the following features:
- **Daily Email Summary:**
- Generate an email brief from the summarized transcript of the podcast (which can also be sourced from PlayNote).
- Include a direct link to the day's podcast episode in the email.
- **RSS Feed:**
- Provide a standard RSS feed, allowing users to subscribe to the "BMad Daily Digest" in their preferred podcast players.
- **User Accounts & Personalization:**
- Allow users to create accounts.
- Enable email subscription management through accounts.
- Offer options to customize podcast hosts (e.g., select from different AI voices or styles available via play.ai).
- **Expanded Content & Features:**
- Wider range of content sources (beyond Hacker News).
- Advanced audio features (selectable narrators if not covered by customization, variable playback speed within the app).
- Full podcast transcription available on the website.
- Search functionality within the app for past digests or stories.
- **Community & Feedback:**
- In-app user feedback mechanisms (e.g., rating episodes, suggesting improvements).
## 6. Known Technical Constraints or Preferences
- **Development Approach Preference:**
- The full backend (scraping, content aggregation, podcast generation, data storage) is to be built and validated first.
- The frontend UI will be developed subsequently to interact with the established backend API.
- **Technology Stack Preferences (Considered Solid by User):**
- **Frontend:** NextJS React, planned to be hosted on a static S3 site.
- **Backend Services:** AWS Lambda for compute, DynamoDB for storage.
- **Automation Trigger:** Daily execution via a cron job or a REST API call to trigger the Lambda function.
- **Backend Language (Open for Discussion):**
- The user is open to using either Python or TypeScript for the backend, with a note that web scraping capabilities and ease of use with the Algolia API are factors in this decision. This choice will be finalized during more detailed technical planning.
- **Data Source for Hacker News:**
- Utilize the Algolia Hacker News Search API (hn.algolia.com) for fetching posts and comments, as it's generally easier to work with than direct site scraping.
- **Budget Constraints & API Usage:**
- **AWS Services:** Strong preference to operate services (Lambda, DynamoDB, S3, etc.) within the limits of the AWS free tier where possible.
- **play.ai PlayNote API:** The user has an existing purchased subscription, so this service is an exception to the free-tier goal for other services.
- **Timeline:** _(User has not specified a firm timeline for MVP at this stage of the brief)._
- **Risks:**
- Dependency on Algolia HN API (availability, rate limits, potential changes).
- Consistency and quality of AI-generated audio from play.ai.
- Potential API changes or future costs associated with play.ai (beyond current subscription terms).
- Managing daily automated processing effectively.
- **Other User Preferences:** _(User has not specified further preferences at this stage of the brief)._
## 7. Relevant Research (Optional)
- **Hacker News Data Acquisition:** The decision to use the Algolia Hacker News Search API (hn.algolia.com) is based on its known efficiency and ease of use for accessing posts and comments, which is preferable to direct website scraping.

View File

@@ -0,0 +1,65 @@
# Project Structure
The project utilizes a polyrepo structure with separate backend and frontend repositories, each with its own CDK application.
## 1. Backend Repository (`bmad-daily-digest-backend`)
Organized by features within `src/`, using `dash-case` for folders and files (e.g., `src/features/content-ingestion/hn-fetcher-service.ts`).
```plaintext
bmad-daily-digest-backend/
├── .github/
├── cdk/
│ ├── bin/
│ ├── lib/ # Backend Stack, Step Function definitions
│ └── test/
├── src/
│ ├── features/
│ │ ├── dailyJobOrchestrator/ # Main Step Function trigger/definition support
│ │ ├── hnContentPipeline/ # Services for Algolia, scraping, formatting
│ │ ├── playAiIntegration/ # Services for Play.ai submit & polling Lambda logic
│ │ ├── podcastPersistence/ # Services for S3 & DynamoDB storage
│ │ └── publicApi/ # Handlers for API Gateway (status, episodes)
│ ├── shared/
│ │ ├── utils/
│ │ ├── types/
│ │ └── services/ # Optional shared low-level AWS SDK wrappers
├── tests/ # Unit/Integration tests, mirroring src/features/
│ └── features/
... (root config files: .env.example, .eslintrc.js, .gitignore, .prettierrc.js, jest.config.js, package.json, README.md, tsconfig.json)
```
*Key Directories: `cdk/` for IaC, `src/features/` for modular backend logic, `src/shared/` for reusable code, `tests/` for Jest tests.*
## 2. Frontend Repository (`bmad-daily-digest-frontend`)
Aligns with V0.dev generated Next.js App Router structure, using `dash-case` for custom files/folders where applicable.
```plaintext
bmad-daily-digest-frontend/
├── .github/
├── app/
│ ├── (pages)/
│ │ ├── episodes/
│ │ │ ├── page.tsx # List page
│ │ │ └── [episode-id]/
│ │ │ └── page.tsx # Detail page
│ │ └── about/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── globals.css
├── components/
│ ├── ui/ # shadcn/ui based components
│ └── domain/ # Custom composite components (e.g., episode-card)
├── cdk/ # AWS CDK application for frontend infra (S3, CloudFront)
│ ├── bin/
│ └── lib/
├── hooks/
├── lib/
│ ├── types.ts
│ ├── utils.ts
│ └── api-client.ts # Backend API communication
├── public/
├── tests/ # Jest & RTL tests
... (root config files: .env.local.example, .eslintrc.js, components.json, next.config.mjs, package.json, tailwind.config.ts, tsconfig.json)
```
*Key Directories: `app/` for Next.js routes, `components/` for UI, `cdk/` for frontend IaC, `lib/` for utilities and `api-client.ts`.*

View File

@@ -0,0 +1,126 @@
# Core Workflow / Sequence Diagrams
## 1. Daily Automated Podcast Generation Pipeline (Backend)
```mermaid
sequenceDiagram
participant Sched as Scheduler (EventBridge)
participant Orch as Orchestrator (Step Functions)
participant HNF as HN Data Fetcher Lambda
participant Algolia as Algolia HN API
participant ASL as Article Scraper Lambda
participant EAS as External Article Sites
participant CFL as Content Formatter Lambda
participant PSubL as Play.ai Submit Lambda
participant PlayAI as Play.ai API
participant PStatL as Play.ai Status Poller Lambda
participant PSL as Podcast Storage Lambda
participant S3 as S3 Audio Storage
participant MPL as Metadata Persistence Lambda
participant DDB as DynamoDB (Episodes & HNPostState)
Sched->>Orch: Trigger Daily Workflow
activate Orch
Orch->>HNF: Start: Fetch HN Posts
activate HNF
HNF->>Algolia: Request top N posts
Algolia-->>HNF: Return HN post list
HNF->>DDB: Query HNPostProcessState for repeat status & lastCommentFetchTimestamp
DDB-->>HNF: Return status
HNF-->>Orch: HN Posts Data (with repeat status)
deactivate HNF
Orch->>ASL: For each NEW HN Post: Scrape Article (URL)
activate ASL
ASL->>EAS: Fetch article HTML
EAS-->>ASL: Return HTML
ASL-->>Orch: Scraped Article Content / Scrape Failure+Fallback Flag
deactivate ASL
Orch->>HNF: For each HN Post: Fetch Comments (HN Post ID, isRepeat, lastCommentFetchTimestamp, articleScrapedFailedFlag)
activate HNF
HNF->>Algolia: Request comments for Post ID
Algolia-->>HNF: Return comments
HNF->>DDB: Update HNPostProcessState (lastCommentFetchTimestamp)
DDB-->>HNF: Confirm update
HNF-->>Orch: Selected Comments
deactivate HNF
Orch->>CFL: Format Content for Play.ai (HN Posts, Articles, Comments)
activate CFL
CFL-->>Orch: Formatted Text Payload
deactivate CFL
Orch->>PSubL: Submit to Play.ai (Formatted Text)
activate PSubL
PSubL->>PlayAI: POST /playnotes (text, voice params, auth)
PlayAI-->>PSubL: Return { jobId }
PSubL-->>Orch: Play.ai Job ID
deactivate PSubL
loop Poll for Completion (managed by Orchestrator/Step Functions)
Orch->>Orch: Wait (e.g., M minutes)
Orch->>PStatL: Check Status (Job ID)
activate PStatL
PStatL->>PlayAI: GET /playnote/{jobId} (auth)
PlayAI-->>PStatL: Return { status, audioUrl? }
PStatL-->>Orch: Job Status & audioUrl (if completed)
deactivate PStatL
alt Job Completed
Orch->>PSL: Store Podcast (audioUrl, jobId, episode context)
activate PSL
PSL->>PlayAI: GET audio from audioUrl
PlayAI-->>PSL: Audio Stream/File
PSL->>S3: Upload MP3
S3-->>PSL: Confirm S3 Upload (s3Key, s3Bucket)
PSL-->>Orch: S3 Location
deactivate PSL
Orch->>MPL: Persist Episode Metadata (S3 loc, HN sources, etc.)
activate MPL
MPL->>DDB: Save Episode Item & Update HNPostProcessState (lastProcessedDate)
DDB-->>MPL: Confirm save
MPL-->>Orch: Success
deactivate MPL
else Job Failed or Timeout
Orch->>Orch: Log Error, Terminate Sub-Workflow for this job
end
end
deactivate Orch
```
## 2. Frontend User Requesting and Playing an Episode
```mermaid
sequenceDiagram
participant User as User (Browser)
participant FE_App as Frontend App (Next.js on CloudFront/S3)
participant BE_API as Backend API (API Gateway)
participant API_L as API Lambda
participant DDB as DynamoDB (Episode Metadata)
participant Audio_S3 as Audio Storage (S3 via CloudFront)
User->>FE_App: Requests page (e.g., /episodes or /episodes/{id})
activate FE_App
FE_App->>BE_API: GET /v1/episodes (or /v1/episodes/{id}) (includes API Key)
activate BE_API
BE_API->>API_L: Invoke Lambda with request data
activate API_L
API_L->>DDB: Query for episode(s) metadata
activate DDB
DDB-->>API_L: Return episode data
deactivate DDB
API_L-->>BE_API: Return formatted episode data
deactivate API_L
BE_API-->>FE_App: Return API response (JSON)
deactivate BE_API
FE_App->>FE_App: Render page with episode data (list or detail)
FE_App-->>User: Display page
deactivate FE_App
alt User on Episode Detail Page & Clicks Play
User->>FE_App: Clicks play on HTML5 Audio Player
activate FE_App
Note over FE_App, Audio_S3: Player's src attribute is set to CloudFront URL for audio file in S3.
FE_App->>Audio_S3: Browser requests audio file via CloudFront URL
activate Audio_S3
Audio_S3-->>FE_App: Stream/Return audio file
deactivate Audio_S3
FE_App-->>User: Plays audio
deactivate FE_App
end
```

View File

@@ -0,0 +1,30 @@
# Technology Stack
The following table outlines the definitive technology selections for the BMad Daily Digest project:
| Category | Technology | Version / Details | Description / Purpose | Justification (Optional) |
| :------------------- | :----------------------------- | :------------------------------------- | :------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------- |
| **Languages** | TypeScript | Latest stable (e.g., 5.x) | Primary language for backend and frontend. | Consistency, strong typing. |
| **Runtime** | Node.js | 22.x | Server-side environment for backend & Next.js. | User preference, performance. |
| **Frameworks (Frontend)** | Next.js (with React) | Latest stable (e.g., 14.x) | Frontend web application framework. | User preference, SSG, DX. |
| **Frameworks (Backend)** | AWS Lambda (Node.js runtime) | N/A | Execution environment for serverless functions. | Serverless architecture. |
| | AWS Step Functions | N/A | Orchestration of backend workflows. | Robust state management, retries. |
| **Databases** | AWS DynamoDB | N/A | NoSQL database for metadata. | Scalability, serverless, free-tier. |
| **Cloud Platform** | AWS | N/A | Primary cloud provider. | Comprehensive services, serverless. |
| **Cloud Services** | AWS Lambda, API Gateway, S3, CloudFront, EventBridge Scheduler, CloudWatch, IAM, ACM | N/A | Core services for application hosting and operation. | Standard AWS serverless stack. |
| **Infrastructure as Code (IaC)** | AWS CDK (TypeScript) | v2.x Latest stable | Defining cloud infrastructure. | User preference, TypeScript, repeatability. |
| **UI Libraries (Frontend)** | Tailwind CSS | Latest stable (e.g., 3.x) | Utility-first CSS framework. | User preference, customization. |
| | shadcn/ui | Latest stable | Accessible UI components. | User preference, base for themed components. |
| **HTTP Client (Backend)** | axios | Latest stable | Making HTTP requests from backend. | User preference, feature-rich. |
| **SDKs / Core Libraries (Backend)** | AWS SDK for JavaScript/TypeScript | v3.x (Latest stable) | Programmatic interaction with AWS services. | Official AWS SDK, modular. |
| **Scraping / Content Extraction** | Cheerio | Latest stable | Server-side HTML parsing. | Efficient for static HTML. |
| | @mozilla/readability (JS port) | Latest stable | Extracting primary readable article content. | Key for isolating main content. |
| | Playwright (or Puppeteer) | Latest stable | Browser automation (if required for dynamic content). | Handles dynamic sites; use judiciously. |
| **Bundling (Backend)**| esbuild | Latest stable | Bundling TypeScript Lambda functions. | User preference, speed. |
| **Logging (Backend)** | Pino | Latest stable | Structured, low-overhead logging. | Better observability, JSON logs for CloudWatch. |
| **Testing (Backend)**| Jest, ESLint, Prettier | Latest stable | Unit/integration testing, linting, formatting. | Code quality, consistency. |
| **Testing (Frontend)**| Jest, React Testing Library, ESLint, Prettier | Latest stable | Unit/component testing, linting, formatting. | Code quality, consistency. |
| **CI/CD** | GitHub Actions | N/A | Automation of build, test, quality checks. | Integration with GitHub. |
| **External APIs** | Algolia HN Search API, Play.ai PlayNote API | v1 (for both) | Data sources and audio generation. | Core to product functionality. |
*Note: "Latest stable" versions should be pinned to specific versions in `package.json` files during development.*

View File

@@ -0,0 +1,261 @@
# BMad Daily Digest UI/UX Specification
**Version:** 0.1
**Date:** May 20, 2025
**Author:** JaneAI
## 1\. Introduction
This document defines the user experience (UX) goals, information architecture (IA), user flows, and key visual/interaction specifications for the "BMad Daily Digest" web application's MVP. It builds upon the product vision and requirements outlined in the main PRD and will serve as a direct guide for frontend development. Our core aesthetic is an "80s retro CRT terminal" look and feel.
* **Primary Design Files:** For the MVP, detailed visual mockups in separate design files (e.g., Figma) are not planned. The UI design will be directly derived from the specifications within this document, the "User Interaction and Design Goals" section of the PRD, and the established "80s retro CRT terminal" theme using Tailwind CSS and shadcn/ui.
* **Deployed Storybook / Design System:** A Storybook or formal design system is not an initial deliverable for the MVP. Components will be built and styled directly within the Next.js application using shadcn/ui and Tailwind CSS according to the defined aesthetic. This may evolve post-MVP.
## 2\. Overall UX Goals & Principles
This section draws from the "Target Audience / Users" and "User Interaction and Design Goals" defined in the PRD.
**a. Target User Personas:**
* **Primary Persona:** The "Busy Tech Executive."
* **Description (from PRD):** Extremely time-poor individuals (e.g., VPs, Directors, C-suite in technology companies) with demanding schedules.
* **Needs & Motivations:**
* Need to stay informed about technology trends, competitor moves, and industry sentiment for strategic decision-making.
* Value high-signal, concise, and curated information.
* Familiar with Hacker News but lack the time for in-depth daily reading.
* Likely consume content during commutes, short breaks, or while multitasking, making audio a good fit.
* **Key UX Considerations for this Persona:** The interface must be extremely efficient, quick to scan, with no learning curve and immediate access to content.
**b. Usability Goals (for MVP):**
* **Efficiency:** Users must be able to find and start listening to the latest digest with minimal clicks and time.
* **Clarity:** Information (episode lists, story links, player controls) must be presented clearly and unambiguously, especially given the stylized "CRT terminal" theme which requires careful attention to readability.
* **Discoverability:** Users should easily understand how to navigate between the episode list and detail pages, and how to access source articles/HN discussions.
* **Learnability:** The interface should be immediately intuitive, requiring no explanation for these tech-savvy users.
**c. Design Principles:**
1. **Content First, Efficiency Always:** Prioritize quick access to the audio digest and associated information. Every UI element should serve a clear purpose towards this goal, minimizing clutter.
2. **Authentic Retro Tech Aesthetic:** Consistently apply the "80s retro CRT terminal" theme (dark mode, glowing green ASCII-style visuals) to create a unique and engaging experience, without sacrificing usability.
3. **Simplicity & Focus:** Keep the UI for the MVP focused on core tasks: finding an episode, playing it, and accessing source links. Avoid non-essential features or complex interactions.
4. **Readability within Theme:** While maintaining the retro aesthetic, ensure text is highly readable with sufficient contrast and appropriate "ASCII/bitmap-style" font choices (if used).
5. **Responsive & Accessible Foundation:** Design for responsiveness across desktop and mobile from the start, and ensure basic accessibility principles are met within the chosen theme.
## 3\. Information Architecture (IA)
This section outlines the overall organization and structure of the web application's content and features for the MVP.
**a. Site Map / Screen Inventory (MVP):**
For the MVP, we have identified the following core screens:
```mermaid
graph TD
A[Home / Episode List Page] --> B{Episode Detail Page};
A --> C[About Page];
B --> A;
C --> A;
```
* **Home / Episode List Page (`/` or `/episodes`):** The main landing page, displaying a reverse chronological list of daily podcast episodes.
* **Episode Detail Page (`/episodes/{episodeId}`):** Displays the selected podcast episode, including the audio player, and links to source articles and Hacker News discussions.
* **About Page (`/about`):** Provides information about the "BMad Daily Digest" service.
**b. Navigation Structure (MVP):**
* **Primary Navigation:**
* A simple, persistent header or footer navigation element should be present across all pages.
* This navigation **must** include clear links to:
* "Home" (or "Episodes" leading to the Episode List Page).
* "About" (leading to the About Page).
* The site title/logo (e.g., "BMad Daily Digest") in the header **should** also link to the Home/Episode List Page.
* **Content-Specific Navigation:**
* On the **Episode List Page**, each listed episode **must** function as a direct link to its respective **Episode Detail Page**.
* The **Episode Detail Page** will contain external links to source articles and Hacker News discussions, which **must** open in new browser tabs.
* **Theme Considerations:** All navigation elements (links, buttons if any) must conform to the "80s retro CRT terminal" aesthetic (e.g., styled as glowing text links).
## 4\. User Flows
This section details the primary paths users will take to interact with the "BMad Daily Digest" MVP.
### a. User Flow 1: Consuming the Latest Digest
* **Goal:** The user wants to quickly find and listen to the most recent daily digest.
* **Steps / Diagram:**
```mermaid
graph TD
A[User lands on Home/Episode List Page] --> B[Sees list of episodes, newest first];
B --> C[Clicks on the latest/topmost episode];
C --> D[Navigates to Episode Detail Page for that episode];
D --> E[Presses play on embedded audio player];
E --> F[Listens to podcast];
D --> G{Chooses to explore?};
G -- Yes --> H[Clicks a source article or HN discussion link];
H --> I[Link opens in new tab];
G -- No --> F;
```
### b. User Flow 2: Accessing an Older Digest
* **Goal:** The user wants to find and listen to a specific past episode.
* **Steps / Diagram:**
```mermaid
graph TD
A[User lands on Home/Episode List Page] --> B[Scrolls/browses the list of episodes];
B --> C[Identifies and clicks on a desired older episode];
C --> D[Navigates to Episode Detail Page for that episode];
D --> E[Presses play on embedded audio player];
E --> F[Listens to podcast];
```
### c. User Flow 3: Learning About the Service
* **Goal:** The user wants to understand what "BMad Daily Digest" is.
* **Steps / Diagram:**
```mermaid
graph TD
A[User is on any page of the application] --> B[Locates and clicks the "About" link in site navigation/footer];
B --> C[Navigates to the About Page];
C --> D[Reads information about the service];
```
## 5\. Wireframes & Mockups
As established in the Introduction, for this streamlined MVP, detailed visual mockup files (e.g., in Figma) are not planned. The UI design and layout will be directly derived from the specifications within this document, the agreed-upon "80s retro CRT terminal" aesthetic, and will be kickstarted using an AI UI generation tool with Tailwind CSS and shadcn/ui.
This section provides high-level conceptual descriptions of the key screen layouts to guide that process.
**a. General Layout Principles:**
* **Theme:** All screens must consistently implement the "80s retro CRT terminal" aesthetic (dark mode, glowing green ASCII-style text/elements, potentially a subtle scanline effect or CRT curvature if achievable without sacrificing readability).
* **Typography:** Font choices should align with retro computing/ASCII art styles while ensuring high readability (specific fonts TBD, but likely monospaced or pixel-style for key elements).
* **Navigation:** A persistent, simple navigation area (e.g., a header or footer) will provide access to "Home/Episodes" and "About."
**b. Screen Layout Descriptions (Conceptual):**
**1. Home / Episode List Page (`/` or `/episodes`)**
\* **Header:**
\* Site Title/Logo (e.g., "BMad Daily Digest" styled in the retro theme). Clicking this navigates to this page.
\* Navigation Links: "Episodes" (if not the home page itself), "About."
\* **Main Content Area:**
\* A clear heading like "Latest Digests" or "Episodes."
\* A vertically stacked list of episodes, presented in reverse chronological order.
\* Each list item will display: "Episode [EpisodeNumber]: [PublicationDate] - [PodcastTitle]" as a clickable link/element.
\* If no episodes are available, a clear message like "No digests available yet. Tune in tomorrow\!" styled to fit the theme.
\* Loading/error states will be displayed in this area as needed.
\* **Footer (Optional):**
\* Could repeat navigation links or contain a simple copyright/year.
**2. Episode Detail Page (`/episodes/{episodeId}`)**
\* **Header:** Consistent with the List Page.
\* **Main Content Area:**
\* Episode Identification: Display `PodcastGeneratedTitle`, `EpisodeNumber`, and `PublicationDate` prominently.
\* **Audio Player:** An embedded HTML5 `<audio controls>` element, styled to fit the retro theme as much as possible. The `src` will be the podcast audio file.
\* **Hacker News Stories Section:**
\* A clear sub-heading like "Stories Covered in this Digest" or "Sources."
\* A list of the individual Hacker News stories included in the podcast.
\* For each story:
\* Its title.
\* A link to the "Original Article" (opens in new tab).
\* A link to the "HN Discussion" (opens in new tab).
\* These links should be clearly styled and distinguishable.
\* Loading/error states for episode data will be displayed here.
\* **Footer (Optional):** Consistent with the List Page.
**3. About Page (`/about`)**
\* **Header:** Consistent with other pages.
\* **Main Content Area:**
\* A clear heading like "About BMad Daily Digest."
\* Static text content (Placeholder: "BMad Daily Digest provides a daily audio summary of top Hacker News discussions for busy tech professionals, generated using AI.") explaining the service, its purpose, and a high-level overview of how it's generated. The text itself should be styled in the retro theme.
\* **Footer (Optional):** Consistent with other pages.
## 6\. Component Library / Design System Reference
For the "BMad Daily Digest" MVP, we will proceed as follows:
* **Foundation:** We will **not** be using a pre-existing external, comprehensive design system. Instead, we will be creating a unique, project-specific set of themed UI components.
* **Core Technologies:**
* **shadcn/ui:** This will be used as a base library of accessible and unstyled components. We will heavily customize these components.
* **Tailwind CSS:** This will be the primary utility-first CSS framework used for styling all components and achieving the "80s retro CRT terminal" aesthetic.
* **AI-Assisted Kickstart:** As per Story 3.1 in the PRD, an AI UI generation tool will be leveraged to kickstart the initial UI structure and some of the core presentational components. These AI-generated components will then be refined and extended.
* **No Formal Storybook for MVP:** A deployed Storybook or formal, isolated design system documentation is not a deliverable for the initial MVP. Components will be developed and documented within the Next.js application structure.
**Foundational Components to Thematically Style for MVP:**
The following foundational elements will need careful thematic styling to establish the "80s retro CRT terminal" look and feel:
1. **Text Rendering Components:** Headings, Body Text/Paragraphs, Links (all styled with glowing green ASCII/pixelated look).
2. **Layout Components:** Main Page Wrapper/Container, Header/Navigation Bar, Footer (if any).
3. **List Components:** Episode List Item, Source Story List Item.
4. **Interactive Elements:** Clickable Links/Navigation Items, Audio Player Container (styling around the native player).
5. **Messaging/Feedback Components:** Loading State Indicator, Error Message Display (themed).
## 7\. Branding & Style Guide Reference
This section outlines the core visual elements for the "80s retro CRT terminal" and "80s retro everything" themes.
**a. Color Palette:**
* **Primary Background:** Very dark (e.g., near-black `#0A0A0A` or very dark charcoal/green `#051005`).
* **Primary Text/Foreground ("Glowing Green"):** Vibrant "phosphor" green (e.g., `#39FF14`, `#00FF00`). Must be tested for readability.
* **Accent/Secondary Text:** Dimmer or alternative shade of green (e.g., `#2A8D2A`).
* **Highlight/Interactive Hover/Focus:** Brighter green or primary green with a "glow" effect.
* **Feedback Colors (Error, Success, Warning - if needed for MVP):** Retro-styled amber/orange for errors (e.g., `#FF8C00`), primary green for success.
**b. Typography:**
* **Primary Font Family:** Monospaced, pixelated, or classic computer-terminal style font (e.g., "VT323", "Press Start 2P", "Perfect DOS VGA", or a clean system monospaced font). High readability is paramount.
* **Font Sizes:** Simple typographic scale via Tailwind, suitable for the retro theme.
* **Font Weights:** Likely limited (normal, bold) depending on chosen retro font.
* **Letter Spacing/Line Height:** Adjusted to enhance CRT feel and readability.
**c. Iconography (MVP):**
* **Style:** Minimalist, pixel-art style, or simple ASCII/text-based symbols.
* **Usage:** Sparse for MVP. Navigation might use ASCII arrows (e.g., `-> About`).
**d. Spacing & Grid:**
* **Approach:** Managed via Tailwind CSS utility classes, adhering to a consistent spacing scale aiming for a slightly "blocky" or "grid-aligned" feel.
## 8\. Accessibility (AX) Requirements
The application must be usable by people with a wide range of abilities, striving to meet key principles of WCAG 2.1 Level AA for essential functionalities in the MVP.
**a. Target Compliance (MVP):** Strive for WCAG 2.1 Level AA for key aspects.
**b. Specific Requirements (MVP):**
1. **Contrast Ratios:** All text **must** meet WCAG AA contrast minimums (4.5:1 for normal, 3:1 for large), especially critical for the "glowing green on dark" theme.
2. **Keyboard Navigation:** All interactive elements **must** be focusable and operable via keyboard, with a logical focus order and clear, themed focus indicators.
3. **Screen Reader Compatibility:** Use semantic HTML. Core content **must** be understandable and operable with screen readers. ARIA attributes used judiciously for custom components (shadcn/ui helps).
4. **Resizable Text:** Users **should** be able to resize text up to 200% via browser zoom without loss of functionality or horizontal scrolling.
5. **Images (if any):** Meaningful images **must** have appropriate `alt` text.
6. **Understandable Link Text:** Link text **should** clearly describe its destination or purpose.
## 9\. Responsiveness
The web application must provide a seamless experience across devices, maintaining the "80s retro CRT terminal" aesthetic.
**a. Breakpoints (Leveraging Tailwind CSS Defaults as a Start):**
* `sm`: 640px, `md`: 768px, `lg`: 1024px, `xl`: 1280px, `2xl`: 1536px. (Defaults expected to be sufficient for MVP).
**b. Adaptation Strategy:**
1. **Layout:** Single-column on smaller screens (`sm` and below). Potential for multi-column on wider screens if appropriate, but simplicity prioritized.
2. **Navigation:** Must remain accessible. May collapse to a themed "hamburger" menu or simplified icons on smaller screens if header becomes crowded.
3. **Typography & Spacing:** Adapt via Tailwind responsive utilities to ensure readability.
4. **Interactive Elements:** Adequate touch target sizes on mobile.
5. **Content Prioritization:** Core content always prioritized and accessible.
## 10\. Change Log
| Version | Date | Author | Summary of Changes |
| :------ | :----------- | :------------------------------ | :------------------------------------------------------- |
| 0.1 | May 20, 2025 | Jane (Design Architect) & User | Initial draft of the UI/UX Specification document. |

View File

@@ -0,0 +1,77 @@
# V0.dev Prompt for BMad Daily Digest
**"BMad Daily Digest" MVP UI**
**Overall Project & Theme:**
"Create a 3-page responsive web application called 'BMad Daily Digest' using Next.js (App Router), React, Tailwind CSS, and aiming for shadcn/ui compatible component structures where possible.
The entire application must have a strong '80s retro CRT terminal' aesthetic. This means:
* **Overall Dark Mode:** Use a near-black background (e.g., #0A0A0A or a very dark desaturated green like #051005).
* **Primary Text Color:** A vibrant, "glowing" phosphor green (e.g., #39FF14 or #00FF00). This should be the main color for text, active links, and key interface elements.
* **Secondary Text Color:** A dimmer or slightly desaturated green for less emphasized text.
* **Font:** Use a monospaced, pixelated, or classic computer terminal-style font throughout the application (e.g., VT323, Press Start 2P for headings, or a highly readable system monospaced font like Consolas or Menlo for body copy if specific retro fonts prove hard to read for longer text). Prioritize readability within the theme.
* **Visual Style:** Think minimalist, text-heavy, with sharp edges. Subtle effects like faint scanlines or a very slight screen curvature are a bonus if they don't clutter the UI or impact performance, but not essential for the first pass. No modern rounded corners or gradients unless they specifically enhance the retro terminal feel (e.g., a subtle glow).
* **Interactions:** Links and interactive elements should have a clear hover/focus state, perhaps a brighter green or a block cursor effect, fitting the terminal theme.
The application needs to be responsive, adapting to single-column layouts on mobile."
**Shared Elements:**
"1. **Main Layout Wrapper:** A full-screen component that establishes the dark background and CRT theme for all pages.
2. **Header Component:**
* Displays the site title 'BMad Daily Digest' in the primary glowing green, styled prominently (perhaps with a slightly larger or more distinct retro font). Clicking the title should navigate to the Home/Episode List page.
* Contains simple text-based navigation links: 'Episodes' (links to home/list) and 'About'. These links should also use the glowing green text style and have clear hover/focus states.
* The header should be responsive; on smaller screens, if navigation links become crowded, they can stack or be accessible via a simple themed menu icon (e.g., an ASCII-art style hamburger `☰`).
3. **Footer Component (Optional, Minimalist):**
* If included, a very simple text-based footer with a copyright notice (e.g., '© 2025 BMad Daily Digest') and perhaps repeat navigation links ('Episodes', 'About'), styled minimally in the secondary green text color."
**Page 1: Home / Episode List Page (Default Route `/`)**
"This page lists the daily podcast episodes.
* It should use the shared Header and Footer (if applicable).
* Below the header, display a clear heading like 'LATEST DIGESTS' or 'EPISODE LOG' in the primary glowing green.
* The main content area should display a reverse chronological list of podcast episodes.
* Each episode in the list should be a clickable item/card that navigates to its specific Episode Detail Page (e.g., `/episodes/[id]`).
* The display format for each list item should be: 'EPISODE [EpisodeNumber]: [PublicationDate] - [PodcastGeneratedTitle]'. For example: 'EPISODE 042: 2025-05-20 - Tech Highlights & Discussions'.
* `[EpisodeNumber]` is a number.
* `[PublicationDate]` is a date string (e.g., YYYY-MM-DD).
* `[PodcastGeneratedTitle]` is the title of the podcast for that day.
* The list items should have a clear visual separation and a hover/focus state.
* If there are no episodes, display a message like 'NO DIGESTS AVAILABLE. CHECK BACK TOMORROW.' in the themed style.
* Include a themed loading state (e.g., 'LOADING EPISODES...') to be shown while data is being fetched.
* Include a themed error state (e.g., 'ERROR: COULD NOT LOAD EPISODES.') if data fetching fails."
**Page 2: Episode Detail Page (Dynamic Route, e.g., `/episodes/[episodeId]`)**
"This page displays the details for a single selected podcast episode.
* It should use the shared Header and Footer (if applicable).
* Prominently display the `PodcastGeneratedTitle`, `EpisodeNumber`, and `PublicationDate` of the current episode at the top of the main content area, styled in the primary glowing green.
* Below this, embed a standard HTML5 audio player (`<audio controls>`). The player itself will likely have default browser styling, but ensure the container or area around it fits the overall dark retro theme. The `src` for the audio will be dynamic.
* Below the audio player, include a section with a clear heading like 'STORIES COVERED IN THIS DIGEST' or 'SOURCE LOG'.
* Under this heading, display a list of the Hacker News stories that were included in this podcast episode.
* For each story in this list, display:
* Its title (as plain text).
* A clearly labeled link: 'Read Article' (linking to the original source article URL, should open in a new tab).
* A clearly labeled link: 'HN Discussion' (linking to its Hacker News discussion page URL, should open in a new tab).
* These links should be styled according to the theme (glowing green, clear hover/focus).
* Include themed loading and error states for fetching episode details."
**Page 3: About Page (Static Route, e.g., `/about`)**
"This page provides information about the 'BMad Daily Digest' service.
* It should use the shared Header and Footer (if applicable).
* Display a clear heading like 'ABOUT BMAD DAILY DIGEST'.
* The main content area should display static informational text. For placeholder text, use: 'BMad Daily Digest provides a daily audio summary of top Hacker News discussions for busy tech professionals, generated using AI. Our mission is to keep you informed, efficiently. All content is curated and processed to deliver key insights in an easily digestible audio format, presented with a unique retro-tech vibe.'
* All text and headings should adhere to the '80s retro CRT terminal' theme."
---
**Key Instructions for V0:**
* Prioritize the "80s retro CRT terminal" aesthetic in all generated components: dark background, glowing green text, monospaced/pixel fonts.
* Use Tailwind CSS for all styling.
* Generate React components using TypeScript for a Next.js (App Router) application.
* Ensure layouts are responsive and adapt to a single column on mobile.
* Focus on clean, readable code structure for the generated components.
* The HTML5 audio player controls will likely be browser default, but any surrounding elements should be themed.
* Links for "Read Article" and "HN Discussion" must be distinct and clearly indicate they are external links that open in new tabs.