feat: implement v0.4.0 - Reports, Charts, Comparison, Dark Mode, E2E Testing
Backend (@backend-dev): - Add ReportService with PDF/CSV generation (reportlab, pandas) - Implement Report API endpoints (POST, GET, DELETE, download) - Add ReportRepository and schemas - Configure storage with auto-cleanup (30 days) - Rate limiting: 10 downloads/minute - Professional PDF templates with charts support Frontend (@frontend-dev): - Integrate Recharts for data visualization - Add CostBreakdown, TimeSeries, ComparisonBar charts - Implement scenario comparison page with multi-select - Add dark/light mode toggle with ThemeProvider - Create Reports page with generation form and list - Add new UI components: checkbox, dialog, tabs, label, skeleton - Implement useComparison and useReports hooks QA (@qa-engineer): - Setup Playwright E2E testing framework - Create 7 test spec files with 94 test cases - Add visual regression testing with baselines - Configure multi-browser testing (Chrome, Firefox, WebKit) - Add mobile responsive tests - Create test fixtures and helpers - Setup GitHub Actions CI workflow Documentation (@spec-architect): - Create detailed kanban-v0.4.0.md with 27 tasks - Update progress.md with v0.4.0 tracking - Create v0.4.0 planning prompt Features: ✅ PDF/CSV Report Generation ✅ Interactive Charts (Pie, Area, Bar) ✅ Scenario Comparison (2-4 scenarios) ✅ Dark/Light Mode Toggle ✅ E2E Test Suite (94 tests) Dependencies added: - Backend: reportlab, pandas, slowapi - Frontend: recharts, date-fns, @radix-ui/react-checkbox/dialog/tabs - Testing: @playwright/test 27 tasks completed, 100% v0.4.0 implementation
This commit is contained in:
54
src/repositories/report.py
Normal file
54
src/repositories/report.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""Report repository with specific methods."""
|
||||
|
||||
from typing import Optional, List
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, update, desc
|
||||
|
||||
from src.models.report import Report
|
||||
from src.repositories.base import BaseRepository
|
||||
|
||||
|
||||
class ReportRepository(BaseRepository[Report]):
|
||||
"""Repository for Report model with specific methods."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(Report)
|
||||
|
||||
async def get_by_scenario(
|
||||
self, db: AsyncSession, scenario_id: UUID, skip: int = 0, limit: int = 100
|
||||
) -> List[Report]:
|
||||
"""Get reports for a specific scenario."""
|
||||
query = (
|
||||
select(Report)
|
||||
.where(Report.scenario_id == scenario_id)
|
||||
.order_by(desc(Report.created_at))
|
||||
.offset(skip)
|
||||
.limit(limit)
|
||||
)
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
|
||||
async def count_by_scenario(self, db: AsyncSession, scenario_id: UUID) -> int:
|
||||
"""Count reports for a specific scenario."""
|
||||
query = select(Report).where(Report.scenario_id == scenario_id)
|
||||
result = await db.execute(query)
|
||||
return len(result.scalars().all())
|
||||
|
||||
async def update_file_size(
|
||||
self, db: AsyncSession, report_id: UUID, file_size_bytes: int
|
||||
) -> Optional[Report]:
|
||||
"""Update report file size."""
|
||||
result = await db.execute(
|
||||
update(Report)
|
||||
.where(Report.id == report_id)
|
||||
.values(file_size_bytes=file_size_bytes)
|
||||
.returning(Report)
|
||||
)
|
||||
await db.commit()
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
|
||||
# Singleton instance
|
||||
report_repository = ReportRepository()
|
||||
Reference in New Issue
Block a user