Files
jobtrackingapp/docs/architecture/attachment-storage.md
T

2.6 KiB

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.