Feature Owner: scorevi (Sean Patrick Caintic)
Module: Diagnose
Priority: P1
Sprint #12: Fully Implemented
Date: 2026-06-29
EXECUTIVE SUMMARY
What is this feature? Archive Project enables creators to soft-delete quests and adventures by setting their publishing_status to "archived." Archived content is hidden from active views but recoverable via restore. It includes ownership verification and a dedicated listing endpoint for archived content.
Why does it matter? Creators accumulate drafts, experiments, and outdated content over time. Without archiving, the content library becomes cluttered and unmanageable. Archiving provides a safe "undo" path before permanent deletion.
What's the MVP scope? Archive endpoint for quests and adventures with ownership verification, list-archived endpoint returning both content types, and a TrashContent.tsx UI with Restore and Delete Forever actions.
1. USER PAIN POINT & SOLUTION
Current State (Without Feature)
Creators either keep all content indefinitely (cluttered library) or permanently delete it without a safety net. No intermediate state exists between active and deleted.
Pain Point
Type | Impact |
|---|---|
Emotional | Anxiety about accidentally deleting valuable work |
Functional | No way to hide outdated content without losing it |
Business | Content library becomes unusable at scale; poor creator experience |
Future State
Creators archive content they no longer need active. Archived items are hidden from the main library but visible in a dedicated trash view. Content can be restored to "draft" status or permanently deleted.
Marketing Hook
"Archive with confidence. Your content is never truly gone until you say so."
2. 4D FRAMEWORK MAPPING
Phase | Mapping |
|---|---|
Diagnose | Archive outdated or low-quality content identified by validator |
Design | Content lifecycle management (draft → published → archived → deleted) |
Develop | Safe content management during active development |
Deliver | Clean content library for export workflows |
3. USER FLOWS
Entry Point
Content Library → Context menu on quest/adventure card → "Archive"
TrashContent.tsx component
Success Criteria
Content publishing_status changes to "archived"
Content hidden from main library views
Content visible in archived list
Ownership verification succeeds (creator can only archive own content)
Main Flow
Creator selects quest or adventure to archive
System calls verifyContentOwnership() to confirm ownership
PATCH /api/creator/archive-content updates publishing_status to "archived"
Content disappears from active library
Creator can view archived content via GET /api/creator/list-archived
From TrashContent.tsx, creator can Restore or Delete Forever
Edge Cases
Archive already-archived content: Idempotent (status already "archived")
Archive non-existent content: 404
Archive content owned by another creator: verifyContentOwnership() blocks with 403
Publishing status 'archived' not in Zod questSchema enum: Archive route bypasses Zod, uses raw Supabase call
Decision Points
Archive vs. Delete Forever (archive is reversible, delete is not)
Restore to "draft" vs. "published" (always restores to "draft")
4. INFORMATION ARCHITECTURE
Primary
Content ID (UUID), content type (quests | adventures), publishing_status
Secondary
Archive timestamp, archived by (creator_id)
Actions
Archive, List Archived, Restore, Delete Forever
5. WIREFRAMES
Excluded — existing UI (TrashContent.tsx, 300 lines).
6. WIREFLOWS
Excluded — existing UI implemented.
7. PROTOTYPE
Excluded — feature is fully implemented.
8. BACKEND SCHEMA
Publishing Status Lifecycle
draft → published → archived → (permanently deleted) ↑ | └── Restore ─────────┘
Key Schema Note
Layer | Supports 'archived'? |
|---|---|
DB CHECK constraint | Yes — 'archived' is a valid status |
Zod questSchema enum | No — 'archived' is NOT in the enum |
Archive route behavior | Bypasses Zod, uses raw Supabase |
The archiveContentSchema validates only content_id (UUID) and content_type (enum of "quests" | "adventures"). The actual status update bypasses Zod validation entirely.
9. API ENDPOINTS
Method | Path | Auth | Purpose | File |
|---|---|---|---|---|
PATCH | /api/creator/archive-content | Clerk | Set status to "archived" | 64 lines |
GET | /api/creator/list-archived | Clerk | List archived quests AND adventures | Verified existing |
archive-content (PATCH)
Schema:
archiveContentSchema—{ content_id: UUID, content_type: z.enum(["quests","adventures"]) }Logic:
Validate input with archiveContentSchema
verifyContentOwnership()— confirms creator owns the contentRaw Supabase call:
.from(content_type).update({ publishing_status: "archived" }).eq("id", content_id)Returns success/error response
Note: Bypasses Zod questSchema/adventureSchema — raw DB update
list-archived (GET)
Returns archived quests AND adventures in a single response
No pagination in MVP
10. DATA REQUIREMENTS
Frontend Needs
Archive button with confirmation dialog
Trash view with list of archived items
Item type indicator (quest vs. adventure)
Restore and Delete Forever action buttons
API Calls
PATCH /api/creator/archive-content (single archive)
GET /api/creator/list-archived (list archived)
PATCH /api/creator/restore-content (restore from trash)
DELETE /api/creator/permanent-delete (delete forever)
Caching
Active content list: Invalidate on archive
Archived list: Refetch on archive/restore/delete actions
11. PERFORMANCE CONSIDERATIONS
DB Optimization
publishing_status should be indexed for filtered queries (active vs. archived)
Single endpoint returns both quests and adventures (reduces API calls)
Response Time
Archive operation: Single UPDATE, sub-50ms
List archived: Two queries (quests + adventures), may benefit from union or parallel queries
Access Control
Clerk authentication required
verifyContentOwnership()ensures creator can only archive their own contentRLS policies prevent cross-creator access
Auth Logic
Ownership check via creator_id match before any status change
No admin override (MVP — creators manage only their own content)
Validation
Input validated via archiveContentSchema (Zod)
Status update is raw SQL (no Zod on output) — safe because only setting a fixed value
13. ERROR HANDLING
Error | Response |
|---|---|
Invalid content_id (not UUID) | 400 — Zod validation error |
Invalid content_type | 400 — Zod enum validation error |
Content not found | 404 |
Content not owned by requester | 403 — verifyContentOwnership() failure |
Already archived | 200 — Idempotent success |
DB error | 500 — Internal server error |
14. TESTING CHECKLIST
Happy Path
Archive a quest → status changes to "archived"
Archive an adventure → status changes to "archived"
List archived content → both quests and adventures appear
Archived content NOT visible in main library
Restore archived content → status returns to "draft"
Delete forever from trash → content permanently removed
Edge Cases
Archive content that is already archived (idempotent)
Attempt to archive content owned by another creator (blocked)
Archive content with invalid content_type (blocked by Zod)
Archive content with non-UUID content_id (blocked by Zod)
List archived when nothing is archived (empty list)
15. OPEN QUESTIONS
Should Zod questSchema and adventureSchema be updated to include 'archived' in their publishing_status enums?
Is pagination needed for list-archived at scale?
16. OUT OF SCOPE
Bulk archive (multiple items at once)
Archive scheduling (auto-archive after inactivity)
Archive retention policies (auto-delete after X days)
17. SUCCESS METRICS
Archive-to-restore ratio (indicating safe usage)
Average items in trash per creator
Time from archive to permanent delete
Reduction in active library clutter
18. DEPENDENCIES
verifyContentOwnership() utility function
Publishing status DB CHECK constraint (includes 'archived')
Restore Project feature (1.5)
Permanent Delete feature (1.6)
19. TIMELINE
Completed — Feature is fully implemented in Sprint #12.
Document Version
1.0 - Initial version - 2026-06-29 08:13 UTC
1.1 - Added Document Version section and update author to have full name - 2026-06-29 08:44 UTC