generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") } model User { id BigInt @id @default(autoincrement()) email String? @unique @db.VarChar(191) phone String? @unique @db.VarChar(50) password_hash String @db.VarChar(255) nickname String? @db.VarChar(100) avatar_url String? @db.VarChar(500) role String @default("user") @db.VarChar(50) status String @default("active") @db.VarChar(50) wechat_openid String? @unique @db.VarChar(191) last_login_at DateTime? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([role, status]) @@index([created_at]) @@map("users") } model UserModelPreference { id BigInt @id @default(autoincrement()) user_id BigInt scope_key String @default("global") @db.VarChar(120) project_id BigInt? preference_key String @db.VarChar(120) text_provider_code String? @db.VarChar(100) image_provider_code String? @db.VarChar(100) video_provider_code String? @db.VarChar(100) voice_provider_code String? @db.VarChar(100) metadata_json Json? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([user_id, scope_key, preference_key], map: "ump_user_scope_key_unique") @@index([user_id, scope_key], map: "ump_user_scope_idx") @@index([project_id], map: "ump_project_idx") @@map("user_model_preferences") } model Project { id BigInt @id @default(autoincrement()) user_id BigInt title String? @db.VarChar(255) input_mode String @db.VarChar(50) genre String? @db.VarChar(100) style_code String? @db.VarChar(100) output_type String? @db.VarChar(50) output_mode String @default("image_manga") @db.VarChar(50) visual_mode String? @db.VarChar(100) video_generation_level String? @db.VarChar(50) target_episode_count Int? episode_duration Int? status String @default("draft") @db.VarChar(80) copyright_status String @default("pending") @db.VarChar(80) payment_status String @default("unpaid") @db.VarChar(80) quality_level String? @db.VarChar(50) is_long_series Boolean @default(false) engine_version String @default("legacy_v1") @db.VarChar(50) production_lifecycle String @default("legacy_snapshot") @db.VarChar(80) created_at DateTime @default(now()) updated_at DateTime @updatedAt completed_at DateTime? @@index([user_id, status]) @@index([engine_version, production_lifecycle], map: "project_engine_lifecycle_idx") @@index([genre, status]) @@index([created_at]) @@map("projects") } model ProductionContract { id BigInt @id @default(autoincrement()) project_id BigInt contract_type String @db.VarChar(50) schema_version String @db.VarChar(80) version Int scope_key String @default("project") @db.VarChar(100) parent_contract_id BigInt? source_snapshot_id String? @db.VarChar(160) input_hash String @db.VarChar(64) input_snapshot_json Json? payload_json Json source_refs_json Json? quality_result_json Json? reviewer_delta_json Json? status String @default("draft") @db.VarChar(50) downstream_status String @default("blocked") @db.VarChar(50) created_by_user_id BigInt? confirmed_at DateTime? released_at DateTime? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([project_id, contract_type, scope_key, version], map: "pc_project_type_scope_version_key") @@index([project_id, contract_type, status], map: "pc_project_type_status_idx") @@index([parent_contract_id], map: "pc_parent_idx") @@index([input_hash], map: "pc_input_hash_idx") @@index([downstream_status], map: "pc_downstream_status_idx") @@map("production_contracts") } model ProductionSourceSnapshot { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt? snapshot_version Int source_type String @db.VarChar(50) title String? @db.VarChar(255) content_hash String @db.VarChar(64) content_text String @db.LongText chapter_manifest_json Json? metadata_json Json? created_by_user_id BigInt? created_at DateTime @default(now()) @@unique([project_id, snapshot_version], map: "pss_project_version_key") @@index([project_id, novel_source_id], map: "pss_project_source_idx") @@index([content_hash], map: "pss_content_hash_idx") @@map("production_source_snapshots") } model ProductionContractReview { id BigInt @id @default(autoincrement()) project_id BigInt contract_id BigInt reviewer_type String @db.VarChar(80) reviewer_version String @db.VarChar(80) review_no Int passed Boolean @default(false) quality_score Decimal? @db.Decimal(5, 2) issues_json Json? delta_json Json? provider_log_id BigInt? created_by_user_id BigInt? created_at DateTime @default(now()) @@unique([contract_id, reviewer_type, review_no], map: "pcr_contract_reviewer_no_key") @@index([project_id, reviewer_type], map: "pcr_project_reviewer_idx") @@index([contract_id, passed], map: "pcr_contract_passed_idx") @@index([provider_log_id], map: "pcr_provider_log_idx") @@map("production_contract_reviews") } model NovelSource { id BigInt @id @default(autoincrement()) project_id BigInt source_type String @db.VarChar(50) title String? @db.VarChar(255) author_name String? @db.VarChar(100) raw_asset_id BigInt? raw_text String? @db.LongText clean_text String? @db.LongText word_count Int? chapter_count Int? parse_status String @default("pending") @db.VarChar(50) parse_report Json? design_json Json? volume_plan_json Json? ai_provider_code String? @db.VarChar(100) ai_model_name String? @db.VarChar(160) ai_cost_estimate Decimal? @db.Decimal(12, 4) ai_cost_actual Decimal? @db.Decimal(12, 4) created_at DateTime @default(now()) @@index([project_id]) @@index([parse_status]) @@index([ai_provider_code], map: "ns_ai_provider_idx") @@map("novel_sources") } model NovelChapter { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt? volume_no Int? volume_title String? @db.VarChar(255) chapter_no Int title String? @db.VarChar(255) content String @db.LongText summary String? @db.Text visual_summary String? @db.Text outline_json Json? analysis_json Json? word_count Int? status String @default("draft") @db.VarChar(50) ai_provider_code String? @db.VarChar(100) ai_model_name String? @db.VarChar(160) ai_cost_estimate Decimal? @db.Decimal(12, 4) ai_cost_actual Decimal? @db.Decimal(12, 4) created_at DateTime @default(now()) @@unique([novel_source_id, chapter_no]) @@index([project_id, chapter_no]) @@index([novel_source_id, volume_no]) @@index([project_id, status]) @@index([ai_provider_code], map: "nc_ai_provider_idx") @@map("novel_chapters") } model NovelReadingProgress { id BigInt @id @default(autoincrement()) user_id BigInt novel_source_id BigInt chapter_id BigInt page_index Int @default(0) page_count Int @default(1) progress_percent Decimal? @db.Decimal(6, 3) updated_at DateTime @updatedAt @@unique([user_id, novel_source_id]) @@index([user_id, updated_at]) @@index([novel_source_id]) @@map("novel_reading_progress") } model NovelBookmark { id BigInt @id @default(autoincrement()) user_id BigInt novel_source_id BigInt chapter_id BigInt page_index Int @default(0) title String? @db.VarChar(255) note_text String? @db.Text created_at DateTime @default(now()) @@index([user_id, novel_source_id, created_at]) @@index([chapter_id]) @@map("novel_bookmarks") } model NovelAnnotation { id BigInt @id @default(autoincrement()) user_id BigInt novel_source_id BigInt chapter_id BigInt page_index Int @default(0) selected_text String @db.Text note_text String? @db.Text color String? @db.VarChar(30) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([user_id, novel_source_id, created_at]) @@index([chapter_id]) @@map("novel_annotations") } model NovelGenerationPlan { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt? user_id BigInt novel_scale String @default("medium") @db.VarChar(30) target_words Int? target_chapters Int? genre String? @db.VarChar(100) style_code String? @db.VarChar(100) brief_json Json? ip_bible_json Json? volume_plan_json Json? pipeline_config_json Json? quality_threshold_json Json? automation_level String @default("L1") @db.VarChar(20) status String @default("draft") @db.VarChar(50) current_chapter_no Int @default(0) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, status], map: "npg_project_status_idx") @@index([novel_source_id], map: "npg_source_idx") @@index([user_id, status], map: "npg_user_status_idx") @@index([novel_scale, automation_level], map: "npg_scale_level_idx") @@map("novel_generation_plans") } model NovelChapterVersion { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt? novel_chapter_id BigInt? chapter_no Int version_no Int version_type String @db.VarChar(50) title String? @db.VarChar(255) content_text String? @db.LongText content_json Json? source_agent String? @db.VarChar(100) provider_code String? @db.VarChar(100) model_name String? @db.VarChar(100) quality_score Decimal? @db.Decimal(5, 2) status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) @@unique([novel_source_id, chapter_no, version_no, version_type], map: "ncv_source_chapter_version_type_key") @@index([project_id, chapter_no], map: "ncv_project_chapter_idx") @@index([novel_chapter_id], map: "ncv_chapter_idx") @@index([source_agent], map: "ncv_agent_idx") @@index([status], map: "ncv_status_idx") @@map("novel_chapter_versions") } model NovelContextMemory { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt? chapter_no Int? memory_type String @db.VarChar(80) memory_text String? @db.LongText memory_json Json? importance_level Int @default(0) status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) @@index([project_id, memory_type], map: "ncm_project_type_idx") @@index([novel_source_id, chapter_no], map: "ncm_source_chapter_idx") @@index([memory_type, status], map: "ncm_type_status_idx") @@index([importance_level], map: "ncm_importance_idx") @@map("novel_context_memories") } model NovelQualityReport { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt? novel_chapter_id BigInt? chapter_no Int? report_type String @db.VarChar(50) total_score Decimal? @db.Decimal(5, 2) score_json Json? problems_json Json? suggestions_json Json? pass_status Boolean @default(false) rewrite_required Boolean @default(false) source_agent String? @db.VarChar(100) provider_code String? @db.VarChar(100) model_name String? @db.VarChar(100) created_at DateTime @default(now()) @@index([project_id, chapter_no], map: "nqr_project_chapter_idx") @@index([novel_source_id, chapter_no], map: "nqr_source_chapter_idx") @@index([novel_chapter_id], map: "nqr_chapter_idx") @@index([pass_status], map: "nqr_pass_idx") @@index([source_agent], map: "nqr_agent_idx") @@map("novel_quality_reports") } model NovelVersionSnapshot { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt version_no Int title String? @db.VarChar(255) snapshot_scope String @db.VarChar(50) chapter_start Int? chapter_end Int? source_hash String? @db.VarChar(128) snapshot_text String? @db.LongText snapshot_json Json? created_for String? @db.VarChar(50) created_by_user_id BigInt? created_at DateTime @default(now()) @@unique([novel_source_id, version_no], map: "nvs_source_version_key") @@index([project_id], map: "nvs_project_idx") @@index([created_for], map: "nvs_for_idx") @@index([chapter_start, chapter_end], map: "nvs_range_idx") @@map("novel_version_snapshots") } model NovelDerivativeJob { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt snapshot_id BigInt? user_id BigInt derivative_type String @db.VarChar(50) target_project_id BigInt? target_ref_id BigInt? chapter_start Int? chapter_end Int? config_json Json? status String @default("pending") @db.VarChar(50) progress_json Json? error_message String? @db.Text created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, derivative_type], map: "ndj_project_type_idx") @@index([novel_source_id, status], map: "ndj_source_status_idx") @@index([snapshot_id], map: "ndj_snapshot_idx") @@index([user_id, status], map: "ndj_user_status_idx") @@index([target_project_id], map: "ndj_target_project_idx") @@map("novel_derivative_jobs") } model AgentPrompt { id BigInt @id @default(autoincrement()) agent_name String @db.VarChar(100) version Int @default(1) provider_type String @default("NovelProvider") @db.VarChar(80) default_provider_code String? @db.VarChar(100) system_prompt String @db.LongText user_prompt_template String @db.LongText output_schema_json Json? temperature Decimal? @db.Decimal(4, 2) max_output_tokens Int? is_active Boolean @default(true) created_at DateTime @default(now()) @@unique([agent_name, version], map: "ap_name_version_key") @@index([agent_name, is_active], map: "ap_name_active_idx") @@index([provider_type], map: "ap_provider_type_idx") @@map("agent_prompts") } model AgentRun { id BigInt @id @default(autoincrement()) project_id BigInt? novel_source_id BigInt? chapter_no Int? agent_name String @db.VarChar(100) prompt_version Int? provider_code String? @db.VarChar(100) model_name String? @db.VarChar(100) provider_log_id BigInt? input_json Json? output_json Json? output_text String? @db.LongText status String @default("running") @db.VarChar(50) quality_score Decimal? @db.Decimal(5, 2) error_code String? @db.VarChar(100) error_message String? @db.Text started_at DateTime? finished_at DateTime? created_at DateTime @default(now()) @@index([project_id, agent_name], map: "ar_project_agent_idx") @@index([novel_source_id, chapter_no], map: "ar_source_chapter_idx") @@index([status, created_at], map: "ar_status_created_idx") @@index([provider_log_id], map: "ar_provider_log_idx") @@map("agent_runs") } model CopyrightRecord { id BigInt @id @default(autoincrement()) project_id BigInt user_id BigInt authorization_type String @db.VarChar(50) statement_text String @db.Text ip String? @db.VarChar(80) user_agent String? @db.Text confirmed_at DateTime @default(now()) @@index([project_id]) @@index([user_id]) @@index([authorization_type]) @@map("copyright_records") } model StoryBible { id BigInt @id @default(autoincrement()) project_id BigInt title String? @db.VarChar(255) logline String? @db.Text main_plot String? @db.Text core_conflict String? @db.Text selling_points String? @db.Text tone String? @db.Text world_summary String? @db.Text ending_direction String? @db.Text taboo_rules String? @db.Text production_bible_json Json? quality_report_json Json? version Int @default(1) status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, status]) @@map("story_bibles") } model WorldBible { id BigInt @id @default(autoincrement()) project_id BigInt world_type String? @db.VarChar(100) setting_text String? @db.Text rules_text String? @db.Text power_system String? @db.Text social_structure String? @db.Text time_period String? @db.Text visual_rules String? @db.Text forbidden_rules String? @db.Text status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) @@index([project_id, status]) @@map("world_bibles") } model Character { id BigInt @id @default(autoincrement()) project_id BigInt story_character_id BigInt? global_character_id BigInt? global_character_look_version_id BigInt? global_character_asset_id BigInt? name String @db.VarChar(100) alias_names Json? role_type String @db.VarChar(50) gender_label String? @db.VarChar(50) age_group String? @db.VarChar(50) identity_desc String? @db.Text appearance_desc String? @db.Text face_desc String? @db.Text hair_desc String? @db.Text eye_desc String? @db.Text body_desc String? @db.Text costume_rules String? @db.Text special_props String? @db.Text personality_desc String? @db.Text speech_style String? @db.Text relationship_desc String? @db.Text character_arc String? @db.Text negative_rules String? @db.Text anchor_asset_id BigInt? wardrobe_variant String? @db.VarChar(100) voice_provider_code String? @db.VarChar(100) voice_model String? @db.VarChar(100) voice_id String? @db.VarChar(100) voice_style String? @db.Text performance_style String? @db.Text inherit_voice_from_global Boolean @default(false) inherit_digital_human_from_global Boolean @default(false) importance_level Int @default(0) status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, role_type]) @@index([project_id, status]) @@index([story_character_id]) @@index([global_character_id]) @@index([global_character_look_version_id]) @@index([global_character_asset_id]) @@map("characters") } model StoryCharacter { id BigInt @id @default(autoincrement()) project_id BigInt novel_source_id BigInt? story_bible_id BigInt? global_character_id BigInt? name String @db.VarChar(100) alias_names Json? role_type String @default("supporting") @db.VarChar(50) identity_desc String? @db.Text background_desc String? @db.Text personality_desc String? @db.Text relationship_json Json? character_arc String? @db.Text world_role_desc String? @db.Text negative_rules String? @db.Text source_type String @default("character_extraction") @db.VarChar(50) source_version_id BigInt? status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, status]) @@index([novel_source_id]) @@index([story_bible_id]) @@index([global_character_id]) @@index([source_type]) @@map("story_characters") } model CharacterExtractionVersion { id BigInt @id @default(autoincrement()) project_id BigInt story_bible_id BigInt? provider_log_id BigInt? source_type String @db.VarChar(50) source_label String? @db.VarChar(120) prompt_category String? @db.VarChar(100) prompt_version String? @db.VarChar(80) prompt_text String? @db.LongText provider_code String? @db.VarChar(100) model_name String? @db.VarChar(100) raw_text String? @db.LongText role_pool_plan_json Json? characters_json Json? quality_score Int? review_comment String? @db.Text status String @default("active") @db.VarChar(50) created_by_user_id BigInt? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, status]) @@index([story_bible_id]) @@index([provider_log_id]) @@index([source_type]) @@map("character_extraction_versions") } model GlobalCharacter { id BigInt @id @default(autoincrement()) name String @db.VarChar(100) display_name String? @db.VarChar(100) role_archetype String @default("lead") @db.VarChar(50) gender_label String? @db.VarChar(50) age_group String? @db.VarChar(50) identity_desc String? @db.Text appearance_desc String? @db.Text face_desc String? @db.Text hair_desc String? @db.Text eye_desc String? @db.Text body_desc String? @db.Text default_costume_rules String? @db.Text wardrobe_json Json? special_props String? @db.Text personality_desc String? @db.Text speech_style String? @db.Text voice_provider_code String? @db.VarChar(100) voice_model String? @db.VarChar(100) voice_id String? @db.VarChar(100) voice_style String? @db.Text performance_style String? @db.Text negative_rules String? @db.Text anchor_asset_id BigInt? voice_sample_asset_id BigInt? commercial_status String @default("internal_test") @db.VarChar(50) usage_scope String @default("internal") @db.VarChar(50) status String @default("active") @db.VarChar(50) created_by_user_id BigInt? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([status, role_archetype]) @@index([commercial_status]) @@index([created_by_user_id]) @@map("global_characters") } model GlobalCharacterAsset { id BigInt @id @default(autoincrement()) global_character_id BigInt look_version_id BigInt? asset_id BigInt? asset_type String @db.VarChar(50) source_type String @default("upload") @db.VarChar(50) source_label String? @db.VarChar(160) label String? @db.VarChar(100) prompt_text String? @db.Text negative_prompt String? @db.Text model_name String? @db.VarChar(160) seed String? @db.VarChar(100) resolution String? @db.VarChar(50) aspect_ratio String? @db.VarChar(50) cost_estimate Decimal? @db.Decimal(12, 4) cost_actual Decimal? @db.Decimal(12, 4) quality_score Decimal? @db.Decimal(5, 2) consistency_score Decimal? @db.Decimal(5, 2) face_similarity_score Decimal? @db.Decimal(5, 2) license_status String @default("internal_test") @db.VarChar(50) commercial_allowed Boolean @default(false) review_status String @default("pending") @db.VarChar(50) reviewer_note String? @db.Text is_primary Boolean @default(false) usage_count Int @default(0) metadata_json Json? status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) @@index([global_character_id, asset_type]) @@index([look_version_id]) @@index([source_type]) @@index([review_status]) @@index([asset_id]) @@map("global_character_assets") } model CharacterProviderBinding { id BigInt @id @default(autoincrement()) global_character_id BigInt look_version_id BigInt? source_asset_id BigInt? provider_code String @db.VarChar(100) provider_asset_type String @default("video_character_element") @db.VarChar(50) provider_element_id String @db.VarChar(191) element_name String @db.VarChar(160) element_description String? @db.Text source_duration Decimal? @db.Decimal(5, 2) voice_bound Boolean @default(false) voice_id String? @db.VarChar(160) voice_description String? @db.Text binding_version Int @default(1) validation_score Decimal? @db.Decimal(5, 2) validation_report_json Json? status String @default("candidate") @db.VarChar(50) is_primary Boolean @default(false) created_by_user_id BigInt? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([provider_code, provider_element_id], map: "cpb_provider_element_key") @@index([global_character_id, provider_code, status], map: "cpb_character_provider_status_idx") @@index([look_version_id], map: "cpb_look_version_idx") @@index([source_asset_id], map: "cpb_source_asset_idx") @@index([is_primary, status], map: "cpb_primary_status_idx") @@map("character_provider_bindings") } model GlobalCharacterLookVersion { id BigInt @id @default(autoincrement()) global_character_id BigInt version_name String @db.VarChar(160) style_type String? @db.VarChar(80) appearance_desc String? @db.Text hair_desc String? @db.Text makeup_desc String? @db.Text body_desc String? @db.Text costume_rules String? @db.Text color_palette String? @db.Text key_props String? @db.Text negative_rules String? @db.Text main_anchor_asset_id BigInt? status String @default("candidate") @db.VarChar(50) quality_score Decimal? @db.Decimal(5, 2) reviewer_comment String? @db.Text source_project_id BigInt? created_by_user_id BigInt? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([global_character_id, status]) @@index([main_anchor_asset_id]) @@index([source_project_id]) @@map("global_character_look_versions") } model CharacterImage { id BigInt @id @default(autoincrement()) project_id BigInt character_id BigInt asset_id BigInt? image_type String @db.VarChar(50) prompt_text String? @db.Text negative_prompt String? @db.Text is_anchor Boolean @default(false) prompt_quality_score Decimal? @db.Decimal(5, 2) quality_score Decimal? @db.Decimal(5, 2) status String @default("pending") @db.VarChar(50) created_at DateTime @default(now()) @@index([project_id]) @@index([character_id, image_type]) @@index([character_id, is_anchor]) @@map("character_images") } model CharacterImageQualityReview { id BigInt @id @default(autoincrement()) project_id BigInt character_id BigInt character_image_id BigInt asset_id BigInt image_type String @db.VarChar(80) review_round Int @default(1) review_mode String @default("post_generation_visual") @db.VarChar(80) threshold_score Decimal @default(96.00) @db.Decimal(5, 2) score Decimal? @db.Decimal(5, 2) grade String? @db.VarChar(20) passed Boolean @default(false) status String @default("pending") @db.VarChar(50) dimensions_json Json? strengths_json Json? issues_json Json? improvement_rules_json Json? character_observations_json Json? quality_gate_json Json? provider_log_id BigInt? provider_code String? @db.VarChar(100) model_name String? @db.VarChar(160) raw_text String? @db.LongText error_message String? @db.Text created_at DateTime @default(now()) @@index([project_id, created_at], map: "ciqr_project_created_idx") @@index([character_id, image_type], map: "ciqr_character_type_idx") @@index([character_image_id, review_round], map: "ciqr_image_round_idx") @@index([asset_id], map: "ciqr_asset_idx") @@index([image_type, passed], map: "ciqr_type_passed_idx") @@map("character_image_quality_reviews") } model CharacterMemory { id BigInt @id @default(autoincrement()) project_id BigInt character_id BigInt episode_id BigInt? memory_type String @db.VarChar(50) content String @db.Text created_at DateTime @default(now()) @@index([project_id, character_id]) @@index([project_id, episode_id]) @@index([memory_type]) @@map("character_memories") } model CharacterDesignVersion { id BigInt @id @default(autoincrement()) project_id BigInt character_id BigInt version_no Int prompt_text String? @db.Text negative_prompt String? @db.Text image_asset_id BigInt? notes String? @db.Text source String @default("workshop") @db.VarChar(50) is_final Boolean @default(false) created_by_user_id BigInt? created_at DateTime @default(now()) @@unique([character_id, version_no]) @@index([project_id, character_id]) @@index([character_id, is_final]) @@index([image_asset_id]) @@map("character_design_versions") } model CharacterPromptVersion { id BigInt @id @default(autoincrement()) project_id BigInt? character_id BigInt? global_character_id BigInt? look_version_id BigInt? version_no Int layer_code String @default("main_anchor") @db.VarChar(80) channel String @default("chatgpt_web") @db.VarChar(80) title String? @db.VarChar(160) source_type String @default("system_refresh") @db.VarChar(80) source_label String? @db.VarChar(160) prompt_engine_version String? @db.VarChar(80) prompt_text String @db.LongText negative_prompt String? @db.LongText model_name String? @db.VarChar(160) usage_note String? @db.Text quality_score Decimal? @db.Decimal(5, 2) review_comment String? @db.Text is_active Boolean @default(false) metadata_json Json? created_by_user_id BigInt? status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([character_id, version_no], map: "cpv_character_version_key") @@unique([global_character_id, version_no], map: "cpv_global_version_key") @@index([project_id], map: "cpv_project_idx") @@index([character_id, layer_code, channel], map: "cpv_character_layer_channel_idx") @@index([global_character_id, layer_code, channel], map: "cpv_global_layer_channel_idx") @@index([look_version_id], map: "cpv_look_version_idx") @@index([is_active, status], map: "cpv_active_status_idx") @@map("character_prompt_versions") } model CharacterPromptReview { id BigInt @id @default(autoincrement()) project_id BigInt task_id BigInt? character_id BigInt? global_character_id BigInt? prompt_version_id BigInt? layer_code String @db.VarChar(80) image_type String? @db.VarChar(80) review_round Int @default(1) review_mode String @default("api_preflight") @db.VarChar(80) prompt_engine_version String? @db.VarChar(80) threshold_score Decimal @default(92.00) @db.Decimal(5, 2) score Decimal? @db.Decimal(5, 2) passed Boolean @default(false) status String @default("pending") @db.VarChar(50) source_prompt String? @db.LongText optimized_prompt String? @db.LongText negative_prompt String? @db.LongText issues_json Json? suggestions_json Json? reusable_rules_json Json? quality_gate_json Json? provider_log_id BigInt? provider_code String? @db.VarChar(100) model_name String? @db.VarChar(160) raw_text String? @db.LongText error_message String? @db.Text created_at DateTime @default(now()) @@index([project_id, created_at], map: "cpr_project_created_idx") @@index([task_id], map: "cpr_task_idx") @@index([character_id, layer_code], map: "cpr_character_layer_idx") @@index([global_character_id, layer_code], map: "cpr_global_layer_idx") @@index([prompt_version_id], map: "cpr_prompt_version_idx") @@index([layer_code, passed], map: "cpr_layer_passed_idx") @@map("character_prompt_reviews") } model CharacterPromptOptimizationLesson { id BigInt @id @default(autoincrement()) scope_type String @default("global") @db.VarChar(50) layer_code String @db.VarChar(80) lesson_type String @default("prompt_rule") @db.VarChar(80) title String? @db.VarChar(160) rule_text String @db.Text prompt_engine_version String? @db.VarChar(80) source_review_id BigInt? source_character_id BigInt? source_prompt_version_id BigInt? quality_score Decimal? @db.Decimal(5, 2) usage_count Int @default(0) metadata_json Json? status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([scope_type, layer_code, status], map: "cpol_scope_layer_status_idx") @@index([source_review_id], map: "cpol_review_idx") @@index([source_character_id], map: "cpol_character_idx") @@map("character_prompt_optimization_lessons") } model CharacterState { id BigInt @id @default(autoincrement()) project_id BigInt character_id BigInt state_code String @db.VarChar(80) display_name String? @db.VarChar(120) description String? @db.Text wardrobe_rules String? @db.Text emotion_rules String? @db.Text prompt_suffix String? @db.Text negative_rules String? @db.Text reference_asset_id BigInt? status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([character_id, state_code]) @@index([project_id, character_id]) @@index([status]) @@index([reference_asset_id]) @@map("character_states") } model Episode { id BigInt @id @default(autoincrement()) project_id BigInt episode_no Int source_chapter_ids Json? title String? @db.VarChar(255) summary String? @db.Text opening_hook String? @db.Text middle_conflict String? @db.Text ending_hook String? @db.Text target_duration Int? status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([project_id, episode_no]) @@index([project_id, status]) @@map("episodes") } model EpisodeScript { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt script_text String? @db.LongText narration_text String? @db.LongText dialogue_json Json? version Int @default(1) status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id]) @@index([episode_id, version]) @@map("episode_scripts") } model StoryboardShot { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt shot_no Int scene_name String? @db.VarChar(255) location_desc String? @db.Text characters_json Json? visual_desc String? @db.Text action_desc String? @db.Text dialogue_text String? @db.Text narration_text String? @db.Text camera_motion String? @db.VarChar(100) effect_type String? @db.VarChar(100) duration Decimal? @db.Decimal(6, 2) scene_type String? @db.VarChar(50) importance_score Int? emotion_score Int? action_score Int? route_tier String? @db.VarChar(50) prompt_text String? @db.Text negative_prompt String? @db.Text live_action_desc String? @db.Text actor_action String? @db.Text camera_instruction String? @db.Text performance_instruction String? @db.Text video_prompt String? @db.Text transition_to_next String? @db.VarChar(50) transition_to_next_duration Decimal? @db.Decimal(5, 2) transition_to_next_reason String? @db.Text active_generation_plan_id BigInt? keyframe_asset_id BigInt? video_clip_asset_id BigInt? video_status String? @db.VarChar(50) status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([episode_id, shot_no]) @@index([project_id, episode_id, shot_no]) @@index([project_id, status]) @@index([scene_type]) @@index([route_tier]) @@index([active_generation_plan_id], map: "ss_active_generation_plan_idx") @@map("storyboard_shots") } model ShotGenerationPlan { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt shot_id BigInt revision Int plan_version String @db.VarChar(80) plan_hash String @db.VarChar(64) status String @default("frozen") @db.VarChar(50) source_engine_version String @db.VarChar(50) provider_code String @db.VarChar(100) provider_id BigInt? capability_registry_version_id BigInt? parameter_schema_version_id BigInt? pricing_version_id BigInt? model_name String? @db.VarChar(160) endpoint String? @db.VarChar(255) capability_version String? @db.VarChar(100) route_tier String? @db.VarChar(50) effective_mode String? @db.VarChar(30) resolution_recommendation String? @db.VarChar(30) effective_generation_resolution String? @db.VarChar(30) aspect_ratio String? @db.VarChar(30) duration Decimal? @db.Decimal(6, 2) sound_enabled Boolean @default(true) multi_shot Boolean @default(false) native_4k_candidate Boolean @default(false) project_native_4k_enabled Boolean @default(false) required_assets_json Json? element_plan_json Json? voice_plan_json Json? keyframe_plan_json Json? video_request_json Json? router_decision_json Json quality_policy_json Json retry_policy_json Json fallback_chain_json Json cost_policy_json Json? provider_snapshot_json Json? prompt_snapshot_json Json? frozen_by_user_id BigInt? frozen_at DateTime @default(now()) created_at DateTime @default(now()) @@unique([shot_id, revision], map: "sgp_shot_revision_key") @@unique([shot_id, plan_hash], map: "sgp_shot_hash_key") @@index([project_id, episode_id, shot_id], map: "sgp_project_episode_shot_idx") @@index([provider_code, capability_version], map: "sgp_provider_capability_idx") @@index([capability_registry_version_id], map: "sgp_capability_registry_idx") @@index([parameter_schema_version_id], map: "sgp_parameter_schema_idx") @@index([pricing_version_id], map: "sgp_pricing_version_idx") @@index([status, created_at], map: "sgp_status_created_idx") @@map("shot_generation_plans") } model ShotImage { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt? shot_id BigInt generation_plan_id BigInt? asset_id BigInt? image_type String @default("preview") @db.VarChar(50) prompt_text String? @db.Text negative_prompt String? @db.Text quality_score Decimal? @db.Decimal(5, 2) status String @default("pending") @db.VarChar(50) created_at DateTime @default(now()) @@index([project_id, episode_id]) @@index([shot_id, image_type]) @@index([generation_plan_id], map: "si_generation_plan_idx") @@map("shot_images") } model ActorProfile { id BigInt @id @default(autoincrement()) project_id BigInt character_id BigInt actor_desc String? @db.Text appearance_rules String? @db.Text wardrobe_rules String? @db.Text performance_style String? @db.Text voice_style String? @db.Text reference_asset_ids Json? anchor_asset_id BigInt? status String @default("draft") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([project_id, character_id]) @@index([project_id, status]) @@index([character_id]) @@map("actor_profiles") } model VideoClip { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt shot_id BigInt generation_plan_id BigInt? provider_id BigInt? input_asset_id BigInt? output_asset_id BigInt? duration Decimal? @db.Decimal(6, 2) prompt_text String? @db.Text status String @default("pending") @db.VarChar(50) cost_actual Decimal? @db.Decimal(12, 4) retry_count Int @default(0) quality_status String? @db.VarChar(50) quality_score Decimal? @db.Decimal(5, 2) quality_issues Json? engine_version String? @db.VarChar(80) asset_lock_json Json? motion_control_json Json? camera_control_json Json? composer_usage_json Json? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, episode_id]) @@index([shot_id, status]) @@index([provider_id]) @@index([engine_version]) @@index([generation_plan_id], map: "vc_generation_plan_idx") @@map("video_clips") } model PlotMemory { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt? chapter_id BigInt? memory_type String @db.VarChar(50) content String @db.Text importance_level Int @default(0) status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) @@index([project_id, episode_id]) @@index([project_id, memory_type]) @@map("plot_memories") } model PlotThread { id BigInt @id @default(autoincrement()) project_id BigInt thread_name String @db.VarChar(255) thread_type String @db.VarChar(80) description String? @db.Text start_episode_no Int? expected_resolve_episode_no Int? resolved_episode_no Int? status String @default("open") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, status]) @@index([project_id, thread_type]) @@map("plot_threads") } model ContinuityCheck { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt? check_type String @db.VarChar(80) result_status String @db.VarChar(50) issue_text String? @db.Text suggestion_text String? @db.Text created_at DateTime @default(now()) @@index([project_id, episode_id]) @@index([result_status]) @@map("continuity_checks") } model Asset { id BigInt @id @default(autoincrement()) user_id BigInt? project_id BigInt? asset_type String @db.VarChar(50) file_path String @db.VarChar(500) file_url String? @db.VarChar(500) mime_type String? @db.VarChar(100) width Int? height Int? duration Decimal? @db.Decimal(10, 2) size BigInt? hash String? @db.VarChar(128) display_name String? @db.VarChar(255) selection_status String @default("candidate") @db.VarChar(30) selection_note String? @db.Text metadata_json Json? visibility String @default("private") @db.VarChar(30) status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) @@index([project_id, asset_type]) @@index([project_id, selection_status]) @@index([user_id, asset_type]) @@index([hash]) @@map("assets") } model RenderTask { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt? shot_id BigInt? generation_plan_id BigInt? task_type String @db.VarChar(80) provider_id BigInt? status String @default("pending") @db.VarChar(50) input_json Json? input_hash String? @db.VarChar(128) idempotency_key String? @unique @db.VarChar(191) output_asset_id BigInt? provider_request_id String? @db.VarChar(255) retry_count Int @default(0) max_retry Int @default(0) cost_estimate Decimal? @db.Decimal(12, 4) cost_actual Decimal? @db.Decimal(12, 4) error_code String? @db.VarChar(100) error_message String? @db.Text created_at DateTime @default(now()) started_at DateTime? finished_at DateTime? @@index([project_id, status]) @@index([task_type, status]) @@index([project_id, episode_id]) @@index([input_hash]) @@index([generation_plan_id], map: "rt_generation_plan_idx") @@map("render_tasks") } model ProviderConfig { id BigInt @id @default(autoincrement()) provider_type String @db.VarChar(80) provider_code String @db.VarChar(100) display_name String? @db.VarChar(100) mode String @default("mock") @db.VarChar(50) model_name String? @db.VarChar(100) config_json Json? fallback_provider_id BigInt? is_enabled Boolean @default(true) priority Int @default(0) rate_limit_json Json? cost_rule_json Json? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@unique([provider_type, provider_code]) @@index([provider_type, is_enabled]) @@map("provider_configs") } model ModelCapabilityVersion { id BigInt @id @default(autoincrement()) provider_type String @db.VarChar(80) provider_code String @db.VarChar(100) model_name String? @db.VarChar(160) revision Int version_key String @db.VarChar(160) content_hash String @db.VarChar(64) status String @default("published") @db.VarChar(50) capability_json Json source_json Json? effective_at DateTime @default(now()) created_by_user_id BigInt? created_at DateTime @default(now()) @@unique([provider_type, provider_code, revision], map: "mcv_provider_revision_key") @@unique([provider_type, provider_code, content_hash], map: "mcv_provider_hash_key") @@index([provider_code, status, effective_at], map: "mcv_provider_status_effective_idx") @@map("model_capability_versions") } model ModelParameterSchemaVersion { id BigInt @id @default(autoincrement()) provider_type String @db.VarChar(80) provider_code String @db.VarChar(100) model_name String? @db.VarChar(160) revision Int version_key String @db.VarChar(160) content_hash String @db.VarChar(64) status String @default("published") @db.VarChar(50) schema_json Json source_json Json? effective_at DateTime @default(now()) created_by_user_id BigInt? created_at DateTime @default(now()) @@unique([provider_type, provider_code, revision], map: "mpsv_provider_revision_key") @@unique([provider_type, provider_code, content_hash], map: "mpsv_provider_hash_key") @@index([provider_code, status, effective_at], map: "mpsv_provider_status_effective_idx") @@map("model_parameter_schema_versions") } model ModelPricingVersion { id BigInt @id @default(autoincrement()) provider_type String @db.VarChar(80) provider_code String @db.VarChar(100) model_name String? @db.VarChar(160) revision Int version_key String @db.VarChar(160) content_hash String @db.VarChar(64) status String @default("published") @db.VarChar(50) pricing_json Json source_json Json? effective_at DateTime @default(now()) created_by_user_id BigInt? created_at DateTime @default(now()) @@unique([provider_type, provider_code, revision], map: "mpv_provider_revision_key") @@unique([provider_type, provider_code, content_hash], map: "mpv_provider_hash_key") @@index([provider_code, status, effective_at], map: "mpv_provider_status_effective_idx") @@map("model_pricing_versions") } model ProviderLog { id BigInt @id @default(autoincrement()) provider_id BigInt? task_id BigInt? project_id BigInt? provider_type String @db.VarChar(80) provider_code String? @db.VarChar(100) model_name String? @db.VarChar(100) request_json Json? response_json Json? input_size Int? output_size Int? cost_estimate Decimal? @db.Decimal(12, 4) cost_actual Decimal? @db.Decimal(12, 4) status String @default("success") @db.VarChar(50) error_code String? @db.VarChar(100) error_message String? @db.Text started_at DateTime? finished_at DateTime? created_at DateTime @default(now()) @@index([provider_type, status]) @@index([project_id]) @@index([task_id]) @@index([created_at]) @@map("provider_logs") } model Order { id BigInt @id @default(autoincrement()) user_id BigInt project_id BigInt? order_no String @unique @db.VarChar(100) package_code String? @db.VarChar(100) amount Decimal @default(0) @db.Decimal(12, 2) currency String @default("CNY") @db.VarChar(20) payment_method String? @db.VarChar(50) payment_status String @default("pending") @db.VarChar(50) paid_at DateTime? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([user_id, payment_status]) @@index([project_id]) @@map("orders") } model QuotaAccount { id BigInt @id @default(autoincrement()) user_id BigInt @unique total_quota Decimal @default(0) @db.Decimal(12, 2) available_quota Decimal @default(0) @db.Decimal(12, 2) frozen_quota Decimal @default(0) @db.Decimal(12, 2) used_quota Decimal @default(0) @db.Decimal(12, 2) status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([status]) @@map("quota_accounts") } model QuotaLog { id BigInt @id @default(autoincrement()) user_id BigInt project_id BigInt? task_id BigInt? change_type String @db.VarChar(50) amount Decimal @db.Decimal(12, 2) balance_after Decimal? @db.Decimal(12, 2) reason String? @db.VarChar(255) metadata_json Json? created_at DateTime @default(now()) @@index([user_id, created_at]) @@index([project_id]) @@index([task_id]) @@map("quota_logs") } model RevisionRequest { id BigInt @id @default(autoincrement()) project_id BigInt user_id BigInt revision_type String @db.VarChar(50) target_type String? @db.VarChar(80) target_id BigInt? description String @db.Text status String @default("pending") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, status]) @@index([user_id, status]) @@map("revision_requests") } model ContentReview { id BigInt @id @default(autoincrement()) project_id BigInt? user_id BigInt? target_type String @db.VarChar(80) target_id BigInt? review_type String @db.VarChar(80) result_status String @default("pending") @db.VarChar(50) risk_level String? @db.VarChar(50) issue_text String? @db.Text suggestion_text String? @db.Text reviewer_id BigInt? reviewed_at DateTime? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, result_status]) @@index([target_type, target_id]) @@index([review_type, result_status]) @@map("content_reviews") } model CaseShowcase { id BigInt @id @default(autoincrement()) project_id BigInt user_id BigInt? title String @db.VarChar(255) cover_asset_id BigInt? video_asset_id BigInt? authorization_status String @default("pending") @db.VarChar(50) visibility String @default("private") @db.VarChar(30) sort_order Int @default(0) published_at DateTime? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([visibility, sort_order]) @@index([project_id]) @@map("case_showcases") } model HitAnalysisCase { id BigInt @id @default(autoincrement()) title String @db.VarChar(255) source_platform String? @db.VarChar(100) source_url String? @db.VarChar(500) content_type String @default("short_drama") @db.VarChar(80) genre String? @db.VarChar(100) language String @default("zh-CN") @db.VarChar(30) target_audience String? @db.VarChar(255) duration_seconds Int? episode_count Int? tags_json Json? metrics_json Json? transcript_text String? @db.LongText summary_text String? @db.Text analysis_json Json? diagnosis_score Decimal? @db.Decimal(5, 2) status String @default("draft") @db.VarChar(50) created_by_user_id BigInt? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([source_platform]) @@index([genre, status]) @@index([status, diagnosis_score]) @@index([created_at]) @@map("hit_analysis_cases") } model HitAnalysisSegment { id BigInt @id @default(autoincrement()) case_id BigInt segment_no Int start_second Int? end_second Int? scene_type String? @db.VarChar(80) hook_type String? @db.VarChar(100) emotion String? @db.VarChar(80) conflict_type String? @db.VarChar(100) plot_function String? @db.VarChar(120) visual_strategy String? @db.VarChar(120) dialogue_pattern String? @db.VarChar(120) camera_notes String? @db.Text importance_score Int? emotion_score Int? action_score Int? tags_json Json? summary_text String? @db.Text prompt_seed String? @db.Text created_at DateTime @default(now()) @@unique([case_id, segment_no]) @@index([case_id]) @@index([scene_type]) @@index([hook_type]) @@map("hit_analysis_segments") } model CreativePattern { id BigInt @id @default(autoincrement()) source_case_id BigInt? pattern_type String @db.VarChar(80) title String @db.VarChar(255) genre String? @db.VarChar(100) language String @default("zh-CN") @db.VarChar(30) description String? @db.Text structure_json Json? prompt_template String? @db.Text negative_prompt String? @db.Text tags_json Json? usage_count Int @default(0) effectiveness_score Decimal? @db.Decimal(5, 2) status String @default("active") @db.VarChar(50) created_by_user_id BigInt? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([pattern_type, status]) @@index([genre, status]) @@index([source_case_id]) @@map("creative_patterns") } model ProjectCreativePattern { id BigInt @id @default(autoincrement()) project_id BigInt creative_pattern_id BigInt source String @default("user_selected") @db.VarChar(50) snapshot_json Json? sort_order Int @default(0) created_at DateTime @default(now()) @@unique([project_id, creative_pattern_id]) @@index([project_id, sort_order]) @@index([creative_pattern_id]) @@map("project_creative_patterns") } model ProjectPipelineConfig { id BigInt @id @default(autoincrement()) project_id BigInt @unique ip_isolation_enabled Boolean @default(true) video_engine_enabled Boolean @default(true) scene_composer_enabled Boolean @default(false) default_generation_mode String @default("single_model") @db.VarChar(50) video_engine_version String @default("video_engine_v1") @db.VarChar(80) scene_composer_version String @default("scene_composer_plan_v2") @db.VarChar(80) ip_rules_json Json? video_engine_config_json Json? scene_composer_config_json Json? created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([scene_composer_enabled]) @@index([default_generation_mode]) @@map("project_pipeline_configs") } model ProjectVisualAsset { id BigInt @id @default(autoincrement()) project_id BigInt user_id BigInt asset_id BigInt? asset_kind String @db.VarChar(50) asset_type String @db.VarChar(80) name String @db.VarChar(160) label String? @db.VarChar(160) ownership_type String @default("shared_story") @db.VarChar(50) owner_character_id BigInt? source_type String @default("manual") @db.VarChar(80) source_label String? @db.VarChar(160) aliases_json Json? allowed_roles_json Json? detected_from String? @db.VarChar(160) importance Int @default(50) visual_lock String? @db.LongText key_objects_json Json? prompt_block String? @db.LongText anchor_prompt String? @db.LongText prompt_text String? @db.LongText negative_prompt String? @db.LongText reference_images_json Json? anchor_images_json Json? render_variants_json Json? linked_assets_json Json? reuse_rule String? @db.LongText story_scope String? @db.VarChar(120) version_note String? @db.LongText notes String? @db.LongText usage_tags_json Json? quality_score Decimal? @db.Decimal(5, 2) is_primary Boolean @default(false) metadata_json Json? status String @default("active") @db.VarChar(50) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([project_id, asset_kind, status], map: "pva_project_kind_status_idx") @@index([project_id, asset_type], map: "pva_project_type_idx") @@index([project_id, ownership_type], map: "pva_project_ownership_idx") @@index([project_id, status, importance], map: "pva_project_status_importance_idx") @@index([owner_character_id], map: "pva_owner_character_idx") @@index([asset_id], map: "pva_asset_idx") @@index([user_id, asset_kind], map: "pva_user_kind_idx") @@map("project_visual_assets") } model AnalyticsEvent { id BigInt @id @default(autoincrement()) project_id BigInt episode_id BigInt? event_type String @db.VarChar(80) platform String? @db.VarChar(80) metric_json Json? created_at DateTime @default(now()) @@index([project_id]) @@index([episode_id]) @@index([event_type, created_at]) @@map("analytics_events") } model SystemConfig { id BigInt @id @default(autoincrement()) config_key String @unique @db.VarChar(191) config_value Json? description String? @db.Text is_public Boolean @default(false) created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([is_public]) @@map("system_configs") } model OperationLog { id BigInt @id @default(autoincrement()) user_id BigInt? operator_role String? @db.VarChar(50) action String @db.VarChar(100) target_type String? @db.VarChar(80) target_id BigInt? ip String? @db.VarChar(80) user_agent String? @db.Text metadata_json Json? created_at DateTime @default(now()) @@index([user_id, created_at]) @@index([target_type, target_id]) @@index([action, created_at]) @@map("operation_logs") }