package freedoc import ( "errors" "time" ) var ( ErrNotFound = errors.New("freeform document not found") ErrForbidden = errors.New("permission denied to access document") ErrConflict = errors.New("optimistic concurrency conflict: version or sha mismatch") ErrInvalidParam = errors.New("invalid parameter") ErrMessageNotExportable = errors.New("chat message is not exportable or content is empty") ) // FreeformDocument 自由私密/共享文档元数据 type FreeformDocument struct { DocID string `json:"doc_id"` ProjectID int64 `json:"project_id"` OwnerUserID int `json:"owner_user_id"` SourceMessageID *int64 `json:"source_message_id,omitempty"` SourceContentSHA256 string `json:"source_content_sha256"` ClientKey *string `json:"client_key,omitempty"` Title string `json:"title"` GovernanceMode string `json:"governance_mode"` // 恒为 'freeform' Space string `json:"space"` // 'my_private' | 'project_shared' | 'trash' CurrentVersionID int `json:"current_version_id"` CurrentSHA256 string `json:"current_sha256"` // 上传附件注册时持久化的源文件元数据;非上传文档恒为零值。 SourceFilename string `json:"source_filename,omitempty"` SourceMimeType string `json:"source_mime_type,omitempty"` SourceSizeBytes int64 `json:"source_size_bytes,omitempty"` SourceAssetID int64 `json:"source_asset_id,omitempty"` IsDeleted bool `json:"is_deleted"` DeletedAt *time.Time `json:"deleted_at,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // FreeformDocumentVersion 自由文档历史版本快照 type FreeformDocumentVersion struct { ID int64 `json:"id"` DocID string `json:"doc_id"` VersionNo int `json:"version_no"` ContentSHA256 string `json:"content_sha256"` ContentMarkdown string `json:"content_markdown"` CreatedBy int `json:"created_by"` ChangeSummary string `json:"change_summary"` CreatedAt time.Time `json:"created_at"` } // FreeformDocDetail 自由文档详情(含当前版本 Markdown 正文) type FreeformDocDetail struct { Document FreeformDocument `json:"document"` Content string `json:"content_markdown"` } // FreeformDocSummary 列表项概要 type FreeformDocSummary struct { DocID string `json:"doc_id"` ProjectID int64 `json:"project_id"` OwnerUserID int `json:"owner_user_id"` Title string `json:"title"` Space string `json:"space"` CurrentVersionID int `json:"current_version_id"` CurrentSHA256 string `json:"current_sha256"` // 上传附件注册时持久化的源文件元数据;非上传文档恒为零值。 SourceFilename string `json:"source_filename,omitempty"` SourceMimeType string `json:"source_mime_type,omitempty"` SourceSizeBytes int64 `json:"source_size_bytes,omitempty"` SourceAssetID int64 `json:"source_asset_id,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // CreateFromMessageRequest 从单条消息保存到私密文档请求 type CreateFromMessageRequest struct { MessageID int64 `json:"message_id"` ProjectID int64 `json:"project_id"` Title string `json:"title,omitempty"` ExpectedSHA256 string `json:"expected_sha256,omitempty"` } // CreateFreeformDocRequest 直接创建空白/自定义自由文档请求(上传附件即时注册事实源) type CreateFreeformDocRequest struct { ProjectID int64 `json:"project_id"` Title string `json:"title"` ContentMarkdown string `json:"content_markdown"` Space string `json:"space,omitempty"` // 默认 'my_private' // ClientKey 可选幂等键(如 doc-upload-{ts}-{idx}),同用户重复提交返回已有文档 ClientKey string `json:"client_key,omitempty"` // 可选上传源文件元数据:换设备/共享后恢复文件预览与路由的事实源。 SourceFilename string `json:"source_filename,omitempty"` SourceMimeType string `json:"source_mime_type,omitempty"` SourceSizeBytes int64 `json:"source_size_bytes,omitempty"` SourceAssetID int64 `json:"source_asset_id,omitempty"` } // UpdateFreeformDocRequest 更新自由文档请求 type UpdateFreeformDocRequest struct { Title *string `json:"title,omitempty"` ContentMarkdown *string `json:"content_markdown,omitempty"` ChangeSummary string `json:"change_summary,omitempty"` ExpectedVersion *int `json:"expected_version,omitempty"` ExpectedSHA256 *string `json:"expected_sha256,omitempty"` } // summary 投影为列表概要(内存模式与 PG 行扫描共用同一字段集)。 func (d FreeformDocument) summary() FreeformDocSummary { return FreeformDocSummary{ DocID: d.DocID, ProjectID: d.ProjectID, OwnerUserID: d.OwnerUserID, Title: d.Title, Space: d.Space, CurrentVersionID: d.CurrentVersionID, CurrentSHA256: d.CurrentSHA256, SourceFilename: d.SourceFilename, SourceMimeType: d.SourceMimeType, SourceSizeBytes: d.SourceSizeBytes, SourceAssetID: d.SourceAssetID, CreatedAt: d.CreatedAt, UpdatedAt: d.UpdatedAt, } }