feat(backend): implement database layer with models, schemas and repositories

Complete backend core implementation (BE-001 to BE-005):

BE-001: Database Connection & Session Management
- Create src/core/database.py with async SQLAlchemy 2.0
- Configure engine with pool_size=20
- Implement get_db() FastAPI dependency

BE-002: SQLAlchemy Models (5 models)
- Base model with TimestampMixin
- Scenario: status enum, relationships, cost tracking
- ScenarioLog: message hash, PII detection, metrics
- ScenarioMetric: time-series with extra_data (JSONB)
- AwsPricing: service pricing with region support
- Report: format enum, file tracking, extra_data

BE-003: Pydantic Schemas
- Scenario: Create, Update, Response, List schemas
- Log: Ingest, Response schemas
- Metric: Summary, CostBreakdown, MetricsResponse
- Common: PaginatedResponse generic type

BE-004: Base Repository Pattern
- Generic BaseRepository[T] with CRUD operations
- Methods: get, get_multi, count, create, update, delete
- Dynamic filter support

BE-005: Scenario Repository
- Extends BaseRepository[Scenario]
- Specific methods: get_by_name, list_by_status, list_by_region
- Business methods: update_status, increment_total_requests, update_total_cost
- ScenarioStatus enum
- Singleton instance: scenario_repository

All models, schemas and repositories tested and working.

Tasks: BE-001, BE-002, BE-003, BE-004, BE-005 complete
This commit is contained in:
Luca Sacchi Ricciardi
2026-04-07 14:20:02 +02:00
parent 216f9e229c
commit ebefc323c3
18 changed files with 1322 additions and 0 deletions

29
src/models/report.py Normal file
View File

@@ -0,0 +1,29 @@
"""Report model."""
import uuid
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, Enum
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from src.models.base import Base, TimestampMixin
class Report(Base, TimestampMixin):
"""Generated report tracking model."""
__tablename__ = "reports"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
scenario_id = Column(
UUID(as_uuid=True),
ForeignKey("scenarios.id", ondelete="CASCADE"),
nullable=False,
)
format = Column(Enum("pdf", "csv", name="report_format"), nullable=False)
file_path = Column(String(500), nullable=False)
file_size_bytes = Column(Integer, nullable=True)
generated_by = Column(String(100), nullable=True)
extra_data = Column(JSONB, default=dict)
# Relationships
scenario = relationship("Scenario", back_populates="reports")