Hackathon Draft Deletion Failure (Endpoint Mismatch)
Description
Drafted hackathons cannot be deleted from the organization dashboard. While the "Delete Draft" button is present and triggers the confirmation dialog, the actual deletion request fails silently — the draft remains in the list after confirmation and refresh.
Impact: Medium — users are unable to clean up stale or accidental drafts, leading to cluttered dashboards and a degraded organizational experience.
Step-by-Step Reproduction
- Navigate to an organization's hackathon list (
/organizations/[id]/hackathons)
- Identify a hackathon in "Draft" status
- Click the "Delete Draft" (trash icon) button
- Confirm the deletion in
DeleteHackathonDialog
- Observed: A success or failure toast may appear, but the draft remains in the list upon refresh
- Expected: The draft should be permanently removed from the organization's hackathon list
Root Cause Analysis
The investigation reveals a discrepancy between how drafts are managed and how they are deleted — they use different, incompatible API routes.
Endpoint Mismatch
Draft Operations (Create, Update, Fetch)
- All draft operations are scoped to the organization and use the following route pattern:
DELETE /organizations/${organizationId}/hackathons/draft/${draftId}
- Logic found in:
lib/api/hackathons/draft.ts
Deletion Logic
- The deletion currently uses a generic top-level hackathon endpoint that is not aware of the draft resource:
DELETE /api/hackathons/${hackathonId}
- Logic found in:
lib/api/hackathons.ts — function deleteHackathon
- Hook:
hooks/hackathon/use-delete-hackathon.ts
Because drafts are not exposed through the top-level /hackathons/ resource on the backend, calling deleteHackathon against a draft ID either silently fails or deletes nothing — explaining why the toast may appear to succeed while the record persists.
Missing Draft Deletion Function
lib/api/hackathons/draft.ts lacks a dedicated deleteDraft function, unlike its counterparts for updating and publishing. The system falls back to the general deleteHackathon function, which targets the wrong endpoint for draft resources. This gap is the direct cause of the failure.
Technical Details
Files to Modify
1. lib/api/hackathons/draft.ts
- Action: Add a new
deleteDraft function that targets the organization-scoped draft deletion route:
DELETE /organizations/${organizationId}/hackathons/draft/${draftId}
- The function signature should accept both
organizationId and draftId to correctly construct the scoped route
- Follow the existing patterns in
draft.ts for error handling and response typing — strictly no any types
2. hooks/hackathon/use-delete-hackathon.ts
- Action: Update the hook to determine whether the deletion target is a draft or a published hackathon, and route accordingly:
- If the target is a draft, call the new
deleteDraft function
- Otherwise, continue using the existing
deleteHackathon function
- The hook should accept either a
type parameter ('draft' | 'hackathon') or automatically detect the resource type from the data available at the call site — choose the approach that produces the cleanest, most maintainable interface
3. page.tsx (Organization Hackathon List)
- Action: Ensure the
isDraft status (or equivalent draft indicator) is correctly passed to the deletion hook or used to select the correct deletion path at the call site
- Confirm the
DeleteHackathonDialog receives and forwards the draft status so the hook has everything it needs to route the request correctly
Relevant Hooks & API
- Hook:
useDeleteHackathon in hooks/hackathon/use-delete-hackathon.ts
- API functions:
deleteHackathon in lib/api/hackathons.ts, new deleteDraft in lib/api/hackathons/draft.ts
Proposed Resolution Plan
-
Implement deleteDraft in lib/api/hackathons/draft.ts targeting the organization-scoped route with both organizationId and draftId
-
Refactor useDeleteHackathon to accept a type parameter ('draft' | 'hackathon') or auto-detect the resource type, and internally route to the correct API function based on that value
-
Update page.tsx to ensure isDraft is passed through the deletion flow so the hook can make the correct routing decision
-
Test both paths — deletion of a draft and deletion of a published hackathon — to ensure neither regresses after the refactor
⚠️ Caution
This is a production environment — not a sandbox.
- Code must be performant, accessible, and clean
- No dummy data — all deletion logic must use real organization and draft IDs from the API
- AI-generated code will be scrutinized; poorly structured or "hallucinated" code will result in immediate issue closure
- Follow the existing design system: shadcn/ui, Tailwind, Framer Motion
- Strictly no
any types in the new deleteDraft function or the refactored hook
Testing & Verification
Automated Tests
npm run lint # Ensure code quality
npm run build # Verify no breaking changes in routing or types
Manual Verification
Hackathon Draft Deletion Failure (Endpoint Mismatch)
Description
Drafted hackathons cannot be deleted from the organization dashboard. While the "Delete Draft" button is present and triggers the confirmation dialog, the actual deletion request fails silently — the draft remains in the list after confirmation and refresh.
Impact: Medium — users are unable to clean up stale or accidental drafts, leading to cluttered dashboards and a degraded organizational experience.
Step-by-Step Reproduction
/organizations/[id]/hackathons)DeleteHackathonDialogRoot Cause Analysis
The investigation reveals a discrepancy between how drafts are managed and how they are deleted — they use different, incompatible API routes.
Endpoint Mismatch
Draft Operations (Create, Update, Fetch)
DELETE /organizations/${organizationId}/hackathons/draft/${draftId}lib/api/hackathons/draft.tsDeletion Logic
DELETE /api/hackathons/${hackathonId}lib/api/hackathons.ts— functiondeleteHackathonhooks/hackathon/use-delete-hackathon.tsBecause drafts are not exposed through the top-level
/hackathons/resource on the backend, callingdeleteHackathonagainst a draft ID either silently fails or deletes nothing — explaining why the toast may appear to succeed while the record persists.Missing Draft Deletion Function
lib/api/hackathons/draft.tslacks a dedicateddeleteDraftfunction, unlike its counterparts for updating and publishing. The system falls back to the generaldeleteHackathonfunction, which targets the wrong endpoint for draft resources. This gap is the direct cause of the failure.Technical Details
Files to Modify
1.
lib/api/hackathons/draft.tsdeleteDraftfunction that targets the organization-scoped draft deletion route:DELETE /organizations/${organizationId}/hackathons/draft/${draftId}organizationIdanddraftIdto correctly construct the scoped routedraft.tsfor error handling and response typing — strictly noanytypes2.
hooks/hackathon/use-delete-hackathon.tsdeleteDraftfunctiondeleteHackathonfunctiontypeparameter ('draft' | 'hackathon') or automatically detect the resource type from the data available at the call site — choose the approach that produces the cleanest, most maintainable interface3.
page.tsx(Organization Hackathon List)isDraftstatus (or equivalent draft indicator) is correctly passed to the deletion hook or used to select the correct deletion path at the call siteDeleteHackathonDialogreceives and forwards the draft status so the hook has everything it needs to route the request correctlyRelevant Hooks & API
useDeleteHackathoninhooks/hackathon/use-delete-hackathon.tsdeleteHackathoninlib/api/hackathons.ts, newdeleteDraftinlib/api/hackathons/draft.tsProposed Resolution Plan
Implement
deleteDraftinlib/api/hackathons/draft.tstargeting the organization-scoped route with bothorganizationIdanddraftIdRefactor
useDeleteHackathonto accept atypeparameter ('draft' | 'hackathon') or auto-detect the resource type, and internally route to the correct API function based on that valueUpdate
page.tsxto ensureisDraftis passed through the deletion flow so the hook can make the correct routing decisionTest both paths — deletion of a draft and deletion of a published hackathon — to ensure neither regresses after the refactor
anytypes in the newdeleteDraftfunction or the refactored hookTesting & Verification
Automated Tests
Manual Verification
/organizations/[id]/hackathonsand identify a draft — confirm the "Delete Draft" button and dialog are present/organizations/${organizationId}/hackathons/draft/${draftId}) and not the top-level/hackathons/endpoint — confirm via network tabdeleteHackathonpath still functions correctly with no regressionuseDeleteHackathonhook correctly routes todeleteDraftfor drafts anddeleteHackathonfor published hackathons based on thetypeparameter or auto-detectiondeleteDraftfunction indraft.tshas noanytypes and follows the existing error handling and response typing patterns in the file