Creator Quest Card Background Audio

1. Front Matter


2. Introduction & Goals

Problem Summary

Creators need per-card audio support for narration, ambience, and guided content. The feature adds a reusable audio upload UI across quest card editors and persists audio URL in each card’s content payload.

Goals

  • Allow creators to upload background audio per quest content card.

  • Persist card-level audio_url in card content JSON.

  • Provide immediate in-editor preview and remove action.

  • Ensure learner renderers can consume audio_url for playback.

Non-Goals

  • Global quest-level audio replacement (already a separate media feature).

  • Audio editing/mixing/transcoding pipeline.

  • Server-managed streaming/DRM features.

Glossary

  • Card Audio: Background audio file tied to an individual quest content card.

  • audio_url: Content JSON field storing the public URL for card audio.

  • Primary Upload Field: Existing upload path for link-based media uploads.

  • Audio Upload Field: Upload mode that writes audio_url instead of link.


3. High-Level Architecture

System Diagram

+----------------------+
| Creator Form Editor |
+----------------------+
|
v
+----------------------+
| CardAudioUpload |
+----------------------+
|
v
+----------------------+
| useQuestFileUpload |
+----------------------+
|
v
+------------------------------------------------------+
| POST /api/creator/quest-content-cards/upload-media |
+------------------------------------------------------+
|
+----+----+
| |
| |
v v
+-------------------------------+ +--------------------------------------+
| Supabase Storage | | quest_content_cards.content.audio_url |
| public-assets | +--------------------------------------+
+-------------------------------+ |
v
+-------------------------------+
| Immediate local state update |
+-------------------------------+
|
v
+------------------------------------------------------+
| PUT /api/creator/quest-content-cards/update |
+------------------------------------------------------+
|
v
+--------------------------------------+
| Learner renderers consume audio_url |
+--------------------------------------+

Technologies Used

  • Next.js App Router (client + API routes)

  • Supabase Storage for file upload

  • Supabase Postgres JSON content persistence (quest_content_cards.content)

  • React hooks for upload state and immediate UI feedback


4. Detailed Design & Implementation

Data Model / Schema

QuestContentCard.content includes optional audio field:

  • audio_url?: string

Defined in types/quest-content-cards.d.ts.

Creator UI Integration

The shared CardAudioUpload component is wired into multiple card editors inside app/quest-editor/[questID]/(sections)/content/form-editor/page.tsx, including:

  • Discussion card

  • Text card

  • Image card

  • Video card

  • File card

  • Link card

  • Codeblock card

Behavior in CardAudioUpload:

  • Accepts audio/* files.

  • Enforces 10MB client-side file size limit.

  • Uploads using uploadField = "audio_url".

  • On success, applies onUpdate({ audio_url: result.link }).

  • Supports remove action via onUpdate({ audio_url: undefined }).

  • Displays audio preview player when audio_url exists.

Upload Hook

useQuestFileUpload in form editor:

  • Builds FormData with file, quest_id, card_type, card_id, upload_field.

  • Calls POST /api/creator/quest-content-cards/upload-media.

  • Returns normalized URL from link or file_url.

Backend Upload Route

In app/api/creator/quest-content-cards/upload-media/route.ts:

  • Validates required fields.

  • Validates card_type against allowed set.

  • Verifies quest ownership and agency scope.

  • Uploads file to storage path:

    • quests/{quest_id}/content-cards/{card_id}/content.{ext}

  • If upload_field === "audio_url", updates card content with:

    • audio_url: publicUrl

  • Returns success, file_url, file_path, link, card.

Save/Persist Behavior in Editor

In form editor, handleUpdateCardContent updates local editing state and card list state immediately. When updates include audio_url, it triggers immediate persistence via updateContentCard(...) so audio changes are saved without waiting for full modal save.

Learner Consumption

Learner card renderers consume card.content.audio_url and auto-play looped audio where supported (for example activity and content-card renderers), confirming end-to-end path from creator upload to learner playback.


5. Infrastructure & Operations

Dependencies

  • quest_content_cards table with JSON content payload.

  • Supabase Storage bucket public-assets.

  • Agency ownership auth helpers for creator authorization.

Monitoring & Alerting

Current behavior is log + toast driven:

  • Upload and API failures are logged via console.error.

  • Creator UI shows toast success/error feedback.

No dedicated metric stream exists yet for audio upload success/failure rate.

Deployment Plan

  1. Verify storage bucket access and public URL generation.

  2. Verify agency/ownership checks in creator routes.

  3. Validate upload + immediate save on each supported card type.

  4. Validate learner playback for cards with audio_url.


6. Testing & Quality Assurance

Test Strategy

  • Unit/integration tests:

    • Upload route success/failure paths.

    • Ownership rejection cases.

    • upload_field = audio_url branch behavior.

  • UI tests:

    • Audio tab visible on supported card editors.

    • 10MB validation error handling.

    • Remove audio action clears preview and persists.

  • End-to-end tests:

    • Upload in creator form editor.

    • Reload content cards and confirm persisted audio_url.

    • Open learner view and confirm playback.

Known Limitations

  • 10MB audio limit is currently client-side; no explicit server-side size guard in upload route.

  • Upload route cleanup logic targets content.link cleanup and does not explicitly clean replaced audio_url objects.

  • File path naming (content.{ext}) may overwrite previous uploads per card, which is acceptable for replacement but should be documented.


7. Maintenance & Support

Troubleshooting

  • Upload fails immediately: Check missing form fields or invalid card type payload.

  • Upload succeeds but no playback: Verify audio_url saved in card content and reachable public URL.

  • Audio removed in UI but returns after refresh: Confirm immediate updateContentCard succeeded and route returned 200.

  • Permission errors: Verify creator ownership and agency membership context.

Handover Tasks for Patrick Babala

  1. Add explicit server-side validation for audio MIME and max file size.

  2. Add cleanup strategy for replaced audio_url files to avoid orphaned storage objects.

  3. Add automated coverage for immediate audio_url persistence branch.

  4. Verify all intended quest card editors include CardAudioUpload in Week acceptance criteria.

  5. Add structured telemetry for upload failure categories.

Changelog

  • 1.0 - Approved, Technical guide created for creator per-card audio feature.


Was this article helpful?