task_id: task_create_page_upload entity_id: page_upload generated_at: '2025-12-18T15:16:50.299695' workflow_version: v001 target: type: page definition: id: page_upload path: /upload title: Upload Music description: Song upload page (musicians only) data_needs: - api_id: api_upload_song purpose: Upload song file on_load: false - api_id: api_get_artist_albums purpose: Select album on_load: true - api_id: api_get_genres purpose: Select genres on_load: true components: - component_upload_form - component_waveform_display auth: required: true roles: - musician redirect_if_unauthorized: /login related: models: [] apis: - id: api_get_artist_albums definition: &id001 id: api_get_artist_albums method: GET path: /api/artists/:id/albums description: Get all albums by artist responses: - status: 200 description: List of albums schema: albums: - id: uuid title: string cover_art_url: string release_date: string album_type: string auth: required: false depends_on_models: - model_artist - model_album - id: api_upload_song definition: &id003 id: api_upload_song method: POST path: /api/songs/upload description: Upload new song (musicians only) request_body: file: binary title: string album_id: uuid genre_ids: array[uuid] release_date: string track_number: integer responses: - status: 201 description: Song uploaded successfully schema: id: uuid title: string file_url: string duration: integer - status: 400 description: Invalid file format or size schema: error: string - status: 403 description: User is not a musician schema: error: string auth: required: true roles: - musician depends_on_models: - model_song - model_artist - id: api_get_genres definition: &id005 id: api_get_genres method: GET path: /api/discover/genres description: Get all genres responses: - status: 200 description: List of genres schema: genres: - id: uuid name: string slug: string auth: required: false depends_on_models: - model_genre components: - id: component_upload_form definition: &id002 id: component_upload_form name: UploadForm description: Song upload form with file input props: - name: albums type: array[Album] required: true - name: genres type: array[Genre] required: true state: - name: file type: File - name: title type: string - name: selectedAlbum type: string - name: selectedGenres type: array[string] - name: uploadProgress type: number events: - name: onUpload payload: file: File metadata: object - name: onCancel payload: null uses_apis: - api_upload_song uses_components: - component_waveform_display - id: component_waveform_display definition: &id004 id: component_waveform_display name: WaveformDisplay description: Audio waveform visualization props: - name: audioUrl type: string required: true - name: waveformData type: array[number] required: false - name: currentTime type: number required: false events: - name: onSeek payload: time: number uses_apis: [] uses_components: [] dependencies: entity_ids: - api_get_artist_albums - component_upload_form - api_upload_song - component_waveform_display - api_get_genres definitions: - id: api_get_artist_albums type: api definition: *id001 - id: component_upload_form type: component definition: *id002 - id: api_upload_song type: api definition: *id003 - id: component_waveform_display type: component definition: *id004 - id: api_get_genres type: api definition: *id005 files: to_create: - app/upload/page.tsx reference: [] acceptance: - criterion: Page renders at /upload verification: Navigate to /upload - criterion: Data fetching works verification: Check network tab - criterion: Components render correctly verification: Visual inspection