Files
FlowReader/_bmad-output/planning-artifacts/epics.md
T

13 KiB

stepsCompleted, inputDocuments
stepsCompleted inputDocuments
step-01-validate-prerequisites
step-02-design-epics
step-03-create-stories
c:\Users\Michael\VSCODE\FlowReader_bmad-output\planning-artifacts\prd.md
c:\Users\Michael\VSCODE\FlowReader_bmad-output\planning-artifacts\architecture.md

FlowReader - Epic Breakdown

Overview

This document provides the complete epic and story breakdown for FlowReader, decomposing the requirements from the PRD and Architecture inputs into implementable stories.

Requirements Inventory

Functional Requirements

FR1: Inscription autonome d'un nouvel utilisateur. FR2: Authentification sécurisée (Session/JWT). FR3: Isolation stricte des données (Flux, Lectures, Favoris) par compte utilisateur. FR4: Ajout de flux via URL (support RSS/Atom auto-détecté). FR5: Détection automatique des métadonnées (Titre, Icône) à l'ajout. FR6: Importation de flux en masse via fichier OPML. FR7: Gestion des flux (Renommer, Supprimer). FR8: Dashboard unifié "Nouveautés" trié par date. FR9: Mode "Lecture Plaisir" avec extraction du contenu principal (nettoyage HTML). FR10: Marquage "Lu" manuel ou automatique (scroll/swipe). FR11: Marquage "Tout lu" par flux ou global. FR12: Gestion des Favoris ("Star" / "Read Later"). FR13: Push temps réel des nouveaux articles (Websockets) vers le client connecté. FR14: Synchronisation instantanée de l'état de lecture entre appareils. FR15: Liste des utilisateurs inscrits (Vue Admin). FR16: Suppression de compte utilisateur.

NonFunctional Requirements

NFR1: Empreinte mémoire totale (Back+Front) < 150 Mo RAM. NFR2: Temps de chargement article (TTI) < 100ms perçu. NFR3: Score Lighthouse Mobile > 90. NFR4: Architecture SPA (Single Page App) optimisée "Offline First" (Optimistic UI). NFR5: Redémarrage conteneur (Recovery Time) < 5 secondes. NFR6: Résilience totale aux flux défaillants (Timeout 5s strict, pas de blocage global). NFR7: Isolation des données inter-utilisateurs validée par tests. NFR8: Aucune télémétrie ou fuite de données (Privacy by Design).

Additional Requirements

From Architecture:

  • Starter Template: Custom Composite Stack (Go Chi + Vite + Postgres).
  • Database: PostgreSQL with strict tuning (shared_buffers=24MB).
  • Infra: Docker Compose with healthchecks.
  • Migration: SQL Migrations via golang-migrate or goose.
  • API: REST JSON API + OpenAPI 3.0 Specs.
  • Testing: Integration tests with TestContainers (or similar isolation).

From UX/Vision (PRD):

  • Mobile First: Swipes, transitions, One-handed usage.
  • Zéro Friction: Add feed < 2 clicks.

FR Coverage Map

FR1: Epic 1 - Inscription autonome FR2: Epic 1 - Authentification sécurisée FR3: Epic 1/4 - Isolation stricte (Fondation en Epic 1, Validation en Epic 4) FR4: Epic 2 - Ajout de flux via URL FR5: Epic 2 - Détection métadonnées FR6: Epic 2 - Import OPML FR7: Epic 2 - Gestion flux FR8: Epic 3 - Dashboard Nouveautés FR9: Epic 3 - Mode Lecture Plaisir FR10: Epic 3 - Marquage Lu FR11: Epic 3 - Marquage Tout Lu FR12: Epic 3 - Gestion Favoris FR13: Epic 3 - Push Websockets FR14: Epic 4 - Sync Multi-device FR15: Epic 4 - Vue Admin FR16: Epic 4 - Suppression Compte

Epic List

Epic 1: "Walking Skeleton" & User Access

Goal: Establish the complete infrastructure and allow secure user access. Outcome: Users can visit the app, register, login, and see a secure empty state. FRs covered: FR1, FR2, FR3 (partial), FR16 (partial)

