project-standalo-note-to-app/.workflow/versions/v001/design/design_document.yml

1666 lines
46 KiB
YAML

# Design Document v001
# Voice Recording App with AI-Powered Summarization and Automatic App Generation
# Created: 2024-12-19T06:00:00Z
workflow_version: "v001"
feature: "Voice recording app with AI-powered summarization and automatic app generation"
created_at: "2024-12-19T06:00:00Z"
updated_at: "2024-12-19T06:00:00Z"
approved_at: null
status: draft
revision: 1
revision_notes: "Initial design document"
# ============================================================================
# EXTERNAL DEPENDENCIES (Pre-existing entities)
# ============================================================================
external_dependencies:
models: []
api_endpoints: []
components: []
# ============================================================================
# LAYER 1: DATA MODELS
# ============================================================================
data_models:
# USER MODEL
- id: model_user
name: User
description: "Application user account with email/password authentication"
table_name: users
fields:
- name: id
type: uuid
constraints: [primary_key]
description: "Unique user identifier"
- name: email
type: string
constraints: [unique, not_null, indexed]
description: "User email address for login"
- name: name
type: string
constraints: [not_null]
description: "User's display name"
- name: password_hash
type: string
constraints: [not_null]
description: "Bcrypt hashed password"
relations: []
indexes:
- fields: [email]
unique: true
name: idx_users_email
timestamps: true
soft_delete: false
validations:
- field: email
rule: email
message: "Invalid email format"
- field: name
rule: "min:1"
message: "Name is required"
- field: password_hash
rule: "min:60"
message: "Invalid password hash"
# RECORDING MODEL
- id: model_recording
name: Recording
description: "Voice recording with transcript and summary"
table_name: recordings
fields:
- name: id
type: uuid
constraints: [primary_key]
description: "Unique recording identifier"
- name: user_id
type: uuid
constraints: [foreign_key, not_null, indexed]
description: "Owner of this recording"
- name: title
type: string
constraints: [not_null]
description: "Recording title (auto-generated or user-edited)"
- name: audio_file_path
type: string
constraints: [not_null]
description: "Path to audio file in MinIO/S3"
- name: duration
type: integer
constraints: [not_null]
description: "Recording duration in seconds"
- name: transcript
type: text
constraints: []
description: "Full transcript from Whisper STT"
- name: summary
type: text
constraints: []
description: "AI-generated summary from Gemini"
- name: is_transcribing
type: boolean
constraints: [not_null, default]
default: false
description: "Whether currently transcribing"
relations:
- type: belongs_to
target: model_user
foreign_key: user_id
on_delete: cascade
indexes:
- fields: [user_id, created_at]
unique: false
name: idx_recordings_user_created
timestamps: true
soft_delete: false
validations:
- field: duration
rule: "min:1"
message: "Duration must be at least 1 second"
# GENERATED APP MODEL
- id: model_generated_app
name: GeneratedApp
description: "AI-generated application from recording content"
table_name: generated_apps
fields:
- name: id
type: uuid
constraints: [primary_key]
description: "Unique app identifier"
- name: user_id
type: uuid
constraints: [foreign_key, not_null, indexed]
description: "Owner of this app"
- name: recording_id
type: uuid
constraints: [foreign_key, not_null, indexed]
description: "Source recording that triggered generation"
- name: title
type: string
constraints: [not_null]
description: "App title from AI analysis"
- name: description
type: text
constraints: []
description: "App description"
- name: html_content
type: text
constraints: [not_null]
description: "Complete HTML/CSS/JS for iframe rendering"
- name: prd_content
type: text
constraints: []
description: "Product Requirements Document (PRD) generated by AI"
- name: ui_ux_design
type: text
constraints: []
description: "UI/UX design notes from AI"
- name: app_type
type: string
constraints: []
description: "Type of app determined by AI (e.g., todo, calculator, form)"
- name: status
type: enum
enum_values: [generating, completed, failed]
constraints: [not_null, default]
default: generating
description: "Generation status"
relations:
- type: belongs_to
target: model_user
foreign_key: user_id
on_delete: cascade
- type: belongs_to
target: model_recording
foreign_key: recording_id
on_delete: cascade
indexes:
- fields: [user_id, created_at]
unique: false
name: idx_apps_user_created
- fields: [recording_id]
unique: false
name: idx_apps_recording
timestamps: true
soft_delete: false
validations: []
# ============================================================================
# LAYER 2: API ENDPOINTS
# ============================================================================
api_endpoints:
# ========================================
# AUTHENTICATION ENDPOINTS
# ========================================
- id: api_register_user
method: POST
path: /api/auth/register
summary: "Register a new user"
description: "Create a new user account with email and password"
tags: [auth]
path_params: []
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties:
- name: email
type: string
required: true
validations: [email]
description: "User email address"
- name: name
type: string
required: true
validations: ["min:1", "max:100"]
description: "User display name"
- name: password
type: string
required: true
validations: ["min:8"]
description: "Password (min 8 characters)"
example:
email: "user@example.com"
name: "John Doe"
password: "securepass123"
responses:
- status: 201
description: "User created successfully"
schema:
type: object
properties:
- name: id
type: uuid
- name: email
type: string
- name: name
type: string
- name: created_at
type: datetime
example:
id: "550e8400-e29b-41d4-a716-446655440000"
email: "user@example.com"
name: "John Doe"
created_at: "2024-12-19T06:00:00Z"
- status: 400
description: "Validation error"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Invalid email or password too short"
- status: 409
description: "Email already exists"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Email already registered"
depends_on_models: [model_user]
depends_on_apis: []
auth:
required: false
roles: []
rate_limit:
requests: 10
window: "1h"
- id: api_login_user
method: POST
path: /api/auth/login
summary: "Login user"
description: "Authenticate user with email and password, return session token"
tags: [auth]
path_params: []
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties:
- name: email
type: string
required: true
validations: [email]
description: "User email"
- name: password
type: string
required: true
description: "User password"
example:
email: "user@example.com"
password: "securepass123"
responses:
- status: 200
description: "Login successful"
schema:
type: object
properties:
- name: user
type: object
- name: token
type: string
example:
user:
id: "550e8400-e29b-41d4-a716-446655440000"
email: "user@example.com"
name: "John Doe"
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
- status: 401
description: "Invalid credentials"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Invalid email or password"
depends_on_models: [model_user]
depends_on_apis: []
auth:
required: false
roles: []
rate_limit:
requests: 20
window: "1h"
- id: api_logout_user
method: POST
path: /api/auth/logout
summary: "Logout user"
description: "Invalidate current session token"
tags: [auth]
path_params: []
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "Logout successful"
schema:
type: object
properties:
- name: success
type: boolean
example:
success: true
depends_on_models: []
depends_on_apis: []
auth:
required: true
roles: []
- id: api_get_current_user
method: GET
path: /api/auth/me
summary: "Get current user"
description: "Get currently authenticated user information"
tags: [auth]
path_params: []
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "User data"
schema:
type: object
properties:
- name: id
type: uuid
- name: email
type: string
- name: name
type: string
- name: created_at
type: datetime
example:
id: "550e8400-e29b-41d4-a716-446655440000"
email: "user@example.com"
name: "John Doe"
created_at: "2024-12-19T06:00:00Z"
- status: 401
description: "Not authenticated"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Not authenticated"
depends_on_models: [model_user]
depends_on_apis: []
auth:
required: true
roles: []
# ========================================
# RECORDING ENDPOINTS
# ========================================
- id: api_list_recordings
method: GET
path: /api/recordings
summary: "List user recordings"
description: "Get all recordings for authenticated user, sorted by creation date"
tags: [recordings]
path_params: []
query_params:
- name: limit
type: integer
required: false
default: 50
description: "Maximum number of recordings to return"
- name: offset
type: integer
required: false
default: 0
description: "Number of recordings to skip"
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "Recordings list"
schema:
type: object
properties:
- name: recordings
type: array
- name: total
type: integer
example:
recordings:
- id: "rec-123"
title: "Meeting Notes"
duration: 180
created_at: "2024-12-19T06:00:00Z"
total: 42
depends_on_models: [model_recording]
depends_on_apis: []
auth:
required: true
roles: []
- id: api_create_recording
method: POST
path: /api/recordings
summary: "Create new recording"
description: "Upload audio file and create recording metadata"
tags: [recordings]
path_params: []
query_params: []
request_body:
content_type: multipart/form-data
schema:
type: object
properties:
- name: audio
type: file
required: true
description: "Audio file (webm, mp3, wav)"
- name: title
type: string
required: false
description: "Recording title (auto-generated if not provided)"
- name: duration
type: integer
required: true
description: "Duration in seconds"
responses:
- status: 201
description: "Recording created"
schema:
type: object
properties:
- name: id
type: uuid
- name: title
type: string
- name: audio_file_path
type: string
- name: duration
type: integer
- name: created_at
type: datetime
example:
id: "rec-123"
title: "Recording 2024-12-19"
audio_file_path: "recordings/user-123/rec-123.webm"
duration: 180
created_at: "2024-12-19T06:00:00Z"
- status: 400
description: "Invalid audio file"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Invalid audio format"
depends_on_models: [model_recording]
depends_on_apis: []
auth:
required: true
roles: []
- id: api_get_recording
method: GET
path: /api/recordings/[id]
summary: "Get single recording"
description: "Get recording details including transcript and summary"
tags: [recordings]
path_params:
- name: id
type: uuid
description: "Recording ID"
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "Recording details"
schema:
type: object
properties:
- name: id
type: uuid
- name: title
type: string
- name: audio_file_path
type: string
- name: duration
type: integer
- name: transcript
type: string
- name: summary
type: string
- name: is_transcribing
type: boolean
- name: created_at
type: datetime
- status: 404
description: "Recording not found"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Recording not found"
depends_on_models: [model_recording]
depends_on_apis: []
auth:
required: true
roles: []
- id: api_delete_recording
method: DELETE
path: /api/recordings/[id]
summary: "Delete recording"
description: "Delete recording and associated audio file"
tags: [recordings]
path_params:
- name: id
type: uuid
description: "Recording ID"
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "Recording deleted"
schema:
type: object
properties:
- name: success
type: boolean
example:
success: true
- status: 404
description: "Recording not found"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Recording not found"
depends_on_models: [model_recording]
depends_on_apis: []
auth:
required: true
roles: []
- id: api_transcribe_recording
method: POST
path: /api/recordings/[id]/transcribe
summary: "Transcribe recording"
description: "Run Whisper STT on audio file to generate transcript"
tags: [recordings, ai]
path_params:
- name: id
type: uuid
description: "Recording ID"
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "Transcription started"
schema:
type: object
properties:
- name: recording_id
type: uuid
- name: is_transcribing
type: boolean
example:
recording_id: "rec-123"
is_transcribing: true
- status: 404
description: "Recording not found"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Recording not found"
depends_on_models: [model_recording]
depends_on_apis: []
auth:
required: true
roles: []
- id: api_summarize_recording
method: POST
path: /api/recordings/[id]/summarize
summary: "Summarize recording"
description: "Use Gemini to generate summary from transcript"
tags: [recordings, ai]
path_params:
- name: id
type: uuid
description: "Recording ID"
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "Summary generated"
schema:
type: object
properties:
- name: recording_id
type: uuid
- name: summary
type: string
example:
recording_id: "rec-123"
summary: "Meeting discussion about Q1 goals..."
- status: 400
description: "No transcript available"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Transcript not available"
- status: 404
description: "Recording not found"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Recording not found"
depends_on_models: [model_recording]
depends_on_apis: [api_transcribe_recording]
auth:
required: true
roles: []
# ========================================
# GENERATED APP ENDPOINTS
# ========================================
- id: api_list_apps
method: GET
path: /api/apps
summary: "List generated apps"
description: "Get all apps generated for authenticated user"
tags: [apps]
path_params: []
query_params:
- name: limit
type: integer
required: false
default: 50
description: "Maximum number of apps to return"
- name: offset
type: integer
required: false
default: 0
description: "Number of apps to skip"
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "Apps list"
schema:
type: object
properties:
- name: apps
type: array
- name: total
type: integer
example:
apps:
- id: "app-123"
title: "Todo App"
app_type: "todo"
status: "completed"
created_at: "2024-12-19T06:00:00Z"
total: 12
depends_on_models: [model_generated_app]
depends_on_apis: []
auth:
required: true
roles: []
- id: api_generate_app
method: POST
path: /api/apps/generate
summary: "Generate app from recording"
description: "Trigger AI app generation based on recording summary (wake word detection)"
tags: [apps, ai]
path_params: []
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties:
- name: recording_id
type: uuid
required: true
description: "Source recording ID"
example:
recording_id: "rec-123"
responses:
- status: 201
description: "App generation started"
schema:
type: object
properties:
- name: id
type: uuid
- name: recording_id
type: uuid
- name: status
type: string
example:
id: "app-123"
recording_id: "rec-123"
status: "generating"
- status: 400
description: "Recording has no summary"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Recording summary not available"
- status: 404
description: "Recording not found"
schema:
type: object
properties:
- name: error
type: string
example:
error: "Recording not found"
depends_on_models: [model_generated_app, model_recording]
depends_on_apis: [api_summarize_recording]
auth:
required: true
roles: []
- id: api_get_app
method: GET
path: /api/apps/[id]
summary: "Get single generated app"
description: "Get app details including HTML content for iframe rendering"
tags: [apps]
path_params:
- name: id
type: uuid
description: "App ID"
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "App details"
schema:
type: object
properties:
- name: id
type: uuid
- name: recording_id
type: uuid
- name: title
type: string
- name: description
type: string
- name: html_content
type: string
- name: app_type
type: string
- name: status
type: string
- name: created_at
type: datetime
- status: 404
description: "App not found"
schema:
type: object
properties:
- name: error
type: string
example:
error: "App not found"
depends_on_models: [model_generated_app]
depends_on_apis: []
auth:
required: true
roles: []
- id: api_delete_app
method: DELETE
path: /api/apps/[id]
summary: "Delete generated app"
description: "Delete generated app (recording remains)"
tags: [apps]
path_params:
- name: id
type: uuid
description: "App ID"
query_params: []
request_body:
content_type: application/json
schema:
type: object
properties: []
responses:
- status: 200
description: "App deleted"
schema:
type: object
properties:
- name: success
type: boolean
example:
success: true
- status: 404
description: "App not found"
schema:
type: object
properties:
- name: error
type: string
example:
error: "App not found"
depends_on_models: [model_generated_app]
depends_on_apis: []
auth:
required: true
roles: []
# ============================================================================
# LAYER 3: PAGES
# ============================================================================
pages:
- id: page_home
name: "Home"
path: /
layout: layout_public
data_needs: []
components: [component_header, component_hero, component_features]
seo:
title: "NoteToApp - Voice Recording with AI Summarization"
description: "Record voice notes, get AI summaries, and generate apps automatically"
auth:
required: false
roles: []
redirect: ""
state:
local: []
global: []
- id: page_login
name: "Login"
path: /login
layout: layout_auth
data_needs: []
components: [component_login_form]
seo:
title: "Login - NoteToApp"
description: "Login to your account"
auth:
required: false
roles: []
redirect: ""
state:
local: [error, isLoading]
global: []
- id: page_register
name: "Register"
path: /register
layout: layout_auth
data_needs: []
components: [component_register_form]
seo:
title: "Register - NoteToApp"
description: "Create a new account"
auth:
required: false
roles: []
redirect: ""
state:
local: [error, isLoading]
global: []
- id: page_dashboard
name: "Dashboard"
path: /dashboard
layout: layout_app
data_needs:
- api_id: api_get_current_user
purpose: "Display user info"
on_load: true
- api_id: api_list_recordings
purpose: "Show recent recordings"
on_load: true
components: [component_header, component_sidebar, component_record_button, component_wake_word_indicator, component_recording_list]
seo:
title: "Dashboard - NoteToApp"
description: "Your voice recordings and generated apps"
auth:
required: true
roles: []
redirect: /login
state:
local: [isRecording, isListening, currentRecording]
global: [user]
- id: page_recordings
name: "Recordings"
path: /recordings
layout: layout_app
data_needs:
- api_id: api_list_recordings
purpose: "Display all recordings"
on_load: true
components: [component_header, component_sidebar, component_recording_list, component_recording_card]
seo:
title: "Recordings - NoteToApp"
description: "All your voice recordings"
auth:
required: true
roles: []
redirect: /login
state:
local: [searchQuery, sortBy]
global: [user]
- id: page_recording_detail
name: "Recording Detail"
path: /recordings/[id]
layout: layout_app
data_needs:
- api_id: api_get_recording
purpose: "Display recording details"
on_load: true
components: [component_header, component_sidebar, component_audio_player, component_transcript_viewer, component_summary_display]
seo:
title: "Recording Detail - NoteToApp"
description: "View recording transcript and summary"
auth:
required: true
roles: []
redirect: /login
state:
local: [isPlaying, currentTime, isTranscribing]
global: [user]
- id: page_apps
name: "Generated Apps"
path: /apps
layout: layout_app
data_needs:
- api_id: api_list_apps
purpose: "Display generated apps gallery"
on_load: true
components: [component_header, component_sidebar, component_app_gallery, component_app_card]
seo:
title: "Generated Apps - NoteToApp"
description: "Your AI-generated applications"
auth:
required: true
roles: []
redirect: /login
state:
local: [filterType]
global: [user]
- id: page_app_detail
name: "App Preview"
path: /apps/[id]
layout: layout_app
data_needs:
- api_id: api_get_app
purpose: "Display app in iframe"
on_load: true
components: [component_header, component_sidebar, component_app_iframe_viewer]
seo:
title: "App Preview - NoteToApp"
description: "View generated application"
auth:
required: true
roles: []
redirect: /login
state:
local: [isLoading]
global: [user]
# ============================================================================
# LAYER 3: COMPONENTS
# ============================================================================
components:
# ========================================
# LAYOUT COMPONENTS
# ========================================
- id: component_header
name: Header
props:
- name: user
type: User | null
required: false
default: null
description: "Current user for displaying name/avatar"
events: []
uses_apis: []
uses_components: []
internal_state: []
variants: [default]
- id: component_sidebar
name: Sidebar
props:
- name: activePath
type: string
required: true
description: "Current route path for highlighting"
events:
- name: onNavigate
payload: "string"
description: "Fired when navigation item clicked"
uses_apis: []
uses_components: []
internal_state: [isCollapsed]
variants: [default]
- id: component_hero
name: Hero
props: []
events:
- name: onGetStarted
payload: "void"
description: "Fired when CTA button clicked"
uses_apis: []
uses_components: []
internal_state: []
variants: [default]
- id: component_features
name: Features
props: []
events: []
uses_apis: []
uses_components: []
internal_state: []
variants: [default]
# ========================================
# AUTHENTICATION COMPONENTS
# ========================================
- id: component_login_form
name: LoginForm
props: []
events:
- name: onSuccess
payload: "User"
description: "Fired when login successful"
- name: onError
payload: "string"
description: "Fired when login fails"
uses_apis: [api_login_user]
uses_components: []
internal_state: [email, password, isLoading, error]
variants: [default]
- id: component_register_form
name: RegisterForm
props: []
events:
- name: onSuccess
payload: "User"
description: "Fired when registration successful"
- name: onError
payload: "string"
description: "Fired when registration fails"
uses_apis: [api_register_user]
uses_components: []
internal_state: [email, name, password, confirmPassword, isLoading, error]
variants: [default]
# ========================================
# RECORDING COMPONENTS
# ========================================
- id: component_record_button
name: RecordButton
props:
- name: isRecording
type: boolean
required: true
description: "Whether currently recording"
- name: isTranscribing
type: boolean
required: false
default: false
description: "Whether transcribing in real-time"
events:
- name: onStartRecording
payload: "void"
description: "Fired when recording starts"
- name: onStopRecording
payload: "Blob"
description: "Fired when recording stops, includes audio blob"
uses_apis: []
uses_components: []
internal_state: [mediaRecorder, audioChunks]
variants: [default, large]
- id: component_wake_word_indicator
name: WakeWordIndicator
props:
- name: isListening
type: boolean
required: true
description: "Whether wake word detection is active"
- name: wakeWord
type: string
required: true
description: "The wake word phrase"
events:
- name: onWakeWordDetected
payload: "void"
description: "Fired when wake word is detected"
uses_apis: []
uses_components: []
internal_state: [lastDetectionTime]
variants: [default]
- id: component_recording_list
name: RecordingList
props:
- name: recordings
type: "Recording[]"
required: true
description: "Array of recordings to display"
- name: isLoading
type: boolean
required: false
default: false
description: "Whether recordings are being loaded"
events:
- name: onSelectRecording
payload: "string"
description: "Fired when recording is clicked, payload is recording ID"
- name: onDeleteRecording
payload: "string"
description: "Fired when delete confirmed, payload is recording ID"
uses_apis: []
uses_components: [component_recording_card]
internal_state: []
variants: [default, compact]
- id: component_recording_card
name: RecordingCard
props:
- name: recording
type: Recording
required: true
description: "Recording to display"
- name: showActions
type: boolean
required: false
default: true
description: "Show edit/delete buttons"
events:
- name: onClick
payload: "string"
description: "Fired when card clicked, payload is recording ID"
- name: onDelete
payload: "string"
description: "Fired when delete confirmed, payload is recording ID"
uses_apis: []
uses_components: []
internal_state: [isDeleting]
variants: [default, compact]
- id: component_audio_player
name: AudioPlayer
props:
- name: audioUrl
type: string
required: true
description: "URL to audio file"
- name: duration
type: integer
required: true
description: "Duration in seconds"
events:
- name: onPlayPause
payload: "boolean"
description: "Fired when play/pause toggled, payload is isPlaying"
- name: onSeek
payload: "number"
description: "Fired when user seeks, payload is new time in seconds"
uses_apis: []
uses_components: []
internal_state: [isPlaying, currentTime, audioElement]
variants: [default]
- id: component_transcript_viewer
name: TranscriptViewer
props:
- name: transcript
type: string
required: true
description: "Transcript text to display"
- name: isLive
type: boolean
required: false
default: false
description: "Whether showing live transcription"
events: []
uses_apis: []
uses_components: []
internal_state: []
variants: [default, live]
- id: component_summary_display
name: SummaryDisplay
props:
- name: summary
type: string
required: true
description: "AI-generated summary text"
- name: isLoading
type: boolean
required: false
default: false
description: "Whether summary is being generated"
events: []
uses_apis: []
uses_components: []
internal_state: []
variants: [default]
# ========================================
# GENERATED APP COMPONENTS
# ========================================
- id: component_app_gallery
name: AppGallery
props:
- name: apps
type: "GeneratedApp[]"
required: true
description: "Array of generated apps to display"
- name: isLoading
type: boolean
required: false
default: false
description: "Whether apps are being loaded"
events:
- name: onSelectApp
payload: "string"
description: "Fired when app is clicked, payload is app ID"
uses_apis: []
uses_components: [component_app_card]
internal_state: []
variants: [grid, list]
- id: component_app_card
name: AppCard
props:
- name: app
type: GeneratedApp
required: true
description: "Generated app to display"
- name: showActions
type: boolean
required: false
default: true
description: "Show delete button"
events:
- name: onClick
payload: "string"
description: "Fired when card clicked, payload is app ID"
- name: onDelete
payload: "string"
description: "Fired when delete confirmed, payload is app ID"
uses_apis: []
uses_components: []
internal_state: [isDeleting]
variants: [default, compact]
- id: component_app_iframe_viewer
name: AppIframeViewer
props:
- name: htmlContent
type: string
required: true
description: "HTML content to render in iframe"
- name: title
type: string
required: true
description: "App title for accessibility"
events:
- name: onLoadComplete
payload: "void"
description: "Fired when iframe finishes loading"
uses_apis: []
uses_components: []
internal_state: [isLoading, iframeRef]
variants: [default, fullscreen]
# ============================================================================
# DEPENDENCY GRAPH
# ============================================================================
dependency_graph:
layers:
- layer: 1
name: "Data Models"
description: "Database schema - no dependencies"
items:
- id: model_user
type: model
dependencies: []
- id: model_recording
type: model
dependencies: []
- id: model_generated_app
type: model
dependencies: []
- layer: 2
name: "API Endpoints"
description: "Backend APIs - depend on models"
items:
- id: api_register_user
type: api
dependencies: [model_user]
- id: api_login_user
type: api
dependencies: [model_user]
- id: api_logout_user
type: api
dependencies: []
- id: api_get_current_user
type: api
dependencies: [model_user]
- id: api_list_recordings
type: api
dependencies: [model_recording]
- id: api_create_recording
type: api
dependencies: [model_recording]
- id: api_get_recording
type: api
dependencies: [model_recording]
- id: api_delete_recording
type: api
dependencies: [model_recording]
- id: api_transcribe_recording
type: api
dependencies: [model_recording]
- id: api_summarize_recording
type: api
dependencies: [model_recording]
- id: api_list_apps
type: api
dependencies: [model_generated_app]
- id: api_generate_app
type: api
dependencies: [model_generated_app, model_recording]
- id: api_get_app
type: api
dependencies: [model_generated_app]
- id: api_delete_app
type: api
dependencies: [model_generated_app]
- layer: 3
name: "UI Components & Pages"
description: "Frontend - depend on APIs"
items:
# Components
- id: component_header
type: component
dependencies: []
- id: component_sidebar
type: component
dependencies: []
- id: component_hero
type: component
dependencies: []
- id: component_features
type: component
dependencies: []
- id: component_login_form
type: component
dependencies: [api_login_user]
- id: component_register_form
type: component
dependencies: [api_register_user]
- id: component_record_button
type: component
dependencies: []
- id: component_wake_word_indicator
type: component
dependencies: []
- id: component_recording_list
type: component
dependencies: [component_recording_card]
- id: component_recording_card
type: component
dependencies: []
- id: component_audio_player
type: component
dependencies: []
- id: component_transcript_viewer
type: component
dependencies: []
- id: component_summary_display
type: component
dependencies: []
- id: component_app_gallery
type: component
dependencies: [component_app_card]
- id: component_app_card
type: component
dependencies: []
- id: component_app_iframe_viewer
type: component
dependencies: []
# Pages
- id: page_home
type: page
dependencies: [component_header, component_hero, component_features]
- id: page_login
type: page
dependencies: [component_login_form]
- id: page_register
type: page
dependencies: [component_register_form]
- id: page_dashboard
type: page
dependencies: [api_get_current_user, api_list_recordings, component_header, component_sidebar, component_record_button, component_wake_word_indicator, component_recording_list]
- id: page_recordings
type: page
dependencies: [api_list_recordings, component_header, component_sidebar, component_recording_list, component_recording_card]
- id: page_recording_detail
type: page
dependencies: [api_get_recording, component_header, component_sidebar, component_audio_player, component_transcript_viewer, component_summary_display]
- id: page_apps
type: page
dependencies: [api_list_apps, component_header, component_sidebar, component_app_gallery, component_app_card]
- id: page_app_detail
type: page
dependencies: [api_get_app, component_header, component_sidebar, component_app_iframe_viewer]
dependency_map:
# Models
model_user:
depends_on: []
depended_by: [api_register_user, api_login_user, api_get_current_user]
model_recording:
depends_on: []
depended_by: [api_list_recordings, api_create_recording, api_get_recording, api_delete_recording, api_transcribe_recording, api_summarize_recording, api_generate_app]
model_generated_app:
depends_on: []
depended_by: [api_list_apps, api_generate_app, api_get_app, api_delete_app]
# APIs - Auth
api_register_user:
depends_on: [model_user]
depended_by: [component_register_form]
api_login_user:
depends_on: [model_user]
depended_by: [component_login_form]
api_logout_user:
depends_on: []
depended_by: []
api_get_current_user:
depends_on: [model_user]
depended_by: [page_dashboard]
# APIs - Recordings
api_list_recordings:
depends_on: [model_recording]
depended_by: [page_dashboard, page_recordings]
api_create_recording:
depends_on: [model_recording]
depended_by: []
api_get_recording:
depends_on: [model_recording]
depended_by: [page_recording_detail]
api_delete_recording:
depends_on: [model_recording]
depended_by: []
api_transcribe_recording:
depends_on: [model_recording]
depended_by: []
api_summarize_recording:
depends_on: [model_recording]
depended_by: []
# APIs - Apps
api_list_apps:
depends_on: [model_generated_app]
depended_by: [page_apps]
api_generate_app:
depends_on: [model_generated_app, model_recording]
depended_by: []
api_get_app:
depends_on: [model_generated_app]
depended_by: [page_app_detail]
api_delete_app:
depends_on: [model_generated_app]
depended_by: []
# Components
component_header:
depends_on: []
depended_by: [page_home, page_dashboard, page_recordings, page_recording_detail, page_apps, page_app_detail]
component_sidebar:
depends_on: []
depended_by: [page_dashboard, page_recordings, page_recording_detail, page_apps, page_app_detail]
component_hero:
depends_on: []
depended_by: [page_home]
component_features:
depends_on: []
depended_by: [page_home]
component_login_form:
depends_on: [api_login_user]
depended_by: [page_login]
component_register_form:
depends_on: [api_register_user]
depended_by: [page_register]
component_record_button:
depends_on: []
depended_by: [page_dashboard]
component_wake_word_indicator:
depends_on: []
depended_by: [page_dashboard]
component_recording_list:
depends_on: [component_recording_card]
depended_by: [page_dashboard, page_recordings]
component_recording_card:
depends_on: []
depended_by: [component_recording_list, page_recordings]
component_audio_player:
depends_on: []
depended_by: [page_recording_detail]
component_transcript_viewer:
depends_on: []
depended_by: [page_recording_detail]
component_summary_display:
depends_on: []
depended_by: [page_recording_detail]
component_app_gallery:
depends_on: [component_app_card]
depended_by: [page_apps]
component_app_card:
depends_on: []
depended_by: [component_app_gallery, page_apps]
component_app_iframe_viewer:
depends_on: []
depended_by: [page_app_detail]
# Pages
page_home:
depends_on: [component_header, component_hero, component_features]
depended_by: []
page_login:
depends_on: [component_login_form]
depended_by: []
page_register:
depends_on: [component_register_form]
depended_by: []
page_dashboard:
depends_on: [api_get_current_user, api_list_recordings, component_header, component_sidebar, component_record_button, component_wake_word_indicator, component_recording_list]
depended_by: []
page_recordings:
depends_on: [api_list_recordings, component_header, component_sidebar, component_recording_list, component_recording_card]
depended_by: []
page_recording_detail:
depends_on: [api_get_recording, component_header, component_sidebar, component_audio_player, component_transcript_viewer, component_summary_display]
depended_by: []
page_apps:
depends_on: [api_list_apps, component_header, component_sidebar, component_app_gallery, component_app_card]
depended_by: []
page_app_detail:
depends_on: [api_get_app, component_header, component_sidebar, component_app_iframe_viewer]
depended_by: []