Skip to main content

Hub Development

Patterns and conventions for Hub development: backend and frontend.

Architecture Overview

Hub is the orchestration platform for Sigilweaver deployments. It manages:

  • Server registration and health monitoring
  • User authentication and RBAC
  • Workflow storage and execution scheduling
  • Audit logging
hub/
├── backend/ # FastAPI + PostgreSQL
│ ├── app/
│ │ ├── api/ # Routes and models
│ │ ├── db/ # SQLAlchemy models + Alembic
│ │ └── domain/ # Business logic
│ └── tests/
├── frontend/ # React + Vite
│ └── src/
│ ├── api/ # API client
│ ├── components/ # Reusable components
│ ├── pages/ # Route pages
│ └── state/ # State management
└── docker-compose.yml # PostgreSQL

Development Setup

Prerequisites

From the repository root:

# Start PostgreSQL
cd hub && docker compose up -d && cd ..

Backend

cd hub/backend

# Install dependencies
uv sync --all-extras

# Run migrations
uv run alembic upgrade head

# Start dev server
uv run uvicorn app.main:app --reload --port 25802

Frontend

cd hub/frontend

# Install dependencies
npm install

# Start dev server
npm run dev

Or use the dev script from the repository root:

./scripts/dev.py --hub

Database Migrations

Hub uses Alembic for database migrations.

cd hub/backend

# Create a new migration
uv run alembic revision --autogenerate -m "Add workflow table"

# Apply all migrations
uv run alembic upgrade head

# Rollback one migration
uv run alembic downgrade -1

# View migration history
uv run alembic history

Important: Always review autogenerated migrations before applying. Alembic sometimes generates unnecessary operations.

Role-Based Access Control

Hub implements hierarchical RBAC:

RoleLevelCapabilities
Owner0Everything.
Admin1Manage users, servers, schedules.
Auditor2Read-only access to audit logs.
User3Execute workflows, view assigned servers.
# Checking permissions in routes
from app.domain.auth.roles import require_role, Role

@router.post("/servers")
async def register_server(
data: ServerCreate,
user: User = Depends(require_role(Role.ADMIN))
):
# Only admins can register servers
...

Authentication Flow

  1. Registration: First user automatically becomes Owner
  2. Login: Returns JWT access token + sets refresh token cookie
  3. Sessions: Server-side session tracking enables revocation
  4. Expiration: Configurable session lifetime (default 24 hours)

Zero-Trust Principles

  • All requests require authentication (except /auth/login, /auth/register)
  • Sessions are database-backed for server-side invalidation
  • Data source credentials never transit through Hub; issued as capability tokens

API Patterns

Route Structure

# app/api/routes/servers.py

from fastapi import APIRouter, Depends
from app.api.dependencies import get_current_user
from app.domain.servers import ServerService

router = APIRouter(prefix="/servers", tags=["servers"])

@router.get("")
async def list_servers(
user: User = Depends(get_current_user),
service: ServerService = Depends()
):
return await service.list_for_user(user)

Dependency Injection

# app/api/dependencies.py

async def get_current_user(
token: str = Depends(oauth2_scheme),
session: AsyncSession = Depends(get_db)
) -> User:
# Validate token, return user
...

Testing

Backend

cd hub/backend

# All tests
uv run pytest tests/ -v

# With coverage
uv run pytest tests/ --cov=app --cov-report=html

# Specific test
uv run pytest tests/test_auth.py::test_login -v

Frontend

cd hub/frontend

# Run tests
npm test

# Watch mode
npm run test:watch

Environment Variables

Backend

VariableRequiredDefaultDescription
DATABASE_URLYes-PostgreSQL connection string
SECRET_KEYYes-JWT signing key
SESSION_LIFETIME_HOURSNo24Session expiration
CORS_ORIGINSNo*Allowed CORS origins

Frontend

VariableRequiredDefaultDescription
VITE_API_URLNohttp://localhost:25802Backend API URL

Common Pitfalls

MistakeConsequenceFix
Forgetting to run migrationsTables don't existuv run alembic upgrade head
Hardcoding role checksBypasses RBACUse require_role() dependency
Sync database callsBlocks event loopUse async SQLAlchemy methods
Missing CORS configurationFrontend can't connectSet CORS_ORIGINS