From 0c53d884eba74b8e632698f5fe58d4bc7231df66 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Fri, 26 Jun 2026 18:23:43 +0200 Subject: [PATCH] refactor(schemas): rename SearchSpace -> Workspace in Pydantic schemas (Phase 2 Wave C) Rename schemas/search_space.py -> schemas/workspace.py, the SearchSpace* classes -> Workspace* (incl. UserSearchSpaceAccess -> UserWorkspaceAccess), and the search_space_id / search_space_name fields -> workspace_id / workspace_name across all schema modules. Under hard cutover the serialized JSON keys change outright (no alias). Re-exports in schemas/__init__.py updated. --- surfsense_backend/app/schemas/__init__.py | 32 +++++++++---------- .../app/schemas/chat_comments.py | 4 +-- surfsense_backend/app/schemas/documents.py | 4 +-- surfsense_backend/app/schemas/folders.py | 4 +-- .../app/schemas/image_generation.py | 12 +++---- surfsense_backend/app/schemas/logs.py | 6 ++-- .../app/schemas/model_connections.py | 4 +-- surfsense_backend/app/schemas/new_chat.py | 16 +++++----- .../app/schemas/obsidian_plugin.py | 4 +-- surfsense_backend/app/schemas/prompts.py | 4 +-- surfsense_backend/app/schemas/rbac_schemas.py | 20 ++++++------ surfsense_backend/app/schemas/reports.py | 2 +- .../app/schemas/search_source_connector.py | 6 ++-- surfsense_backend/app/schemas/stripe.py | 4 +-- .../app/schemas/video_presentations.py | 4 +-- .../schemas/{search_space.py => workspace.py} | 14 ++++---- 16 files changed, 70 insertions(+), 70 deletions(-) rename surfsense_backend/app/schemas/{search_space.py => workspace.py} (71%) diff --git a/surfsense_backend/app/schemas/__init__.py b/surfsense_backend/app/schemas/__init__.py index f111f0226..e9a62e5ec 100644 --- a/surfsense_backend/app/schemas/__init__.py +++ b/surfsense_backend/app/schemas/__init__.py @@ -84,7 +84,7 @@ from .rbac_schemas import ( RoleCreate, RoleRead, RoleUpdate, - UserSearchSpaceAccess, + UserWorkspaceAccess, ) from .reports import ( ReportBase, @@ -103,13 +103,13 @@ from .search_source_connector import ( SearchSourceConnectorRead, SearchSourceConnectorUpdate, ) -from .search_space import ( - SearchSpaceApiAccessUpdate, - SearchSpaceBase, - SearchSpaceCreate, - SearchSpaceRead, - SearchSpaceUpdate, - SearchSpaceWithStats, +from .workspace import ( + WorkspaceApiAccessUpdate, + WorkspaceBase, + WorkspaceCreate, + WorkspaceRead, + WorkspaceUpdate, + WorkspaceWithStats, ) from .stripe import ( CreateCreditCheckoutSessionRequest, @@ -242,13 +242,13 @@ __all__ = [ "SearchSourceConnectorCreate", "SearchSourceConnectorRead", "SearchSourceConnectorUpdate", - "SearchSpaceApiAccessUpdate", - # Search space schemas - "SearchSpaceBase", - "SearchSpaceCreate", - "SearchSpaceRead", - "SearchSpaceUpdate", - "SearchSpaceWithStats", + "WorkspaceApiAccessUpdate", + # Workspace schemas + "WorkspaceBase", + "WorkspaceCreate", + "WorkspaceRead", + "WorkspaceUpdate", + "WorkspaceWithStats", "StripeWebhookResponse", "ThreadHistoryLoadResponse", "ThreadListItem", @@ -257,7 +257,7 @@ __all__ = [ # User schemas "UserCreate", "UserRead", - "UserSearchSpaceAccess", + "UserWorkspaceAccess", "UserUpdate", "VerifyConnectionResponse", # Video Presentation schemas diff --git a/surfsense_backend/app/schemas/chat_comments.py b/surfsense_backend/app/schemas/chat_comments.py index 984e8b812..c9d230a6d 100644 --- a/surfsense_backend/app/schemas/chat_comments.py +++ b/surfsense_backend/app/schemas/chat_comments.py @@ -110,8 +110,8 @@ class MentionContextResponse(BaseModel): thread_id: int thread_title: str message_id: int - search_space_id: int - search_space_name: str + workspace_id: int + workspace_name: str class MentionCommentResponse(BaseModel): diff --git a/surfsense_backend/app/schemas/documents.py b/surfsense_backend/app/schemas/documents.py index 49d2836b2..da0c0e506 100644 --- a/surfsense_backend/app/schemas/documents.py +++ b/surfsense_backend/app/schemas/documents.py @@ -30,7 +30,7 @@ class DocumentBase(BaseModel): content: ( list[ExtensionDocumentContent] | list[str] | str ) # Updated to allow string content - search_space_id: int + workspace_id: int class DocumentsCreate(DocumentBase): @@ -59,7 +59,7 @@ class DocumentRead(BaseModel): unique_identifier_hash: str | None created_at: datetime updated_at: datetime | None - search_space_id: int + workspace_id: int folder_id: int | None = None created_by_id: UUID | None = None created_by_name: str | None = None diff --git a/surfsense_backend/app/schemas/folders.py b/surfsense_backend/app/schemas/folders.py index a7e065144..9d3444ed4 100644 --- a/surfsense_backend/app/schemas/folders.py +++ b/surfsense_backend/app/schemas/folders.py @@ -10,7 +10,7 @@ from pydantic import BaseModel, ConfigDict, Field class FolderCreate(BaseModel): name: str = Field(max_length=255, min_length=1) parent_id: int | None = None - search_space_id: int + workspace_id: int class FolderUpdate(BaseModel): @@ -31,7 +31,7 @@ class FolderRead(BaseModel): name: str position: str parent_id: int | None - search_space_id: int + workspace_id: int created_by_id: UUID | None created_at: datetime updated_at: datetime diff --git a/surfsense_backend/app/schemas/image_generation.py b/surfsense_backend/app/schemas/image_generation.py index ebd0fa0ac..60307e827 100644 --- a/surfsense_backend/app/schemas/image_generation.py +++ b/surfsense_backend/app/schemas/image_generation.py @@ -34,15 +34,15 @@ class ImageGenerationCreate(BaseModel): size: str | None = Field(None, max_length=50) style: str | None = Field(None, max_length=50) response_format: str | None = Field(None, max_length=50) - search_space_id: int = Field( - ..., description="Search space ID to associate the generation with" + workspace_id: int = Field( + ..., description="Workspace ID to associate the generation with" ) image_gen_model_id: int | None = Field( None, description=( "Image generation model ID. " "0 = Auto mode, negative = GLOBAL model, positive = BYOK Model row. " - "If not provided, uses the search space's image_gen_model_id preference." + "If not provided, uses the workspace's image_gen_model_id preference." ), ) @@ -61,7 +61,7 @@ class ImageGenerationRead(BaseModel): image_gen_model_id: int | None = None response_data: dict[str, Any] | None = None error_message: str | None = None - search_space_id: int + workspace_id: int created_at: datetime model_config = ConfigDict(from_attributes=True) @@ -76,7 +76,7 @@ class ImageGenerationListRead(BaseModel): n: int | None = None quality: str | None = None size: str | None = None - search_space_id: int + workspace_id: int created_at: datetime is_success: bool image_count: int | None = None @@ -99,7 +99,7 @@ class ImageGenerationListRead(BaseModel): n=obj.n, quality=obj.quality, size=obj.size, - search_space_id=obj.search_space_id, + workspace_id=obj.workspace_id, created_at=obj.created_at, is_success=obj.response_data is not None, image_count=image_count, diff --git a/surfsense_backend/app/schemas/logs.py b/surfsense_backend/app/schemas/logs.py index a47d5db76..a79aab038 100644 --- a/surfsense_backend/app/schemas/logs.py +++ b/surfsense_backend/app/schemas/logs.py @@ -22,7 +22,7 @@ class LogCreate(BaseModel): message: str source: str | None = None log_metadata: dict[str, Any] | None = None - search_space_id: int + workspace_id: int class LogUpdate(BaseModel): @@ -36,7 +36,7 @@ class LogUpdate(BaseModel): class LogRead(LogBase, IDModel, TimestampModel): id: int created_at: datetime - search_space_id: int + workspace_id: int model_config = ConfigDict(from_attributes=True) @@ -45,7 +45,7 @@ class LogFilter(BaseModel): level: LogLevel | None = None status: LogStatus | None = None source: str | None = None - search_space_id: int | None = None + workspace_id: int | None = None start_date: datetime | None = None end_date: datetime | None = None diff --git a/surfsense_backend/app/schemas/model_connections.py b/surfsense_backend/app/schemas/model_connections.py index 0eec666c1..7b7ac33ed 100644 --- a/surfsense_backend/app/schemas/model_connections.py +++ b/surfsense_backend/app/schemas/model_connections.py @@ -34,7 +34,7 @@ class ConnectionRead(BaseModel): api_key: str | None = None extra: dict[str, Any] = Field(default_factory=dict) scope: ConnectionScope | str - search_space_id: int | None = None + workspace_id: int | None = None user_id: uuid.UUID | None = None enabled: bool has_api_key: bool @@ -76,7 +76,7 @@ class ConnectionCreate(BaseModel): api_key: str | None = None extra: dict[str, Any] = Field(default_factory=dict) scope: ConnectionScope = ConnectionScope.SEARCH_SPACE - search_space_id: int | None = None + workspace_id: int | None = None enabled: bool = True models: list[ModelSelection] = Field(default_factory=list) diff --git a/surfsense_backend/app/schemas/new_chat.py b/surfsense_backend/app/schemas/new_chat.py index e486b3dda..356668a7a 100644 --- a/surfsense_backend/app/schemas/new_chat.py +++ b/surfsense_backend/app/schemas/new_chat.py @@ -85,7 +85,7 @@ class NewChatThreadBase(BaseModel): class NewChatThreadCreate(NewChatThreadBase): """Schema for creating a new thread.""" - search_space_id: int + workspace_id: int # Visibility defaults to PRIVATE, but can be set on creation visibility: ChatVisibility = ChatVisibility.PRIVATE @@ -108,7 +108,7 @@ class NewChatThreadRead(NewChatThreadBase, IDModel): Schema for reading a thread (matches assistant-ui ThreadRecord). """ - search_space_id: int + workspace_id: int visibility: ChatVisibility created_by_id: UUID | None = None created_at: datetime @@ -236,7 +236,7 @@ class NewChatRequest(BaseModel): chat_id: int user_query: str - search_space_id: int + workspace_id: int messages: list[ChatMessage] | None = None # Optional chat history from frontend mentioned_document_ids: list[int] | None = ( None # Optional document IDs mentioned with @ in the chat @@ -279,7 +279,7 @@ class NewChatRequest(BaseModel): default=None, description=( "Other chat thread IDs the user @-mentioned. Each is " - "resolved (access-checked, same search space) into a " + "resolved (access-checked, same workspace) into a " "read-only ```` block prepended to " "the agent query. Display chips persist via the " "``mentioned_documents`` list (kind=``thread``)." @@ -330,7 +330,7 @@ class RegenerateRequest(BaseModel): ``data-revert-results`` and do not abort the regeneration. """ - search_space_id: int + workspace_id: int user_query: str | None = ( None # New user query (for edit). None = reload with same query ) @@ -428,7 +428,7 @@ class ResumeDecision(BaseModel): class ResumeRequest(BaseModel): - search_space_id: int + workspace_id: int decisions: list[ResumeDecision] # Mirrors ``NewChatRequest.disabled_tools`` so the resumed run sees the # same tool surface as the originating turn. @@ -520,7 +520,7 @@ class PublicChatSnapshotDetail(BaseModel): class PublicChatSnapshotsBySpaceResponse(BaseModel): - """List of public chat snapshots for a search space.""" + """List of public chat snapshots for a workspace.""" snapshots: list[PublicChatSnapshotDetail] @@ -556,4 +556,4 @@ class CloneResponse(BaseModel): """Response after cloning a public snapshot.""" thread_id: int - search_space_id: int + workspace_id: int diff --git a/surfsense_backend/app/schemas/obsidian_plugin.py b/surfsense_backend/app/schemas/obsidian_plugin.py index 89be08c8e..21943a016 100644 --- a/surfsense_backend/app/schemas/obsidian_plugin.py +++ b/surfsense_backend/app/schemas/obsidian_plugin.py @@ -150,7 +150,7 @@ class ConnectRequest(_PluginBase): vault_id: str vault_name: str - search_space_id: int + workspace_id: int vault_fingerprint: str = Field( ..., description=( @@ -167,7 +167,7 @@ class ConnectResponse(_PluginBase): connector_id: int vault_id: str - search_space_id: int + workspace_id: int capabilities: list[str] server_time_utc: datetime diff --git a/surfsense_backend/app/schemas/prompts.py b/surfsense_backend/app/schemas/prompts.py index 9f11520ff..d744a023f 100644 --- a/surfsense_backend/app/schemas/prompts.py +++ b/surfsense_backend/app/schemas/prompts.py @@ -7,7 +7,7 @@ class PromptCreate(BaseModel): name: str = Field(..., min_length=1, max_length=200) prompt: str = Field(..., min_length=1) mode: str = Field(..., pattern="^(transform|explore)$") - search_space_id: int | None = None + workspace_id: int | None = None is_public: bool = False @@ -23,7 +23,7 @@ class PromptRead(BaseModel): name: str prompt: str mode: str - search_space_id: int | None + workspace_id: int | None is_public: bool version: int created_at: datetime diff --git a/surfsense_backend/app/schemas/rbac_schemas.py b/surfsense_backend/app/schemas/rbac_schemas.py index 8de8426c3..234c4e1a9 100644 --- a/surfsense_backend/app/schemas/rbac_schemas.py +++ b/surfsense_backend/app/schemas/rbac_schemas.py @@ -38,7 +38,7 @@ class RoleRead(RoleBase): """Schema for reading a role.""" id: int - search_space_id: int + workspace_id: int is_system_role: bool created_at: datetime @@ -66,7 +66,7 @@ class MembershipRead(BaseModel): id: int user_id: UUID - search_space_id: int + workspace_id: int role_id: int | None is_owner: bool joined_at: datetime @@ -123,7 +123,7 @@ class InviteRead(InviteBase): id: int invite_code: str - search_space_id: int + workspace_id: int created_by_id: UUID | None uses_count: int is_active: bool @@ -145,15 +145,15 @@ class InviteAcceptResponse(BaseModel): """Response schema for accepting an invite.""" message: str - search_space_id: int - search_space_name: str + workspace_id: int + workspace_name: str role_name: str | None class InviteInfoResponse(BaseModel): """Response schema for getting invite info (public endpoint).""" - search_space_name: str + workspace_name: str role_name: str | None is_valid: bool message: str | None = None @@ -180,11 +180,11 @@ class PermissionsListResponse(BaseModel): # ============ User Access Info ============ -class UserSearchSpaceAccess(BaseModel): - """Schema for user's access info in a search space.""" +class UserWorkspaceAccess(BaseModel): + """Schema for user's access info in a workspace.""" - search_space_id: int - search_space_name: str + workspace_id: int + workspace_name: str is_owner: bool role_name: str | None permissions: list[str] diff --git a/surfsense_backend/app/schemas/reports.py b/surfsense_backend/app/schemas/reports.py index cfd9d89ca..e7444f6c2 100644 --- a/surfsense_backend/app/schemas/reports.py +++ b/surfsense_backend/app/schemas/reports.py @@ -12,7 +12,7 @@ class ReportBase(BaseModel): title: str content: str | None = None report_style: str | None = None - search_space_id: int + workspace_id: int class ReportRead(BaseModel): diff --git a/surfsense_backend/app/schemas/search_source_connector.py b/surfsense_backend/app/schemas/search_source_connector.py index 982931859..b915e8015 100644 --- a/surfsense_backend/app/schemas/search_source_connector.py +++ b/surfsense_backend/app/schemas/search_source_connector.py @@ -73,7 +73,7 @@ class SearchSourceConnectorUpdate(BaseModel): class SearchSourceConnectorRead(SearchSourceConnectorBase, IDModel, TimestampModel): - search_space_id: int + workspace_id: int user_id: uuid.UUID model_config = ConfigDict(from_attributes=True) @@ -129,7 +129,7 @@ class MCPConnectorRead(BaseModel): name: str connector_type: SearchSourceConnectorType server_config: MCPServerConfig - search_space_id: int + workspace_id: int user_id: uuid.UUID created_at: datetime updated_at: datetime @@ -148,7 +148,7 @@ class MCPConnectorRead(BaseModel): name=connector.name, connector_type=connector.connector_type, server_config=server_config, - search_space_id=connector.search_space_id, + workspace_id=connector.workspace_id, user_id=connector.user_id, created_at=connector.created_at, updated_at=connector.updated_at, diff --git a/surfsense_backend/app/schemas/stripe.py b/surfsense_backend/app/schemas/stripe.py index 95c946a3d..b0b6d25de 100644 --- a/surfsense_backend/app/schemas/stripe.py +++ b/surfsense_backend/app/schemas/stripe.py @@ -12,7 +12,7 @@ class CreateCreditCheckoutSessionRequest(BaseModel): """Request body for creating a credit-purchase checkout session.""" quantity: int = Field(ge=1, le=10_000) - search_space_id: int = Field(ge=1) + workspace_id: int = Field(ge=1) class CreateCreditCheckoutSessionResponse(BaseModel): @@ -114,7 +114,7 @@ class UpdateAutoReloadSettingsRequest(BaseModel): class CreateAutoReloadSetupSessionRequest(BaseModel): """Request body for starting the save-a-card (SetupIntent) checkout.""" - search_space_id: int = Field(ge=1) + workspace_id: int = Field(ge=1) class CreateAutoReloadSetupSessionResponse(BaseModel): diff --git a/surfsense_backend/app/schemas/video_presentations.py b/surfsense_backend/app/schemas/video_presentations.py index 68ef3f5ba..f65dee282 100644 --- a/surfsense_backend/app/schemas/video_presentations.py +++ b/surfsense_backend/app/schemas/video_presentations.py @@ -20,7 +20,7 @@ class VideoPresentationBase(BaseModel): title: str slides: list[dict[str, Any]] | None = None scene_codes: list[dict[str, Any]] | None = None - search_space_id: int + workspace_id: int class VideoPresentationCreate(VideoPresentationBase): @@ -65,7 +65,7 @@ class VideoPresentationRead(VideoPresentationBase): "title": obj.title, "slides": slides, "scene_codes": obj.scene_codes, - "search_space_id": obj.search_space_id, + "workspace_id": obj.workspace_id, "status": obj.status, "created_at": obj.created_at, "slide_count": len(obj.slides) if obj.slides else None, diff --git a/surfsense_backend/app/schemas/search_space.py b/surfsense_backend/app/schemas/workspace.py similarity index 71% rename from surfsense_backend/app/schemas/search_space.py rename to surfsense_backend/app/schemas/workspace.py index d74c46716..15c754e81 100644 --- a/surfsense_backend/app/schemas/search_space.py +++ b/surfsense_backend/app/schemas/workspace.py @@ -6,17 +6,17 @@ from pydantic import BaseModel, ConfigDict from .base import IDModel, TimestampModel -class SearchSpaceBase(BaseModel): +class WorkspaceBase(BaseModel): name: str description: str | None = None -class SearchSpaceCreate(SearchSpaceBase): +class WorkspaceCreate(WorkspaceBase): citations_enabled: bool = True qna_custom_instructions: str | None = None -class SearchSpaceUpdate(BaseModel): +class WorkspaceUpdate(BaseModel): name: str | None = None description: str | None = None citations_enabled: bool | None = None @@ -24,11 +24,11 @@ class SearchSpaceUpdate(BaseModel): ai_file_sort_enabled: bool | None = None -class SearchSpaceApiAccessUpdate(BaseModel): +class WorkspaceApiAccessUpdate(BaseModel): api_access_enabled: bool -class SearchSpaceRead(SearchSpaceBase, IDModel, TimestampModel): +class WorkspaceRead(WorkspaceBase, IDModel, TimestampModel): id: int created_at: datetime user_id: uuid.UUID @@ -41,8 +41,8 @@ class SearchSpaceRead(SearchSpaceBase, IDModel, TimestampModel): model_config = ConfigDict(from_attributes=True) -class SearchSpaceWithStats(SearchSpaceRead): - """Extended search space info with member count and ownership status.""" +class WorkspaceWithStats(WorkspaceRead): + """Extended workspace info with member count and ownership status.""" member_count: int = 1 is_owner: bool = False