Archive Asset

1. Front Matter


2. Introduction & Goals

Problem Summary

Creators need a safe way to remove background assets from active libraries without immediate permanent deletion. Archive Asset solves this by implementing soft delete behavior and routing archived items to Trash, where they can be restored within a retention window.

Goals

  • Soft-delete assets by setting deletion metadata instead of hard-deleting immediately.

  • Keep active library listings clean by excluding archived assets.

  • Provide a Trash retrieval path with restore capability.

  • Track retention window data (deleted_at, expires_at) for lifecycle control.

Non-Goals

  • Automatic scheduler-based purge execution in this feature scope.

  • Cryptographic wipe guarantees for storage objects.

  • Full policy engine for retention customization per tenant.

Glossary

  • Soft Delete / Archive: Marking an asset as deleted via metadata fields, not removing DB row or storage object.

  • Trash Bin: UI and API surface for archived assets.

  • Purge: Permanent deletion from storage and metadata table.

  • Retention Window: 30-day period after archive, tracked by expires_at.


3. High-Level Architecture

System Diagram

+------------------------+
| Background Assets UI |
+------------------------+
|
v
+------------------------------------------+
| DELETE /api/creator/delete-assets |
+------------------------------------------+
|
v
+------------------------------------------+
| asset_metadata |
| - deleted_at = current timestamp |
| - expires_at = expiration timestamp |
+------------------------------------------+
|
v
+-------------------------------+
| Asset hidden from active list |
+-------------------------------+
 
 
+------------------------+
| Trash Bin UI |
+------------------------+
|
v
+------------------------------------------+
| GET /api/creator/get-trash-assets |
+------------------------------------------+
|
v
+-------------------------------+
| Archived Assets List |
+-------------------------------+
|
+-----+-----+
| |
| |
v v
+----------------------------------+ +----------------------------------+
| PATCH /api/creator/restore-assets| | DELETE /api/creator/purge-assets |
+----------------------------------+ +----------------------------------+
| |
v v
+----------------------------------+ +-------------------------------+
| deleted_at = NULL | | Remove storage object |
| expires_at = NULL | +-------------------------------+
+----------------------------------+ |
| v
| +-------------------------------+
| | Delete asset_metadata record |
| +-------------------------------+
|
v
+------------------------+
| Background Assets UI |
+------------------------+

Technologies Used

  • Next.js App Router API routes

  • Supabase Postgres (asset_metadata)

  • Supabase Storage (public-assets bucket)

  • Agency ownership auth helper (getAgencyAuthContext, verifyAgencyResourceOwnership)

  • Zod request validation for archive/restore/purge payloads


4. Detailed Design & Implementation

Data Model / Schema

The feature uses the asset_metadata table, created with soft-delete fields.

Relevant columns:

  • id (UUID PK)

  • creator_id (owner)

  • file_name, file_path, file_url, external_url

  • asset_type, source, usage_context, thumbnail_url

  • deleted_at (soft-delete timestamp)

  • expires_at (target auto-purge date)

  • created_at, updated_at

RLS policies exist for select/insert/update/delete on owner rows.

Archive Lifecycle

  1. Creator chooses Move to Trash in Background Assets.

  2. API validates asset_id and ownership.

  3. API sets:

  • deleted_at = now

  • expires_at = now + 30 days

  1. Active list route excludes archived rows using deleted_at IS NULL.

  2. Trash list route includes only archived rows using deleted_at IS NOT NULL.

  3. Restore clears archive fields.

  4. Purge permanently removes storage objects and metadata row.

API Specification

DELETE /api/creator/delete-assets

  • Purpose: Archive asset (soft delete)

  • Auth: Required

  • Body: { asset_id: uuid }

  • Behavior: Sets deleted_at, expires_at

GET /api/creator/list-assets

  • Purpose: Active asset list

  • Auth: Required

  • Behavior: Returns assets where deleted_at IS NULL

GET /api/creator/get-trash-assets

  • Purpose: Archived asset list

  • Auth: Required

  • Behavior: Returns assets where deleted_at IS NOT NULL, newest first

PATCH /api/creator/restore-assets

  • Purpose: Restore archived asset

  • Auth: Required

  • Body: { asset_id: uuid }

  • Behavior: Sets deleted_at = null, expires_at = null

DELETE /api/creator/purge-assets

  • Purpose: Permanently delete archived asset

  • Auth: Required

  • Body: { asset_id: uuid }

  • Behavior: Removes storage file(s) then deletes DB row

UI Integration

  • Active assets page links to Trash Bin.

  • Delete action in asset list opens Move to Trash modal.

  • Trash page shows countdown badge derived from deleted_at.

  • Trash page supports Restore and Delete Permanently actions.


5. Infrastructure & Operations

Dependencies

  • asset_metadata table and indexes

  • Supabase Storage bucket for uploaded files

  • Ownership checks via agency auth helpers

  • Frontend fetch flows using no-store patterns for freshness

Monitoring & Alerting

Current behavior is log-driven and toast-driven:

  • API logs server errors to console

  • UI displays toast feedback on fetch/archive/restore/purge failures

No dedicated metrics/alerts currently exist for archive failure rate or purge drift.

Deployment Plan

  1. Validate migration state in target environment.

  2. Confirm RLS and ownership helpers in agency and creator contexts.

  3. Run archive/restore/purge smoke tests with uploaded and external assets.

  4. Verify active list/trash list filtering consistency.

  5. Confirm video thumbnail cleanup path during purge.


6. Testing & Quality Assurance

Test Strategy

  • API tests:

  • Valid and invalid UUID payloads

  • Ownership mismatch rejection

  • Soft-delete field updates

  • Restore nullification of archive fields

  • UI tests:

  • Move to Trash removes card from active list

  • Trash list shows archived assets and countdown

  • Restore reappears in active library

  • Integration tests:

  • Purge removes both storage object and metadata row

Known Limitations

  • expires_at is set but no automatic background purge scheduler is shown in current implementation.

  • Permanent delete confirmation keyword enforcement is currently UI-side only in purge modal.

  • Error telemetry is not centralized (console + toasts only).


7. Maintenance & Support

Troubleshooting

  • Asset still visible after archive: Check deleted_at update success and active-list cache behavior.

  • Asset not in Trash: Verify get-trash-assets filter and ownership scope.

  • Restore fails: Confirm row ownership and existence of asset_id.

  • Purge removes DB row but file remains: Inspect storage remove call and file path correctness.

Week 12 Handover Tasks for Christian (To Do)

  1. Confirm Week 12 acceptance criteria for archive-retention behavior.

  2. Add automated tests for archive -> restore -> purge lifecycle.

  3. Decide whether to add server-side enforcement for typed permanent delete challenge.

  4. Propose/implement retention-job strategy for expires_at auto purge.

  5. Add operational metric hooks (archive success rate, restore success rate, purge failures).

Changelog

  • 1.0 - Handover Draft: Technical documentation prepared for implementation/hardening handoff, July 2026.


Was this article helpful?