""" ThinkStorm Data Models & Enums Defines lifecycle states, operational entities, and schema types. """ from enum import Enum from dataclasses import dataclass, field from typing import Optional, List, Dict, Any from datetime import datetime class LifecycleState(str, Enum): SUBMITTED = "SUBMITTED" AVAILABLE = "AVAILABLE" CLAIMED = "CLAIMED" ACTIVE = "ACTIVE" COMPLETED = "COMPLETED" ABANDONED = "ABANDONED" RETIRED = "RETIRED" QUARANTINED = "QUARANTINED" REJECTED = "REJECTED" DUPLICATE = "DUPLICATE" TRASHED = "TRASHED" class ProcessingState(str, Enum): IDLE = "IDLE" QUEUED = "QUEUED" PROCESSING = "PROCESSING" PARTIAL = "PARTIAL" ERROR = "ERROR" class URLSafetyState(str, Enum): PENDING = "PENDING" CHECKING = "CHECKING" SAFE = "SAFE" SUSPICIOUS = "SUSPICIOUS" MALICIOUS = "MALICIOUS" UNKNOWN = "UNKNOWN" ERROR = "ERROR" class AutomationPolicy(str, Enum): APPROVED = "APPROVED" BLOCKED = "BLOCKED" REQUIRES_REVIEW = "REQUIRES_REVIEW" class WorkTrackState(str, Enum): PLANNED = "PLANNED" ACTIVE = "ACTIVE" PAUSED = "PAUSED" COMPLETED = "COMPLETED" ABANDONED = "ABANDONED" RETIRED = "RETIRED" class UserRole(str, Enum): ANONYMOUS = "ANONYMOUS" USER = "USER" ADMIN = "ADMIN" class ProcessorStatus(str, Enum): PENDING = "PENDING" RUNNING = "RUNNING" COMPLETED = "COMPLETED" FAILED = "FAILED" CANCELLED = "CANCELLED" @dataclass class User: id: int username: str password_hash: str role: UserRole = UserRole.USER created_at: str = "" @dataclass class IdeaURL: id: Optional[int] idea_id: str url: str safety_state: URLSafetyState = URLSafetyState.PENDING automation_policy: AutomationPolicy = AutomationPolicy.REQUIRES_REVIEW virustotal_data: Dict[str, Any] = field(default_factory=dict) admin_review_required: bool = False reviewed_by: Optional[str] = None reviewed_at: Optional[str] = None decision: Optional[str] = None @dataclass class Idea: id: str # e.g. TS-0001 original_text: str submitted_at: str title: str = "" summary: str = "" categories: List[str] = field(default_factory=list) tags: List[str] = field(default_factory=list) lifecycle_state: LifecycleState = LifecycleState.SUBMITTED processing_state: ProcessingState = ProcessingState.IDLE enrichment_level: int = 0 claimed_by: Optional[str] = None claimed_at: Optional[str] = None released_at: Optional[str] = None previous_lifecycle_state: Optional[str] = None trashed_at: Optional[str] = None profile_id: Optional[str] = None profile_version: int = 1 opengist_id: Optional[str] = None opengist_url: Optional[str] = None gitea_repo_name: Optional[str] = None gitea_repo_url: Optional[str] = None created_at: str = "" updated_at: str = "" urls: List[IdeaURL] = field(default_factory=list) relationships: List[Dict[str, Any]] = field(default_factory=list) submission_image: Optional[Dict[str, Any]] = None source_channel: str = "web" source_sender_uuid: Optional[str] = None source_group_id: Optional[str] = None source_event_id: Optional[str] = None @dataclass class SubmittedImage: raw_bytes: bytes filename: str content_type: str source: str = "web" # "web" | "signal" @dataclass class IdeaSubmission: text: str source: str = "web" # "web" | "signal" image: Optional[SubmittedImage] = None sender_uuid: Optional[str] = None sender_number: Optional[str] = None sender_name: Optional[str] = None group_id: Optional[str] = None message_id: Optional[str] = None event_id: Optional[str] = None reply_to: Optional[str] = None received_at: Optional[str] = None @dataclass class WorkTrackOutput: id: Optional[int] work_track_id: str name: str artifact_path: str content: str version: int = 1 is_current: bool = True model_used: Optional[str] = None opengist_file: Optional[str] = None created_at: str = "" updated_at: str = "" @dataclass class WorkTrack: id: str # e.g. WT-0001 idea_id: str work_type_id: str # ARTICLE, BLOG_ENTRY, CODING_PROJECT, YOUTUBE_VIDEO name: str state: WorkTrackState = WorkTrackState.PLANNED workflow_id: str = "" model_override: Optional[str] = None created_at: str = "" started_at: Optional[str] = None completed_at: Optional[str] = None outputs: List[WorkTrackOutput] = field(default_factory=list) external_resources: List[Dict[str, Any]] = field(default_factory=list) @dataclass class PromptVersion: id: Optional[int] prompt_definition_id: str version: int system_prompt: str user_prompt_template: str applies_to: Dict[str, Any] = field(default_factory=dict) model_policy: str = "reasoning" expected_outputs: List[str] = field(default_factory=list) prompt_hash: str = "" created_by: str = "system" created_at: str = "" @dataclass class PromptDefinition: id: str # e.g. prior-art-software name: str stage: str description: str current_version: int = 1 enabled: bool = True created_at: str = "" versions: List[PromptVersion] = field(default_factory=list) @dataclass class PromptProfile: id: str # e.g. software-idea-v1 name: str description: str prompt_assignments: Dict[str, str] = field(default_factory=dict) # stage -> prompt_id@version is_default: bool = False created_at: str = "" @dataclass class ProcessorRun: id: str # e.g. RUN-0001 idea_id: str work_track_id: Optional[str] processor_name: str stage: str prompt_id: Optional[str] prompt_version: Optional[int] prompt_hash: Optional[str] model_policy: str resolved_provider: str resolved_model: str input_tokens: int = 0 output_tokens: int = 0 total_tokens: int = 0 started_at: str = "" completed_at: Optional[str] = None duration_ms: int = 0 output_artifact: Optional[str] = None output_data: Dict[str, Any] = field(default_factory=dict) error_message: Optional[str] = None status: ProcessorStatus = ProcessorStatus.PENDING @dataclass class ServiceConfig: id: str name: str endpoint: str api_key_masked: str enabled: bool config_json: Dict[str, Any] = field(default_factory=dict) last_tested_at: Optional[str] = None health_status: str = "UNKNOWN" last_error: Optional[str] = None @dataclass class AuditEvent: id: Optional[int] user_id: str action: str entity_type: str entity_id: str details: Dict[str, Any] created_at: str = ""