90ac0b81d1
Add full V2 architecture: identity, content, studio (.NET 10) and file, render, notification, gateway (Go) services with vendored deps, plus DB migrations, event/API contracts, and an init-db script. Wire the Next.js frontend to the gateway: server-side JWT auth routes (login/register/refresh/logout/me), gateway fetch helper, and session/ cookie/jwt helpers under src/lib. Containerize the stack via docker-compose.v2.yml and per-service Dockerfiles. Base images resolve through a Nexus mirror (Docker Hub) and MCR directly; npm/NuGet pull from Nexus groups. Self-host fonts via next/font/local to avoid Google Fonts (geo-blocked). Add CI workflow and ignore .env.v2, *.stackdump, and .NET bin/obj. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
115 lines
4.5 KiB
YAML
115 lines
4.5 KiB
YAML
# =====================================================================
|
|
# File Events — published by File Service
|
|
# =====================================================================
|
|
events:
|
|
|
|
file.uploaded.v1:
|
|
routing_key: file.uploaded.v1
|
|
description: A file upload has completed and is ready to use.
|
|
payload:
|
|
type: object
|
|
required: [file_id, user_id, file_type, size_bytes, url]
|
|
properties:
|
|
file_id: { type: string, format: uuid }
|
|
tenant_id: { type: string, format: uuid }
|
|
user_id: { type: string, format: uuid }
|
|
folder_id: { type: string, format: uuid, nullable: true }
|
|
name: { type: string }
|
|
file_type: { type: string, enum: [Video, Image, Audio, Voiceover, Document, Other] }
|
|
mime_type: { type: string }
|
|
size_bytes: { type: integer, format: int64 }
|
|
url: { type: string }
|
|
thumbnail_url: { type: string, nullable: true }
|
|
duration_sec: { type: number, nullable: true }
|
|
width: { type: integer, nullable: true }
|
|
height: { type: integer, nullable: true }
|
|
source:
|
|
type: string
|
|
enum: [upload, export, snapshot, voiceover_record, stock]
|
|
|
|
file.processed.v1:
|
|
routing_key: file.processed.v1
|
|
description: Post-upload processing (thumbnail, waveform, transcode) finished.
|
|
payload:
|
|
type: object
|
|
required: [file_id, status]
|
|
properties:
|
|
file_id: { type: string, format: uuid }
|
|
tenant_id: { type: string, format: uuid }
|
|
user_id: { type: string, format: uuid }
|
|
status: { type: string, enum: [Ready, Failed, Quarantined] }
|
|
thumbnail_url: { type: string, nullable: true }
|
|
waveform_generated: { type: boolean }
|
|
duration_sec: { type: number, nullable: true }
|
|
error_message: { type: string, nullable: true }
|
|
|
|
file.deleted.v1:
|
|
routing_key: file.deleted.v1
|
|
payload:
|
|
type: object
|
|
required: [file_id, user_id, size_bytes_freed]
|
|
properties:
|
|
file_id: { type: string, format: uuid }
|
|
tenant_id: { type: string, format: uuid }
|
|
user_id: { type: string, format: uuid }
|
|
size_bytes_freed: { type: integer, format: int64 }
|
|
deleted_by:
|
|
type: string
|
|
enum: [user, auto_cleanup, admin, quota_exceeded]
|
|
|
|
file.quota_warning.v1:
|
|
routing_key: file.quota_warning.v1
|
|
description: User passed 90% of storage quota.
|
|
payload:
|
|
type: object
|
|
required: [user_id, used_bytes, quota_bytes, percent_used]
|
|
properties:
|
|
user_id: { type: string, format: uuid }
|
|
tenant_id: { type: string, format: uuid }
|
|
used_bytes: { type: integer, format: int64 }
|
|
quota_bytes: { type: integer, format: int64 }
|
|
percent_used: { type: number }
|
|
|
|
file.quota_exceeded.v1:
|
|
routing_key: file.quota_exceeded.v1
|
|
description: User hit 100% storage quota — uploads blocked.
|
|
payload:
|
|
type: object
|
|
required: [user_id, used_bytes, quota_bytes]
|
|
properties:
|
|
user_id: { type: string, format: uuid }
|
|
tenant_id: { type: string, format: uuid }
|
|
used_bytes: { type: integer, format: int64 }
|
|
quota_bytes: { type: integer, format: int64 }
|
|
attempted_upload_size_bytes: { type: integer, format: int64, nullable: true }
|
|
|
|
file.cleanup.scheduled.v1:
|
|
routing_key: file.cleanup.scheduled.v1
|
|
description: An entity has been queued for automatic deletion.
|
|
payload:
|
|
type: object
|
|
required: [cleanup_id, entity_type, entity_id, scheduled_delete_at]
|
|
properties:
|
|
cleanup_id: { type: string, format: uuid }
|
|
tenant_id: { type: string, format: uuid, nullable: true }
|
|
user_id: { type: string, format: uuid, nullable: true }
|
|
entity_type:
|
|
type: string
|
|
enum: [Export, TempRenderFolder, OrphanedFile, UnusedUpload, SnapshotExpired]
|
|
entity_id: { type: string, format: uuid }
|
|
scheduled_delete_at: { type: string, format: date-time }
|
|
notify_user_at: { type: string, format: date-time, nullable: true }
|
|
|
|
file.cleanup.executed.v1:
|
|
routing_key: file.cleanup.executed.v1
|
|
payload:
|
|
type: object
|
|
required: [cleanup_id, status, bytes_freed]
|
|
properties:
|
|
cleanup_id: { type: string, format: uuid }
|
|
entity_type: { type: string }
|
|
entity_id: { type: string, format: uuid }
|
|
status: { type: string, enum: [Done, Skipped, Failed] }
|
|
bytes_freed: { type: integer, format: int64 }
|
|
error_message: { type: string, nullable: true }
|