feat: workspace backend foundation (PR-1)

- Add workspaces table migration (2026_06_01_add_workspaces)
- Create Workspace model with repo_id, user_id, branch, path, status
- Add workspace_id nullable FK to ToolInstance
- Create GitService for clone/fetch/pull/branch_exists_remotely
- Create WorkspaceManager for create/delete/sync lifecycle
- Create workspace CRUD API with 409 handling for duplicates and instances
- Wire workspace routes into FastAPI app
- 17 tests passing (8 unit + 9 integration), 1 skipped

Quality gates: ruff clean
This commit is contained in:
2026-05-31 23:02:45 +02:00
parent d2b6bba15c
commit d567225bf7
14 changed files with 2354 additions and 0 deletions
+5
View File
@@ -14,6 +14,7 @@ if TYPE_CHECKING:
from src.models.project import Project
from src.models.tool_type import ToolType
from src.models.user import User
from src.models.workspace import Workspace
class ToolInstance(UUIDPrimaryKeyMixin, TimestampMixin, Base):
@@ -60,8 +61,12 @@ class ToolInstance(UUIDPrimaryKeyMixin, TimestampMixin, Base):
UUID(), ForeignKey("config_profiles.id", ondelete="SET NULL"), nullable=True
)
ssh_key_ids: Mapped[list[str] | None] = mapped_column(JSON, nullable=True)
workspace_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(), ForeignKey("workspaces.id", ondelete="SET NULL"), nullable=True
)
tool_type: Mapped["ToolType"] = relationship()
workspace: Mapped["Workspace | None"] = relationship()
repository: Mapped["GitRepository"] = relationship()
project: Mapped["Project"] = relationship()
owner: Mapped["User"] = relationship()