Files
openrouter-watcher/prompt/prompt-ingaggio-authentication.md
Luca Sacchi Ricciardi 02473bc39e feat(schemas): T17 add Pydantic auth schemas
Add authentication schemas for user registration and login:
- UserRegister: email, password (with strength validation), password_confirm
- UserLogin: email, password
- UserResponse: id, email, created_at, is_active (orm_mode=True)
- TokenResponse: access_token, token_type, expires_in
- TokenData: user_id, exp

Includes field validators for password strength and password confirmation matching.

Test coverage: 19 tests for all schemas
2026-04-07 13:52:33 +02:00

8.2 KiB

Prompt di Ingaggio: User Authentication (T17-T22)

🎯 MISSIONE

Implementare la fase User Authentication (T17-T22) del progetto OpenRouter API Key Monitor seguendo rigorosamente TDD.


📋 CONTEXTO

AGENTE: @tdd-developer

Repository: /home/google/Sources/LucaSacchiNet/openrouter-watcher

Stato Attuale:

  • Setup completato (T01-T05): 59 test
  • Database & Models (T06-T11): 73 test
  • Security Services (T12-T16): 70 test
  • 🎯 Totale: 202 test passanti, 100% coverage sui moduli implementati

Servizi Pronti da utilizzare:

  • hash_password(), verify_password() - in services/password.py
  • create_access_token(), decode_access_token() - in services/jwt.py
  • EncryptionService - in services/encryption.py
  • generate_api_token(), verify_api_token() - in services/token.py
  • User, ApiKey, UsageStats, ApiToken models
  • get_db(), Base - in database.py

Documentazione:

  • PRD: /home/google/Sources/LucaSacchiNet/openrouter-watcher/prd.md
  • Architecture: /home/google/Sources/LucaSacchiNet/openrouter-watcher/export/architecture.md
  • Prompt Dettagliato: /home/google/Sources/LucaSacchiNet/openrouter-watcher/prompt/prompt-authentication.md

🔧 TASK DA IMPLEMENTARE

T17: Creare Pydantic Schemas per Autenticazione

File: src/openrouter_monitor/schemas/auth.py

Requisiti:

  • UserRegister: email (EmailStr), password (min 12), password_confirm
    • Validatore: richiama validate_password_strength()
    • Root validator: password == password_confirm
  • UserLogin: email, password
  • UserResponse: id, email, created_at, is_active (orm_mode=True)
  • TokenResponse: access_token, token_type="bearer", expires_in
  • TokenData: user_id (sub), exp

Test: tests/unit/schemas/test_auth_schemas.py


T18: Implementare Endpoint POST /api/auth/register

File: src/openrouter_monitor/routers/auth.py

Requisiti:

  • Endpoint: POST /api/auth/register
  • Riceve: UserRegister schema
  • Logica:
    1. Verifica email non esista: db.query(User).filter(User.email == ...).first()
    2. Se esiste: HTTPException 400 "Email already registered"
    3. Hash password: hash_password(user_data.password)
    4. Crea User: User(email=..., password_hash=...)
    5. Salva: db.add(), db.commit(), db.refresh()
    6. Ritorna: UserResponse, status 201

Test: Register success, email duplicata (400), password debole (422)


T19: Implementare Endpoint POST /api/auth/login

File: src/openrouter_monitor/routers/auth.py

Requisiti:

  • Endpoint: POST /api/auth/login
  • Riceve: UserLogin schema
  • Logica:
    1. Trova utente per email
    2. Se non trovato o inattivo: HTTPException 401 "Invalid credentials"
    3. Verifica password: verify_password(credentials.password, user.password_hash)
    4. Se fallita: HTTPException 401
    5. Genera JWT: create_access_token(data={"sub": str(user.id)})
    6. Ritorna: TokenResponse con access_token

Test: Login success (200 + token), email inesistente (401), password sbagliata (401), utente inattivo (401)


T20: Implementare Endpoint POST /api/auth/logout

File: src/openrouter_monitor/routers/auth.py

Requisiti:

  • Endpoint: POST /api/auth/logout
  • Richiede: current_user: User = Depends(get_current_user)
  • Logica: JWT stateless, logout gestito lato client
  • Ritorna: {"message": "Successfully logged out"}

Test: Logout con token valido (200), senza token (401)


T21: Implementare Dipendenza get_current_user

File: src/openrouter_monitor/dependencies/auth.py

Requisiti:

from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

security = HTTPBearer()

