feat: implement tool instances backend and session navigation
Backend: - Create ToolInstance model with status tracking - Add Alembic migration for tool_instances table - Create Docker service for compose template rendering and container execution - Add CRUD API endpoints for tool instances - Add lifecycle endpoints (start/stop/restart) - Add user sessions endpoint for navigation - Register routers in main.py Frontend: - Create SessionsProvider with React context - Create sessions API client - Update AppShell with sessions section in navigation - Add session status indicators and polling - Add CSS for session navigation Quality gates: typecheck ✓, lint ✓, build ✓
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
# Tool Instances - Design
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Tool Instance System
|
||||
├── Backend
|
||||
│ ├── ToolInstance Model
|
||||
│ ├── Session API (CRUD + lifecycle)
|
||||
│ ├── Docker Service (compose execution)
|
||||
│ └── Status Polling
|
||||
├── Frontend
|
||||
│ ├── SessionStore (active sessions)
|
||||
│ ├── AppShell Integration (nav entries)
|
||||
│ ├── Instance Manager (repo page)
|
||||
│ └── Session Launcher (create dialog)
|
||||
└── Docker
|
||||
├── Compose Template Rendering
|
||||
├── Container Execution
|
||||
└── Volume Management
|
||||
```
|
||||
|
||||
## Data Model
|
||||
|
||||
### ToolInstance
|
||||
```python
|
||||
class ToolInstance(Base):
|
||||
id: UUID
|
||||
name: str # Generated: "vscode-myrepo-abc123"
|
||||
display_name: str # User-friendly name
|
||||
tool_type_id: UUID -> ToolType
|
||||
repository_id: UUID -> GitRepository
|
||||
project_id: UUID -> Project
|
||||
owner_id: UUID -> User
|
||||
status: str # pending, building, running, stopped, error
|
||||
container_id: str | None
|
||||
compose_path: str | None # Path to rendered compose file
|
||||
url: str | None # Access URL
|
||||
port: int | None
|
||||
last_started_at: datetime | None
|
||||
last_stopped_at: datetime | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
```
|
||||
|
||||
## API Design
|
||||
|
||||
### Endpoints
|
||||
```
|
||||
POST /projects/{id}/repositories/{id}/instances
|
||||
GET /projects/{id}/repositories/{id}/instances
|
||||
GET /projects/{id}/repositories/{id}/instances/{id}
|
||||
PUT /projects/{id}/repositories/{id}/instances/{id}
|
||||
DELETE /projects/{id}/repositories/{id}/instances/{id}
|
||||
POST /projects/{id}/repositories/{id}/instances/{id}/start
|
||||
POST /projects/{id}/repositories/{id}/instances/{id}/stop
|
||||
POST /projects/{id}/repositories/{id}/instances/{id}/restart
|
||||
GET /projects/{id}/repositories/{id}/instances/{id}/status
|
||||
GET /projects/{id}/repositories/{id}/instances/{id}/logs
|
||||
GET /users/me/sessions # Active sessions for nav
|
||||
```
|
||||
|
||||
## Docker Integration
|
||||
|
||||
### Compose Template Rendering
|
||||
```yaml
|
||||
# Template variables:
|
||||
# {{REPO_PATH}} - Absolute path to repo
|
||||
# {{INSTANCE_NAME}} - Unique instance name
|
||||
# {{TOOL_PORT}} - Exposed port
|
||||
|
||||
services:
|
||||
{{INSTANCE_NAME}}:
|
||||
image: codercom/code-server:latest
|
||||
volumes:
|
||||
- {{REPO_PATH}}:/workspace
|
||||
ports:
|
||||
- "{{TOOL_PORT}}:8080"
|
||||
environment:
|
||||
- PASSWORD={{INSTANCE_NAME}}
|
||||
```
|
||||
|
||||
### Execution Flow
|
||||
1. Create instance directory: `data/instances/{instance_id}/`
|
||||
2. Render compose file to `docker-compose.yml`
|
||||
3. Run `docker compose -f {path} up -d`
|
||||
4. Capture container ID from output
|
||||
5. Poll status until running or error
|
||||
|
||||
## Frontend Integration
|
||||
|
||||
### Session Store
|
||||
```typescript
|
||||
interface Session {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
toolType: string;
|
||||
toolIcon: string;
|
||||
repositoryId: string;
|
||||
projectId: string;
|
||||
status: "pending" | "running" | "stopped" | "error";
|
||||
url: string | null;
|
||||
}
|
||||
|
||||
const useSessions = () => {
|
||||
const sessions = useAtom(sessionsAtom);
|
||||
const addSession = (session: Session) => { ... };
|
||||
const removeSession = (id: string) => { ... };
|
||||
const updateStatus = (id: string, status: string) => { ... };
|
||||
return { sessions, addSession, removeSession, updateStatus };
|
||||
};
|
||||
```
|
||||
|
||||
### AppShell Navigation
|
||||
- Add "Sessions" section in nav
|
||||
- Show active sessions with tool icons
|
||||
- Session status indicator (green dot for running)
|
||||
- Click opens tool in new tab
|
||||
- Dropdown for managing sessions
|
||||
|
||||
### Repository Page
|
||||
- "Launch Tool" button
|
||||
- Dialog to select tool type
|
||||
- Instance list with status/actions
|
||||
- Quick actions: start/stop/delete
|
||||
|
||||
## State Machine
|
||||
|
||||
```
|
||||
[create] -> pending -> [docker up] -> building -> [container running] -> running
|
||||
|
|
||||
v
|
||||
[docker error] -> error
|
||||
|
||||
[running] -> [stop] -> stopped
|
||||
[stopped] -> [start] -> pending -> building -> running
|
||||
[any] -> [delete] -> [docker down] -> deleted
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
- Only repository owner can create instances
|
||||
- Instances run in isolated Docker networks
|
||||
- No privileged containers
|
||||
- Resource limits (CPU, memory) on containers
|
||||
Reference in New Issue
Block a user