import Foundation struct ProjectItem: Codable, Identifiable, Sendable { let id: String let name: String let created_at: String } struct RequirementItem: Codable, Identifiable, Sendable { let id: String let project_id: String let name: String let status: String let current_version: Int let created_at: String let source_path: String let extraction: RequirementExtraction? let metadata_ready: Bool let metadata_complete: Bool let metadata_missing_tables: [String] } struct RequirementExtraction: Codable, Sendable { let requirement_name: String let tasks: [ExtractedTask] let open_questions: [String] } struct ExtractedTask: Codable, Identifiable, Sendable { var id: String { name + targets.joined(separator: "|") } let name: String let sources: [String] let targets: [String] let field_mappings: [JSONValue] let rules: [String] } struct CaseCount: Codable, Identifiable, Sendable { var id: String { status } let status: String let count: Int } struct TestCaseItem: Codable, Identifiable, Sendable { let id: String let requirement_id: String let requirement_name: String let name: String let table_name: String let category: String let status: String let version: Int let fields: [String] let sql: String let assertions: [CaseAssertion] let validation_errors: [String] let created_at: String } struct CaseAssertion: Codable, Sendable { let type: String let actual: String? let expected: JSONValue? let minimum: Double? let maximum: Double? } enum JSONValue: Codable, Sendable, CustomStringConvertible { case string(String) case number(Double) case boolean(Bool) case object([String: JSONValue]) case array([JSONValue]) case null init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if container.decodeNil() { self = .null } else if let value = try? container.decode(Bool.self) { self = .boolean(value) } else if let value = try? container.decode(Double.self) { self = .number(value) } else if let value = try? container.decode(String.self) { self = .string(value) } else if let value = try? container.decode([String: JSONValue].self) { self = .object(value) } else { self = .array(try container.decode([JSONValue].self)) } } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .string(let value): try container.encode(value) case .number(let value): try container.encode(value) case .boolean(let value): try container.encode(value) case .object(let value): try container.encode(value) case .array(let value): try container.encode(value) case .null: try container.encodeNil() } } var description: String { switch self { case .string(let value): value case .number(let value): value.rounded() == value ? String(Int(value)) : String(value) case .boolean(let value): String(value) case .object(let value): value.map { "\($0.key)=\($0.value)" }.sorted().joined(separator: ", ") case .array(let value): value.map(\.description).joined(separator: ", ") case .null: "null" } } } struct MetadataColumn: Codable, Identifiable, Sendable { var id: Int { cid } let cid: Int let name: String let type: String let notNull: Int let defaultValue: String? let pk: Int var ordinalText: String { String(cid + 1) } var nullableText: String { notNull == 0 ? "是" : "否" } var defaultText: String { defaultValue ?? "—" } var primaryKeyText: String { pk > 0 ? "是" : "—" } enum CodingKeys: String, CodingKey { case cid, name, type, pk case notNull = "notnull" case defaultValue = "dflt_value" } } struct MetadataTableItem: Codable, Identifiable, Sendable { let id: String let requirement_id: String let requirement_name: String let database_name: String let name: String let type: String let row_count: Int let columns: [MetadataColumn] } struct RunItem: Codable, Identifiable, Sendable { let id: String let requirement_id: String let requirement_version: Int let status: String let batch_id: String let biz_date: String? let started_at: String let finished_at: String? } struct MetricItem: Codable, Identifiable, Sendable { let id: Int let requirement_id: String let table_name: String let field_name: String? let batch_id: String let biz_date: String? let metric_type: String let metric_value: Double? let metric_json: String? let definition_version: Int let collected_at: String } struct ReportItem: Codable, Identifiable, Sendable { let id: String let run_id: String let requirement_id: String let requirement_version: Int let status: String let format: String let file_path: String let content: String let created_at: String } struct CaseResultItem: Codable, Identifiable, Sendable { let id: Int let run_id: String let case_id: String let requirement_id: String let case_name: String let status: String let actual_json: String? let assertion_json: String let sample_json: String? let error_message: String? let duration_ms: Int let created_at: String } struct FailureAnalysis: Codable, Sendable { let summary: String let suspected_layer: String let root_cause: String let evidence: [String] let recommendations: [String] let validation_sql: [String] let confidence: String } struct FailureAnalysisItem: Codable, Identifiable, Sendable { let id: Int let result_id: Int let run_id: String let case_id: String let requirement_id: String let status: String let created_at: String let analysis: FailureAnalysis } struct CaseAgentMessageItem: Codable, Identifiable, Sendable { let id: Int let requirement_id: String let role: String let content: String let operation_json: String? let created_at: String } struct CaseChatProgressEvent: Codable, Identifiable, Sendable { var id: Int { sequence } let type: String let sequence: Int let phase: String let status: String let title: String let detail: String let timestamp: String } struct TestRunProgressEvent: Codable, Identifiable, Sendable { var id: Int { sequence } let type: String let sequence: Int let event: String let run_id: String? let case_id: String? let case_name: String? let status: String let index: Int? let total: Int? let duration_ms: Int? let error: String? let detail: String? let timestamp: String } struct CaseReviewEventItem: Codable, Identifiable, Sendable { let id: Int let case_id: String let requirement_id: String let case_version: Int let decision: String let comment: String? let created_at: String } struct Dashboard: Codable, Sendable { let projects: [ProjectItem] let requirements: [RequirementItem] let cases: [CaseCount] let case_items: [TestCaseItem] let metadata: [MetadataTableItem] let runs: [RunItem] let metrics: [MetricItem] let reports: [ReportItem] let result_items: [CaseResultItem] let failure_analyses: [FailureAnalysisItem] let case_agent_messages: [CaseAgentMessageItem] let case_review_events: [CaseReviewEventItem] static let empty = Dashboard( projects: [], requirements: [], cases: [], case_items: [], metadata: [], runs: [], metrics: [], reports: [], result_items: [], failure_analyses: [], case_agent_messages: [], case_review_events: [] ) }