Deploy update
This commit is contained in:
parent
1a39be31ee
commit
0f13aee7fb
|
|
@ -1,74 +1,184 @@
|
|||
---
|
||||
description: Implement an approved entity from the manifest
|
||||
allowed-tools: Read, Write, Bash
|
||||
description: Implement a task from the workflow
|
||||
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
|
||||
---
|
||||
|
||||
# Implement Entity
|
||||
# Implement Task
|
||||
|
||||
Implement the entity: "$ARGUMENTS"
|
||||
Implement the task: "$ARGUMENTS"
|
||||
|
||||
## CRITICAL RULES
|
||||
## ⚠️ CRITICAL: WORKFLOW COMPLIANCE
|
||||
|
||||
⚠️ **GUARDRAIL ENFORCEMENT ACTIVE**
|
||||
You MUST follow the design document exactly. All implementations must match the specifications.
|
||||
|
||||
You can ONLY write to files that:
|
||||
1. Are defined in `project_manifest.json`
|
||||
2. Have status = `APPROVED`
|
||||
3. Match the `file_path` in the manifest EXACTLY
|
||||
## Pre-Implementation Checklist
|
||||
|
||||
## Steps
|
||||
Before writing ANY code, complete these steps:
|
||||
|
||||
1. **Verify Phase**: Must be in `IMPLEMENTATION_PHASE`
|
||||
### 1. Load Workflow Context
|
||||
|
||||
2. **Find Entity** in manifest:
|
||||
- If "$ARGUMENTS" is `--all`: implement all APPROVED entities
|
||||
- Otherwise: find the specific entity by ID
|
||||
```bash
|
||||
# Check workflow status
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py status
|
||||
|
||||
3. **For Each Entity**:
|
||||
# Verify we're in IMPLEMENTING phase
|
||||
```
|
||||
|
||||
a. **Load Definition** from manifest
|
||||
### 2. Find Task Context
|
||||
|
||||
b. **Verify Status** is `APPROVED`
|
||||
Read the task file and context for the entity you're implementing:
|
||||
|
||||
c. **Generate Code** matching the specification:
|
||||
- Props must match manifest exactly
|
||||
- Types must match manifest exactly
|
||||
- File path must match `file_path` in manifest
|
||||
```
|
||||
.workflow/versions/v001/tasks/task_create_<entity_id>.yml
|
||||
.workflow/versions/v001/contexts/<entity_id>.yml
|
||||
```
|
||||
|
||||
d. **Write File** to the exact path in manifest
|
||||
### 3. Load Generated Types (MANDATORY)
|
||||
|
||||
e. **Run Validations**:
|
||||
**ALWAYS** import and use the generated types:
|
||||
|
||||
```typescript
|
||||
// For components - import from generated types
|
||||
import type { SongCardProps } from '@/types/component-props';
|
||||
import type { Song, Album, Artist } from '@/types';
|
||||
|
||||
// For APIs - import request/response types
|
||||
import type { GetSongResponse } from '@/types/api-types';
|
||||
```
|
||||
|
||||
### 4. Read Design Specification
|
||||
|
||||
The context file contains the EXACT specification you must follow:
|
||||
- `target.definition.props` - Component props (use these EXACTLY)
|
||||
- `target.definition.events` - Event handlers (implement ALL)
|
||||
- `target.definition.fields` - Model fields (match EXACTLY)
|
||||
- `acceptance` - Acceptance criteria to satisfy
|
||||
|
||||
## Implementation Rules
|
||||
|
||||
### Components
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
// STEP 1: Import generated types (REQUIRED)
|
||||
import type { [ComponentName]Props } from '@/types/component-props';
|
||||
import type { Song, Album, Artist } from '@/types';
|
||||
|
||||
// STEP 2: Use the imported interface (DO NOT redefine props)
|
||||
export function [ComponentName]({
|
||||
// Destructure props matching the design spec EXACTLY
|
||||
}: [ComponentName]Props) {
|
||||
|
||||
// STEP 3: Implement all events from the design
|
||||
|
||||
return (
|
||||
// JSX implementation
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**❌ WRONG - Do not flatten object props:**
|
||||
```tsx
|
||||
interface SongCardProps {
|
||||
id: string;
|
||||
title: string;
|
||||
artistName: string; // WRONG!
|
||||
}
|
||||
```
|
||||
|
||||
**✅ CORRECT - Use typed object props from design:**
|
||||
```tsx
|
||||
import type { SongCardProps } from '@/types/component-props';
|
||||
// Props are: { song: Song, showArtist?: boolean, showAlbum?: boolean }
|
||||
```
|
||||
|
||||
### API Routes (Next.js App Router)
|
||||
|
||||
```typescript
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import type { [EndpointName]Request, [EndpointName]Response } from '@/types/api-types';
|
||||
|
||||
export async function [METHOD](request: NextRequest) {
|
||||
// Implement according to design spec
|
||||
// - Validate request body against schema
|
||||
// - Return response matching schema
|
||||
}
|
||||
```
|
||||
|
||||
### Prisma Models
|
||||
|
||||
Match the design document field names and types exactly:
|
||||
```prisma
|
||||
model [ModelName] {
|
||||
// Fields from design_document.yml data_models section
|
||||
// Match: name, type, constraints
|
||||
}
|
||||
```
|
||||
|
||||
## Post-Implementation Validation
|
||||
|
||||
After implementing, run validation:
|
||||
|
||||
```bash
|
||||
# Type check
|
||||
npx tsc --noEmit
|
||||
|
||||
# Run implementation validator
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate
|
||||
|
||||
# Update task status
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py task <task_id> completed
|
||||
```
|
||||
|
||||
## Example: Implementing SongCard
|
||||
|
||||
1. **Read context:**
|
||||
```bash
|
||||
npm run lint --if-present
|
||||
npm run type-check --if-present
|
||||
cat .workflow/versions/v001/contexts/component_song_card.yml
|
||||
```
|
||||
|
||||
4. **Status Updates** (handled by post-hook):
|
||||
- Entity status changes to `IMPLEMENTED`
|
||||
- Timestamp recorded
|
||||
2. **Check generated types:**
|
||||
```bash
|
||||
cat types/component-props.ts | grep -A 10 "SongCardProps"
|
||||
```
|
||||
|
||||
## Code Templates
|
||||
3. **Implement matching design:**
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
### Component (Frontend)
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import type { SongCardProps } from '@/types/component-props';
|
||||
import type { Song } from '@/types';
|
||||
|
||||
interface [Name]Props {
|
||||
// From manifest.props
|
||||
}
|
||||
|
||||
export const [Name]: React.FC<[Name]Props> = (props) => {
|
||||
export function SongCard({
|
||||
song, // Song object, not flat props!
|
||||
showArtist = true,
|
||||
showAlbum = false,
|
||||
onPlay,
|
||||
onAddToPlaylist
|
||||
}: SongCardProps) {
|
||||
return (
|
||||
// Implementation
|
||||
<div onClick={() => onPlay?.({ songId: song.id })}>
|
||||
<img src={song.coverArtUrl} alt={song.title} />
|
||||
<h3>{song.title}</h3>
|
||||
{showArtist && <p>{song.artist?.name}</p>}
|
||||
{showAlbum && <p>{song.album?.title}</p>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
}
|
||||
```
|
||||
|
||||
### API Endpoint (Backend)
|
||||
```typescript
|
||||
import { Request, Response } from 'express';
|
||||
4. **Validate:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate
|
||||
```
|
||||
|
||||
export async function handler(req: Request, res: Response) {
|
||||
// From manifest.request/response schemas
|
||||
}
|
||||
## Checklist Reference Update
|
||||
|
||||
After successful implementation, mark the item as checked:
|
||||
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py checklist check \
|
||||
--item component_song_card \
|
||||
--reference "components/SongCard.tsx:1-50"
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,29 +1,119 @@
|
|||
---
|
||||
description: Validate manifest integrity and completeness
|
||||
allowed-tools: Bash, Read
|
||||
description: Validate implementation against design document
|
||||
allowed-tools: Read, Bash, Glob, Grep
|
||||
---
|
||||
|
||||
# Validate Manifest
|
||||
# Validate Implementation
|
||||
|
||||
Run validation checks on `project_manifest.json`.
|
||||
Validate: "$ARGUMENTS"
|
||||
|
||||
## Command
|
||||
## Purpose
|
||||
|
||||
Check that implementations match the design document specifications exactly.
|
||||
|
||||
## Validation Steps
|
||||
|
||||
### 1. Run Implementation Validator
|
||||
|
||||
```bash
|
||||
python3 "$CLAUDE_PROJECT_DIR/skills/guardrail-orchestrator/scripts/validate_manifest.py" $ARGUMENTS
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate --checklist
|
||||
```
|
||||
|
||||
## Options
|
||||
### 2. Review Errors
|
||||
|
||||
- No arguments: Basic validation
|
||||
- `--strict`: Treat warnings as errors
|
||||
The validator checks:
|
||||
- **Components**: Props match design, events implemented
|
||||
- **APIs**: Routes exist, methods implemented, schemas match
|
||||
- **Models**: Prisma fields match design
|
||||
|
||||
## What It Checks
|
||||
### 3. Fix Issues
|
||||
|
||||
1. **Structure**: Required top-level keys exist
|
||||
2. **Pages**: Have paths, components, file_paths
|
||||
3. **Components**: Have props with types, valid dependencies
|
||||
4. **APIs**: Have methods, paths, request/response schemas
|
||||
5. **Database**: Tables have primary keys, valid foreign keys
|
||||
6. **Dependencies**: No orphans, no circular references
|
||||
7. **Naming**: Follows conventions
|
||||
For each error, check:
|
||||
|
||||
1. **Read the design spec:**
|
||||
```bash
|
||||
cat .workflow/versions/v001/contexts/<entity_id>.yml
|
||||
```
|
||||
|
||||
2. **Check generated types:**
|
||||
```bash
|
||||
cat types/component-props.ts | grep -A 20 "<ComponentName>Props"
|
||||
```
|
||||
|
||||
3. **Fix the implementation** to match the design
|
||||
|
||||
4. **Re-validate:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate
|
||||
```
|
||||
|
||||
### 4. View Checklist
|
||||
|
||||
```bash
|
||||
# View markdown checklist
|
||||
cat .workflow/versions/v001/implementation_checklist.md
|
||||
|
||||
# Or use the workflow command
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py checklist show
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Props Don't Match Design
|
||||
|
||||
**Problem:** Component uses flat props instead of typed objects
|
||||
|
||||
```tsx
|
||||
// ❌ Wrong
|
||||
interface SongCardProps {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
// ✅ Correct - from generated types
|
||||
import type { SongCardProps } from '@/types/component-props';
|
||||
// SongCardProps = { song: Song; showArtist?: boolean; }
|
||||
```
|
||||
|
||||
### Missing Events
|
||||
|
||||
**Problem:** Design specifies events not implemented
|
||||
|
||||
```tsx
|
||||
// Design specifies: onPlay, onAddToPlaylist
|
||||
// Implementation only has: onPlay
|
||||
|
||||
// Fix: Add missing event
|
||||
export function SongCard({ song, onPlay, onAddToPlaylist }: SongCardProps) {
|
||||
// Implement onAddToPlaylist handler
|
||||
}
|
||||
```
|
||||
|
||||
### API Route Missing
|
||||
|
||||
**Problem:** API route file doesn't exist
|
||||
|
||||
```
|
||||
Expected: app/api/songs/[id]/route.ts
|
||||
Actual: (not found)
|
||||
```
|
||||
|
||||
Fix: Create the route file following the design spec.
|
||||
|
||||
## Validation Report Symbols
|
||||
|
||||
- ✅ **Passed** - Implementation matches design
|
||||
- ⚠️ **Warning** - Minor issue (e.g., optional field missing)
|
||||
- ❌ **Error** - Critical mismatch with design
|
||||
|
||||
## Post-Validation
|
||||
|
||||
After all errors are fixed:
|
||||
|
||||
```bash
|
||||
# Verify clean validation
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate
|
||||
|
||||
# If passed, transition to REVIEWING phase
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py transition REVIEWING
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
---
|
||||
description: Orchestrate the full implementation workflow
|
||||
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Task
|
||||
---
|
||||
|
||||
# Workflow Orchestrator
|
||||
|
||||
Command: "$ARGUMENTS"
|
||||
|
||||
## Workflow Phases
|
||||
|
||||
```
|
||||
INITIALIZING → DESIGNING → AWAITING_DESIGN_APPROVAL → DESIGN_APPROVED
|
||||
↓ ↓
|
||||
[create] [generate-types]
|
||||
↓
|
||||
IMPLEMENTING
|
||||
↓
|
||||
[validate --checklist]
|
||||
↓
|
||||
REVIEWING
|
||||
↓
|
||||
SECURITY_REVIEW
|
||||
↓
|
||||
AWAITING_IMPL_APPROVAL
|
||||
↓
|
||||
COMPLETED
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### Start New Workflow
|
||||
```bash
|
||||
/guardrail:workflow start "feature description"
|
||||
```
|
||||
|
||||
### Check Status
|
||||
```bash
|
||||
/guardrail:workflow status
|
||||
```
|
||||
|
||||
### Generate Types (after design approval)
|
||||
```bash
|
||||
/guardrail:workflow generate-types
|
||||
```
|
||||
|
||||
### Implement Task
|
||||
```bash
|
||||
/guardrail:workflow implement <task_id>
|
||||
# or implement all Layer 1 tasks:
|
||||
/guardrail:workflow implement --layer 1
|
||||
```
|
||||
|
||||
### Validate
|
||||
```bash
|
||||
/guardrail:workflow validate
|
||||
```
|
||||
|
||||
### View Checklist
|
||||
```bash
|
||||
/guardrail:workflow checklist
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution Flow
|
||||
|
||||
### Phase: DESIGN_APPROVED → IMPLEMENTING
|
||||
|
||||
When design is approved, ALWAYS run these steps first:
|
||||
|
||||
1. **Generate TypeScript types from design:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py generate-types --output-dir types
|
||||
```
|
||||
|
||||
2. **Transition to IMPLEMENTING:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py transition IMPLEMENTING
|
||||
```
|
||||
|
||||
3. **View dependency graph to understand task order:**
|
||||
```bash
|
||||
cat .workflow/versions/v001/dependency_graph.yml
|
||||
```
|
||||
|
||||
### Phase: IMPLEMENTING
|
||||
|
||||
For each task (respecting dependency layers):
|
||||
|
||||
1. **Read task context:**
|
||||
```bash
|
||||
cat .workflow/versions/v001/contexts/<entity_id>.yml
|
||||
```
|
||||
|
||||
2. **Read generated types:**
|
||||
```bash
|
||||
cat types/component-props.ts # For components
|
||||
cat types/types.ts # For models
|
||||
cat types/api-types.ts # For APIs
|
||||
```
|
||||
|
||||
3. **Implement following the design EXACTLY**
|
||||
- Import types from `@/types`
|
||||
- Use typed props (not flat props)
|
||||
- Implement all events
|
||||
- Match field names exactly
|
||||
|
||||
4. **Update task status:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py task <task_id> completed
|
||||
```
|
||||
|
||||
5. **Run validation after each layer:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate --checklist
|
||||
```
|
||||
|
||||
### Phase: REVIEWING
|
||||
|
||||
1. **Run full validation:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate --checklist
|
||||
```
|
||||
|
||||
2. **Fix any remaining issues**
|
||||
|
||||
3. **Run type check:**
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
4. **Run linter:**
|
||||
```bash
|
||||
npm run lint
|
||||
```
|
||||
|
||||
5. **Transition to security review:**
|
||||
```bash
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py transition SECURITY_REVIEW
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Rules (MANDATORY)
|
||||
|
||||
### Rule 1: Always Import Generated Types
|
||||
|
||||
```typescript
|
||||
// ✅ CORRECT
|
||||
import type { SongCardProps } from '@/types/component-props';
|
||||
import type { Song } from '@/types';
|
||||
|
||||
// ❌ WRONG - defining own interface
|
||||
interface SongCardProps {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Rule 2: Use Object Props, Not Flat Props
|
||||
|
||||
```typescript
|
||||
// ✅ CORRECT - design says: song: Song
|
||||
function SongCard({ song, showArtist }: SongCardProps) {
|
||||
return <div>{song.title} by {song.artist?.name}</div>;
|
||||
}
|
||||
|
||||
// ❌ WRONG - flattening the Song object
|
||||
function SongCard({ id, title, artistName }: SongCardProps) {
|
||||
return <div>{title} by {artistName}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
### Rule 3: Implement ALL Events from Design
|
||||
|
||||
```typescript
|
||||
// Design specifies: onPlay, onAddToPlaylist
|
||||
// ✅ CORRECT - both events implemented
|
||||
function SongCard({ song, onPlay, onAddToPlaylist }: SongCardProps) {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => onPlay?.({ songId: song.id })}>Play</button>
|
||||
<button onClick={() => onAddToPlaylist?.({ songId: song.id })}>Add</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Rule 4: Match Prisma Schema to Design
|
||||
|
||||
```prisma
|
||||
// Design says: role enum with values [musician, listener, label]
|
||||
model User {
|
||||
role UserRole // ✅ Use enum
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
musician
|
||||
listener
|
||||
label
|
||||
}
|
||||
```
|
||||
|
||||
### Rule 5: Validate After Each Implementation
|
||||
|
||||
```bash
|
||||
# After implementing, always validate
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py validate
|
||||
|
||||
# Mark task complete only if validation passes
|
||||
python3 skills/guardrail-orchestrator/scripts/workflow_manager.py task <task_id> completed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Phase | Action | Command |
|
||||
|-------|--------|---------|
|
||||
| Start | Create workflow | `version_manager.py create "feature"` |
|
||||
| Design | Validate design | `validate_design.py` |
|
||||
| Approved | Generate types | `workflow_manager.py generate-types` |
|
||||
| Implement | Start task | Read context → Import types → Code |
|
||||
| Validate | Check impl | `workflow_manager.py validate --checklist` |
|
||||
| Review | Fix issues | Check errors → Fix → Re-validate |
|
||||
| Complete | Archive | `workflow_manager.py transition COMPLETED` |
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
api_key: pk_user_8d080a1a699dc2a1769ca99ded0ca39fa80324b8713cf55ea7fecc1c372379a6
|
||||
project_id: ""
|
||||
repo_id: ""
|
||||
environment: development
|
||||
app_id: cmjb04ana0001qp0tijyy9emq
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"taskId": "workflow_v001_implementation",
|
||||
"workflowVersion": "v001",
|
||||
"phase": "IMPLEMENTING",
|
||||
"feature": "a platform where musician can upload their songs",
|
||||
"startedAt": "2025-12-18T15:21:00Z",
|
||||
"designApproved": true
|
||||
}
|
||||
|
|
@ -39,3 +39,8 @@ yarn-error.log*
|
|||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# Eureka Factory credentials
|
||||
.claude/eureka-factory.yaml
|
||||
.claude/eureka-factory.yml
|
||||
.claude/eureka-factory.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
versions:
|
||||
- version: v001
|
||||
feature: a platform where musician can upload their songs
|
||||
status: pending
|
||||
started_at: '2025-12-18T14:52:33.788070'
|
||||
completed_at: null
|
||||
tasks_count: 0
|
||||
operations_count: 0
|
||||
- version: v002
|
||||
feature: add header and navigation link to each pages
|
||||
status: completed
|
||||
started_at: '2025-12-18T17:06:07.870800'
|
||||
completed_at: '2025-12-18T17:13:46.853854'
|
||||
tasks_count: 0
|
||||
operations_count: 0
|
||||
- version: v003
|
||||
feature: add label management system
|
||||
status: completed
|
||||
started_at: '2025-12-18T17:39:16.643117'
|
||||
completed_at: '2025-12-18T17:52:33.852962'
|
||||
tasks_count: 0
|
||||
operations_count: 0
|
||||
- version: v004
|
||||
feature: add share music system
|
||||
status: completed
|
||||
started_at: '2025-12-18T18:05:50.056169'
|
||||
completed_at: '2025-12-18T18:24:29.951800'
|
||||
tasks_count: 0
|
||||
operations_count: 0
|
||||
latest_version: v004
|
||||
total_versions: 4
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
task_id: task_create_api_add_song_to_playlist
|
||||
entity_id: api_add_song_to_playlist
|
||||
generated_at: '2025-12-18T15:16:50.269977'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_add_song_to_playlist
|
||||
method: POST
|
||||
path: /api/playlists/:id/songs
|
||||
description: Add song to playlist
|
||||
request_body:
|
||||
song_id: uuid
|
||||
position: integer
|
||||
responses:
|
||||
- status: 201
|
||||
description: Song added to playlist
|
||||
schema:
|
||||
playlist_id: uuid
|
||||
song_id: uuid
|
||||
position: integer
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
- id: model_playlist_song
|
||||
definition: &id002
|
||||
id: model_playlist_song
|
||||
name: PlaylistSong
|
||||
table_name: playlist_songs
|
||||
description: Junction table with ordering for playlists
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: playlist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: playlists.id
|
||||
- name: song_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: songs.id
|
||||
- name: position
|
||||
type: integer
|
||||
constraints:
|
||||
- not_null
|
||||
- name: added_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_playlist
|
||||
foreign_key: playlist_id
|
||||
- type: belongs_to
|
||||
to: model_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- playlist_id
|
||||
- position
|
||||
unique: true
|
||||
- fields:
|
||||
- playlist_id
|
||||
- song_id
|
||||
unique: true
|
||||
timestamps: false
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_playlist_song
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/id/songs/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/playlists/:id/songs returns success response
|
||||
verification: curl -X POST /api/playlists/:id/songs
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
task_id: task_create_api_create_album
|
||||
entity_id: api_create_album
|
||||
generated_at: '2025-12-18T15:16:50.255667'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_create_album
|
||||
method: POST
|
||||
path: /api/albums
|
||||
description: Create new album
|
||||
request_body:
|
||||
title: string
|
||||
description: string
|
||||
cover_art_url: string
|
||||
release_date: string
|
||||
album_type: enum[album, ep, single]
|
||||
responses:
|
||||
- status: 201
|
||||
description: Album created
|
||||
schema:
|
||||
id: uuid
|
||||
title: string
|
||||
cover_art_url: string
|
||||
auth:
|
||||
required: true
|
||||
roles:
|
||||
- musician
|
||||
depends_on_models:
|
||||
- model_album
|
||||
- model_artist
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_album
|
||||
definition: &id002
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_album
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_album
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/albums/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/albums returns success response
|
||||
verification: curl -X POST /api/albums
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
task_id: task_create_api_create_artist_profile
|
||||
entity_id: api_create_artist_profile
|
||||
generated_at: '2025-12-18T15:16:50.234771'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_create_artist_profile
|
||||
method: POST
|
||||
path: /api/artists
|
||||
description: Create artist profile (musicians only)
|
||||
request_body:
|
||||
stage_name: string
|
||||
bio: string
|
||||
cover_image_url: string
|
||||
social_links:
|
||||
twitter: string
|
||||
instagram: string
|
||||
facebook: string
|
||||
website: string
|
||||
responses:
|
||||
- status: 201
|
||||
description: Artist profile created
|
||||
schema:
|
||||
id: uuid
|
||||
stage_name: string
|
||||
bio: string
|
||||
cover_image_url: string
|
||||
- status: 403
|
||||
description: User is not a musician
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: true
|
||||
roles:
|
||||
- musician
|
||||
depends_on_models:
|
||||
- model_artist
|
||||
- model_user
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_user
|
||||
definition: &id002
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_user
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_user
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/artists/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/artists returns success response
|
||||
verification: curl -X POST /api/artists
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
task_id: task_create_api_create_label_profile
|
||||
entity_id: api_create_label_profile
|
||||
generated_at: '2025-12-18T15:16:50.286319'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_create_label_profile
|
||||
method: POST
|
||||
path: /api/labels
|
||||
description: Create label profile
|
||||
request_body:
|
||||
label_name: string
|
||||
description: string
|
||||
logo_url: string
|
||||
website: string
|
||||
responses:
|
||||
- status: 201
|
||||
description: Label created
|
||||
schema:
|
||||
id: uuid
|
||||
label_name: string
|
||||
auth:
|
||||
required: true
|
||||
roles:
|
||||
- label
|
||||
depends_on_models:
|
||||
- model_label
|
||||
related:
|
||||
models:
|
||||
- id: model_label
|
||||
definition: &id001
|
||||
id: model_label
|
||||
name: Label
|
||||
table_name: labels
|
||||
description: Organization profile for labels
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: label_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: logo_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: website
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_artist
|
||||
foreign_key: label_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_label
|
||||
definitions:
|
||||
- id: model_label
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/labels/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/labels returns success response
|
||||
verification: curl -X POST /api/labels
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
task_id: task_create_api_create_playlist
|
||||
entity_id: api_create_playlist
|
||||
generated_at: '2025-12-18T15:16:50.263480'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_create_playlist
|
||||
method: POST
|
||||
path: /api/playlists
|
||||
description: Create new playlist
|
||||
request_body:
|
||||
name: string
|
||||
description: string
|
||||
is_public: boolean
|
||||
responses:
|
||||
- status: 201
|
||||
description: Playlist created
|
||||
schema:
|
||||
id: uuid
|
||||
name: string
|
||||
description: string
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/playlists returns success response
|
||||
verification: curl -X POST /api/playlists
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
task_id: task_create_api_delete_album
|
||||
entity_id: api_delete_album
|
||||
generated_at: '2025-12-18T15:16:50.262237'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_delete_album
|
||||
method: DELETE
|
||||
path: /api/albums/:id
|
||||
description: Delete album
|
||||
responses:
|
||||
- status: 204
|
||||
description: Album deleted
|
||||
- status: 403
|
||||
description: Unauthorized
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_album
|
||||
related:
|
||||
models:
|
||||
- id: model_album
|
||||
definition: &id001
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_album
|
||||
definitions:
|
||||
- id: model_album
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/albums/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: DELETE /api/albums/:id returns success response
|
||||
verification: curl -X DELETE /api/albums/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
task_id: task_create_api_delete_playlist
|
||||
entity_id: api_delete_playlist
|
||||
generated_at: '2025-12-18T15:16:50.268842'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_delete_playlist
|
||||
method: DELETE
|
||||
path: /api/playlists/:id
|
||||
description: Delete playlist
|
||||
responses:
|
||||
- status: 204
|
||||
description: Playlist deleted
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: DELETE /api/playlists/:id returns success response
|
||||
verification: curl -X DELETE /api/playlists/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
task_id: task_create_api_delete_song
|
||||
entity_id: api_delete_song
|
||||
generated_at: '2025-12-18T15:16:50.252212'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_delete_song
|
||||
method: DELETE
|
||||
path: /api/songs/:id
|
||||
description: Delete song
|
||||
responses:
|
||||
- status: 204
|
||||
description: Song deleted
|
||||
- status: 403
|
||||
description: Unauthorized
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_song
|
||||
related:
|
||||
models:
|
||||
- id: model_song
|
||||
definition: &id001
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/songs/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: DELETE /api/songs/:id returns success response
|
||||
verification: curl -X DELETE /api/songs/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
task_id: task_create_api_forgot_password
|
||||
entity_id: api_forgot_password
|
||||
generated_at: '2025-12-18T15:16:50.229463'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_forgot_password
|
||||
method: POST
|
||||
path: /api/auth/forgot-password
|
||||
description: Request password reset email
|
||||
request_body:
|
||||
email: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Reset email sent
|
||||
schema:
|
||||
message: string
|
||||
- status: 404
|
||||
description: Email not found
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
related:
|
||||
models:
|
||||
- id: model_user
|
||||
definition: &id001
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_user
|
||||
definitions:
|
||||
- id: model_user
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/auth/forgot-password/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/auth/forgot-password returns success response
|
||||
verification: curl -X POST /api/auth/forgot-password
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
task_id: task_create_api_get_album
|
||||
entity_id: api_get_album
|
||||
generated_at: '2025-12-18T15:16:50.257721'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_album
|
||||
method: GET
|
||||
path: /api/albums/:id
|
||||
description: Get album details with songs
|
||||
responses:
|
||||
- status: 200
|
||||
description: Album details
|
||||
schema:
|
||||
id: uuid
|
||||
title: string
|
||||
description: string
|
||||
cover_art_url: string
|
||||
release_date: string
|
||||
artist:
|
||||
id: uuid
|
||||
stage_name: string
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
duration: integer
|
||||
track_number: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_album
|
||||
- model_song
|
||||
- model_artist
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_album
|
||||
definition: &id002
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
- id: model_song
|
||||
definition: &id003
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_album
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_album
|
||||
type: model
|
||||
definition: *id002
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/api/albums/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/albums/:id returns success response
|
||||
verification: curl -X GET /api/albums/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
task_id: task_create_api_get_artist
|
||||
entity_id: api_get_artist
|
||||
generated_at: '2025-12-18T15:16:50.237033'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_artist
|
||||
method: GET
|
||||
path: /api/artists/:id
|
||||
description: Get artist profile by ID
|
||||
responses:
|
||||
- status: 200
|
||||
description: Artist profile
|
||||
schema:
|
||||
id: uuid
|
||||
stage_name: string
|
||||
bio: string
|
||||
cover_image_url: string
|
||||
social_links: object
|
||||
verified: boolean
|
||||
- status: 404
|
||||
description: Artist not found
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_artist
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/artists/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/artists/:id returns success response
|
||||
verification: curl -X GET /api/artists/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
task_id: task_create_api_get_artist_albums
|
||||
entity_id: api_get_artist_albums
|
||||
generated_at: '2025-12-18T15:16:50.242502'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
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
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_album
|
||||
definition: &id002
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_album
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_album
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/artists/id/albums/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/artists/:id/albums returns success response
|
||||
verification: curl -X GET /api/artists/:id/albums
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
task_id: task_create_api_get_artist_songs
|
||||
entity_id: api_get_artist_songs
|
||||
generated_at: '2025-12-18T15:16:50.239966'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_artist_songs
|
||||
method: GET
|
||||
path: /api/artists/:id/songs
|
||||
description: Get all songs by artist
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of songs
|
||||
schema:
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
duration: integer
|
||||
cover_art_url: string
|
||||
play_count: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_artist
|
||||
- model_song
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_song
|
||||
definition: &id002
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/artists/id/songs/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/artists/:id/songs returns success response
|
||||
verification: curl -X GET /api/artists/:id/songs
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
task_id: task_create_api_get_current_user
|
||||
entity_id: api_get_current_user
|
||||
generated_at: '2025-12-18T15:16:50.232153'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_current_user
|
||||
method: GET
|
||||
path: /api/users/me
|
||||
description: Get current user profile
|
||||
responses:
|
||||
- status: 200
|
||||
description: User profile
|
||||
schema:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
avatar_url: string
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_user
|
||||
related:
|
||||
models:
|
||||
- id: model_user
|
||||
definition: &id001
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_user
|
||||
definitions:
|
||||
- id: model_user
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/users/me/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/users/me returns success response
|
||||
verification: curl -X GET /api/users/me
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
task_id: task_create_api_get_genres
|
||||
entity_id: api_get_genres
|
||||
generated_at: '2025-12-18T15:16:50.279777'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
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
|
||||
related:
|
||||
models:
|
||||
- id: model_genre
|
||||
definition: &id001
|
||||
id: model_genre
|
||||
name: Genre
|
||||
table_name: genres
|
||||
description: Music category for discovery
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: slug
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_many
|
||||
to: model_song
|
||||
through: song_genres
|
||||
foreign_key: genre_id
|
||||
indexes:
|
||||
- fields:
|
||||
- slug
|
||||
unique: true
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_genre
|
||||
definitions:
|
||||
- id: model_genre
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/discover/genres/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/discover/genres returns success response
|
||||
verification: curl -X GET /api/discover/genres
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
task_id: task_create_api_get_label_artists
|
||||
entity_id: api_get_label_artists
|
||||
generated_at: '2025-12-18T15:16:50.287533'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_label_artists
|
||||
method: GET
|
||||
path: /api/labels/:id/artists
|
||||
description: Get artists under label
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of artists
|
||||
schema:
|
||||
artists:
|
||||
- id: uuid
|
||||
stage_name: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_label
|
||||
- model_artist
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_label
|
||||
definition: &id002
|
||||
id: model_label
|
||||
name: Label
|
||||
table_name: labels
|
||||
description: Organization profile for labels
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: label_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: logo_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: website
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_artist
|
||||
foreign_key: label_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_label
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_label
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/labels/id/artists/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/labels/:id/artists returns success response
|
||||
verification: curl -X GET /api/labels/:id/artists
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
task_id: task_create_api_get_new_releases
|
||||
entity_id: api_get_new_releases
|
||||
generated_at: '2025-12-18T15:16:50.277976'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_new_releases
|
||||
method: GET
|
||||
path: /api/discover/new-releases
|
||||
description: Get recently released songs
|
||||
query_params:
|
||||
limit: integer
|
||||
offset: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of new releases
|
||||
schema:
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
release_date: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
related:
|
||||
models:
|
||||
- id: model_song
|
||||
definition: &id001
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/discover/new-releases/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/discover/new-releases returns success response
|
||||
verification: curl -X GET /api/discover/new-releases
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
task_id: task_create_api_get_playlist
|
||||
entity_id: api_get_playlist
|
||||
generated_at: '2025-12-18T15:16:50.265868'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_playlist
|
||||
method: GET
|
||||
path: /api/playlists/:id
|
||||
description: Get playlist details with songs
|
||||
responses:
|
||||
- status: 200
|
||||
description: Playlist details
|
||||
schema:
|
||||
id: uuid
|
||||
name: string
|
||||
description: string
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
artist:
|
||||
stage_name: string
|
||||
position: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
- id: model_playlist_song
|
||||
definition: &id002
|
||||
id: model_playlist_song
|
||||
name: PlaylistSong
|
||||
table_name: playlist_songs
|
||||
description: Junction table with ordering for playlists
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: playlist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: playlists.id
|
||||
- name: song_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: songs.id
|
||||
- name: position
|
||||
type: integer
|
||||
constraints:
|
||||
- not_null
|
||||
- name: added_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_playlist
|
||||
foreign_key: playlist_id
|
||||
- type: belongs_to
|
||||
to: model_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- playlist_id
|
||||
- position
|
||||
unique: true
|
||||
- fields:
|
||||
- playlist_id
|
||||
- song_id
|
||||
unique: true
|
||||
timestamps: false
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_playlist_song
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/playlists/:id returns success response
|
||||
verification: curl -X GET /api/playlists/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
task_id: task_create_api_get_song
|
||||
entity_id: api_get_song
|
||||
generated_at: '2025-12-18T15:16:50.247175'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_song
|
||||
method: GET
|
||||
path: /api/songs/:id
|
||||
description: Get song details
|
||||
responses:
|
||||
- status: 200
|
||||
description: Song details
|
||||
schema:
|
||||
id: uuid
|
||||
title: string
|
||||
duration: integer
|
||||
file_url: string
|
||||
cover_art_url: string
|
||||
artist:
|
||||
id: uuid
|
||||
stage_name: string
|
||||
album:
|
||||
id: uuid
|
||||
title: string
|
||||
genres: array
|
||||
play_count: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
- model_artist
|
||||
- model_album
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_album
|
||||
definition: &id002
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
- id: model_song
|
||||
definition: &id003
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_album
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_album
|
||||
type: model
|
||||
definition: *id002
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/api/songs/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/songs/:id returns success response
|
||||
verification: curl -X GET /api/songs/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
task_id: task_create_api_get_songs_by_genre
|
||||
entity_id: api_get_songs_by_genre
|
||||
generated_at: '2025-12-18T15:16:50.280833'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_songs_by_genre
|
||||
method: GET
|
||||
path: /api/discover/genres/:slug
|
||||
description: Get songs by genre
|
||||
query_params:
|
||||
limit: integer
|
||||
offset: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of songs in genre
|
||||
schema:
|
||||
genre:
|
||||
name: string
|
||||
songs: array
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_genre
|
||||
- model_song
|
||||
related:
|
||||
models:
|
||||
- id: model_song
|
||||
definition: &id001
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
- id: model_genre
|
||||
definition: &id002
|
||||
id: model_genre
|
||||
name: Genre
|
||||
table_name: genres
|
||||
description: Music category for discovery
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: slug
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_many
|
||||
to: model_song
|
||||
through: song_genres
|
||||
foreign_key: genre_id
|
||||
indexes:
|
||||
- fields:
|
||||
- slug
|
||||
unique: true
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_song
|
||||
- model_genre
|
||||
definitions:
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_genre
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/discover/genres/slug/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/discover/genres/:slug returns success response
|
||||
verification: curl -X GET /api/discover/genres/:slug
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
task_id: task_create_api_get_trending_songs
|
||||
entity_id: api_get_trending_songs
|
||||
generated_at: '2025-12-18T15:16:50.275382'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_trending_songs
|
||||
method: GET
|
||||
path: /api/discover/trending
|
||||
description: Get trending songs
|
||||
query_params:
|
||||
limit: integer
|
||||
offset: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of trending songs
|
||||
schema:
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
artist:
|
||||
stage_name: string
|
||||
play_count: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
- model_artist
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_song
|
||||
definition: &id002
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/discover/trending/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/discover/trending returns success response
|
||||
verification: curl -X GET /api/discover/trending
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
task_id: task_create_api_get_user_playlists
|
||||
entity_id: api_get_user_playlists
|
||||
generated_at: '2025-12-18T15:16:50.264680'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_get_user_playlists
|
||||
method: GET
|
||||
path: /api/playlists
|
||||
description: Get current user's playlists
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of playlists
|
||||
schema:
|
||||
playlists:
|
||||
- id: uuid
|
||||
name: string
|
||||
cover_image_url: string
|
||||
song_count: integer
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/playlists returns success response
|
||||
verification: curl -X GET /api/playlists
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
task_id: task_create_api_increment_play_count
|
||||
entity_id: api_increment_play_count
|
||||
generated_at: '2025-12-18T15:16:50.253941'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_increment_play_count
|
||||
method: POST
|
||||
path: /api/songs/:id/play
|
||||
description: Increment play count
|
||||
request_body: null
|
||||
responses:
|
||||
- status: 200
|
||||
description: Play count incremented
|
||||
schema:
|
||||
play_count: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
related:
|
||||
models:
|
||||
- id: model_song
|
||||
definition: &id001
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/songs/id/play/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/songs/:id/play returns success response
|
||||
verification: curl -X POST /api/songs/:id/play
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
task_id: task_create_api_login
|
||||
entity_id: api_login
|
||||
generated_at: '2025-12-18T15:16:50.228086'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_login
|
||||
method: POST
|
||||
path: /api/auth/login
|
||||
description: Login with email and password
|
||||
request_body:
|
||||
email: string
|
||||
password: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Login successful
|
||||
schema:
|
||||
user:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
token: string
|
||||
- status: 401
|
||||
description: Invalid credentials
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
related:
|
||||
models:
|
||||
- id: model_user
|
||||
definition: &id001
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_user
|
||||
definitions:
|
||||
- id: model_user
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/auth/login/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/auth/login returns success response
|
||||
verification: curl -X POST /api/auth/login
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
task_id: task_create_api_register
|
||||
entity_id: api_register
|
||||
generated_at: '2025-12-18T15:16:50.226614'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_register
|
||||
method: POST
|
||||
path: /api/auth/register
|
||||
description: Register new user account
|
||||
request_body:
|
||||
email: string
|
||||
password: string
|
||||
name: string
|
||||
role: enum[musician, listener, label]
|
||||
responses:
|
||||
- status: 201
|
||||
description: User created successfully
|
||||
schema:
|
||||
user:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
token: string
|
||||
- status: 400
|
||||
description: Validation error
|
||||
schema:
|
||||
error: string
|
||||
- status: 409
|
||||
description: Email already exists
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
related:
|
||||
models:
|
||||
- id: model_user
|
||||
definition: &id001
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_user
|
||||
definitions:
|
||||
- id: model_user
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/auth/register/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/auth/register returns success response
|
||||
verification: curl -X POST /api/auth/register
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
task_id: task_create_api_remove_song_from_playlist
|
||||
entity_id: api_remove_song_from_playlist
|
||||
generated_at: '2025-12-18T15:16:50.271730'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_remove_song_from_playlist
|
||||
method: DELETE
|
||||
path: /api/playlists/:playlistId/songs/:songId
|
||||
description: Remove song from playlist
|
||||
responses:
|
||||
- status: 204
|
||||
description: Song removed from playlist
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
- id: model_playlist_song
|
||||
definition: &id002
|
||||
id: model_playlist_song
|
||||
name: PlaylistSong
|
||||
table_name: playlist_songs
|
||||
description: Junction table with ordering for playlists
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: playlist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: playlists.id
|
||||
- name: song_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: songs.id
|
||||
- name: position
|
||||
type: integer
|
||||
constraints:
|
||||
- not_null
|
||||
- name: added_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_playlist
|
||||
foreign_key: playlist_id
|
||||
- type: belongs_to
|
||||
to: model_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- playlist_id
|
||||
- position
|
||||
unique: true
|
||||
- fields:
|
||||
- playlist_id
|
||||
- song_id
|
||||
unique: true
|
||||
timestamps: false
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_playlist_song
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/playlistId/songs/songId/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: DELETE /api/playlists/:playlistId/songs/:songId returns success response
|
||||
verification: curl -X DELETE /api/playlists/:playlistId/songs/:songId
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
task_id: task_create_api_reorder_playlist_songs
|
||||
entity_id: api_reorder_playlist_songs
|
||||
generated_at: '2025-12-18T15:16:50.273600'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_reorder_playlist_songs
|
||||
method: PUT
|
||||
path: /api/playlists/:id/reorder
|
||||
description: Reorder songs in playlist
|
||||
request_body:
|
||||
song_ids: array[uuid]
|
||||
responses:
|
||||
- status: 200
|
||||
description: Playlist reordered
|
||||
schema:
|
||||
message: string
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
- id: model_playlist_song
|
||||
definition: &id002
|
||||
id: model_playlist_song
|
||||
name: PlaylistSong
|
||||
table_name: playlist_songs
|
||||
description: Junction table with ordering for playlists
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: playlist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: playlists.id
|
||||
- name: song_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: songs.id
|
||||
- name: position
|
||||
type: integer
|
||||
constraints:
|
||||
- not_null
|
||||
- name: added_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_playlist
|
||||
foreign_key: playlist_id
|
||||
- type: belongs_to
|
||||
to: model_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- playlist_id
|
||||
- position
|
||||
unique: true
|
||||
- fields:
|
||||
- playlist_id
|
||||
- song_id
|
||||
unique: true
|
||||
timestamps: false
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_playlist_song
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/id/reorder/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: PUT /api/playlists/:id/reorder returns success response
|
||||
verification: curl -X PUT /api/playlists/:id/reorder
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
task_id: task_create_api_reset_password
|
||||
entity_id: api_reset_password
|
||||
generated_at: '2025-12-18T15:16:50.230797'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_reset_password
|
||||
method: POST
|
||||
path: /api/auth/reset-password
|
||||
description: Reset password with token
|
||||
request_body:
|
||||
token: string
|
||||
password: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Password reset successful
|
||||
schema:
|
||||
message: string
|
||||
- status: 400
|
||||
description: Invalid or expired token
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
related:
|
||||
models:
|
||||
- id: model_user
|
||||
definition: &id001
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_user
|
||||
definitions:
|
||||
- id: model_user
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/auth/reset-password/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/auth/reset-password returns success response
|
||||
verification: curl -X POST /api/auth/reset-password
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
task_id: task_create_api_search
|
||||
entity_id: api_search
|
||||
generated_at: '2025-12-18T15:16:50.283107'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_search
|
||||
method: GET
|
||||
path: /api/search
|
||||
description: Search songs, artists, and albums
|
||||
query_params:
|
||||
q: string
|
||||
type: enum[song, artist, album, all]
|
||||
limit: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: Search results
|
||||
schema:
|
||||
songs: array
|
||||
artists: array
|
||||
albums: array
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
- model_artist
|
||||
- model_album
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_album
|
||||
definition: &id002
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
- id: model_song
|
||||
definition: &id003
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_album
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_album
|
||||
type: model
|
||||
definition: *id002
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/api/search/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: GET /api/search returns success response
|
||||
verification: curl -X GET /api/search
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
task_id: task_create_api_update_album
|
||||
entity_id: api_update_album
|
||||
generated_at: '2025-12-18T15:16:50.260977'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_update_album
|
||||
method: PUT
|
||||
path: /api/albums/:id
|
||||
description: Update album metadata
|
||||
request_body:
|
||||
title: string
|
||||
description: string
|
||||
cover_art_url: string
|
||||
release_date: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Album updated
|
||||
schema:
|
||||
id: uuid
|
||||
title: string
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_album
|
||||
related:
|
||||
models:
|
||||
- id: model_album
|
||||
definition: &id001
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_album
|
||||
definitions:
|
||||
- id: model_album
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/albums/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: PUT /api/albums/:id returns success response
|
||||
verification: curl -X PUT /api/albums/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
task_id: task_create_api_update_artist
|
||||
entity_id: api_update_artist
|
||||
generated_at: '2025-12-18T15:16:50.238503'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_update_artist
|
||||
method: PUT
|
||||
path: /api/artists/:id
|
||||
description: Update artist profile
|
||||
request_body:
|
||||
stage_name: string
|
||||
bio: string
|
||||
cover_image_url: string
|
||||
social_links: object
|
||||
responses:
|
||||
- status: 200
|
||||
description: Artist updated
|
||||
schema:
|
||||
id: uuid
|
||||
stage_name: string
|
||||
bio: string
|
||||
- status: 403
|
||||
description: Unauthorized
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_artist
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/artists/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: PUT /api/artists/:id returns success response
|
||||
verification: curl -X PUT /api/artists/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
task_id: task_create_api_update_current_user
|
||||
entity_id: api_update_current_user
|
||||
generated_at: '2025-12-18T15:16:50.233456'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_update_current_user
|
||||
method: PUT
|
||||
path: /api/users/me
|
||||
description: Update current user profile
|
||||
request_body:
|
||||
name: string
|
||||
avatar_url: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: User updated
|
||||
schema:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
avatar_url: string
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_user
|
||||
related:
|
||||
models:
|
||||
- id: model_user
|
||||
definition: &id001
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_user
|
||||
definitions:
|
||||
- id: model_user
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/users/me/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: PUT /api/users/me returns success response
|
||||
verification: curl -X PUT /api/users/me
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
task_id: task_create_api_update_playlist
|
||||
entity_id: api_update_playlist
|
||||
generated_at: '2025-12-18T15:16:50.267642'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_update_playlist
|
||||
method: PUT
|
||||
path: /api/playlists/:id
|
||||
description: Update playlist metadata
|
||||
request_body:
|
||||
name: string
|
||||
description: string
|
||||
is_public: boolean
|
||||
responses:
|
||||
- status: 200
|
||||
description: Playlist updated
|
||||
schema:
|
||||
id: uuid
|
||||
name: string
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
related:
|
||||
models:
|
||||
- id: model_playlist
|
||||
definition: &id001
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_playlist
|
||||
definitions:
|
||||
- id: model_playlist
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/playlists/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: PUT /api/playlists/:id returns success response
|
||||
verification: curl -X PUT /api/playlists/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
task_id: task_create_api_update_song
|
||||
entity_id: api_update_song
|
||||
generated_at: '2025-12-18T15:16:50.250397'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
id: api_update_song
|
||||
method: PUT
|
||||
path: /api/songs/:id
|
||||
description: Update song metadata
|
||||
request_body:
|
||||
title: string
|
||||
album_id: uuid
|
||||
genre_ids: array[uuid]
|
||||
release_date: string
|
||||
is_public: boolean
|
||||
responses:
|
||||
- status: 200
|
||||
description: Song updated
|
||||
schema:
|
||||
id: uuid
|
||||
title: string
|
||||
- status: 403
|
||||
description: Unauthorized
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: true
|
||||
owner_only: true
|
||||
depends_on_models:
|
||||
- model_song
|
||||
related:
|
||||
models:
|
||||
- id: model_song
|
||||
definition: &id001
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/api/songs/id/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: PUT /api/songs/:id returns success response
|
||||
verification: curl -X PUT /api/songs/:id
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
task_id: task_create_api_upload_song
|
||||
entity_id: api_upload_song
|
||||
generated_at: '2025-12-18T15:16:50.244501'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: api
|
||||
definition:
|
||||
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
|
||||
related:
|
||||
models:
|
||||
- id: model_artist
|
||||
definition: &id001
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
- id: model_song
|
||||
definition: &id002
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- model_artist
|
||||
- model_song
|
||||
definitions:
|
||||
- id: model_artist
|
||||
type: model
|
||||
definition: *id001
|
||||
- id: model_song
|
||||
type: model
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/api/songs/upload/route.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: POST /api/songs/upload returns success response
|
||||
verification: curl -X POST /api/songs/upload
|
||||
- criterion: Request validation implemented
|
||||
verification: Test with invalid data
|
||||
- criterion: Error responses match contract
|
||||
verification: Test error scenarios
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
task_id: task_create_component_album_card
|
||||
entity_id: component_album_card
|
||||
generated_at: '2025-12-18T15:16:50.313541'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_album_card
|
||||
name: AlbumCard
|
||||
description: Album display card
|
||||
props:
|
||||
- name: album
|
||||
type: Album
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
albumId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/AlbumCard.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
task_id: task_create_component_album_header
|
||||
entity_id: component_album_header
|
||||
generated_at: '2025-12-18T15:16:50.319775'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_album_header
|
||||
name: AlbumHeader
|
||||
description: Album detail header with cover art
|
||||
props:
|
||||
- name: album
|
||||
type: Album
|
||||
required: true
|
||||
- name: artist
|
||||
type: Artist
|
||||
required: true
|
||||
events:
|
||||
- name: onPlayAll
|
||||
payload: null
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/AlbumHeader.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
task_id: task_create_component_artist_card
|
||||
entity_id: component_artist_card
|
||||
generated_at: '2025-12-18T15:16:50.314121'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_artist_card
|
||||
name: ArtistCard
|
||||
description: Artist preview card
|
||||
props:
|
||||
- name: artist
|
||||
type: Artist
|
||||
required: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
artistId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/ArtistCard.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
task_id: task_create_component_artist_header
|
||||
entity_id: component_artist_header
|
||||
generated_at: '2025-12-18T15:16:50.319067'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_artist_header
|
||||
name: ArtistHeader
|
||||
description: Artist profile header with cover image
|
||||
props:
|
||||
- name: artist
|
||||
type: Artist
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components:
|
||||
- component_social_links
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components:
|
||||
- id: component_social_links
|
||||
definition: &id001
|
||||
id: component_social_links
|
||||
name: SocialLinks
|
||||
description: Social media links display
|
||||
props:
|
||||
- name: links
|
||||
type: object
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_social_links
|
||||
definitions:
|
||||
- id: component_social_links
|
||||
type: component
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/components/ArtistHeader.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
task_id: task_create_component_audio_player
|
||||
entity_id: component_audio_player
|
||||
generated_at: '2025-12-18T15:16:50.310377'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_audio_player
|
||||
name: AudioPlayer
|
||||
description: Global audio player with full controls
|
||||
props:
|
||||
- name: currentSong
|
||||
type: Song
|
||||
required: false
|
||||
- name: queue
|
||||
type: array[Song]
|
||||
required: false
|
||||
- name: autoplay
|
||||
type: boolean
|
||||
default: false
|
||||
state:
|
||||
- name: isPlaying
|
||||
type: boolean
|
||||
- name: currentTime
|
||||
type: number
|
||||
- name: volume
|
||||
type: number
|
||||
- name: isShuffle
|
||||
type: boolean
|
||||
- name: repeatMode
|
||||
type: enum[off, one, all]
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onPause
|
||||
payload: null
|
||||
- name: onSeek
|
||||
payload:
|
||||
time: number
|
||||
- name: onVolumeChange
|
||||
payload:
|
||||
volume: number
|
||||
- name: onNext
|
||||
payload: null
|
||||
- name: onPrevious
|
||||
payload: null
|
||||
- name: onShuffle
|
||||
payload: null
|
||||
- name: onRepeat
|
||||
payload: null
|
||||
uses_apis:
|
||||
- api_increment_play_count
|
||||
uses_components:
|
||||
- component_waveform_display
|
||||
- component_player_controls
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_increment_play_count
|
||||
definition: &id002
|
||||
id: api_increment_play_count
|
||||
method: POST
|
||||
path: /api/songs/:id/play
|
||||
description: Increment play count
|
||||
request_body: null
|
||||
responses:
|
||||
- status: 200
|
||||
description: Play count incremented
|
||||
schema:
|
||||
play_count: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
components:
|
||||
- id: component_waveform_display
|
||||
definition: &id001
|
||||
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: []
|
||||
- id: component_player_controls
|
||||
definition: &id003
|
||||
id: component_player_controls
|
||||
name: PlayerControls
|
||||
description: Play/pause/seek controls
|
||||
props:
|
||||
- name: isPlaying
|
||||
type: boolean
|
||||
required: true
|
||||
- name: currentTime
|
||||
type: number
|
||||
required: true
|
||||
- name: duration
|
||||
type: number
|
||||
required: true
|
||||
events:
|
||||
- name: onPlay
|
||||
payload: null
|
||||
- name: onPause
|
||||
payload: null
|
||||
- name: onSeek
|
||||
payload:
|
||||
time: number
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_waveform_display
|
||||
- api_increment_play_count
|
||||
- component_player_controls
|
||||
definitions:
|
||||
- id: component_waveform_display
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: api_increment_play_count
|
||||
type: api
|
||||
definition: *id002
|
||||
- id: component_player_controls
|
||||
type: component
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/components/AudioPlayer.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
task_id: task_create_component_auth_form
|
||||
entity_id: component_auth_form
|
||||
generated_at: '2025-12-18T15:16:50.321537'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_auth_form
|
||||
name: AuthForm
|
||||
description: Reusable authentication form
|
||||
props:
|
||||
- name: mode
|
||||
type: enum[login, register, forgot]
|
||||
required: true
|
||||
state:
|
||||
- name: email
|
||||
type: string
|
||||
- name: password
|
||||
type: string
|
||||
- name: name
|
||||
type: string
|
||||
- name: role
|
||||
type: string
|
||||
events:
|
||||
- name: onSubmit
|
||||
payload: object
|
||||
uses_apis:
|
||||
- api_login
|
||||
- api_register
|
||||
- api_forgot_password
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_forgot_password
|
||||
definition: &id001
|
||||
id: api_forgot_password
|
||||
method: POST
|
||||
path: /api/auth/forgot-password
|
||||
description: Request password reset email
|
||||
request_body:
|
||||
email: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Reset email sent
|
||||
schema:
|
||||
message: string
|
||||
- status: 404
|
||||
description: Email not found
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
- id: api_register
|
||||
definition: &id002
|
||||
id: api_register
|
||||
method: POST
|
||||
path: /api/auth/register
|
||||
description: Register new user account
|
||||
request_body:
|
||||
email: string
|
||||
password: string
|
||||
name: string
|
||||
role: enum[musician, listener, label]
|
||||
responses:
|
||||
- status: 201
|
||||
description: User created successfully
|
||||
schema:
|
||||
user:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
token: string
|
||||
- status: 400
|
||||
description: Validation error
|
||||
schema:
|
||||
error: string
|
||||
- status: 409
|
||||
description: Email already exists
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
- id: api_login
|
||||
definition: &id003
|
||||
id: api_login
|
||||
method: POST
|
||||
path: /api/auth/login
|
||||
description: Login with email and password
|
||||
request_body:
|
||||
email: string
|
||||
password: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Login successful
|
||||
schema:
|
||||
user:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
token: string
|
||||
- status: 401
|
||||
description: Invalid credentials
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- api_forgot_password
|
||||
- api_register
|
||||
- api_login
|
||||
definitions:
|
||||
- id: api_forgot_password
|
||||
type: api
|
||||
definition: *id001
|
||||
- id: api_register
|
||||
type: api
|
||||
definition: *id002
|
||||
- id: api_login
|
||||
type: api
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/components/AuthForm.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
task_id: task_create_component_avatar_upload
|
||||
entity_id: component_avatar_upload
|
||||
generated_at: '2025-12-18T15:16:50.327669'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_avatar_upload
|
||||
name: AvatarUpload
|
||||
description: Avatar image upload component
|
||||
props:
|
||||
- name: currentAvatarUrl
|
||||
type: string
|
||||
required: false
|
||||
state:
|
||||
- name: file
|
||||
type: File
|
||||
- name: preview
|
||||
type: string
|
||||
events:
|
||||
- name: onUpload
|
||||
payload:
|
||||
file: File
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/AvatarUpload.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
task_id: task_create_component_create_playlist_modal
|
||||
entity_id: component_create_playlist_modal
|
||||
generated_at: '2025-12-18T15:16:50.325506'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_create_playlist_modal
|
||||
name: CreatePlaylistModal
|
||||
description: Modal for creating new playlist
|
||||
props:
|
||||
- name: isOpen
|
||||
type: boolean
|
||||
required: true
|
||||
state:
|
||||
- name: name
|
||||
type: string
|
||||
- name: description
|
||||
type: string
|
||||
- name: isPublic
|
||||
type: boolean
|
||||
events:
|
||||
- name: onCreate
|
||||
payload:
|
||||
name: string
|
||||
description: string
|
||||
isPublic: boolean
|
||||
- name: onClose
|
||||
payload: null
|
||||
uses_apis:
|
||||
- api_create_playlist
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_create_playlist
|
||||
definition: &id001
|
||||
id: api_create_playlist
|
||||
method: POST
|
||||
path: /api/playlists
|
||||
description: Create new playlist
|
||||
request_body:
|
||||
name: string
|
||||
description: string
|
||||
is_public: boolean
|
||||
responses:
|
||||
- status: 201
|
||||
description: Playlist created
|
||||
schema:
|
||||
id: uuid
|
||||
name: string
|
||||
description: string
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- api_create_playlist
|
||||
definitions:
|
||||
- id: api_create_playlist
|
||||
type: api
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/components/CreatePlaylistModal.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
task_id: task_create_component_genre_badge
|
||||
entity_id: component_genre_badge
|
||||
generated_at: '2025-12-18T15:16:50.317487'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_genre_badge
|
||||
name: GenreBadge
|
||||
description: Genre tag display
|
||||
props:
|
||||
- name: genre
|
||||
type: Genre
|
||||
required: true
|
||||
- name: clickable
|
||||
type: boolean
|
||||
default: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
genreSlug: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/GenreBadge.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
task_id: task_create_component_genre_header
|
||||
entity_id: component_genre_header
|
||||
generated_at: '2025-12-18T15:16:50.328870'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_genre_header
|
||||
name: GenreHeader
|
||||
description: Genre browse page header
|
||||
props:
|
||||
- name: genre
|
||||
type: Genre
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/GenreHeader.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
task_id: task_create_component_player_controls
|
||||
entity_id: component_player_controls
|
||||
generated_at: '2025-12-18T15:16:50.312220'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_player_controls
|
||||
name: PlayerControls
|
||||
description: Play/pause/seek controls
|
||||
props:
|
||||
- name: isPlaying
|
||||
type: boolean
|
||||
required: true
|
||||
- name: currentTime
|
||||
type: number
|
||||
required: true
|
||||
- name: duration
|
||||
type: number
|
||||
required: true
|
||||
events:
|
||||
- name: onPlay
|
||||
payload: null
|
||||
- name: onPause
|
||||
payload: null
|
||||
- name: onSeek
|
||||
payload:
|
||||
time: number
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/PlayerControls.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
task_id: task_create_component_playlist_card
|
||||
entity_id: component_playlist_card
|
||||
generated_at: '2025-12-18T15:16:50.314728'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_playlist_card
|
||||
name: PlaylistCard
|
||||
description: Playlist preview card
|
||||
props:
|
||||
- name: playlist
|
||||
type: Playlist
|
||||
required: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
playlistId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/PlaylistCard.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
task_id: task_create_component_playlist_header
|
||||
entity_id: component_playlist_header
|
||||
generated_at: '2025-12-18T15:16:50.320366'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_playlist_header
|
||||
name: PlaylistHeader
|
||||
description: Playlist header with cover and controls
|
||||
props:
|
||||
- name: playlist
|
||||
type: Playlist
|
||||
required: true
|
||||
- name: isOwner
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlayAll
|
||||
payload: null
|
||||
- name: onEdit
|
||||
payload: null
|
||||
- name: onDelete
|
||||
payload: null
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/PlaylistHeader.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
task_id: task_create_component_profile_form
|
||||
entity_id: component_profile_form
|
||||
generated_at: '2025-12-18T15:16:50.326476'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_profile_form
|
||||
name: ProfileForm
|
||||
description: User profile edit form
|
||||
props:
|
||||
- name: user
|
||||
type: User
|
||||
required: true
|
||||
state:
|
||||
- name: name
|
||||
type: string
|
||||
- name: avatarUrl
|
||||
type: string
|
||||
events:
|
||||
- name: onSave
|
||||
payload:
|
||||
name: string
|
||||
avatarUrl: string
|
||||
uses_apis:
|
||||
- api_update_current_user
|
||||
uses_components:
|
||||
- component_avatar_upload
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_update_current_user
|
||||
definition: &id001
|
||||
id: api_update_current_user
|
||||
method: PUT
|
||||
path: /api/users/me
|
||||
description: Update current user profile
|
||||
request_body:
|
||||
name: string
|
||||
avatar_url: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: User updated
|
||||
schema:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
avatar_url: string
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_user
|
||||
components:
|
||||
- id: component_avatar_upload
|
||||
definition: &id002
|
||||
id: component_avatar_upload
|
||||
name: AvatarUpload
|
||||
description: Avatar image upload component
|
||||
props:
|
||||
- name: currentAvatarUrl
|
||||
type: string
|
||||
required: false
|
||||
state:
|
||||
- name: file
|
||||
type: File
|
||||
- name: preview
|
||||
type: string
|
||||
events:
|
||||
- name: onUpload
|
||||
payload:
|
||||
file: File
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- api_update_current_user
|
||||
- component_avatar_upload
|
||||
definitions:
|
||||
- id: api_update_current_user
|
||||
type: api
|
||||
definition: *id001
|
||||
- id: component_avatar_upload
|
||||
type: component
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/components/ProfileForm.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
task_id: task_create_component_search_bar
|
||||
entity_id: component_search_bar
|
||||
generated_at: '2025-12-18T15:16:50.323230'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_search_bar
|
||||
name: SearchBar
|
||||
description: Search input with autocomplete
|
||||
props:
|
||||
- name: placeholder
|
||||
type: string
|
||||
default: Search songs, artists, albums...
|
||||
state:
|
||||
- name: query
|
||||
type: string
|
||||
events:
|
||||
- name: onSearch
|
||||
payload:
|
||||
query: string
|
||||
uses_apis:
|
||||
- api_search
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_search
|
||||
definition: &id001
|
||||
id: api_search
|
||||
method: GET
|
||||
path: /api/search
|
||||
description: Search songs, artists, and albums
|
||||
query_params:
|
||||
q: string
|
||||
type: enum[song, artist, album, all]
|
||||
limit: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: Search results
|
||||
schema:
|
||||
songs: array
|
||||
artists: array
|
||||
albums: array
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
- model_artist
|
||||
- model_album
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- api_search
|
||||
definitions:
|
||||
- id: api_search
|
||||
type: api
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/components/SearchBar.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
task_id: task_create_component_search_results
|
||||
entity_id: component_search_results
|
||||
generated_at: '2025-12-18T15:16:50.324165'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_search_results
|
||||
name: SearchResults
|
||||
description: Search results with filters
|
||||
props:
|
||||
- name: results
|
||||
type: object
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components:
|
||||
- component_song_card
|
||||
- component_artist_card
|
||||
- component_album_card
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components:
|
||||
- id: component_artist_card
|
||||
definition: &id001
|
||||
id: component_artist_card
|
||||
name: ArtistCard
|
||||
description: Artist preview card
|
||||
props:
|
||||
- name: artist
|
||||
type: Artist
|
||||
required: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
artistId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_album_card
|
||||
definition: &id002
|
||||
id: component_album_card
|
||||
name: AlbumCard
|
||||
description: Album display card
|
||||
props:
|
||||
- name: album
|
||||
type: Album
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
albumId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_song_card
|
||||
definition: &id003
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_artist_card
|
||||
- component_album_card
|
||||
- component_song_card
|
||||
definitions:
|
||||
- id: component_artist_card
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: component_album_card
|
||||
type: component
|
||||
definition: *id002
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/components/SearchResults.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
task_id: task_create_component_section_header
|
||||
entity_id: component_section_header
|
||||
generated_at: '2025-12-18T15:16:50.328281'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_section_header
|
||||
name: SectionHeader
|
||||
description: Section title with optional action
|
||||
props:
|
||||
- name: title
|
||||
type: string
|
||||
required: true
|
||||
- name: actionLabel
|
||||
type: string
|
||||
required: false
|
||||
events:
|
||||
- name: onActionClick
|
||||
payload: null
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/SectionHeader.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
task_id: task_create_component_social_links
|
||||
entity_id: component_social_links
|
||||
generated_at: '2025-12-18T15:16:50.321018'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_social_links
|
||||
name: SocialLinks
|
||||
description: Social media links display
|
||||
props:
|
||||
- name: links
|
||||
type: object
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/SocialLinks.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
task_id: task_create_component_song_card
|
||||
entity_id: component_song_card
|
||||
generated_at: '2025-12-18T15:16:50.312893'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/SongCard.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
task_id: task_create_component_track_list
|
||||
entity_id: component_track_list
|
||||
generated_at: '2025-12-18T15:16:50.318077'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
id: component_track_list
|
||||
name: TrackList
|
||||
description: List of songs with track numbers
|
||||
props:
|
||||
- name: songs
|
||||
type: array[Song]
|
||||
required: true
|
||||
- name: showTrackNumber
|
||||
type: boolean
|
||||
default: true
|
||||
- name: reorderable
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onReorder
|
||||
payload:
|
||||
songIds: array[string]
|
||||
uses_apis: []
|
||||
uses_components:
|
||||
- component_song_card
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components:
|
||||
- id: component_song_card
|
||||
definition: &id001
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_song_card
|
||||
definitions:
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id001
|
||||
files:
|
||||
to_create:
|
||||
- app/components/TrackList.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
task_id: task_create_component_upload_form
|
||||
entity_id: component_upload_form
|
||||
generated_at: '2025-12-18T15:16:50.315310'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
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
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_upload_song
|
||||
definition: &id002
|
||||
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
|
||||
components:
|
||||
- id: component_waveform_display
|
||||
definition: &id001
|
||||
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:
|
||||
- component_waveform_display
|
||||
- api_upload_song
|
||||
definitions:
|
||||
- id: component_waveform_display
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: api_upload_song
|
||||
type: api
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/components/UploadForm.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
task_id: task_create_component_waveform_display
|
||||
entity_id: component_waveform_display
|
||||
generated_at: '2025-12-18T15:16:50.316857'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: component
|
||||
definition:
|
||||
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: []
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- app/components/WaveformDisplay.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Component renders without errors
|
||||
verification: Import and render in test
|
||||
- criterion: Props are typed correctly
|
||||
verification: TypeScript compilation
|
||||
- criterion: Events fire correctly
|
||||
verification: Test event handlers
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
task_id: task_create_model_album
|
||||
entity_id: model_album
|
||||
generated_at: '2025-12-18T15:16:50.221462'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_album
|
||||
name: Album
|
||||
table_name: albums
|
||||
description: Collection of songs
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: album_type
|
||||
type: enum
|
||||
values:
|
||||
- album
|
||||
- ep
|
||||
- single
|
||||
default: album
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: album_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- release_date
|
||||
timestamps: true
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/album.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
task_id: task_create_model_artist
|
||||
entity_id: model_artist
|
||||
generated_at: '2025-12-18T15:16:50.218607'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_artist
|
||||
name: Artist
|
||||
table_name: artists
|
||||
description: Extended profile for musicians
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: stage_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: bio
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: social_links
|
||||
type: jsonb
|
||||
description: JSON object with {twitter, instagram, facebook, website}
|
||||
constraints:
|
||||
- nullable
|
||||
- name: verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_song
|
||||
foreign_key: artist_id
|
||||
- type: has_many
|
||||
to: model_album
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_label
|
||||
foreign_key: label_id
|
||||
optional: true
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
- fields:
|
||||
- stage_name
|
||||
timestamps: true
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/artist.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
task_id: task_create_model_genre
|
||||
entity_id: model_genre
|
||||
generated_at: '2025-12-18T15:16:50.220626'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_genre
|
||||
name: Genre
|
||||
table_name: genres
|
||||
description: Music category for discovery
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: slug
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_many
|
||||
to: model_song
|
||||
through: song_genres
|
||||
foreign_key: genre_id
|
||||
indexes:
|
||||
- fields:
|
||||
- slug
|
||||
unique: true
|
||||
timestamps: true
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/genre.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
task_id: task_create_model_label
|
||||
entity_id: model_label
|
||||
generated_at: '2025-12-18T15:16:50.219701'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_label
|
||||
name: Label
|
||||
table_name: labels
|
||||
description: Organization profile for labels
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: label_name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: logo_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: website
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_artist
|
||||
foreign_key: label_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
unique: true
|
||||
timestamps: true
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/label.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
task_id: task_create_model_playlist
|
||||
entity_id: model_playlist
|
||||
generated_at: '2025-12-18T15:16:50.224750'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_playlist
|
||||
name: Playlist
|
||||
table_name: playlists
|
||||
description: User-created song collection
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: user_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: users.id
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: description
|
||||
type: text
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_image_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: false
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_user
|
||||
foreign_key: user_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: playlist_id
|
||||
indexes:
|
||||
- fields:
|
||||
- user_id
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/playlist.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
task_id: task_create_model_playlist_song
|
||||
entity_id: model_playlist_song
|
||||
generated_at: '2025-12-18T15:16:50.225730'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_playlist_song
|
||||
name: PlaylistSong
|
||||
table_name: playlist_songs
|
||||
description: Junction table with ordering for playlists
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: playlist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: playlists.id
|
||||
- name: song_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: songs.id
|
||||
- name: position
|
||||
type: integer
|
||||
constraints:
|
||||
- not_null
|
||||
- name: added_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_playlist
|
||||
foreign_key: playlist_id
|
||||
- type: belongs_to
|
||||
to: model_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- playlist_id
|
||||
- position
|
||||
unique: true
|
||||
- fields:
|
||||
- playlist_id
|
||||
- song_id
|
||||
unique: true
|
||||
timestamps: false
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/playlistsong.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
task_id: task_create_model_song
|
||||
entity_id: model_song
|
||||
generated_at: '2025-12-18T15:16:50.222463'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_song
|
||||
name: Song
|
||||
table_name: songs
|
||||
description: Audio track with metadata
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: artist_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: artists.id
|
||||
- name: album_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- nullable
|
||||
- foreign_key
|
||||
references: albums.id
|
||||
- name: title
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: duration
|
||||
type: integer
|
||||
description: Duration in seconds
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_url
|
||||
type: string
|
||||
description: Cloud storage URL for audio file
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_format
|
||||
type: enum
|
||||
values:
|
||||
- mp3
|
||||
- wav
|
||||
constraints:
|
||||
- not_null
|
||||
- name: file_size
|
||||
type: integer
|
||||
description: File size in bytes
|
||||
constraints:
|
||||
- not_null
|
||||
- name: waveform_data
|
||||
type: jsonb
|
||||
description: Waveform visualization data
|
||||
constraints:
|
||||
- nullable
|
||||
- name: cover_art_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: release_date
|
||||
type: date
|
||||
constraints:
|
||||
- nullable
|
||||
- name: play_count
|
||||
type: integer
|
||||
default: 0
|
||||
- name: is_public
|
||||
type: boolean
|
||||
default: true
|
||||
- name: track_number
|
||||
type: integer
|
||||
description: Position in album
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_artist
|
||||
foreign_key: artist_id
|
||||
- type: belongs_to
|
||||
to: model_album
|
||||
foreign_key: album_id
|
||||
optional: true
|
||||
- type: has_many
|
||||
to: model_genre
|
||||
through: song_genres
|
||||
foreign_key: song_id
|
||||
- type: has_many
|
||||
to: model_playlist_song
|
||||
foreign_key: song_id
|
||||
indexes:
|
||||
- fields:
|
||||
- artist_id
|
||||
- fields:
|
||||
- album_id
|
||||
- fields:
|
||||
- release_date
|
||||
- fields:
|
||||
- play_count
|
||||
- fields:
|
||||
- is_public
|
||||
timestamps: true
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/song.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
task_id: task_create_model_song_genre
|
||||
entity_id: model_song_genre
|
||||
generated_at: '2025-12-18T15:16:50.224015'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_song_genre
|
||||
name: SongGenre
|
||||
table_name: song_genres
|
||||
description: Junction table for song-genre many-to-many
|
||||
fields:
|
||||
- name: song_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: songs.id
|
||||
- name: genre_id
|
||||
type: uuid
|
||||
constraints:
|
||||
- not_null
|
||||
- foreign_key
|
||||
references: genres.id
|
||||
relations:
|
||||
- type: belongs_to
|
||||
to: model_song
|
||||
foreign_key: song_id
|
||||
- type: belongs_to
|
||||
to: model_genre
|
||||
foreign_key: genre_id
|
||||
indexes:
|
||||
- fields:
|
||||
- song_id
|
||||
- genre_id
|
||||
unique: true
|
||||
timestamps: false
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/songgenre.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
task_id: task_create_model_user
|
||||
entity_id: model_user
|
||||
generated_at: '2025-12-18T15:16:50.217528'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: model
|
||||
definition:
|
||||
id: model_user
|
||||
name: User
|
||||
table_name: users
|
||||
description: Base user entity with authentication
|
||||
fields:
|
||||
- name: id
|
||||
type: uuid
|
||||
constraints:
|
||||
- primary_key
|
||||
- name: email
|
||||
type: string
|
||||
constraints:
|
||||
- unique
|
||||
- not_null
|
||||
- name: password_hash
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: name
|
||||
type: string
|
||||
constraints:
|
||||
- not_null
|
||||
- name: role
|
||||
type: enum
|
||||
values:
|
||||
- musician
|
||||
- listener
|
||||
- label
|
||||
constraints:
|
||||
- not_null
|
||||
- name: email_verified
|
||||
type: boolean
|
||||
default: false
|
||||
- name: avatar_url
|
||||
type: string
|
||||
constraints:
|
||||
- nullable
|
||||
- name: created_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
- name: updated_at
|
||||
type: timestamp
|
||||
constraints:
|
||||
- not_null
|
||||
relations:
|
||||
- type: has_one
|
||||
to: model_artist
|
||||
foreign_key: user_id
|
||||
condition: role = 'musician'
|
||||
- type: has_one
|
||||
to: model_label
|
||||
foreign_key: user_id
|
||||
condition: role = 'label'
|
||||
- type: has_many
|
||||
to: model_playlist
|
||||
foreign_key: user_id
|
||||
indexes:
|
||||
- fields:
|
||||
- email
|
||||
unique: true
|
||||
- fields:
|
||||
- role
|
||||
timestamps: true
|
||||
related:
|
||||
models: []
|
||||
apis: []
|
||||
components: []
|
||||
dependencies:
|
||||
entity_ids: []
|
||||
definitions: []
|
||||
files:
|
||||
to_create:
|
||||
- prisma/schema.prisma
|
||||
- app/models/user.ts
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Model defined in Prisma schema
|
||||
verification: Check prisma/schema.prisma
|
||||
- criterion: TypeScript types exported
|
||||
verification: Import type in test file
|
||||
- criterion: Relations properly configured
|
||||
verification: Check Prisma relations
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
task_id: task_create_page_album_detail
|
||||
entity_id: page_album_detail
|
||||
generated_at: '2025-12-18T15:16:50.297890'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_album_detail
|
||||
path: /album/:id
|
||||
title: Album
|
||||
description: Album detail with track list
|
||||
data_needs:
|
||||
- api_id: api_get_album
|
||||
purpose: Album details and songs
|
||||
on_load: true
|
||||
components:
|
||||
- component_album_header
|
||||
- component_track_list
|
||||
- component_song_card
|
||||
auth:
|
||||
required: false
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_get_album
|
||||
definition: &id003
|
||||
id: api_get_album
|
||||
method: GET
|
||||
path: /api/albums/:id
|
||||
description: Get album details with songs
|
||||
responses:
|
||||
- status: 200
|
||||
description: Album details
|
||||
schema:
|
||||
id: uuid
|
||||
title: string
|
||||
description: string
|
||||
cover_art_url: string
|
||||
release_date: string
|
||||
artist:
|
||||
id: uuid
|
||||
stage_name: string
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
duration: integer
|
||||
track_number: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_album
|
||||
- model_song
|
||||
- model_artist
|
||||
components:
|
||||
- id: component_track_list
|
||||
definition: &id001
|
||||
id: component_track_list
|
||||
name: TrackList
|
||||
description: List of songs with track numbers
|
||||
props:
|
||||
- name: songs
|
||||
type: array[Song]
|
||||
required: true
|
||||
- name: showTrackNumber
|
||||
type: boolean
|
||||
default: true
|
||||
- name: reorderable
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onReorder
|
||||
payload:
|
||||
songIds: array[string]
|
||||
uses_apis: []
|
||||
uses_components:
|
||||
- component_song_card
|
||||
- id: component_song_card
|
||||
definition: &id002
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_album_header
|
||||
definition: &id004
|
||||
id: component_album_header
|
||||
name: AlbumHeader
|
||||
description: Album detail header with cover art
|
||||
props:
|
||||
- name: album
|
||||
type: Album
|
||||
required: true
|
||||
- name: artist
|
||||
type: Artist
|
||||
required: true
|
||||
events:
|
||||
- name: onPlayAll
|
||||
payload: null
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_track_list
|
||||
- component_song_card
|
||||
- api_get_album
|
||||
- component_album_header
|
||||
definitions:
|
||||
- id: component_track_list
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id002
|
||||
- id: api_get_album
|
||||
type: api
|
||||
definition: *id003
|
||||
- id: component_album_header
|
||||
type: component
|
||||
definition: *id004
|
||||
files:
|
||||
to_create:
|
||||
- app/album/:id/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /album/:id
|
||||
verification: Navigate to /album/:id
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
task_id: task_create_page_artist_profile
|
||||
entity_id: page_artist_profile
|
||||
generated_at: '2025-12-18T15:16:50.295445'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_artist_profile
|
||||
path: /artist/:id
|
||||
title: Artist Profile
|
||||
description: Artist profile with songs and albums
|
||||
data_needs:
|
||||
- api_id: api_get_artist
|
||||
purpose: Artist details
|
||||
on_load: true
|
||||
- api_id: api_get_artist_songs
|
||||
purpose: Artist songs
|
||||
on_load: true
|
||||
- api_id: api_get_artist_albums
|
||||
purpose: Artist albums
|
||||
on_load: true
|
||||
components:
|
||||
- component_artist_header
|
||||
- component_song_card
|
||||
- component_album_card
|
||||
- component_social_links
|
||||
auth:
|
||||
required: false
|
||||
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_get_artist_songs
|
||||
definition: &id004
|
||||
id: api_get_artist_songs
|
||||
method: GET
|
||||
path: /api/artists/:id/songs
|
||||
description: Get all songs by artist
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of songs
|
||||
schema:
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
duration: integer
|
||||
cover_art_url: string
|
||||
play_count: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_artist
|
||||
- model_song
|
||||
- id: api_get_artist
|
||||
definition: &id005
|
||||
id: api_get_artist
|
||||
method: GET
|
||||
path: /api/artists/:id
|
||||
description: Get artist profile by ID
|
||||
responses:
|
||||
- status: 200
|
||||
description: Artist profile
|
||||
schema:
|
||||
id: uuid
|
||||
stage_name: string
|
||||
bio: string
|
||||
cover_image_url: string
|
||||
social_links: object
|
||||
verified: boolean
|
||||
- status: 404
|
||||
description: Artist not found
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_artist
|
||||
components:
|
||||
- id: component_artist_header
|
||||
definition: &id002
|
||||
id: component_artist_header
|
||||
name: ArtistHeader
|
||||
description: Artist profile header with cover image
|
||||
props:
|
||||
- name: artist
|
||||
type: Artist
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components:
|
||||
- component_social_links
|
||||
- id: component_album_card
|
||||
definition: &id003
|
||||
id: component_album_card
|
||||
name: AlbumCard
|
||||
description: Album display card
|
||||
props:
|
||||
- name: album
|
||||
type: Album
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
albumId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_song_card
|
||||
definition: &id006
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_social_links
|
||||
definition: &id007
|
||||
id: component_social_links
|
||||
name: SocialLinks
|
||||
description: Social media links display
|
||||
props:
|
||||
- name: links
|
||||
type: object
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- api_get_artist_albums
|
||||
- component_artist_header
|
||||
- component_album_card
|
||||
- api_get_artist_songs
|
||||
- api_get_artist
|
||||
- component_song_card
|
||||
- component_social_links
|
||||
definitions:
|
||||
- id: api_get_artist_albums
|
||||
type: api
|
||||
definition: *id001
|
||||
- id: component_artist_header
|
||||
type: component
|
||||
definition: *id002
|
||||
- id: component_album_card
|
||||
type: component
|
||||
definition: *id003
|
||||
- id: api_get_artist_songs
|
||||
type: api
|
||||
definition: *id004
|
||||
- id: api_get_artist
|
||||
type: api
|
||||
definition: *id005
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id006
|
||||
- id: component_social_links
|
||||
type: component
|
||||
definition: *id007
|
||||
files:
|
||||
to_create:
|
||||
- app/artist/:id/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /artist/:id
|
||||
verification: Navigate to /artist/:id
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
task_id: task_create_page_forgot_password
|
||||
entity_id: page_forgot_password
|
||||
generated_at: '2025-12-18T15:16:50.291947'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_forgot_password
|
||||
path: /forgot-password
|
||||
title: Forgot Password
|
||||
description: Password reset request page
|
||||
data_needs:
|
||||
- api_id: api_forgot_password
|
||||
purpose: Request password reset
|
||||
on_load: false
|
||||
components:
|
||||
- component_auth_form
|
||||
auth:
|
||||
required: false
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_forgot_password
|
||||
definition: &id002
|
||||
id: api_forgot_password
|
||||
method: POST
|
||||
path: /api/auth/forgot-password
|
||||
description: Request password reset email
|
||||
request_body:
|
||||
email: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Reset email sent
|
||||
schema:
|
||||
message: string
|
||||
- status: 404
|
||||
description: Email not found
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
components:
|
||||
- id: component_auth_form
|
||||
definition: &id001
|
||||
id: component_auth_form
|
||||
name: AuthForm
|
||||
description: Reusable authentication form
|
||||
props:
|
||||
- name: mode
|
||||
type: enum[login, register, forgot]
|
||||
required: true
|
||||
state:
|
||||
- name: email
|
||||
type: string
|
||||
- name: password
|
||||
type: string
|
||||
- name: name
|
||||
type: string
|
||||
- name: role
|
||||
type: string
|
||||
events:
|
||||
- name: onSubmit
|
||||
payload: object
|
||||
uses_apis:
|
||||
- api_login
|
||||
- api_register
|
||||
- api_forgot_password
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_auth_form
|
||||
- api_forgot_password
|
||||
definitions:
|
||||
- id: component_auth_form
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: api_forgot_password
|
||||
type: api
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/forgot-password/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /forgot-password
|
||||
verification: Navigate to /forgot-password
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
task_id: task_create_page_genre_browse
|
||||
entity_id: page_genre_browse
|
||||
generated_at: '2025-12-18T15:16:50.309059'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_genre_browse
|
||||
path: /genre/:slug
|
||||
title: Browse Genre
|
||||
description: Browse songs by genre
|
||||
data_needs:
|
||||
- api_id: api_get_songs_by_genre
|
||||
purpose: Load genre songs
|
||||
on_load: true
|
||||
components:
|
||||
- component_genre_header
|
||||
- component_song_card
|
||||
auth:
|
||||
required: false
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_get_songs_by_genre
|
||||
definition: &id002
|
||||
id: api_get_songs_by_genre
|
||||
method: GET
|
||||
path: /api/discover/genres/:slug
|
||||
description: Get songs by genre
|
||||
query_params:
|
||||
limit: integer
|
||||
offset: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of songs in genre
|
||||
schema:
|
||||
genre:
|
||||
name: string
|
||||
songs: array
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_genre
|
||||
- model_song
|
||||
components:
|
||||
- id: component_genre_header
|
||||
definition: &id001
|
||||
id: component_genre_header
|
||||
name: GenreHeader
|
||||
description: Genre browse page header
|
||||
props:
|
||||
- name: genre
|
||||
type: Genre
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_song_card
|
||||
definition: &id003
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_genre_header
|
||||
- api_get_songs_by_genre
|
||||
- component_song_card
|
||||
definitions:
|
||||
- id: component_genre_header
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: api_get_songs_by_genre
|
||||
type: api
|
||||
definition: *id002
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/genre/:slug/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /genre/:slug
|
||||
verification: Navigate to /genre/:slug
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
task_id: task_create_page_home
|
||||
entity_id: page_home
|
||||
generated_at: '2025-12-18T15:16:50.293122'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_home
|
||||
path: /
|
||||
title: Discover Music
|
||||
description: Main discovery feed
|
||||
data_needs:
|
||||
- api_id: api_get_trending_songs
|
||||
purpose: Show trending songs
|
||||
on_load: true
|
||||
- api_id: api_get_new_releases
|
||||
purpose: Show new releases
|
||||
on_load: true
|
||||
- api_id: api_get_genres
|
||||
purpose: Genre navigation
|
||||
on_load: true
|
||||
components:
|
||||
- component_song_card
|
||||
- component_genre_badge
|
||||
- component_section_header
|
||||
auth:
|
||||
required: false
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_get_new_releases
|
||||
definition: &id003
|
||||
id: api_get_new_releases
|
||||
method: GET
|
||||
path: /api/discover/new-releases
|
||||
description: Get recently released songs
|
||||
query_params:
|
||||
limit: integer
|
||||
offset: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of new releases
|
||||
schema:
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
release_date: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
- id: api_get_trending_songs
|
||||
definition: &id005
|
||||
id: api_get_trending_songs
|
||||
method: GET
|
||||
path: /api/discover/trending
|
||||
description: Get trending songs
|
||||
query_params:
|
||||
limit: integer
|
||||
offset: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of trending songs
|
||||
schema:
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
artist:
|
||||
stage_name: string
|
||||
play_count: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
- model_artist
|
||||
- id: api_get_genres
|
||||
definition: &id006
|
||||
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_genre_badge
|
||||
definition: &id001
|
||||
id: component_genre_badge
|
||||
name: GenreBadge
|
||||
description: Genre tag display
|
||||
props:
|
||||
- name: genre
|
||||
type: Genre
|
||||
required: true
|
||||
- name: clickable
|
||||
type: boolean
|
||||
default: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
genreSlug: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_section_header
|
||||
definition: &id002
|
||||
id: component_section_header
|
||||
name: SectionHeader
|
||||
description: Section title with optional action
|
||||
props:
|
||||
- name: title
|
||||
type: string
|
||||
required: true
|
||||
- name: actionLabel
|
||||
type: string
|
||||
required: false
|
||||
events:
|
||||
- name: onActionClick
|
||||
payload: null
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_song_card
|
||||
definition: &id004
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_genre_badge
|
||||
- component_section_header
|
||||
- api_get_new_releases
|
||||
- component_song_card
|
||||
- api_get_trending_songs
|
||||
- api_get_genres
|
||||
definitions:
|
||||
- id: component_genre_badge
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: component_section_header
|
||||
type: component
|
||||
definition: *id002
|
||||
- id: api_get_new_releases
|
||||
type: api
|
||||
definition: *id003
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id004
|
||||
- id: api_get_trending_songs
|
||||
type: api
|
||||
definition: *id005
|
||||
- id: api_get_genres
|
||||
type: api
|
||||
definition: *id006
|
||||
files:
|
||||
to_create:
|
||||
- app//page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /
|
||||
verification: Navigate to /
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
task_id: task_create_page_login
|
||||
entity_id: page_login
|
||||
generated_at: '2025-12-18T15:16:50.289459'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_login
|
||||
path: /login
|
||||
title: Login
|
||||
description: User login page
|
||||
data_needs:
|
||||
- api_id: api_login
|
||||
purpose: Authenticate user
|
||||
on_load: false
|
||||
components:
|
||||
- component_auth_form
|
||||
auth:
|
||||
required: false
|
||||
redirect_if_authenticated: /
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_login
|
||||
definition: &id002
|
||||
id: api_login
|
||||
method: POST
|
||||
path: /api/auth/login
|
||||
description: Login with email and password
|
||||
request_body:
|
||||
email: string
|
||||
password: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: Login successful
|
||||
schema:
|
||||
user:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
token: string
|
||||
- status: 401
|
||||
description: Invalid credentials
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
components:
|
||||
- id: component_auth_form
|
||||
definition: &id001
|
||||
id: component_auth_form
|
||||
name: AuthForm
|
||||
description: Reusable authentication form
|
||||
props:
|
||||
- name: mode
|
||||
type: enum[login, register, forgot]
|
||||
required: true
|
||||
state:
|
||||
- name: email
|
||||
type: string
|
||||
- name: password
|
||||
type: string
|
||||
- name: name
|
||||
type: string
|
||||
- name: role
|
||||
type: string
|
||||
events:
|
||||
- name: onSubmit
|
||||
payload: object
|
||||
uses_apis:
|
||||
- api_login
|
||||
- api_register
|
||||
- api_forgot_password
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_auth_form
|
||||
- api_login
|
||||
definitions:
|
||||
- id: component_auth_form
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: api_login
|
||||
type: api
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/login/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /login
|
||||
verification: Navigate to /login
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
task_id: task_create_page_playlist_detail
|
||||
entity_id: page_playlist_detail
|
||||
generated_at: '2025-12-18T15:16:50.303413'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_playlist_detail
|
||||
path: /playlist/:id
|
||||
title: Playlist
|
||||
description: Playlist detail with songs
|
||||
data_needs:
|
||||
- api_id: api_get_playlist
|
||||
purpose: Playlist details and songs
|
||||
on_load: true
|
||||
components:
|
||||
- component_playlist_header
|
||||
- component_track_list
|
||||
- component_song_card
|
||||
auth:
|
||||
required: false
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_get_playlist
|
||||
definition: &id003
|
||||
id: api_get_playlist
|
||||
method: GET
|
||||
path: /api/playlists/:id
|
||||
description: Get playlist details with songs
|
||||
responses:
|
||||
- status: 200
|
||||
description: Playlist details
|
||||
schema:
|
||||
id: uuid
|
||||
name: string
|
||||
description: string
|
||||
songs:
|
||||
- id: uuid
|
||||
title: string
|
||||
artist:
|
||||
stage_name: string
|
||||
position: integer
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
- model_playlist_song
|
||||
components:
|
||||
- id: component_playlist_header
|
||||
definition: &id001
|
||||
id: component_playlist_header
|
||||
name: PlaylistHeader
|
||||
description: Playlist header with cover and controls
|
||||
props:
|
||||
- name: playlist
|
||||
type: Playlist
|
||||
required: true
|
||||
- name: isOwner
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlayAll
|
||||
payload: null
|
||||
- name: onEdit
|
||||
payload: null
|
||||
- name: onDelete
|
||||
payload: null
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_track_list
|
||||
definition: &id002
|
||||
id: component_track_list
|
||||
name: TrackList
|
||||
description: List of songs with track numbers
|
||||
props:
|
||||
- name: songs
|
||||
type: array[Song]
|
||||
required: true
|
||||
- name: showTrackNumber
|
||||
type: boolean
|
||||
default: true
|
||||
- name: reorderable
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onReorder
|
||||
payload:
|
||||
songIds: array[string]
|
||||
uses_apis: []
|
||||
uses_components:
|
||||
- component_song_card
|
||||
- id: component_song_card
|
||||
definition: &id004
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_playlist_header
|
||||
- component_track_list
|
||||
- api_get_playlist
|
||||
- component_song_card
|
||||
definitions:
|
||||
- id: component_playlist_header
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: component_track_list
|
||||
type: component
|
||||
definition: *id002
|
||||
- id: api_get_playlist
|
||||
type: api
|
||||
definition: *id003
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id004
|
||||
files:
|
||||
to_create:
|
||||
- app/playlist/:id/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /playlist/:id
|
||||
verification: Navigate to /playlist/:id
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
task_id: task_create_page_playlists
|
||||
entity_id: page_playlists
|
||||
generated_at: '2025-12-18T15:16:50.302020'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_playlists
|
||||
path: /playlists
|
||||
title: My Playlists
|
||||
description: User's playlists
|
||||
data_needs:
|
||||
- api_id: api_get_user_playlists
|
||||
purpose: Load playlists
|
||||
on_load: true
|
||||
components:
|
||||
- component_playlist_card
|
||||
- component_create_playlist_modal
|
||||
auth:
|
||||
required: true
|
||||
redirect_if_unauthorized: /login
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_get_user_playlists
|
||||
definition: &id002
|
||||
id: api_get_user_playlists
|
||||
method: GET
|
||||
path: /api/playlists
|
||||
description: Get current user's playlists
|
||||
responses:
|
||||
- status: 200
|
||||
description: List of playlists
|
||||
schema:
|
||||
playlists:
|
||||
- id: uuid
|
||||
name: string
|
||||
cover_image_url: string
|
||||
song_count: integer
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_playlist
|
||||
components:
|
||||
- id: component_playlist_card
|
||||
definition: &id001
|
||||
id: component_playlist_card
|
||||
name: PlaylistCard
|
||||
description: Playlist preview card
|
||||
props:
|
||||
- name: playlist
|
||||
type: Playlist
|
||||
required: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
playlistId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_create_playlist_modal
|
||||
definition: &id003
|
||||
id: component_create_playlist_modal
|
||||
name: CreatePlaylistModal
|
||||
description: Modal for creating new playlist
|
||||
props:
|
||||
- name: isOpen
|
||||
type: boolean
|
||||
required: true
|
||||
state:
|
||||
- name: name
|
||||
type: string
|
||||
- name: description
|
||||
type: string
|
||||
- name: isPublic
|
||||
type: boolean
|
||||
events:
|
||||
- name: onCreate
|
||||
payload:
|
||||
name: string
|
||||
description: string
|
||||
isPublic: boolean
|
||||
- name: onClose
|
||||
payload: null
|
||||
uses_apis:
|
||||
- api_create_playlist
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_playlist_card
|
||||
- api_get_user_playlists
|
||||
- component_create_playlist_modal
|
||||
definitions:
|
||||
- id: component_playlist_card
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: api_get_user_playlists
|
||||
type: api
|
||||
definition: *id002
|
||||
- id: component_create_playlist_modal
|
||||
type: component
|
||||
definition: *id003
|
||||
files:
|
||||
to_create:
|
||||
- app/playlists/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /playlists
|
||||
verification: Navigate to /playlists
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
task_id: task_create_page_profile
|
||||
entity_id: page_profile
|
||||
generated_at: '2025-12-18T15:16:50.305216'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_profile
|
||||
path: /profile
|
||||
title: Profile Settings
|
||||
description: User profile settings
|
||||
data_needs:
|
||||
- api_id: api_get_current_user
|
||||
purpose: Load user data
|
||||
on_load: true
|
||||
- api_id: api_update_current_user
|
||||
purpose: Update profile
|
||||
on_load: false
|
||||
components:
|
||||
- component_profile_form
|
||||
- component_avatar_upload
|
||||
auth:
|
||||
required: true
|
||||
redirect_if_unauthorized: /login
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_update_current_user
|
||||
definition: &id001
|
||||
id: api_update_current_user
|
||||
method: PUT
|
||||
path: /api/users/me
|
||||
description: Update current user profile
|
||||
request_body:
|
||||
name: string
|
||||
avatar_url: string
|
||||
responses:
|
||||
- status: 200
|
||||
description: User updated
|
||||
schema:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
avatar_url: string
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_user
|
||||
- id: api_get_current_user
|
||||
definition: &id003
|
||||
id: api_get_current_user
|
||||
method: GET
|
||||
path: /api/users/me
|
||||
description: Get current user profile
|
||||
responses:
|
||||
- status: 200
|
||||
description: User profile
|
||||
schema:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
avatar_url: string
|
||||
auth:
|
||||
required: true
|
||||
depends_on_models:
|
||||
- model_user
|
||||
components:
|
||||
- id: component_profile_form
|
||||
definition: &id002
|
||||
id: component_profile_form
|
||||
name: ProfileForm
|
||||
description: User profile edit form
|
||||
props:
|
||||
- name: user
|
||||
type: User
|
||||
required: true
|
||||
state:
|
||||
- name: name
|
||||
type: string
|
||||
- name: avatarUrl
|
||||
type: string
|
||||
events:
|
||||
- name: onSave
|
||||
payload:
|
||||
name: string
|
||||
avatarUrl: string
|
||||
uses_apis:
|
||||
- api_update_current_user
|
||||
uses_components:
|
||||
- component_avatar_upload
|
||||
- id: component_avatar_upload
|
||||
definition: &id004
|
||||
id: component_avatar_upload
|
||||
name: AvatarUpload
|
||||
description: Avatar image upload component
|
||||
props:
|
||||
- name: currentAvatarUrl
|
||||
type: string
|
||||
required: false
|
||||
state:
|
||||
- name: file
|
||||
type: File
|
||||
- name: preview
|
||||
type: string
|
||||
events:
|
||||
- name: onUpload
|
||||
payload:
|
||||
file: File
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- api_update_current_user
|
||||
- component_profile_form
|
||||
- api_get_current_user
|
||||
- component_avatar_upload
|
||||
definitions:
|
||||
- id: api_update_current_user
|
||||
type: api
|
||||
definition: *id001
|
||||
- id: component_profile_form
|
||||
type: component
|
||||
definition: *id002
|
||||
- id: api_get_current_user
|
||||
type: api
|
||||
definition: *id003
|
||||
- id: component_avatar_upload
|
||||
type: component
|
||||
definition: *id004
|
||||
files:
|
||||
to_create:
|
||||
- app/profile/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /profile
|
||||
verification: Navigate to /profile
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
task_id: task_create_page_register
|
||||
entity_id: page_register
|
||||
generated_at: '2025-12-18T15:16:50.290659'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_register
|
||||
path: /register
|
||||
title: Register
|
||||
description: User registration page
|
||||
data_needs:
|
||||
- api_id: api_register
|
||||
purpose: Create new account
|
||||
on_load: false
|
||||
components:
|
||||
- component_auth_form
|
||||
auth:
|
||||
required: false
|
||||
redirect_if_authenticated: /
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_register
|
||||
definition: &id002
|
||||
id: api_register
|
||||
method: POST
|
||||
path: /api/auth/register
|
||||
description: Register new user account
|
||||
request_body:
|
||||
email: string
|
||||
password: string
|
||||
name: string
|
||||
role: enum[musician, listener, label]
|
||||
responses:
|
||||
- status: 201
|
||||
description: User created successfully
|
||||
schema:
|
||||
user:
|
||||
id: uuid
|
||||
email: string
|
||||
name: string
|
||||
role: string
|
||||
token: string
|
||||
- status: 400
|
||||
description: Validation error
|
||||
schema:
|
||||
error: string
|
||||
- status: 409
|
||||
description: Email already exists
|
||||
schema:
|
||||
error: string
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_user
|
||||
components:
|
||||
- id: component_auth_form
|
||||
definition: &id001
|
||||
id: component_auth_form
|
||||
name: AuthForm
|
||||
description: Reusable authentication form
|
||||
props:
|
||||
- name: mode
|
||||
type: enum[login, register, forgot]
|
||||
required: true
|
||||
state:
|
||||
- name: email
|
||||
type: string
|
||||
- name: password
|
||||
type: string
|
||||
- name: name
|
||||
type: string
|
||||
- name: role
|
||||
type: string
|
||||
events:
|
||||
- name: onSubmit
|
||||
payload: object
|
||||
uses_apis:
|
||||
- api_login
|
||||
- api_register
|
||||
- api_forgot_password
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_auth_form
|
||||
- api_register
|
||||
definitions:
|
||||
- id: component_auth_form
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: api_register
|
||||
type: api
|
||||
definition: *id002
|
||||
files:
|
||||
to_create:
|
||||
- app/register/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /register
|
||||
verification: Navigate to /register
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
task_id: task_create_page_search
|
||||
entity_id: page_search
|
||||
generated_at: '2025-12-18T15:16:50.306942'
|
||||
workflow_version: v001
|
||||
target:
|
||||
type: page
|
||||
definition:
|
||||
id: page_search
|
||||
path: /search
|
||||
title: Search
|
||||
description: Search results page
|
||||
data_needs:
|
||||
- api_id: api_search
|
||||
purpose: Search songs, artists, albums
|
||||
on_load: false
|
||||
components:
|
||||
- component_search_bar
|
||||
- component_search_results
|
||||
- component_song_card
|
||||
- component_artist_card
|
||||
- component_album_card
|
||||
auth:
|
||||
required: false
|
||||
related:
|
||||
models: []
|
||||
apis:
|
||||
- id: api_search
|
||||
definition: &id005
|
||||
id: api_search
|
||||
method: GET
|
||||
path: /api/search
|
||||
description: Search songs, artists, and albums
|
||||
query_params:
|
||||
q: string
|
||||
type: enum[song, artist, album, all]
|
||||
limit: integer
|
||||
responses:
|
||||
- status: 200
|
||||
description: Search results
|
||||
schema:
|
||||
songs: array
|
||||
artists: array
|
||||
albums: array
|
||||
auth:
|
||||
required: false
|
||||
depends_on_models:
|
||||
- model_song
|
||||
- model_artist
|
||||
- model_album
|
||||
components:
|
||||
- id: component_search_results
|
||||
definition: &id001
|
||||
id: component_search_results
|
||||
name: SearchResults
|
||||
description: Search results with filters
|
||||
props:
|
||||
- name: results
|
||||
type: object
|
||||
required: true
|
||||
events: []
|
||||
uses_apis: []
|
||||
uses_components:
|
||||
- component_song_card
|
||||
- component_artist_card
|
||||
- component_album_card
|
||||
- id: component_album_card
|
||||
definition: &id002
|
||||
id: component_album_card
|
||||
name: AlbumCard
|
||||
description: Album display card
|
||||
props:
|
||||
- name: album
|
||||
type: Album
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
albumId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_artist_card
|
||||
definition: &id003
|
||||
id: component_artist_card
|
||||
name: ArtistCard
|
||||
description: Artist preview card
|
||||
props:
|
||||
- name: artist
|
||||
type: Artist
|
||||
required: true
|
||||
events:
|
||||
- name: onClick
|
||||
payload:
|
||||
artistId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
- id: component_search_bar
|
||||
definition: &id004
|
||||
id: component_search_bar
|
||||
name: SearchBar
|
||||
description: Search input with autocomplete
|
||||
props:
|
||||
- name: placeholder
|
||||
type: string
|
||||
default: Search songs, artists, albums...
|
||||
state:
|
||||
- name: query
|
||||
type: string
|
||||
events:
|
||||
- name: onSearch
|
||||
payload:
|
||||
query: string
|
||||
uses_apis:
|
||||
- api_search
|
||||
uses_components: []
|
||||
- id: component_song_card
|
||||
definition: &id006
|
||||
id: component_song_card
|
||||
name: SongCard
|
||||
description: Song display card with play button
|
||||
props:
|
||||
- name: song
|
||||
type: Song
|
||||
required: true
|
||||
- name: showArtist
|
||||
type: boolean
|
||||
default: true
|
||||
- name: showAlbum
|
||||
type: boolean
|
||||
default: false
|
||||
events:
|
||||
- name: onPlay
|
||||
payload:
|
||||
songId: string
|
||||
- name: onAddToPlaylist
|
||||
payload:
|
||||
songId: string
|
||||
uses_apis: []
|
||||
uses_components: []
|
||||
dependencies:
|
||||
entity_ids:
|
||||
- component_search_results
|
||||
- component_album_card
|
||||
- component_artist_card
|
||||
- component_search_bar
|
||||
- api_search
|
||||
- component_song_card
|
||||
definitions:
|
||||
- id: component_search_results
|
||||
type: component
|
||||
definition: *id001
|
||||
- id: component_album_card
|
||||
type: component
|
||||
definition: *id002
|
||||
- id: component_artist_card
|
||||
type: component
|
||||
definition: *id003
|
||||
- id: component_search_bar
|
||||
type: component
|
||||
definition: *id004
|
||||
- id: api_search
|
||||
type: api
|
||||
definition: *id005
|
||||
- id: component_song_card
|
||||
type: component
|
||||
definition: *id006
|
||||
files:
|
||||
to_create:
|
||||
- app/search/page.tsx
|
||||
reference: []
|
||||
acceptance:
|
||||
- criterion: Page renders at /search
|
||||
verification: Navigate to /search
|
||||
- criterion: Data fetching works
|
||||
verification: Check network tab
|
||||
- criterion: Components render correctly
|
||||
verification: Visual inspection
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,149 @@
|
|||
# Implementation Checklist
|
||||
|
||||
Generated: 2025-12-18T15:56:52
|
||||
|
||||
## Components
|
||||
|
||||
- [❌] AudioPlayer (`component_audio_player`)
|
||||
- [❌] prop: `currentSong`: Song
|
||||
- [❌] prop: `queue`: array[Song]
|
||||
- [❌] prop: `autoplay`: boolean
|
||||
- [⚠️] event: `onPlay`
|
||||
- [⚠️] event: `onPause`
|
||||
- [⚠️] event: `onSeek`
|
||||
- [⚠️] event: `onVolumeChange`
|
||||
- [⚠️] event: `onNext`
|
||||
- [⚠️] event: `onPrevious`
|
||||
- [⚠️] event: `onShuffle`
|
||||
- [⚠️] event: `onRepeat`
|
||||
- [❌] PlayerControls (`component_player_controls`)
|
||||
- [✅] prop: `isPlaying`: boolean
|
||||
- [❌] prop: `currentTime`: number
|
||||
- [❌] prop: `duration`: number
|
||||
- [⚠️] event: `onPlay`
|
||||
- [⚠️] event: `onPause`
|
||||
- [⚠️] event: `onSeek`
|
||||
- [❌] SongCard (`component_song_card`)
|
||||
- [❌] prop: `song`: Song
|
||||
- [❌] prop: `showArtist`: boolean
|
||||
- [❌] prop: `showAlbum`: boolean
|
||||
- [✅] event: `onPlay`
|
||||
- [⚠️] event: `onAddToPlaylist`
|
||||
- [❌] AlbumCard (`component_album_card`)
|
||||
- [❌] prop: `album`: Album
|
||||
- [❌] prop: `showArtist`: boolean
|
||||
- [✅] event: `onClick`
|
||||
- [❌] ArtistCard (`component_artist_card`)
|
||||
- [❌] prop: `artist`: Artist
|
||||
- [✅] event: `onClick`
|
||||
- [❌] PlaylistCard (`component_playlist_card`)
|
||||
- [❌] prop: `playlist`: Playlist
|
||||
- [✅] event: `onClick`
|
||||
- [❌] UploadForm (`component_upload_form`)
|
||||
- [✅] prop: `albums`: array[Album]
|
||||
- [❌] prop: `genres`: array[Genre]
|
||||
- [⚠️] event: `onUpload`
|
||||
- [⚠️] event: `onCancel`
|
||||
- [❌] WaveformDisplay (`component_waveform_display`)
|
||||
- [❌] prop: `audioUrl`: string
|
||||
- [❌] prop: `waveformData`: array[number]
|
||||
- [✅] prop: `currentTime`: number
|
||||
- [✅] event: `onSeek`
|
||||
- [❌] GenreBadge (`component_genre_badge`)
|
||||
- [❌] prop: `genre`: Genre
|
||||
- [❌] prop: `clickable`: boolean
|
||||
- [✅] event: `onClick`
|
||||
- [❌] TrackList (`component_track_list`)
|
||||
- [❌] prop: `songs`: array[Song]
|
||||
- [❌] prop: `showTrackNumber`: boolean
|
||||
- [❌] prop: `reorderable`: boolean
|
||||
- [⚠️] event: `onPlay`
|
||||
- [⚠️] event: `onReorder`
|
||||
- [❌] ArtistHeader (`component_artist_header`)
|
||||
- [❌] prop: `artist`: Artist
|
||||
- [❌] AlbumHeader (`component_album_header`)
|
||||
- [❌] prop: `album`: Album
|
||||
- [❌] prop: `artist`: Artist
|
||||
- [✅] event: `onPlayAll`
|
||||
- [❌] PlaylistHeader (`component_playlist_header`)
|
||||
- [❌] prop: `playlist`: Playlist
|
||||
- [✅] prop: `isOwner`: boolean
|
||||
- [✅] event: `onPlayAll`
|
||||
- [✅] event: `onEdit`
|
||||
- [✅] event: `onDelete`
|
||||
- [✅] SocialLinks (`component_social_links`)
|
||||
- [✅] prop: `links`: object
|
||||
- [✅] AuthForm (`component_auth_form`)
|
||||
- [✅] prop: `mode`: enum[login, register, forgot]
|
||||
- [✅] event: `onSubmit`
|
||||
- [✅] SearchBar (`component_search_bar`)
|
||||
- [✅] prop: `placeholder`: string
|
||||
- [✅] event: `onSearch`
|
||||
- [❌] SearchResults (`component_search_results`)
|
||||
- [❌] prop: `results`: object
|
||||
- [⚠️] CreatePlaylistModal (`component_create_playlist_modal`)
|
||||
- [✅] prop: `isOpen`: boolean
|
||||
- [⚠️] event: `onCreate`
|
||||
- [✅] event: `onClose`
|
||||
- [❌] ProfileForm (`component_profile_form`)
|
||||
- [❌] prop: `user`: User
|
||||
- [⚠️] event: `onSave`
|
||||
- [✅] AvatarUpload (`component_avatar_upload`)
|
||||
- [✅] prop: `currentAvatarUrl`: string
|
||||
- [✅] event: `onUpload`
|
||||
- [❌] SectionHeader (`component_section_header`)
|
||||
- [✅] prop: `title`: string
|
||||
- [❌] prop: `actionLabel`: string
|
||||
- [⚠️] event: `onActionClick`
|
||||
- [❌] GenreHeader (`component_genre_header`)
|
||||
- [❌] prop: `genre`: Genre
|
||||
|
||||
## API Endpoints
|
||||
|
||||
- [✅] `POST` /api/auth/register
|
||||
- [✅] `POST` /api/auth/login
|
||||
- [✅] `POST` /api/auth/forgot-password
|
||||
- [✅] `POST` /api/auth/reset-password
|
||||
- [✅] `GET` /api/users/me
|
||||
- [✅] `PUT` /api/users/me
|
||||
- [✅] `POST` /api/artists
|
||||
- [✅] `GET` /api/artists/:id
|
||||
- [✅] `PUT` /api/artists/:id
|
||||
- [✅] `GET` /api/artists/:id/songs
|
||||
- [✅] `GET` /api/artists/:id/albums
|
||||
- [✅] `POST` /api/songs/upload
|
||||
- [✅] `GET` /api/songs/:id
|
||||
- [✅] `PUT` /api/songs/:id
|
||||
- [✅] `DELETE` /api/songs/:id
|
||||
- [✅] `POST` /api/songs/:id/play
|
||||
- [✅] `POST` /api/albums
|
||||
- [✅] `GET` /api/albums/:id
|
||||
- [✅] `PUT` /api/albums/:id
|
||||
- [✅] `DELETE` /api/albums/:id
|
||||
- [✅] `POST` /api/playlists
|
||||
- [✅] `GET` /api/playlists
|
||||
- [✅] `GET` /api/playlists/:id
|
||||
- [✅] `PUT` /api/playlists/:id
|
||||
- [✅] `DELETE` /api/playlists/:id
|
||||
- [✅] `POST` /api/playlists/:id/songs
|
||||
- [⚠️] `DELETE` /api/playlists/:playlistId/songs/:songId
|
||||
- [✅] `PUT` /api/playlists/:id/reorder
|
||||
- [✅] `GET` /api/discover/trending
|
||||
- [✅] `GET` /api/discover/new-releases
|
||||
- [✅] `GET` /api/discover/genres
|
||||
- [✅] `GET` /api/discover/genres/:slug
|
||||
- [✅] `GET` /api/search
|
||||
- [✅] `POST` /api/labels
|
||||
- [✅] `GET` /api/labels/:id/artists
|
||||
|
||||
## Data Models
|
||||
|
||||
- [⚠️] User (`model_user`)
|
||||
- [⚠️] Artist (`model_artist`)
|
||||
- [⚠️] Label (`model_label`)
|
||||
- [⚠️] Genre (`model_genre`)
|
||||
- [⚠️] Album (`model_album`)
|
||||
- [⚠️] Song (`model_song`)
|
||||
- [⚠️] SongGenre (`model_song_genre`)
|
||||
- [⚠️] Playlist (`model_playlist`)
|
||||
- [⚠️] PlaylistSong (`model_playlist_song`)
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
feature: a platform where musician can upload their songs
|
||||
gathered_at: 2025-12-18T14:55:00
|
||||
questions_asked: 8
|
||||
mode: auto
|
||||
|
||||
requirements:
|
||||
user_types:
|
||||
- musician: "Upload and manage music, create artist profile"
|
||||
- listener: "Discover and play music, create playlists"
|
||||
- label: "Manage artist roster (minimal for MVP)"
|
||||
|
||||
authentication:
|
||||
method: email_password
|
||||
features:
|
||||
- registration
|
||||
- login
|
||||
- password_reset
|
||||
- email_verification
|
||||
|
||||
audio:
|
||||
supported_formats:
|
||||
- mp3
|
||||
- wav
|
||||
max_file_size: 50MB
|
||||
storage: cloud
|
||||
|
||||
musician_profile:
|
||||
fields:
|
||||
- name
|
||||
- bio
|
||||
- avatar
|
||||
- cover_image
|
||||
- social_links
|
||||
features:
|
||||
- song_list
|
||||
- album_organization
|
||||
- ep_organization
|
||||
|
||||
music_organization:
|
||||
entities:
|
||||
- song: "Individual track with metadata"
|
||||
- album: "Collection of songs"
|
||||
- genre: "Category for discovery"
|
||||
metadata:
|
||||
- title
|
||||
- duration
|
||||
- release_date
|
||||
- cover_art
|
||||
- genre_tags
|
||||
|
||||
player_features:
|
||||
basic:
|
||||
- play
|
||||
- pause
|
||||
- seek
|
||||
- volume
|
||||
advanced:
|
||||
- queue
|
||||
- shuffle
|
||||
- repeat
|
||||
- waveform_display
|
||||
playlist:
|
||||
- create
|
||||
- edit
|
||||
- delete
|
||||
- reorder
|
||||
|
||||
discovery:
|
||||
search:
|
||||
- by_song_title
|
||||
- by_artist_name
|
||||
- by_album
|
||||
browse:
|
||||
- by_genre
|
||||
- trending
|
||||
- new_releases
|
||||
- featured
|
||||
|
||||
label_features_mvp:
|
||||
- label_profile
|
||||
- artist_roster_view
|
||||
|
||||
acceptance_criteria:
|
||||
- Musician can register and create artist profile
|
||||
- Musician can upload MP3/WAV songs with metadata
|
||||
- Musician can organize songs into albums
|
||||
- Listener can search and browse music
|
||||
- Listener can play songs with full player controls
|
||||
- Listener can create and manage playlists
|
||||
- Label can view their artist roster
|
||||
- All users can authenticate via email/password
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
version: v001
|
||||
feature: a platform where musician can upload their songs
|
||||
session_id: workflow_20251218_145233
|
||||
parent_version: None
|
||||
status: completed
|
||||
started_at: 2025-12-18 14:52:33.788070
|
||||
completed_at: None
|
||||
current_phase: IMPLEMENTING
|
||||
approvals:
|
||||
design:
|
||||
status: approved
|
||||
approved_by: user
|
||||
approved_at: '2025-12-18T15:19:49.601659'
|
||||
rejection_reason: None
|
||||
implementation:
|
||||
status: pending
|
||||
approved_by: None
|
||||
approved_at: None
|
||||
rejection_reason: None
|
||||
task_sessions: []
|
||||
summary:
|
||||
total_tasks: 0
|
||||
tasks_completed: 0
|
||||
entities_created: 0
|
||||
entities_updated: 0
|
||||
entities_deleted: 0
|
||||
files_created: 0
|
||||
files_updated: 0
|
||||
files_deleted: 0
|
||||
updated_at: '2025-12-18T15:19:56.804374'
|
||||
last_validation:
|
||||
status: failed
|
||||
timestamp: '2025-12-18T15:56:52.706556'
|
||||
checklist_path: .workflow/versions/v001/implementation_checklist.md
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
version: v001
|
||||
feature: a platform where musician can upload their songs
|
||||
session_id: workflow_20251218_145233
|
||||
parent_version: None
|
||||
status: completed
|
||||
started_at: 2025-12-18 14:52:33.788070
|
||||
completed_at: None
|
||||
current_phase: DESIGN_APPROVED
|
||||
approvals:
|
||||
design:
|
||||
status: approved
|
||||
approved_by: user
|
||||
approved_at: '2025-12-18T15:19:49.601659'
|
||||
rejection_reason: None
|
||||
implementation:
|
||||
status: pending
|
||||
approved_by: None
|
||||
approved_at: None
|
||||
rejection_reason: None
|
||||
task_sessions: []
|
||||
summary:
|
||||
total_tasks: 0
|
||||
tasks_completed: 0
|
||||
entities_created: 0
|
||||
entities_updated: 0
|
||||
entities_deleted: 0
|
||||
files_created: 0
|
||||
files_updated: 0
|
||||
files_deleted: 0
|
||||
updated_at: '2025-12-18T15:19:49.602581'
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"project": {
|
||||
"name": "sonic-cloud",
|
||||
"version": "0.1.0",
|
||||
"created_at": "2025-12-18T14:32:39.275839",
|
||||
"description": "sonic-cloud - A guardrailed project"
|
||||
},
|
||||
"state": {
|
||||
"current_phase": "DESIGN_PHASE",
|
||||
"approval_status": {
|
||||
"manifest_approved": false,
|
||||
"approved_by": null,
|
||||
"approved_at": null
|
||||
},
|
||||
"revision_history": [
|
||||
{
|
||||
"action": "PROJECT_INITIALIZED",
|
||||
"timestamp": "2025-12-18T14:32:39.275844",
|
||||
"details": "Project sonic-cloud created"
|
||||
}
|
||||
]
|
||||
},
|
||||
"entities": {
|
||||
"pages": [],
|
||||
"components": [],
|
||||
"api_endpoints": [],
|
||||
"database_tables": []
|
||||
},
|
||||
"dependencies": {
|
||||
"component_to_page": {},
|
||||
"api_to_component": {},
|
||||
"table_to_api": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
id: task_create_api_add_song_to_playlist
|
||||
type: create
|
||||
title: Create api_add_song_to_playlist
|
||||
agent: backend
|
||||
entity_id: api_add_song_to_playlist
|
||||
entity_ids:
|
||||
- api_add_song_to_playlist
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_playlist
|
||||
- task_create_model_playlist_song
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_add_song_to_playlist.yml
|
||||
created_at: '2025-12-18T15:16:50.336026'
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
id: task_create_api_create_album
|
||||
type: create
|
||||
title: Create api_create_album
|
||||
agent: backend
|
||||
entity_id: api_create_album
|
||||
entity_ids:
|
||||
- api_create_album
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_artist
|
||||
- task_create_model_album
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_create_album.yml
|
||||
created_at: '2025-12-18T15:16:50.336335'
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
id: task_create_api_create_artist_profile
|
||||
type: create
|
||||
title: Create api_create_artist_profile
|
||||
agent: backend
|
||||
entity_id: api_create_artist_profile
|
||||
entity_ids:
|
||||
- api_create_artist_profile
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_artist
|
||||
- task_create_model_user
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_create_artist_profile.yml
|
||||
created_at: '2025-12-18T15:16:50.336630'
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
id: task_create_api_create_label_profile
|
||||
type: create
|
||||
title: Create api_create_label_profile
|
||||
agent: backend
|
||||
entity_id: api_create_label_profile
|
||||
entity_ids:
|
||||
- api_create_label_profile
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_label
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_create_label_profile.yml
|
||||
created_at: '2025-12-18T15:16:50.336941'
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
id: task_create_api_create_playlist
|
||||
type: create
|
||||
title: Create api_create_playlist
|
||||
agent: backend
|
||||
entity_id: api_create_playlist
|
||||
entity_ids:
|
||||
- api_create_playlist
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_playlist
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_create_playlist.yml
|
||||
created_at: '2025-12-18T15:16:50.337236'
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
id: task_create_api_delete_album
|
||||
type: create
|
||||
title: Create api_delete_album
|
||||
agent: backend
|
||||
entity_id: api_delete_album
|
||||
entity_ids:
|
||||
- api_delete_album
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_album
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_delete_album.yml
|
||||
created_at: '2025-12-18T15:16:50.337534'
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
id: task_create_api_delete_playlist
|
||||
type: create
|
||||
title: Create api_delete_playlist
|
||||
agent: backend
|
||||
entity_id: api_delete_playlist
|
||||
entity_ids:
|
||||
- api_delete_playlist
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_playlist
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_delete_playlist.yml
|
||||
created_at: '2025-12-18T15:16:50.337825'
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
id: task_create_api_delete_song
|
||||
type: create
|
||||
title: Create api_delete_song
|
||||
agent: backend
|
||||
entity_id: api_delete_song
|
||||
entity_ids:
|
||||
- api_delete_song
|
||||
status: pending
|
||||
layer: 2
|
||||
parallel_group: layer_2
|
||||
complexity: medium
|
||||
dependencies:
|
||||
- task_create_model_song
|
||||
context:
|
||||
design_version: 1
|
||||
workflow_version: v001
|
||||
context_snapshot_path: .workflow/versions/v001/contexts/api_delete_song.yml
|
||||
created_at: '2025-12-18T15:16:50.338113'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue