Page:
Development-Guide
No results
1
Development-Guide
xpltd_admin edited this page 2026-04-03 22:53:38 -06:00
Development Guide
| Meta | Value |
|---|---|
| Repo | xpltdco/fractafrag |
| Page | Development-Guide |
| Audience | developers, agents |
| Last Updated | 2026-04-04 |
| Status | current |
Code Organization Patterns
Adding a New API Endpoint
- Create/edit router in
services/api/app/routers/— define the FastAPI route - Add Pydantic schemas in
services/api/app/schemas/schemas.py— request/response models - Register router in
services/api/app/main.py(if new file):app.include_router(router, prefix="/api/v1/...") - Add auth dependency if needed:
current_user: User = Depends(get_current_user) - Database access via async session:
db: AsyncSession = Depends(get_db) - Add frontend API call in the React frontend via Axios or React Query hook
Adding a New Database Table
- Add SQL to
db/init.sql(for fresh installs) - Add ORM model in
services/api/app/models/models.pyusing SQLAlchemy declarative - Create Alembic migration for existing databases:
docker compose exec api alembic revision --autogenerate -m "add my_table" docker compose exec api alembic upgrade head - Add Pydantic schemas for the new model
Adding a Celery Task
- Define task in
services/api/app/worker/__init__.py - Use sync DB session (Celery runs in sync context — use
psycopg2, notasyncpg) - Add retry logic if the task can fail transiently:
@celery_app.task(bind=True, max_retries=3) - Enqueue from API router:
from app.worker import my_task; my_task.delay(args) - Add periodic schedule if needed (Beat schedule in worker
__init__.py)
Adding an MCP Tool
- Add tool function in
services/mcp/server.pywith@mcp.tool()decorator - Call the API internally via httpx:
POST http://api:8000/api/v1/... - Return structured data (dict with clear field names for agent consumption)
Adding a Frontend Page
- Create page component in
services/frontend/src/pages/ - Add route in the React Router configuration
- Create API hooks using TanStack Query:
useQuery,useMutation - Style with Tailwind CSS utility classes
Testing
Test Framework
pytest + pytest-asyncio for the API backend.
Running Tests
# Via Docker (recommended)
make test
# or: docker compose exec api python -m pytest tests/ -v
# Locally (requires dev deps)
cd services/api
pip install -e ".[dev]"
pytest tests/ -v
Test Structure
services/api/tests/
├── conftest.py # Fixtures (async client, test DB)
├── test_auth.py # Auth endpoint tests
├── test_shaders.py # Shader CRUD tests
├── test_feed.py # Feed ranking tests
└── ...
Tests use an in-memory SQLite database (via aiosqlite) for speed. The conftest.py sets up a test FastAPI client with overridden database dependency.
Writing Tests
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_create_shader(client: AsyncClient, auth_headers: dict):
response = await client.post(
"/api/v1/shaders",
json={
"title": "Test Shader",
"glsl_code": "void mainImage(out vec4 f, in vec2 c) { f = vec4(1.0); }",
"shader_type": "2d",
"status": "draft"
},
headers=auth_headers
)
assert response.status_code == 201
assert response.json()["title"] == "Test Shader"
CI/CD Pipeline
Forgejo Actions
Workflow: .forgejo/workflows/ci.yml
Triggers: Push or PR to master branch.
Steps:
- Checkout code
- Install Python deps:
pip install -e ".[dev]"(fromservices/api/) - Lint:
ruff check app/ tests/(continue on error) - Tests:
pytest tests/ -v
Working directory: services/api/
Local CI Simulation
cd services/api
ruff check app/ tests/
pytest tests/ -v
Coding Conventions
Python (API)
- Async-first — all route handlers and DB access use
async/await - Type hints throughout — function signatures, return types, Pydantic models
- Pydantic v2 for all request/response serialization
- SQLAlchemy 2 declarative models with async sessions
- Dependency injection via FastAPI
Depends()for auth, DB, Redis - Linter: ruff (configured in pyproject.toml)
TypeScript (Frontend)
- React 18 with functional components and hooks
- TanStack Query for all API data (no manual fetch/useEffect)
- Zustand for client-only state (auth, UI preferences)
- Tailwind CSS for styling (no custom CSS files unless necessary)
- Axios for HTTP client (configured with base URL and interceptors)
File Naming
- Python: snake_case for files and modules (
glsl_validator.py) - TypeScript: PascalCase for components (
ShaderCanvas.tsx), camelCase for utilities - Docker: service names are lowercase (
api,mcp,renderer)
Development Workflow
Hot Reload
With docker-compose.override.yml (applied automatically):
- API:
uvicorn --reloadwatchesservices/api/app/for Python changes - Frontend: Vite HMR for instant browser updates
- MCP: Volume mount for live changes (manual restart needed)
- Worker: Requires manual restart after task changes:
docker compose restart worker
Database Shell
make db-shell
# or: docker compose exec postgres psql -U fracta -d fractafrag
# Useful queries
\dt -- List tables
\d shaders -- Describe table
SELECT COUNT(*) FROM shaders; -- Count shaders
SELECT * FROM system_config; -- App settings (if any)
Redis Shell
docker compose exec redis redis-cli
# Useful commands
KEYS * -- List all keys
KEYS blocklist:* -- List blocklisted tokens
TTL blocklist:some-token -- Check token expiry
INFO memory -- Memory usage
API Testing with curl
# Register
curl -X POST http://localhost/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"test","email":"test@test.com","password":"test1234"}'
# Login (save token)
TOKEN=$(curl -s -X POST http://localhost/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"test1234"}' | jq -r .access_token)
# Create shader
curl -X POST http://localhost/api/v1/shaders \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Test","glsl_code":"void mainImage(out vec4 f,in vec2 c){f=vec4(1.);}","shader_type":"2d","status":"draft"}'
# Browse feed
curl http://localhost/api/v1/feed
Debugging Celery Tasks
# View worker logs
docker compose logs -f worker
# Start worker with debug logging
docker compose exec worker python -m celery -A app.worker worker --loglevel=debug
# Inspect registered tasks
docker compose exec worker python -m celery -A app.worker inspect registered
# Purge all pending tasks
docker compose exec worker python -m celery -A app.worker purge