Files
BMAD-METHOD/demos/v3-output-demo-files/prd.draft.md
2025-05-21 20:24:31 -05:00

44 KiB

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