refactor: reorganize models into subpackages

Move models into domain subpackages (max 4 files each):
- models/tool/ — tool_type, tool_instance, tool_definition_manifest
- models/config/ — config_profile
- models/user/ — user, user_config, ssh_key
- models/project/ — project, git_repository, workspace
- models/system/ — health_check, notification, instance_event, terminal_session

models/__init__.py continues to re-export all symbols, so consumers
using 'from src.models import X' are unaffected. Updated direct file
imports across the backend to use the new paths.

Quality gates: py_compile passed, ruff passed.
This commit is contained in:
2026-06-04 10:00:10 +02:00
parent 0127d283a6
commit 0591b00ded
62 changed files with 136 additions and 87 deletions
+1
View File
@@ -0,0 +1 @@
"""Config module."""
+4 -4
View File
@@ -14,10 +14,10 @@ from sqlalchemy.orm import selectinload
from src.api.shared_validators import validate_env_vars as _validate_env_vars
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.config_profile import ConfigProfile, ConfigProfileInclude
from src.models import ConfigProfile, ConfigProfileInclude
from src.models.project import Project
from src.models.tool_type import ToolType
from src.models.user_config import UserConfig
from src.models import ToolType
from src.models import UserConfig
from src.services.config_profile_resolver import (
ConfigProfileCycleError,
check_include_cycle,
@@ -991,7 +991,7 @@ async def validate_git_url(
env = None
key_path = None
if data.ssh_key_id:
from src.models.ssh_key import SSHKey
from src.models import SSHKey
from src.services.ssh_keys import _get_fernet
try:
+2 -2
View File
@@ -5,9 +5,9 @@ from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.git_repository import GitRepository
from src.models import GitRepository
from src.models.project import Project
from src.models.ssh_key import SSHKey
from src.models import SSHKey
router = APIRouter(prefix="/dashboard", tags=["dashboard"])
+2 -2
View File
@@ -17,8 +17,8 @@ from src.auth.dependencies import (
get_db_session,
)
from src.config import Settings
from src.models.git_repository import GitRepository
from src.models.ssh_key import SSHKey
from src.models import GitRepository
from src.models import SSHKey
from src.utils.git_files import (
commit_file,
get_file_content,
+2 -2
View File
@@ -8,8 +8,8 @@ from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.tool_instance import ToolInstance
from src.models.tool_type import ToolType
from src.models import ToolInstance
from src.models import ToolType
logger = logging.getLogger(__name__)
+1 -1
View File
@@ -9,7 +9,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import get_current_user, get_db_session
from src.models.user import User
from src.models.user_config import UserConfig
from src.models import UserConfig
from src.services.notification_service import notification_service
router = APIRouter(prefix="/notifications", tags=["notifications"])
+1
View File
@@ -0,0 +1 @@
"""Project module."""
+4 -4
View File
@@ -13,10 +13,10 @@ from src.auth.dependencies import (
get_current_user_id,
get_db_session,
)
from src.models.git_repository import GitRepository
from src.models import GitRepository
from src.models.project import Project
from src.models.ssh_key import SSHKey
from src.models.tool_instance import ToolInstance
from src.models import SSHKey
from src.models import ToolInstance
router = APIRouter(prefix="/projects", tags=["projects"])
@@ -101,7 +101,7 @@ async def list_projects(
)
projects = result.scalars().all()
from src.models.workspace import Workspace
from src.models import Workspace
enriched = []
for project in projects:
+1 -1
View File
@@ -12,7 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import _get_user, get_current_user_id, get_db_session
from src.config import Settings
from src.models.ssh_key import SSHKey
from src.models import SSHKey
router = APIRouter(prefix="/ssh-keys", tags=["ssh-keys"])
+1
View File
@@ -0,0 +1 @@
"""System module."""
+3 -3
View File
@@ -12,9 +12,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
from starlette.websockets import WebSocketDisconnect
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.terminal_session import TerminalSessionModel
from src.models.tool_instance import ToolInstance
from src.models.tool_type import ToolType
from src.models import TerminalSessionModel
from src.models import ToolInstance
from src.models import ToolType
from src.services.terminal_manager import MaxSessionsExceededError, terminal_manager
router = APIRouter()
+1
View File
@@ -0,0 +1 @@
"""Tool module."""
+2 -2
View File
@@ -9,8 +9,8 @@ from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.tool_definition_manifest import ToolDefinitionManifest
from src.models.tool_type import ToolType
from src.models import ToolDefinitionManifest
from src.models import ToolType
from src.services.manifest_compiler import (
compile_compose,
compile_dockerfile,
+11 -11
View File
@@ -30,12 +30,12 @@ from src.auth.dependencies import (
)
from src.services.event_bus import InstanceEventBus
from src.services.lifecycle_hooks import publish_lifecycle_event
from src.models.config_profile import ConfigProfile
from src.models.git_repository import GitRepository
from src.models import ConfigProfile
from src.models import GitRepository
from src.models.project import Project
from src.models.ssh_key import SSHKey
from src.models.tool_instance import ToolInstance
from src.models.tool_type import ToolType
from src.models import SSHKey
from src.models import ToolInstance
from src.models import ToolType
from src.services.clone import check_dirty_state, clone_repository
from src.services.config_profile_resolver import (
ConfigProfileCycleError,
@@ -856,7 +856,7 @@ async def create_instance(
workspace = None
workspace_id = None
if data.workspace_id:
from src.models.workspace import Workspace as WorkspaceModel
from src.models import Workspace as WorkspaceModel
try:
workspace_id = uuid.UUID(data.workspace_id)
@@ -1056,7 +1056,7 @@ services:
elif tool_type.definition_type == "manifest":
# Manifest-based: generate compose only; image built lazily on start
from src.models.tool_definition_manifest import ToolDefinitionManifest
from src.models import ToolDefinitionManifest
manifest_def = await session.get(
ToolDefinitionManifest, tool_type.manifest_id
@@ -1341,7 +1341,7 @@ async def _prepare_manifest_instance(
Returns:
Tuple of (image_tag, compose_content, resolved_manifest, home_dir)
"""
from src.models.tool_definition_manifest import ToolDefinitionManifest
from src.models import ToolDefinitionManifest
tool_type = await session.get(ToolType, instance.tool_type_id)
manifest_def = await session.get(ToolDefinitionManifest, tool_type.manifest_id)
@@ -1537,7 +1537,7 @@ async def start_instance(
container_uid = 0
container_gid = 0
if tool_type and tool_type.definition_type == "manifest" and tool_type.manifest_id:
from src.models.tool_definition_manifest import ToolDefinitionManifest
from src.models import ToolDefinitionManifest
manifest_def = await session.get(ToolDefinitionManifest, tool_type.manifest_id)
if manifest_def:
@@ -1724,7 +1724,7 @@ async def start_instance(
# Determine repo path (workspace takes precedence)
repo_path = ""
if instance.workspace_id:
from src.models.workspace import Workspace as WorkspaceModel
from src.models import Workspace as WorkspaceModel
workspace = await session.get(WorkspaceModel, instance.workspace_id)
if workspace:
@@ -2767,7 +2767,7 @@ async def get_instance_events(
List of event dictionaries.
"""
from sqlalchemy import select
from src.models.instance_event import InstanceEvent
from src.models import InstanceEvent
_user = await _get_user(session, user_id)
_project = await _get_owned_project(project_id, user_id, session)
+1 -1
View File
@@ -12,7 +12,7 @@ from src.api.tool_types_validation import (
validate_required_variables,
)
from src.auth.dependencies import _get_user, get_current_user_id, get_db_session
from src.models.tool_type import ToolType
from src.models import ToolType
from src.models.user import User
router = APIRouter(prefix="/tool-types", tags=["tool-types"])
+1
View File
@@ -0,0 +1 @@
"""User module."""
+1 -1
View File
@@ -7,7 +7,7 @@ from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import _get_user, get_current_user_id, get_db_session
from src.models.user_config import UserConfig
from src.models import UserConfig
logger = logging.getLogger(__name__)
+1
View File
@@ -0,0 +1 @@
"""Workspace module."""
+1 -1
View File
@@ -6,7 +6,7 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.workspace import Workspace
from src.models import Workspace
from src.services.file_service import FileService
router = APIRouter(prefix="/workspaces/{workspace_id}/files")
+1 -1
View File
@@ -6,7 +6,7 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.workspace import Workspace
from src.models import Workspace
from src.services.git_operations import GitOperations
router = APIRouter(prefix="/workspaces/{workspace_id}/git")
+2 -2
View File
@@ -7,8 +7,8 @@ from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.tool_instance import ToolInstance
from src.models.workspace import Workspace
from src.models import ToolInstance
from src.models import Workspace
router = APIRouter(prefix="/workspaces/{workspace_id}/instances")
+3 -3
View File
@@ -9,9 +9,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from src.auth.dependencies import get_current_user_id, get_db_session
from src.models.git_repository import GitRepository
from src.models.tool_instance import ToolInstance
from src.models.workspace import Workspace
from src.models import GitRepository
from src.models import ToolInstance
from src.models import Workspace
from src.services.workspace_manager import WorkspaceHasInstancesError, WorkspaceManager
logger = logging.getLogger(__name__)