Self-hosted Docker Compose manager. - Backend: FastAPI + docker-py + SQLite (JWT auth, file-first stacks, lifecycle, live status, WebSocket logs, docker-run converter, audit log) - Frontend: React + Vite + Tailwind (login/setup, dashboard, stacks, stack detail, Monaco editor, dark/light theme) - Deployment: docker-compose.yml, Dockerfiles, nginx reverse proxy Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
50 lines
1.0 KiB
Python
50 lines
1.0 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
from typing import Optional
|
|
|
|
from sqlmodel import Field, SQLModel
|
|
|
|
|
|
def _now() -> datetime:
|
|
return datetime.now(timezone.utc)
|
|
|
|
|
|
class Stack(SQLModel, table=True):
|
|
# id is the stack directory name (slug)
|
|
id: str = Field(primary_key=True)
|
|
name: str
|
|
description: Optional[str] = None
|
|
stacks_dir_override: Optional[str] = None
|
|
created_at: datetime = Field(default_factory=_now)
|
|
updated_at: datetime = Field(default_factory=_now)
|
|
|
|
|
|
# --- API schemas ---
|
|
|
|
|
|
class StackCreate(SQLModel):
|
|
name: str
|
|
description: Optional[str] = None
|
|
yaml: Optional[str] = None # initial compose content
|
|
env: Optional[str] = None
|
|
|
|
|
|
class StackUpdate(SQLModel):
|
|
name: Optional[str] = None
|
|
description: Optional[str] = None
|
|
yaml: Optional[str] = None
|
|
env: Optional[str] = None
|
|
|
|
|
|
class StackCloneRequest(SQLModel):
|
|
name: str
|
|
|
|
|
|
class ConvertRequest(SQLModel):
|
|
command: str # a `docker run ...` string
|
|
|
|
|
|
class ConvertResponse(SQLModel):
|
|
yaml: str
|