Story 1.1: Project Initialization & Walking Skeleton

As a Developer, I want to initialize the project structure and Docker environment, So that I have a running foundation to build upon.

Acceptance Criteria:

Given A clean git repository When I run docker-compose up Then A Go Backend container should start and listen on port 8080 And A PostgreSQL container should start and accept connections And Calling GET /health on the backend should return 200 OK And The Project Structure should match the Architecture definitions

Story 1.2: Database Migration System

As a Developer, I want a versioned database migration system, So that I can evolve the schema reliably across environments.

Acceptance Criteria:

Given The running Postgres container When I run the migration command (e.g. make migrate-up) Then The users table should be created in the database And A schema_migrations table should track the version And The application should fail to start if DB connection fails

Story 1.3: User Registration API

As a New User, I want to create an account, So that I can have my own private space for feeds.

Acceptance Criteria:

Given The registration endpoint POST /api/v1/auth/register When I send valid email and password (>8 chars) Then A new user record is created in the DB with a Hashed Password (Argon2) And I receive a 201 Created response When I send a duplicate email Then I receive a 409 Conflict error And Inputs are validated (email format, password length)

Story 1.4: Session Authentication

As a Registered User, I want to log in securely, So that I can access my private data.

Acceptance Criteria:

Given A registered user When I POST valid credentials to /api/v1/auth/login Then I receive a 200 OK And A session_id cookie is set (HttpOnly, Secure, SameSite=Strict) And A session record is created in the DB When I call a protected endpoint without the cookie Then I receive 401 Unauthorized

Story 1.5: Frontend Auth Foundation

As a User, I want to log in via a web interface, So that I can access the application easily.

Acceptance Criteria:

Given The frontend application running on Vite When I navigate to /login Then I see a login form When I submit valid credentials Then I am redirected to the Dashboard (/) And My session state is persistent on refresh (checked via /api/v1/users/me)

Epic 2: Feed Core Engine

Goal: Enable the aggregation and management of content feeds. Outcome: Users can populate their reader via URL or OPML, and the backend reliably fetches content. FRs covered: FR4, FR5, FR6, FR7

Story 2.1: Feed Model & Add Feed by URL

As a User, I want to add a feed by providing its URL, So that I can start receiving articles from that source.

Acceptance Criteria:

Given Database migrations for feeds and articles tables When I POST a valid RSS/Atom URL to /api/v1/feeds Then The feed is parsed and stored in the database And Initial articles are fetched and stored And I receive a 201 Created with the feed object

Story 2.2: Feed Metadata Auto-Discovery

As a User, I want feed titles and icons to be detected automatically, So that I don't have to manually configure each feed.

Acceptance Criteria:

Given A feed URL is submitted When The backend parses the feed Then The feed title is extracted from the RSS/Atom XML And The favicon is fetched from the source domain And The feed type (RSS 2.0, Atom 1.0) is detected

Story 2.3: OPML Import

As a User migrating from another reader, I want to import my feeds via OPML file, So that I can quickly set up my account.

Acceptance Criteria:

Given An authenticated user When I POST an OPML file to /api/v1/feeds/import Then All feeds in the OPML are parsed and added And Duplicate feeds (by URL) are skipped And I receive a summary of imported/skipped feeds

Story 2.4: Feed Management (CRUD)

As a User, I want to rename or delete my feeds, So that I can organize my subscriptions.

Acceptance Criteria:

Given An authenticated user with existing feeds When I call GET /api/v1/feeds Then I receive a list of my feeds with metadata When I call PATCH /api/v1/feeds/:id with a new title Then The feed title is updated When I call DELETE /api/v1/feeds/:id Then The feed and its articles are removed

Story 2.5: Background Feed Fetcher

As a User, I want my feeds to update automatically, So that I always have fresh content.

Acceptance Criteria:

Given A scheduled Go worker (e.g., every 15 minutes) When The worker runs Then Each feed is fetched concurrently with 5s timeout And New articles are saved to the database And Failing feeds do not block other feeds And Last fetch status (success/error) is recorded

Epic 3: "Lecture Plaisir" & Real-Time Experience

