Skip to content

Hackathon Draft Deletion Failure (Endpoint Mismatch) #416

Description

@Benjtalkshow

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

  1. Navigate to an organization's hackathon list (/organizations/[id]/hackathons)
  2. Identify a hackathon in "Draft" status
  3. Click the "Delete Draft" (trash icon) button
  4. Confirm the deletion in DeleteHackathonDialog
  5. Observed: A success or failure toast may appear, but the draft remains in the list upon refresh
  6. 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

  1. Implement deleteDraft in lib/api/hackathons/draft.ts targeting the organization-scoped route with both organizationId and draftId

  2. 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

  3. Update page.tsx to ensure isDraft is passed through the deletion flow so the hook can make the correct routing decision

  4. 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

  • Navigate to /organizations/[id]/hackathons and identify a draft — confirm the "Delete Draft" button and dialog are present
  • Confirm deletion — verify the draft is permanently removed from the list after confirmation, both in the immediate UI update and after a hard refresh
  • Verify the deletion request hits the organization-scoped route (/organizations/${organizationId}/hackathons/draft/${draftId}) and not the top-level /hackathons/ endpoint — confirm via network tab
  • Delete a published hackathon via the same UI — confirm the existing deleteHackathon path still functions correctly with no regression
  • Confirm the toast feedback is accurate — success toast only appears when the backend confirms deletion, failure toast appears on error
  • Verify the useDeleteHackathon hook correctly routes to deleteDraft for drafts and deleteHackathon for published hackathons based on the type parameter or auto-detection
  • Confirm the new deleteDraft function in draft.ts has no any types and follows the existing error handling and response typing patterns in the file
  • Test with an invalid or already-deleted draft ID — confirm the error is handled gracefully with an appropriate toast and no UI crash
  • Provide video evidence

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions