Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.veloiq.dev/llms.txt

Use this file to discover all available pages before exploring further.

The auto-generated CRUD layer covers list, get, create, update, and delete for every model. For anything more specific — status transitions, batch operations, or domain-specific actions — create a custom_api.py file in the module directory. The framework scans for this file automatically on startup and registers any routes it finds, so you never need to touch main.py.

When to use custom_api.py

Reach for custom_api.py when you need to:
  • Status transitions — mark a task as complete, confirm an order, archive a record
  • Batch operations — reassign multiple items at once, bulk-apply a tag
  • Domain-specific actions — send a notification, trigger a workflow, compute a derived value

Add custom endpoints to a module

1

Create custom_api.py in the module directory

Add the file alongside the generated files. For an orders module the layout looks like:
modules/orders/
├── __init__.py
├── models.py
├── api.py          ← generated, do not edit
└── custom_api.py   ← you create this
2

Import the router from api.py

Import router from .api — the generated router for this module. Do not import it from veloiq_framework; the router object must be the same instance the generator created so your routes are registered under the correct prefix.
from .api import router
3

Add routes using standard FastAPI decorators

Decorate functions with @router.post, @router.get, and so on, exactly as you would in any FastAPI application. The full example below adds a POST /{order_id}/confirm endpoint and a GET /pending list:
from fastapi import Depends, HTTPException
from sqlmodel import Session
from veloiq_framework import get_session
from .api import router
from .models import Order

@router.post("/{order_id}/confirm")
def confirm_order(order_id: int, session: Session = Depends(get_session)):
    order = session.get(Order, order_id)
    if order is None:
        raise HTTPException(404, f"Order {order_id} not found")
    order.status = "confirmed"
    session.add(order)
    session.commit()
    session.refresh(order)
    return order.model_dump()

@router.get("/pending")
def list_pending(session: Session = Depends(get_session)):
    rows = session.exec(select(Order).where(Order.status == "pending")).all()
    return [r.model_dump() for r in rows]
4

Verify the new endpoints appear in /docs

Restart the backend, or let uvicorn hot-reload pick up the file. Open http://localhost:8000/docs — the new endpoints appear under the module’s section alongside the generated CRUD routes.
Never edit the generated api.py. It is overwritten every time you run veloiq generate. Put all custom logic in custom_api.py.

Task-manager example

For the task-manager tutorial app, create backend/app/modules/tasks/custom_api.py to add a “mark as complete” action:
from fastapi import Depends, HTTPException
from sqlmodel import Session

from veloiq_framework import get_session
from .api import router
from .models import Task


@router.post("/{task_id}/complete")
def complete_task(task_id: int, session: Session = Depends(get_session)):
    task = session.get(Task, task_id)
    if task is None:
        raise HTTPException(404, f"Task {task_id} not found")
    task.status = "done"
    session.add(task)
    session.commit()
    session.refresh(task)
    return task.model_dump()
After the backend reloads, POST /task/{task_id}/complete appears in /docs under the task section.
Generate the custom_api.py stub automatically when you scaffold a module by passing the --with-custom-api flag:
veloiq add-module orders --with-custom-api