Goal: Deliver the core value proposition: a fluid, distraction-free reading experience. Outcome: Users can read, track status, and receive updates instantly in a mobile-first UI. FRs covered: FR8, FR9, FR10, FR11, FR12, FR13

Story 3.1: Dashboard "Nouveautés"

As a User, I want to see all my unread articles in one view, So that I can quickly catch up on new content.

Acceptance Criteria:

Given An authenticated user with feeds When I call GET /api/v1/articles?unread=true Then I receive a paginated list of unread articles sorted by date (newest first) And Each article includes title, source feed, publication date, and excerpt

Story 3.2: Article Detail & Reader Mode

As a User, I want to read articles in a clean, distraction-free format, So that I can focus on the content.

Acceptance Criteria:

Given An article ID When I call GET /api/v1/articles/:id Then I receive the article with its full content And The content is sanitized (no scripts, no ads, clean HTML) And The frontend renders it in a "Reader Mode" layout

Story 3.3: Mark as Read (Manual & Auto)

As a User, I want articles to be marked as read when I finish them, So that I know what I've already seen.

Acceptance Criteria:

Given An article in the UI When I click "Mark as Read" or scroll to the bottom of the article Then The article's read_at timestamp is set via PATCH /api/v1/articles/:id/read And It no longer appears in the "Unread" filter And Frontend uses Optimistic UI (updates immediately before API confirms)

Story 3.4: Mark All as Read

As a User, I want to mark all articles in a feed (or globally) as read, So that I can start fresh when overwhelmed.

Acceptance Criteria:

Given A feed with unread articles When I call POST /api/v1/feeds/:id/mark-all-read Then All articles in that feed are marked as read When I call POST /api/v1/articles/mark-all-read Then All my unread articles globally are marked as read

Story 3.5: Favorites System

As a User, I want to save articles for later, So that I can revisit important content.

Acceptance Criteria:

Given An article When I call PATCH /api/v1/articles/:id/favorite with {favorite: true} Then The article is marked as a favorite When I call GET /api/v1/articles?favorite=true Then I receive only my favorited articles

Story 3.6: Websocket Push Notifications

As a User, I want to receive new articles instantly without refreshing, So that I always have the latest content.

Acceptance Criteria:

Given A connected Websocket (/ws) When The background fetcher finds new articles for my feeds Then A new_article event is pushed to my connection And The frontend updates the Dashboard in real-time And Disconnections are handled gracefully with auto-reconnect

Epic 4: Advanced Systems & Robustness

Goal: Final optimizations, admin tools, and multi-device synchronization. Outcome: A robust, production-ready system meeting strict memory constraints. FRs covered: FR14, FR15, FR16, FR3 (Final Validation)

Story 4.1: Multi-Device Sync

As a User with multiple devices, I want my read/favorite status to sync instantly, So that I can seamlessly switch between devices.

Acceptance Criteria:

Given A user logged in on two devices (e.g., phone and PC) When I mark an article as read on Device A Then Device B receives a Websocket event and updates the UI immediately And The sync works for read and favorite status changes

Story 4.2: Admin User List

As an Administrator, I want to see all registered users, So that I can manage the instance.

Acceptance Criteria:

Given An admin user (e.g., first registered user) When I call GET /api/v1/admin/users Then I receive a list of all users with their email and registration date When A non-admin user calls this endpoint Then They receive 403 Forbidden

Story 4.3: Delete User Account

As an Administrator, I want to delete a user account, So that I can remove inactive or abusive users.

Acceptance Criteria:

Given An admin user When I call DELETE /api/v1/admin/users/:id Then The user's account is deleted And All associated feeds, articles, and sessions are cascade deleted And The deleted user session is invalidated

Story 4.4: Performance & RAM Optimization

As a Self-Hoster, I want the application to run within strict memory limits, So that I can deploy it on low-resource servers.

Acceptance Criteria:

Given A Docker Compose deployment When The application is running with 10 feeds and 500 articles Then Total container memory (App + Postgres) is under 150MB And Postgres is configured with shared_buffers=24MB, max_connections=20 And Go backend is profiled for memory leaks