feat(files): add source-file upload with MinIO storage and Postgres repositories

Why:
- Implements plan 001 Phase 3's upload orchestration.

Changes:
- ObjectStorage port and MinIO adapter, thread-offloaded per ADR-0017.
- Tenant-scoped repositories for api_keys, source_files, ingestion_jobs.
- upload_source_file implementing the two-transaction shape with
  (tenant_id, domain, content_sha256) idempotency.

Impact:
- This phase stores bytes only -- chunks_indexed is always 0 until
  Phase 4/5 add parsing/embedding.
This commit is contained in:
2026-08-19 15:00:27 +03:30
parent e97ce6e5f3
commit c9cf7b368b
19 changed files with 758 additions and 4 deletions

View File

@@ -0,0 +1,7 @@
"""Narrow contracts for external side effects (ADR-0015).
Ports exist for external side effects/persistence that need a swappable or
fake-able boundary — not as a blanket wrapper around every database access.
`object_storage.py` is one: MinIO is a real external system with its own
failure modes, and ADR-0016 requires a hand-written fake for it in tests.
"""

View File

@@ -0,0 +1,14 @@
"""The object-storage port (ADR-0013).
`src/infrastructure/minio/storage.py` is the production adapter; tests use a
hand-written fake (ADR-0016). Application code depends on this Protocol, not
on the `minio` SDK.
"""
from typing import Protocol
class ObjectStorage(Protocol):
async def put_object(self, *, key: str, data: bytes, content_type: str) -> None:
"""Store `data` privately under `key`. Overwrites an existing object."""
...