--- name: programming-stories-requirements description: "Generate concise, well-structured feature requirement documents for the Programming Stories Dashboard project. Use this skill whenever the user wants to plan, spec out, define, or document a new feature, enhancement, or change to the Programming Stories Dashboard — including changes to HackerNewsScraperService, ProgrammingStoriesApi, the Kafka pipeline, filtering logic, API endpoints, the in-memory store, or the Angular frontend integration. Trigger when the user says things like 'I want to add...', 'let's build...', 'I'm thinking of a feature...', 'write up requirements for...', or 'help me spec out...'. The output is a focused requirements doc purpose-built for handing to Claude Code in Plan mode." --- # Programming Stories Requirements Skill Read `~/.claude/skills/requirements/SKILL.md` and follow its workflow, output format, and quality guidance exactly. The Architecture Reference below replaces the generic architecture context in that skill — use it instead of asking the user about the codebase. --- ## Architecture Reference The project is a .NET 10 solution with two services and a Kafka backbone: **HackerNewsScraperService** (`source/HackerNewsScraperService/`) - Worker Service that polls HackerNews Firebase API every 60s - `ScraperService.IsProgrammingRelated()` — keyword filter before publishing - Publishes matching stories as JSON to Kafka topic `programming-stories` - In-memory dedup with a `HashSet` (capped at 1000 IDs) - Config: `Scraper:PollingIntervalSeconds`, `Scraper:MaxStoriesToProcessPerCycle` **ProgrammingStoriesApi** (`source/ProgrammingStoriesApi/`) - ASP.NET Core Minimal API - `StoryConsumerService` — background Kafka consumer that upserts into `StoryStore` - `StoryStore` — thread-safe LRU-style in-memory store, capped at `Store:MaxCount` stories - `GET /api/stories?start=&end=&minScore=` — filtered list, newest first - `GET /api/stories/{id}` — single story by ID - CORS configured for Angular frontend at `http://localhost:4200` **HackerNewsStory** (defined in each project independently): ``` Id, By, Title, Url, Score, Time (unix epoch), Descendants, Type ``` **Infrastructure**: Kafka runs locally via Docker Compose (KRaft mode, `localhost:9092`) --- ## Project-Specific Example **User says**: "I want to add pagination to the stories endpoint." **Good requirements doc**: ```markdown # Feature: Paginated Stories Endpoint ## Goal The `/api/stories` endpoint currently returns all matching stories at once. Add cursor-based pagination so the Angular frontend can load stories incrementally and reduce initial payload size. ## Affected Components - `ProgrammingStoriesApi/Program.cs` — update `/api/stories` endpoint signature and response shape - `ProgrammingStoriesApi/Services/StoryStore.cs` — add paginated query method ## Acceptance Criteria - [ ] `GET /api/stories` accepts optional `cursor` and `limit` query parameters - [ ] Response includes a `nextCursor` field (null when no more results) - [ ] Default page size is 50, configurable via `Store:DefaultPageSize` - [ ] Existing `start`, `end`, and `minScore` filters still work with pagination - [ ] CORS policy requires no changes ## Constraints - Use cursor-based (not offset) pagination to remain stable as new stories arrive - Follow the existing Options pattern for configuration (bind via `builder.Configuration`) - Do not break the existing `/api/stories/{id}` endpoint ## Non-Goals - Frontend Angular implementation — this is API only - Persistent storage or external caching - Authentication or rate limiting ## Notes / Assumptions - The cursor can be opaque to the client — encoding insertion order position is sufficient - StoryStore's LinkedList order makes cursor-based pagination natural ```