async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: Session = Depends(get_db)
) -> User:
    token = credentials.credentials
    try:
        payload = decode_access_token(token)
        user_id = int(payload.get("sub"))
        if not user_id:
            raise HTTPException(401, "Invalid token payload")
    except JWTError:
        raise HTTPException(401, "Invalid or expired token")
    
    user = db.query(User).filter(User.id == user_id).first()
    if not user or not user.is_active:
        raise HTTPException(401, "User not found or inactive")
    return user

Test: Token valido ritorna utente, token mancante (401), token scaduto (401), token invalido (401), utente inesistente (401), utente inattivo (401)


T22: Scrivere Test per Auth Endpoints

File: tests/unit/routers/test_auth.py

Requisiti:

  • Usare TestClient da FastAPI
  • Fixture: test_user, auth_token, authorized_client
  • Test coverage >= 90%

Test da implementare:

  • Register: success (201), email duplicata (400), password debole (422), email invalida (422)
  • Login: success (200 + token), email inesistente (401), password sbagliata (401), utente inattivo (401)
  • Logout: success (200), senza token (401)
  • get_current_user: protetto con token valido, senza token (401), token scaduto (401)

🔄 WORKFLOW TDD

Per OGNI task:

  1. RED: Scrivi test che fallisce (prima del codice!)
  2. GREEN: Implementa codice minimo per passare il test
  3. REFACTOR: Migliora codice, test rimangono verdi

📁 STRUTTURA FILE DA CREARE

src/openrouter_monitor/
├── schemas/
│   ├── __init__.py
│   └── auth.py                    # T17
├── routers/
│   ├── __init__.py
│   └── auth.py                    # T18, T19, T20
└── dependencies/
    ├── __init__.py
    └── auth.py                    # T21

tests/unit/
├── schemas/
│   ├── __init__.py
│   └── test_auth_schemas.py       # T17 + T22
└── routers/
    ├── __init__.py
    └── test_auth.py               # T18-T21 + T22

🧪 ESEMPI TEST

Test Schema

@pytest.mark.unit
def test_user_register_valid_data_passes_validation():
    data = UserRegister(
        email="test@example.com",
        password="SecurePass123!",
        password_confirm="SecurePass123!"
    )
    assert data.email == "test@example.com"

Test Endpoint

@pytest.mark.asyncio
async def test_register_new_user_returns_201(client, db_session):
    response = client.post("/api/auth/register", json={
        "email": "test@example.com",
        "password": "SecurePass123!",
        "password_confirm": "SecurePass123!"
    })
    assert response.status_code == 201
    assert response.json()["email"] == "test@example.com"

CRITERI DI ACCETTAZIONE

  • T17: Schemas auth con validazione completa
  • T18: POST /api/auth/register (201/400/422)
  • T19: POST /api/auth/login (200/401)
  • T20: POST /api/auth/logout (200)
  • T21: get_current_user dependency funzionante
  • T22: Test auth coverage >= 90%
  • Tutti i test passano: pytest tests/unit/routers/test_auth.py -v
  • 6 commit atomici con conventional commits
  • progress.md aggiornato

📝 COMMIT MESSAGES

feat(schemas): T17 add Pydantic auth schemas

feat(auth): T18 implement user registration endpoint

feat(auth): T19 implement user login endpoint

feat(auth): T20 implement user logout endpoint

feat(deps): T21 implement get_current_user dependency

test(auth): T22 add comprehensive auth endpoint tests

🚀 VERIFICA FINALE

cd /home/google/Sources/LucaSacchiNet/openrouter-watcher

# Test schemas
pytest tests/unit/schemas/test_auth_schemas.py -v

# Test routers
pytest tests/unit/routers/test_auth.py -v --cov=src/openrouter_monitor/routers

# Test completo
pytest tests/unit/ -v --cov=src/openrouter_monitor

⚠️ NOTE IMPORTANTI

  • Path assoluti: Usa sempre /home/google/Sources/LucaSacchiNet/openrouter-watcher/
  • Servizi esistenti: Riutilizza hash_password, verify_password, create_access_token, decode_access_token
  • Database: Usa get_db() da database.py per dependency injection
  • Models: Importa da models package (User, ApiKey, etc.)
  • Sicurezza: Mai loggare password o token in plaintext
  • Errori: Errori generici per credenziali invalide (non leakare info)

AGENTE: @tdd-developer

INIZIA CON: T17 - Pydantic schemas

QUANDO FINITO: Conferma completamento e aggiorna progress.md