Trash Bin

Feature Owner: Jethro Magdaleno Lagmay
Module: Dashboards
Priority: High (Data Loss Prevention)
Sprint #12: Sprint 12
Date: June 30, 2026

EXECUTIVE SUMMARY

What is this feature? A transition from a "Hard Delete" model to a "Soft Delete" model for Background Assets. It introduces a dedicated Trash Bin where deleted assets are stored for a 30-day grace period before they can be permanently purged.

Why does it matter? Accidental deletions previously resulted in immediate, irrecoverable data loss (database row dropped, file removed from bucket). This safety net heavily improves Creator UX and drastically reduces potential support tickets for lost work.

What’s the MVP scope?

  • Database schema updates (deleted_at, expires_at).

  • Creation of /creator/trash UI dashboard with a dynamic countdown badge.

  • API endpoints for Soft Delete, Restore, and Purge.

  • Explicitly scoped to Background Assets only (does not include Audio or Characters yet).

  • Manual user purge (Automated backend Cron cleanup is deferred to a future sprint).

1. USER PAIN POINT & SOLUTION

Current State (Without Feature)

  • Pain Point: Clicking "Delete" on an asset instantly destroys the file.

  • Emotional: Extreme frustration and panic when a high-value asset is accidentally removed.

  • Functional: Creators must manually re-upload and re-link assets if a mistake is made.

  • Business Impact: Increased risk of churn for power users; support team burdened with impossible "restore data" requests.

Future State (With Feature) Assets are safely moved out of view but remain in the database for 30 days. Creators have full autonomy to restore their own files or permanently destroy them to free up storage.

Marketing Hook "Never lose your hard work to an accidental click again. Introducing the Creator Trash Bin—your 30-day safety net."

2. 4D FRAMEWORK MAPPING

  • Diagnose: Identified data loss vulnerability during the Background Asset deletion flow.

  • Design: Designed a dedicated Trash Bin interface adhering to WyzLab v1.3 tokens (Orange for destructive, Gold for warnings), including a strict "Type DELETE" modal.

  • Develop: Updated Supabase schema, built Next.js App Router API endpoints with strict Zod validation, and mitigated Next.js aggressive client/server caching.

  • Deliver: Deployed with a critical SQL migration prerequisite. Feature is actively working in the staging/dev environment.

3. USER FLOWS

Entry Point Background Assets Dashboard > Click Trash Icon on Asset OR Click "Trash Bin" button in header.

Success Criteria

  • Trashed asset immediately disappears from the main library.

  • Trashed asset appears in the Trash Bin with an accurate countdown.

  • Restored asset immediately returns to the main library.

Main Flow (Happy Path)

  1. User clicks "Delete" on a background asset.

  2. Asset moves to Trash Bin (soft delete).

  3. User navigates to Trash Bin.

  4. User clicks "Restore" -> Asset is back in Library.

  5. OR User clicks "Purge" -> User types "DELETE" in modal -> Asset is permanently wiped from Storage and DB.

Edge Cases

  • Next.js caching serving stale UI (Mitigated via cache: "no-store").

  • Invalid UUID payloads sent to API (Mitigated via Zod).

  • Malicious user attempts to delete another creator's asset (Mitigated via creator_id matching).

Decision Points

  • Does the user want to restore or purge?

  • Is the user sure they want to purge? (Modal barrier).

4. INFORMATION ARCHITECTURE

  • Primary Information (Always visible): Asset Thumbnail (or generic preview), Asset Name.

  • Secondary Information: Asset Type (e.g., IMAGE, VIDEO), Time Remaining Badge (e.g., "30d left").

  • Tertiary Information (Hidden until needed): Purge confirmation warning text and text input field.

Actions

  • Primary CTA: Restore (moves asset back).

  • Secondary Actions: Purge (opens destructive modal), Cancel (closes modal).

5. WIREFRAMES

N/A - Built directly into code based on existing component library.

6. WIREFLOWS

Background Assets Page -> [Soft Delete Action] -> Trash Bin Page -> [Restore Action] -> Background Assets Page -> OR [Purge Action] -> Purge Modal -> [Type DELETE] -> Asset Destroyed

7. PROTOTYPE

Already synced in the development server.

8. BACKEND SCHEMA

Database Tables Table: public.asset_metadata

  • Added: deleted_at (TIMESTAMPTZ, DEFAULT NULL)

  • Added: expires_at (TIMESTAMPTZ, DEFAULT NULL)

Indexes

  • CREATE INDEX idx_asset_metadata_deleted_at ON public.asset_metadata(deleted_at); (Critical for fast .is("deleted_at", null) queries).

  • CREATE INDEX idx_asset_metadata_creator_id ON public.asset_metadata(creator_id);

Constraints & RLS Policies

  • All destructive/mutative API routes manually verify creator_id matches the authenticated user before executing Supabase commands.

