# File Lifecycle and S3 Cleanup

## Lifecycle States (DB source of truth)

`file_files.lifecycle_status`:

- `temp`: uploaded but not attached
- `active`: referenced by one or more business entities
- `orphan_pending`: currently unreferenced, waiting grace period
- `deleted`: backend cleanup has deleted object(s) and marked terminal state

Supporting timestamps:

- `created_at`: existing file creation time
- `attached_at`: set when file becomes active
- `orphaned_at`: set when file becomes unreferenced
- `lifecycle_deleted_at`: set when cleanup marks lifecycle `deleted`

Notes:

- Existing `status` column (`uploaded/processing/validated/ready/trashed`) remains for processing/trash flow.
- `deleted_at` is still used by trash semantics. Cleanup lifecycle uses `lifecycle_deleted_at`.

## S3 Tags

Single tag key: `gc`

- `gc=temp`: temporary uploads
- `gc=keep`: active or protected files
- `gc=delete`: optional marker immediately before backend delete

S3 tags are markers only. DB lifecycle state and DB reference checks are authoritative.

## Cleanup Job

Scheduler: API process loop (`startFileManagerLifecycleCleanupLoop`).

Behavior:

1. Query DB for `orphan_pending` files where `orphaned_at <= now - ORPHAN_GRACE_PERIOD_DAYS`.
2. Process in batches (`FILE_CLEANUP_BATCH_SIZE`).
3. Re-check DB references per file before deletion.
4. If referenced again: mark `active`, set/keep `gc=keep`.
5. If still unreferenced:
   - optional `gc=delete` tag
   - delete original and thumbnail S3 objects
   - mark lifecycle `deleted` and set `lifecycle_deleted_at`
6. Per-file error handling; one failure does not stop the batch.

The job is idempotent and retry-safe.

## Environment Variables

- `ENABLE_S3_TAGGING` (default `true`)
- `ENABLE_FILE_CLEANUP_JOB` (default `false`)
- `TEMP_FILE_TTL_DAYS` (default `7`)
- `ORPHAN_GRACE_PERIOD_DAYS` (default `30`)
- `FILE_CLEANUP_BATCH_SIZE` (default `100`)
- `FILE_CLEANUP_DRY_RUN` (default `true`)

## Backfill (Dry-Run First)

Command:

```bash
go run ./cmd/file-lifecycle-backfill
```

Optional:

- `BACKFILL_DRY_RUN=true|false` (default `true`)

Output report includes:

- active files
- probable orphan files
- missing S3 key
- invalid references
- skipped records

## Required IAM Permissions

Minimum required:

- `s3:PutObjectTagging`
- `s3:GetObjectTagging`
- `s3:DeleteObject`
- `s3:GetObject`
- `s3:HeadObject`

Only if infra automation updates lifecycle rules:

- `s3:PutLifecycleConfiguration`

## S3 Lifecycle Rules (Manual if no IaC)

Because this repository does not define Terraform/CDK/CloudFormation for S3 bucket lifecycle, configure lifecycle rules in your infra/deployment stack:

1. Rule `gc=temp`:
   - Filter: object tag `gc=temp`
   - Expire after `TEMP_FILE_TTL_DAYS` (recommended default 7 days)

2. Optional rule `gc=delete`:
   - Filter: object tag `gc=delete`
   - Expire after 1 day

Do not use lifecycle expiration as the orphan grace mechanism. Grace period is enforced by DB `orphaned_at`.

## Rollout Plan

1. Deploy schema + code with defaults (`cleanup job off`, `dry-run on`).
2. Enable tagging for new uploads (`ENABLE_S3_TAGGING=true`).
3. Validate attach/detach transitions in logs.
4. Run backfill dry-run and review report.
5. Enable cleanup job in dry-run mode.
6. Switch cleanup dry-run off after validation.
7. Apply S3 lifecycle rules for `gc=temp` (and optional `gc=delete`).

## Rollback Plan

1. Set `ENABLE_FILE_CLEANUP_JOB=false`.
2. Set `FILE_CLEANUP_DRY_RUN=true`.
3. Optionally set `ENABLE_S3_TAGGING=false`.
4. Pause/remove lifecycle rule `gc=delete` if enabled.
