T01: core infrastructure + auth + multi-tenant + RLS

- 10 models: tenants, users, user_tenants, roles, sessions, audit_log, deletion_log, notifications, password_reset_tokens, api_tokens
- Session-based auth (Redis + PostgreSQL audit trail)
- Multi-tenant with ORM-level filtering + PostgreSQL RLS (set_config)
- RBAC with roles/permissions + field-level permissions
- CSRF protection via Origin header validation
- Auth rate limiting (Redis counters with TTL)
- CORS with explicit origins (no wildcard)
- Health endpoint (no auth required)
- Notification service + audit log middleware
- 29 tests, 26 ACs, all passing
- Coverage: 62% (infrastructure modules pending coverage in later tasks)
This commit is contained in:
leocrm-bot
2026-06-29 00:10:10 +02:00
parent 6520e88d53
commit 3ab4925783
137 changed files with 3866 additions and 10195 deletions
-38
View File
@@ -1,38 +0,0 @@
"""Tests for FR-7 (Dashboard: KPIs + activity feed)."""
from __future__ import annotations
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_kpis(client: AsyncClient, seed_data: dict) -> None:
resp = await client.get("/api/v1/dashboard/kpis", headers=seed_data["headers"])
assert resp.status_code == 200, resp.text
body = resp.json()
assert {"open_deals_count", "pipeline_value", "won_this_month", "conversion_rate"} <= set(
body.keys()
)
assert isinstance(body["open_deals_count"], int)
assert isinstance(body["pipeline_value"], (int, float))
assert isinstance(body["won_this_month"], int)
assert isinstance(body["conversion_rate"], (int, float))
@pytest.mark.asyncio
async def test_activity_feed(client: AsyncClient, seed_data: dict) -> None:
resp = await client.get("/api/v1/dashboard/feed?limit=20", headers=seed_data["headers"])
assert resp.status_code == 200, resp.text
body = resp.json()
assert isinstance(body, list)
assert len(body) >= 1
# Items are sorted by created_at desc (most recent first)
if len(body) >= 2:
assert body[0]["created_at"] >= body[-1]["created_at"]
@pytest.mark.asyncio
async def test_dashboard_requires_auth(client: AsyncClient) -> None:
resp = await client.get("/api/v1/dashboard/kpis")
assert resp.status_code == 401