SIGA API is a modular FastAPI backend organized by business domains (each module has controllers, models, schemas, and services). Routing is centralized per module and aggregated at startup, and database changes are managed with Alembic migrations. The app exposes REST endpoints with standardized responses and permission checks.
main.pyDEV_Readme.mdREADME.mdapp/main.py). Each domain exposes a router that’s included at startup.
app/core/Shared infrastructure and cross‑cutting services used across the app:
config.py: environment settings and configuration loading.database.py: database session/engine setup.logging_config.py: logging configuration and logger setup.flower_config.py: Flower (Celery monitoring) configuration.minio_service.py: MinIO/S3 client setup and helpers.celery/: Celery app configuration and task wiring.
celery.py: Celery app instance.celery_db.py: Celery DB integration helpers.tasks/: background tasks (email, sync, DLQ, etc).app/modules/Business-domain modules. Each module follows the same structure:
config/: route registration, module-specific settings, Alembic hooks.controllers/: FastAPI endpoints (request/response layer).models/: SQLAlchemy ORM models.schemas/: Pydantic request/response schemas.services/: business logic and integrations.decorators/, **security/**for specialized needs.alembic/)Alembic manages schema migrations for the SQLAlchemy models. This folder contains the migration environment and all generated migration scripts.
alembic/env.pyAlembic runtime configuration and bootstrap:
Base.metadata so alembic revision --autogenerate can detect model changes.alembic/env.py (as shown by the module-level imports). If a module isn’t imported, its models won’t be included in Base.metadata during autogeneration.alembic/versions/All migration scripts live here:
dev_requirements.txtDevelopment-only dependencies for local work (testing, Celery/Redis, MinIO, etc.).
requirements.txtRuntime/production dependencies (includes Gunicorn, uvloop, Flower).
.envLocal environment values (DB, SMTP, Redis, Celery, MinIO, secrets). Do not commit.
.env.exampleTemplate of required environment variables with placeholders to create a local .env.
.gitignoreGit ignore rules for caches, builds, virtualenvs, logs, and local secrets.
app/modules/basic/Foundational/authentication and shared platform features:
app/modules/protocol/Integration-focused domain (SII/Protocol):
sii_controller.py).sii_services.py).app/modules/basic/ (file overview)config/routes.py: aggregates and exposes all Basic module routers.alembic.py: imports Basic models so Alembic can detect them for migrations.controllers/API endpoints for core platform features:
auth_controller.py: login/authentication flows.user_controller.py: user CRUD and profile ops.group_controller.py: groups and group membership.route_controller.py: route/permission management.card_controller.py, card_type_controller.py: card and card type handling.bio_controller.py: biometrics endpoints.docente_controller.py, funcionario_controller.py: academic/staff endpoints.log_controller.py, dlq_controller.py: logs and failed tasks (DLQ).minio_controller.py: file/storage endpoints.database_controller.py: DB utilities/health endpoints.models/SQLAlchemy ORM entities:
user_model.py, group_model.py, route_model.pygroup_permission_model.py, user_group_model.pyuser_card_model.py, card_type_model.py, user_biometry_model.pyaudit_model.py, log_model.py, file_model.pyuser_type_model.py, dlq_model.pyschemas/Pydantic request/response models for controllers:
auth.py, user_type.py, group.py, route.py, card.py, card_type.py, bio.py, docente.py, funcionario.py, audit.py.
services/Business logic and integrations:
auth_service.py: auth, tokens, login flows.user_service.py: user-related operations.permission_service.py: permission checks and rules.route_service.py: route/permission management.security/auth_security.py: security helpers (token verification, guards).decorators/audit_decorator.py: audit logging.cache_decorator.py: caching helpers (e.g., Redis).permission_decorator.py: permission enforcement.app/modules/basic/config/alembic.pyAlembic discovers models via imports. Example:
from ..models.user_model import User
from ..models.group_model import Group
app/modules/basic/config/routes.pyRoutes for the Basic module:
from ..controllers.user_controller import router as user_router
from fastapi import APIRouter
basicRoutes = APIRouter()
basicRoutes.include_router(user_router, prefix="/v1/basic", tags=["Users"])
Endpoints are declared with FastAPI decorators on a module router, and then aggregated in config/routes.py. They commonly use Depends for auth/db injection and shared decorators (e.g., caching).
Example (from auth_controller.py):
@router.get("/permissions", response_model=UniversalResponse, summary="Obter Permissões")
@cache_response(ttl=240, namespace="siga_permissions")
async def get_permissions(
token_data: dict = Depends(validate_token),
db: AsyncSession = Depends(get_db)
):
# ...existing code...
Example used:
@router.get("/permissions", response_model=UniversalResponse, summary="Obter Permissões")
@router.get("/permissions", ...): registers a GET endpoint at /permissions on this module router.response_model=UniversalResponse: enforces/serializes the output to the shared response schema.summary="Obter Permissões": short description shown in Swagger/OpenAPI docs.@cache_response(ttl=240, namespace="siga_permissions"): caches the response for 240 seconds under a namespace, reducing repeat DB calls.UniversalResponse is the shared response schema used across controllers to keep API outputs consistent.
Controllers typically return either:
UniversalResponse.success_response(payload=...) for successful requests, orUniversalResponse.error_response(code=..., cause=..., message=...) for errors.This ensures a uniform response structure for clients regardless of endpoint.
token_data: dict = Depends(validate_token): runs the validate_token dependency; injects the decoded token data (auth guard).db: AsyncSession = Depends(get_db): injects a database session for the request lifecycle.log_audit_infoFor auditable models, any endpoint that creates, updates, or deletes data must include:
log_audit_info: dict = Depends(get_log_audit_info)This ensures audit metadata (user/ip) is captured and attached during the DB operation.
Log, @auditable)Each module should define a table name prefix and use it in __tablename__ for consistency (e.g., siga_, adoc_, afunc_, etc.).
This keeps tables grouped by domain and avoids naming collisions.
Log base mixinAll models should inherit from Log (in addition to Base).
Log provides shared audit fields:
user_id, ip_addresstimestamp (auto-set on insert/update)status (soft delete via ACTIVE/INACTIVE)It also registers SQLAlchemy events to automatically inject audit data from a request context.
@auditable decoratorOnly models that need audit history should be decorated with @auditable.
This enables the audit logging behavior, but is optional—not every model needs it.
Reference (from log_model.py):
// filepath: [log_model.py](http://_vscodecontentref_/1)
# ...existing code...
class Log:
user_id = Column(Integer, nullable=True, index=True)
ip_address = Column(String(45), nullable=True)
timestamp = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), index=True)
status = Column(Enum(siga_Status_enum), default=siga_Status_enum.ACTIVE, index=True)
def soft_delete(self):
self.status = siga_Status_enum.INACTIVE
# ...existing code...
UniversalResponseAll endpoints return UniversalResponse for a consistent API shape.
The payload inside UniversalResponse must be defined by a Pydantic schema in app/modules/<module>/schemas/.
In practice:
response_model=UniversalResponse.payload and should match a schema (e.g., UserResponse, PermissionResponse, etc.).Main commands:
alembic history # list migration history
alembic upgrade head # apply all pending migrations
alembic downgrade -1 # rollback the last migration
alembic check # compare models vs database
Create a new migration:
# 1) Ensure the module is imported in alembic/env.py
# 2) Autogenerate the migration
alembic revision --autogenerate -m "short_description"
# 3) Review the generated file in alembic/versions/
# 4) Apply the migration
alembic upgrade head
Note: if the module isn’t imported in alembic/env.py, its models won’t be detected.