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

@@ -1,5 +1,17 @@
"""Hand-written fakes for narrow application-owned ports.
"""Hand-written fakes for narrow application-owned ports (ADR-0016)."""
No application ports exist yet (Phase 1 only wires infrastructure client
lifecycle). Fakes are added here as ports are introduced in later phases.
"""
from dataclasses import dataclass, field
@dataclass
class FakeObjectStorage:
"""In-memory `ObjectStorage`. `fail_next` simulates one upload failure."""
objects: dict[str, bytes] = field(default_factory=dict)
fail_next: bool = False
async def put_object(self, *, key: str, data: bytes, content_type: str) -> None:
if self.fail_next:
self.fail_next = False
raise OSError("simulated object storage failure")
self.objects[key] = data