workflow_version: "v004" feature: "add share music system" created_at: "2025-12-18T18:07:00" status: draft revision: 1 data_models: - id: model_share name: Share table_name: shares description: Tracks shared content links with analytics primary_key: id fields: - name: id type: String constraints: [primary_key, cuid] description: Unique identifier for the share - name: type type: ShareType constraints: [required] description: Type of content being shared (SONG, PLAYLIST, ALBUM) - name: targetId type: String constraints: [required] description: ID of the shared content (references songs/playlists/albums) - name: token type: String constraints: [required, unique] description: Unique URL-safe token for share links - name: userId type: String constraints: [optional] description: User who created the share (null for anonymous shares) - name: platform type: String constraints: [optional] description: Platform where content was shared to (twitter, facebook, etc) - name: clickCount type: Int default: 0 description: Number of times the share link was clicked - name: createdAt type: DateTime default: now() description: Timestamp when the share was created relations: [] indexes: - fields: [token] unique: true description: Fast lookup by share token - fields: [targetId, type] description: Fast lookup of shares for specific content timestamps: false validations: - field: token rule: minLength(8) message: Token must be at least 8 characters - field: type rule: enum(SONG, PLAYLIST, ALBUM) message: Type must be SONG, PLAYLIST, or ALBUM api_endpoints: - id: api_create_song_share method: POST path: /api/share/song/[id] description: Generate share link for a song auth: required: false description: No authentication required to share content request_params: - name: id type: string location: path required: true description: Song ID to generate share link for request_body: - name: platform type: string required: false description: Platform being shared to (twitter, facebook, etc) responses: - status: 200 description: Share link created successfully schema: shareUrl: string token: string type: string - status: 404 description: Song not found schema: error: string business_logic: - Verify song exists and is public - Generate unique 10-character alphanumeric token - Create Share record with type=SONG - Return full share URL (https://domain.com/s/[token]) depends_on_models: [model_share] - id: api_create_playlist_share method: POST path: /api/share/playlist/[id] description: Generate share link for a playlist auth: required: false request_params: - name: id type: string location: path required: true description: Playlist ID to generate share link for request_body: - name: platform type: string required: false description: Platform being shared to responses: - status: 200 description: Share link created successfully schema: shareUrl: string token: string type: string - status: 404 description: Playlist not found schema: error: string business_logic: - Verify playlist exists and is public - Generate unique token - Create Share record with type=PLAYLIST - Return full share URL depends_on_models: [model_share] - id: api_create_album_share method: POST path: /api/share/album/[id] description: Generate share link for an album auth: required: false request_params: - name: id type: string location: path required: true description: Album ID to generate share link for request_body: - name: platform type: string required: false description: Platform being shared to responses: - status: 200 description: Share link created successfully schema: shareUrl: string token: string type: string - status: 404 description: Album not found schema: error: string business_logic: - Verify album exists - Generate unique token - Create Share record with type=ALBUM - Return full share URL depends_on_models: [model_share] - id: api_resolve_share method: GET path: /api/share/[token] description: Resolve share token and get content details auth: required: false request_params: - name: token type: string location: path required: true description: Share token to resolve responses: - status: 200 description: Share resolved successfully schema: type: string targetId: string content: object shareUrl: string - status: 404 description: Share not found or content no longer available schema: error: string business_logic: - Lookup Share record by token - Fetch associated content based on type (Song/Playlist/Album) - Include artist information for songs/albums - Include song list for playlists - Verify content is still public and available - Return content details for display depends_on_models: [model_share] - id: api_track_share_click method: POST path: /api/share/[token]/click description: Increment share click count for analytics auth: required: false request_params: - name: token type: string location: path required: true description: Share token to track click for request_body: [] responses: - status: 200 description: Click tracked successfully schema: success: boolean clickCount: integer - status: 404 description: Share not found schema: error: string business_logic: - Find Share record by token - Increment clickCount by 1 - Return new click count depends_on_models: [model_share] pages: - id: page_share path: /s/[token] name: SharePage description: Public landing page for shared music content layout: minimal auth: required: false description: Publicly accessible share page data_needs: - api_id: api_resolve_share purpose: Load shared content details on_load: true description: Fetch content details when page loads - api_id: api_track_share_click purpose: Track analytics on_load: true description: Track that user clicked on share link components: - component_share_content_display seo: dynamic_title: true description: Dynamic based on shared content og_image: true twitter_card: true ui_states: - state: loading description: Fetching shared content - state: content_loaded description: Display shared content with CTA - state: not_found description: Share token invalid or content no longer available - state: private_content description: Content is now private components: - id: component_share_button name: ShareButton description: Button component to trigger share modal file_path: components/ShareButton.tsx props: - name: type type: "'song' | 'playlist' | 'album'" required: true description: Type of content to share - name: targetId type: string required: true description: ID of the content to share - name: title type: string required: true description: Title to display in share modal - name: className type: string required: false description: Additional CSS classes state: - name: isModalOpen type: boolean description: Controls share modal visibility - name: shareUrl type: string | null description: Generated share URL after creation - name: isLoading type: boolean description: Share link generation in progress events: - name: onShare payload: "{ shareUrl: string, token: string }" description: Fired when share link is successfully generated uses_components: [component_share_modal] uses_apis: [api_create_song_share, api_create_playlist_share, api_create_album_share] styling: - Accessible button with share icon - Loading state during share generation - Error state if share creation fails - id: component_share_modal name: ShareModal description: Modal displaying share options and social buttons file_path: components/ShareModal.tsx props: - name: isOpen type: boolean required: true description: Controls modal visibility - name: onClose type: "() => void" required: true description: Callback to close modal - name: shareUrl type: string required: true description: The share URL to display and copy - name: title type: string required: true description: Title of content being shared - name: type type: "'song' | 'playlist' | 'album'" required: true description: Type of content for display context state: - name: copied type: boolean description: Shows copied confirmation after clipboard copy events: - name: onCopy payload: null description: Fired when user copies link to clipboard uses_components: [component_social_share_buttons] uses_apis: [] styling: - Centered modal with backdrop - Copy to clipboard button with icon - Success message after copy - Close button - Responsive design for mobile - id: component_social_share_buttons name: SocialShareButtons description: Social media share buttons for Twitter and Facebook file_path: components/SocialShareButtons.tsx props: - name: url type: string required: true description: URL to share - name: title type: string required: true description: Title/text to include in share - name: type type: "'song' | 'playlist' | 'album'" required: false description: Type of content for customized share text events: - name: onPlatformShare payload: "{ platform: string }" description: Fired when user clicks a social share button uses_components: [] uses_apis: [] business_logic: - Twitter button opens Twitter intent URL with pre-filled text - Facebook button opens Facebook sharer dialog - Generate share text based on content type - URL encode parameters properly styling: - Buttons with platform brand colors - Platform icons (Twitter bird, Facebook f) - Hover and focus states - Responsive layout (stack on mobile) - id: component_share_content_display name: SharedContentDisplay description: Displays shared song/playlist/album with call-to-action file_path: components/SharedContentDisplay.tsx props: - name: type type: "'song' | 'playlist' | 'album'" required: true description: Type of shared content - name: content type: object required: true description: Content data (song/playlist/album with artist info) state: - name: isPlaying type: boolean description: Audio playback state (for songs) uses_components: [] uses_apis: [api_track_share_click] business_logic: - Display cover art, title, artist name - For songs: show waveform, duration, play button - For playlists: show track count, curator - For albums: show release date, track count - 'Call-to-action button: "Listen on Sonic Cloud" or "Sign up to create playlists"' styling: - Large cover art - Prominent title and artist - Clean, minimal design focused on content - Branded CTA button - Preview player for songs (if implemented) utils: - id: util_generate_share_token name: generateShareToken description: Generate unique URL-safe token for share links file_path: lib/share.ts function_signature: "() => string" implementation: - Generate random 10-character alphanumeric string - Use crypto-safe random generation - Verify uniqueness against existing tokens - Return URL-safe token (no special characters) - id: util_build_share_url name: buildShareUrl description: Build full share URL from token file_path: lib/share.ts function_signature: "(token: string) => string" implementation: - Get base URL from environment or request - Construct URL: https://domain.com/s/[token] - Return full shareable URL - id: util_build_social_share_urls name: buildSocialShareUrls description: Generate platform-specific share URLs file_path: lib/share.ts function_signature: "(url: string, title: string, type: string) => { twitter: string, facebook: string }" implementation: - Twitter: https://twitter.com/intent/tweet?text=[title]&url=[url] - Facebook: https://www.facebook.com/sharer/sharer.php?u=[url] - URL encode all parameters - Customize share text based on content type types: - id: type_share_type name: ShareType description: Enum for share content types file_path: types/share.ts definition: "enum ShareType { SONG = 'SONG', PLAYLIST = 'PLAYLIST', ALBUM = 'ALBUM' }" - id: type_share name: Share description: TypeScript type for Share model file_path: types/share.ts definition: | interface Share { id: string; type: ShareType; targetId: string; token: string; userId: string | null; platform: string | null; clickCount: number; createdAt: Date; } - id: type_share_response name: ShareResponse description: API response for share creation file_path: types/share.ts definition: | interface ShareResponse { shareUrl: string; token: string; type: ShareType; } - id: type_resolved_share name: ResolvedShare description: API response for share resolution file_path: types/share.ts definition: | interface ResolvedShare { type: ShareType; targetId: string; content: Song | Playlist | Album; shareUrl: string; } architecture: layer_1_data: - Add Share model to Prisma schema - Create ShareType enum in Prisma - Add optional userId relation to User model - Migration: create shares table with indexes layer_2_api: - POST /api/share/song/[id] - Create song share - POST /api/share/playlist/[id] - Create playlist share - POST /api/share/album/[id] - Create album share - GET /api/share/[token] - Resolve share and fetch content - POST /api/share/[token]/click - Track analytics layer_3_ui: - ShareButton component (trigger) - ShareModal component (display options) - SocialShareButtons component (Twitter/Facebook) - SharedContentDisplay component (public page) - /s/[token] page (public landing page) layer_4_util: - lib/share.ts - Token generation and URL building utilities dependencies: data_to_api: model_share: - api_create_song_share - api_create_playlist_share - api_create_album_share - api_resolve_share - api_track_share_click api_to_component: api_create_song_share: [component_share_button] api_create_playlist_share: [component_share_button] api_create_album_share: [component_share_button] api_resolve_share: [component_share_content_display] api_track_share_click: [component_share_content_display] component_to_page: component_share_button: [page_home, page_artist_profile, page_album_detail, page_playlist_detail, page_search] component_share_content_display: [page_share] component_to_component: component_share_button: - component_share_modal component_share_modal: - component_social_share_buttons implementation_order: phase_1_data: - Add ShareType enum to Prisma schema - Add Share model to Prisma schema - Create and run migration - Generate Prisma client phase_2_utilities: - Create lib/share.ts with token generation - Create types/share.ts with TypeScript types - Add share URL building utilities phase_3_api: - Implement POST /api/share/song/[id] - Implement POST /api/share/playlist/[id] - Implement POST /api/share/album/[id] - Implement GET /api/share/[token] - Implement POST /api/share/[token]/click phase_4_components: - Create SocialShareButtons component - Create ShareModal component - Create ShareButton component - Create SharedContentDisplay component phase_5_pages: - Create /s/[token] page - Integrate ShareButton into existing pages testing_requirements: unit_tests: - Token generation uniqueness - URL building correctness - Share creation for each content type - Share resolution with valid/invalid tokens - Click count increment integration_tests: - Full share flow: create → resolve → display - Social share URL generation - Public page rendering for all content types - Analytics tracking edge_cases: - Share private content (should fail or make public) - Share deleted content (404 on resolution) - Token collision (should regenerate) - Anonymous vs authenticated shares security_considerations: - Share tokens must be cryptographically random (10+ characters) - Rate limit share creation to prevent abuse - Validate content is public before sharing - Sanitize all user input in share URLs - Handle deleted/private content gracefully - No PII in share URLs seo_requirements: - Dynamic Open Graph tags on /s/[token] pages - og:title from shared content - og:image from cover art - og:description from content description - Twitter Card meta tags - Canonical URL handling analytics_requirements: - Track share creation by content type - Track share clicks (clickCount field) - Track platform (Twitter, Facebook, copy link) - Track conversion from share page to signup/login