Feature Owner: scorevi (Sean Patrick Caintic)
Module: Diagnose
Priority: P1
Sprint #12: Fully Implemented
Date: 2026-06-29
EXECUTIVE SUMMARY
What is this feature? Restore Project allows creators to recover archived quests and adventures by reverting their publishing_status from "archived" back to "draft." It is the inverse operation of archiving and serves as the safety net in the content lifecycle.
Why does it matter? Creators sometimes archive content prematurely or change their mind about retiring material. Without restore, archiving becomes a one-way path that carries the same risk as deletion.
What's the MVP scope? Single endpoint that reverts publishing_status to "draft" for any archived quest or adventure, with ownership verification and input validation.
1. USER PAIN POINT & SOLUTION
Current State (Without Feature)
Archiving is permanent in effect — once content is archived, there is no way to bring it back to an active state without manual database intervention.
Pain Point
Type | Impact |
|---|---|
Emotional | Regret after archiving content that might still be useful |
Functional | No recovery path for mistakenly archived content |
Business | Lost content represents wasted creation effort and AI generation costs |
Future State
Creators can browse their archived content and restore any item back to "draft" status with a single click. The full content lifecycle is reversible until permanent deletion.
Marketing Hook
"Changed your mind? One click to bring it back. Archive is safe because restore is instant."
2. 4D FRAMEWORK MAPPING
Phase | Mapping |
|---|---|
Diagnose | Re-evaluate archived content against current standards |
Design | Restored content re-enters the design workflow as draft |
Develop | Resume development on previously archived material |
Deliver | Restored content can be republished and exported |
3. USER FLOWS
Entry Point
TrashContent.tsx → "Restore" button on archived item
Success Criteria
Content publishing_status changes from "archived" to "draft"
Content reappears in active library
Ownership verified before restore
Main Flow
Creator navigates to TrashContent.tsx (archived content list)
Clicks "Restore" on a quest or adventure
System calls verifyContentOwnership() (implicit via RLS)
PATCH /api/creator/restore-content updates publishing_status to "draft"
Content reappears in main library
UI updates to reflect restored state
Edge Cases
Restore non-archived content: Status changes to "draft" (may overwrite "published")
Restore content owned by another creator: verifyContentOwnership() blocks
Restore already-deleted content: 404 (content no longer exists)
Decision Points
Always restores to "draft" (never "published") — creator must manually republish
No confirmation dialog in MVP (single-click restore)
4. INFORMATION ARCHITECTURE
Primary
Content ID (UUID), content type (quests | adventures), publishing_status
Secondary
Restore timestamp, restored by (creator_id)
Actions
Restore (from TrashContent.tsx)
5. WIREFRAMES
Excluded — existing UI (TrashContent.tsx Restore button).
6. WIREFLOWS
Excluded — existing UI implemented.
7. PROTOTYPE
Excluded — feature is fully implemented.
8. BACKEND SCHEMA
Status Transition
archived → restore → draft → (creator publishes) → published
restoreContentSchema
{ content_id: UUID, content_type: z.enum(["quests","adventures"]) }
Same schema shape as archiveContentSchema. The route uses a raw Supabase update call, bypassing Zod schema validation for the status field (consistent with archive approach).
9. API ENDPOINTS
Method | Path | Auth | Purpose | File |
|---|---|---|---|---|
PATCH | /api/creator/restore-content | Clerk | Revert status to "draft" | 60 lines |
restore-content (PATCH)
Schema:
restoreContentSchema—{ content_id: UUID, content_type: z.enum(["quests","adventures"]) }Logic:
Validate input with restoreContentSchema
verifyContentOwnership()— confirms creator owns the contentRaw Supabase call:
.from(content_type).update({ publishing_status: "draft" }).eq("id", content_id)Returns success/error response
Note: Always restores to "draft", regardless of previous status
10. DATA REQUIREMENTS
Frontend Needs
Restore button in TrashContent.tsx
Visual feedback on restore success
Automatic list refresh after restore
API Calls
PATCH /api/creator/restore-content
GET /api/creator/list-archived (refresh after restore)
Caching
Archived list: Invalidate on restore
11. PERFORMANCE CONSIDERATIONS
DB Optimization
Single UPDATE operation, no joins
publishing_status index benefits both archive and restore operations
Response Time
Sub-50ms for single-item restore (simple UPDATE)
Access Control
Clerk authentication required
verifyContentOwnership()ensures creator can only restore their own contentRLS policies prevent cross-creator access
Auth Logic
Ownership verified before status change
No elevation of privilege (cannot restore another creator's content)
Validation
Input validated via restoreContentSchema (Zod)
Status update is raw SQL (no Zod on output) — consistent with archive route pattern
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 |
Content already deleted (not archived) | 404 — row doesn't match |
14. TESTING CHECKLIST
Happy Path
Restore archived quest → status changes to "draft"
Restore archived adventure → status changes to "draft"
Restored content appears in active library
Restored content disappears from archived list
Edge Cases
Restore content that is already "draft" (idempotent)
Restore content that is "published" (downgrades to draft)
Attempt to restore content owned by another creator (blocked)
Restore with invalid UUID format (blocked by Zod)
Restore with invalid content_type (blocked by Zod)
15. OPEN QUESTIONS
Should restore preserve the previous status (e.g., restore "published" to "published") instead of always defaulting to "draft"?
Should restore require a confirmation step to prevent accidental recovery?
16. OUT OF SCOPE
Bulk restore (multiple items at once)
Restore with version history (restore to specific point in time)
Restore audit log (who restored what and when beyond timestamp)
17. SUCCESS METRICS
Restore rate (% of archived items that get restored)
Time from archive to restore
Zero support tickets for "accidentally archived content"
18. DEPENDENCIES
Archive Project feature (1.4) — restore only applies to archived content
verifyContentOwnership() utility function
TrashContent.tsx UI component
19. TIMELINE
Completed — Feature is fully implemented in Sprint #12.
Document Version
1.0 - Initial version - 2026-06-29 08:16 UTC
1.1 - Added Document Version section and update author to have full name - 2026-06-29 08:44 UTC