feat/Update_Controllers_to_Allow_for_Premium_Membership
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# Attachment storage invariants
|
||||
|
||||
Updated: 2026-08-02
|
||||
|
||||
Attachments remain local files under `Data:AttachmentsRoot/<jobId>/` with metadata in `Attachments`. No object-store abstraction or schema migration is used.
|
||||
|
||||
## Invariants
|
||||
|
||||
- Every managed path resolves beneath `Data:AttachmentsRoot` without crossing a symlink/junction.
|
||||
- Stored filenames are generated and stable. Renaming changes only the user-visible `FileName` metadata.
|
||||
- A committed row normally has its final file. A temporary suffix is the only recognized recoverable exception.
|
||||
- Unknown plain files are reported and preserved; reconciliation never guesses that a legacy orphan is safe to delete.
|
||||
- All row lookups remain parent/job tenant-scoped.
|
||||
|
||||
## Durable filesystem states
|
||||
|
||||
| State | Meaning | Startup action |
|
||||
|---|---|---|
|
||||
| `<final>.uploading` and matching DB row | metadata committed; promotion was interrupted | atomically promote to `<final>` |
|
||||
| `<final>.uploading` without DB row | copy/request failed before commit | purge the staging file |
|
||||
| `<final>.deleting` and matching DB row | delete stopped before DB commit | restore to `<final>` |
|
||||
| `<final>.deleting` without DB row | DB deletion committed; purge was interrupted | purge the quarantined file |
|
||||
| plain file without DB row | unknown/legacy orphan | report only |
|
||||
| DB row without final or recognized state | missing bytes | report only |
|
||||
|
||||
Upload validates the complete batch before copying, stages every file, commits all metadata and derived flags in one database transaction, then promotes files. A post-commit promotion failure returns 202 and leaves `.uploading` for startup recovery.
|
||||
|
||||
Delete first atomically renames bytes to `.deleting`, removes metadata and updates flags in one transaction, then purges. A database failure restores the file. A post-commit purge failure returns 202 and leaves a retryable marker.
|
||||
|
||||
## Operations
|
||||
|
||||
Reconciliation runs once after database initialization and before the API begins serving. It logs counts only—never file contents or paths. Nonzero missing, unsafe, unknown-orphan or failure counts require operator review. Persistent suffix-state failures are retried on the next safe service restart.
|
||||
|
||||
Rollback requires draining/reconciling `.uploading` and `.deleting` markers before reverting the application. Do not delete unknown plain files. The same managed-root and quarantine conventions must be reused by account deletion (SEC-009).
|
||||
|
||||
Object storage, content deduplication, periodic multi-replica reconciliation and destructive legacy-orphan cleanup are explicitly deferred until deployment topology or measured volume requires them.
|
||||
Reference in New Issue
Block a user