9. API ENDPOINTS

  • GET /api/creator/list-assets (Modified)

    • Returns all assets where deleted_at IS NULL.

  • GET /api/creator/get-trash-assets (New)

    • Returns all assets where deleted_at IS NOT NULL.

  • DELETE /api/creator/delete-assets (Refactored)

    • Zod Validated: asset_id (UUID).

    • Performs Soft Delete (UPDATE deleted_at = NOW()).

  • PATCH /api/creator/restore-assets (New)

    • Zod Validated: asset_id (UUID).

    • Clears Trash timestamps (UPDATE deleted_at = NULL).

  • DELETE /api/creator/purge-assets (New)

    • Zod Validated: asset_id (UUID).

    • Hard Delete: Removes from Supabase public-assets bucket (including .jpg thumbnails for videos), then DELETE FROM asset_metadata.

10. DATA REQUIREMENTS

Frontend Needs

  • Array of AssetType objects mapped properly (converting file_name to name, file_url to url).

  • Calculation of days remaining between now() and deleted_at + 30 days.

API Calls Frontend Will Make

  • Uses custom hook useBackgroundAssets() for main library.

  • Directly fetches /get-trash-assets on the Trash page.

  • Dispatches DELETE and PATCH requests on user interaction.

Caching Strategy

  • Server: export const dynamic = "force-dynamic"; and revalidate = 0; on GET routes.

  • Client: cache: "no-store" added to fetch() in the useBackgroundAssets hook to prevent "Ghost Assets".

11. PERFORMANCE CONSIDERATIONS

  • Database Optimization: The idx_asset_metadata_deleted_at index prevents full-table scans when the main dashboard filters out trashed items.

  • Caching Strategy: Cache is explicitly bypassed. While this slightly increases DB hits, it is strictly necessary to maintain immediate UI consistency for soft-deletes.

  • API Response Time: Expected < 200ms. Storage bucket deletions during Purge may take slightly longer (~400ms).

12. SECURITY & AUTHORIZATION

Who can access this feature? Authenticated Creators only.

Authorization Logic

  1. Backend verifies JWT session via authenticateUser().

  2. Supabase DB .eq("creator_id", creator_id) acts as a tenant barrier, ensuring a user can never fetch, update, or purge an asset they do not own.

Data Validation Strict z.string().uuid() validation on all incoming payload bodies via Zod. Rejects malformed requests with 400 Bad Request.

13. ERROR HANDLING

  • 400 Bad Request: Zod validation fails (e.g., missing or malformed asset_id).

  • 403 Forbidden: Asset creator_id does not match the authenticated user.

  • 404 Not Found: Asset ID does not exist in the database.

  • 500 Internal Error: Supabase connection failure or storage bucket removal failure. Handled via catch (err) { err instanceof Error ... } and relayed to UI via Sonner toasts.

14. TESTING CHECKLIST

Happy Path

  • [x] Click Delete -> Asset moves to Trash.

  • [x] Navigate to Trash -> Asset is visible with accurate Days Left badge.

  • [x] Restore Asset -> Instantly returns to Background Assets.

  • [x] Purge Asset -> Type DELETE in modal -> File permanently deleted.

Edge Cases

  • [x] Ensure deleted items do not persist on the main dashboard (Ghost Assets).

  • [x] Pass invalid string format to Purge API -> Rejected by Zod.

  • [x] Attempt to purge asset without typing exactly "DELETE" in modal -> Button remains disabled.

  • [x] Ensure thumbnail images load correctly in Trash UI, or fall back cleanly if URL is broken.

15. OPEN QUESTIONS

  • Automated Cleanup: When will we implement the Supabase Edge Function / PG_CRON job to automatically wipe assets where expires_at < NOW()? (Targeting next Sprint).

  • Feature Parity: Should we immediately expand this logic to Quests and Character assets, or observe usage data first?

16. OUT OF SCOPE

  • Automated background task to permanently wipe files older than 30 days.

  • Trash Bin support for Quests, Characters, or Audio Assets.

  • Multi-select bulk restore/purge.

17. SUCCESS METRICS

  • Primary: Zero (0) support tickets requesting manual data recovery for accidentally deleted background assets over the next 30 days.

  • Secondary: Telemetry showing a healthy ratio of restore-assets usage vs purge-assets usage, proving the safety net is being utilized.

18. DEPENDENCIES

This feature depends on:

  • Supabase PostgreSQL Database (schema updates).

  • Supabase Storage (Public Bucket file deletion logic).

  • Authenticated User Context.

These features depend on this:

  • Future global Trash Bin implementation will inherit this deleted_at architectural pattern.

19. TIMELINE & OWNERSHIP

Implemented: June 30, 2026
Owner: Jethro Magdaleno Lagmay

Document Version
v1.0 - Initial document


Was this article helpful?