The Cluster ERP server is one FastAPI application that create_app builds in src/cluster_erp/server/app.py. This page explains how its HTTP paths are formed, where the interactive API documentation is available, which content types the routes use, and what happens to one request between the socket and the service. It does not list endpoints; the API reference links one page per route group.
In short¶
- Every backend module mounts its routes under
/api/v1/<module>, the value ofModuleBase.api_prefix(src/cluster_erp/core/module_base.py:37-38). Thefleetandintranetmodules write the same prefix as a literal (src/cluster_erp/modules/fleet/module.py:310,src/cluster_erp/modules/intranet/module.py:172). - The module registry calls each module's
register_routeswhile it loads the module (src/cluster_erp/core/module_registry.py:49-51). - Shared routes outside the modules live in
src/cluster_erp/server/routes/and are included bycreate_app(src/cluster_erp/server/app.py:1432-1450). - The interactive documentation pages exist only when the
debugsetting is on (src/cluster_erp/server/app.py:1296-1303). - Request and response bodies are JSON, except file uploads (multipart form data) and file downloads.
Base paths¶
The table groups the paths that the server answers. The module and shared route counts are on the API reference page.
| Path family | Owner | How the path is formed | Source |
|---|---|---|---|
/api/v1/<module>/... |
28 backend modules | api_prefix plus the router prefix plus the route path |
src/cluster_erp/core/module_base.py:37-38 |
/api/v1/notes, /api/v1/attachments, /api/v1/email, /api/v1/chat |
shared server routes | the router prefix argument |
src/cluster_erp/server/routes/notes.py:14, src/cluster_erp/server/routes/attachments.py:27, src/cluster_erp/server/routes/email.py:22, src/cluster_erp/server/routes/chat.py:23 |
/api/v1/parties/composite, /api/v1/parties/{party_id}/roles/... |
shared server routes | a second router on the parties prefix | src/cluster_erp/server/routes/party_composite.py:27, src/cluster_erp/server/routes/party_roles.py:31 |
/api/v1/{module}/_fields/..., /api/v1/_overlay |
tenant fields | a module name inside the path | src/cluster_erp/server/routes/tenant_fields.py:42-43 |
/api/v1/signup/..., /api/v1/vendor/... |
signup and operator console | included only when multi_tenant is on |
src/cluster_erp/server/app.py:1440-1450 |
/api/v1/modules, /api/v1/_meta, /api/v1/_switches |
application | declared with @app.get |
src/cluster_erp/server/app.py:1507-1572 |
/health, /ready, /.well-known/security.txt |
application | declared with @app.get |
src/cluster_erp/server/app.py:1459-1504 |
/app/..., /app/v/... |
web app static files | app.mount when the webapp folder exists |
src/cluster_erp/server/app.py:1633-1644 |
Module prefixes¶
Most modules create a module_router with prefix=self.api_prefix, include their sub-module routers into it, and include it into the application with an entitlement dependency. The inventory module is an example (src/cluster_erp/modules/inventory/module.py:52-62). Some modules skip the module_router and pass the prefix to app.include_router directly, for example analytics, app_store, logs, mail, privacy, and records (src/cluster_erp/modules/analytics/module.py:55, src/cluster_erp/modules/records/module.py:50-52).
A sub-module router adds its own prefix, for example /warehouses (src/cluster_erp/modules/inventory/warehouses/routes.py:33). Several routers have no prefix and write the resource segment into every route path instead: the crm routers, the calendars router, the parties routers, the sales order routers, the currency router, and the customer subscription router (src/cluster_erp/modules/crm/customers/routes.py:28, src/cluster_erp/modules/calendars/routes.py:44, src/cluster_erp/modules/parties/parties/routes.py:28, src/cluster_erp/modules/sales_orders/orders/routes.py:33, src/cluster_erp/server/routes/currencies.py:18, src/cluster_erp/modules/subscriptions/customer_subscriptions/routes.py:30-34). The module pages show the full path of every route, so a reader does not have to add the parts.
OpenAPI availability¶
create_app passes docs_url="/api/docs" and redoc_url="/api/redoc" only when settings.debug is true; otherwise both are None (src/cluster_erp/server/app.py:1296-1303). The debug setting defaults to False (src/cluster_erp/config/settings.py:176). The call passes no openapi_url argument, so the framework default applies; see the FastAPI reference. Two routes are excluded from the schema with include_in_schema=False: the closed-signup probe and /.well-known/security.txt (src/cluster_erp/server/app.py:1455, src/cluster_erp/server/app.py:1459). Each router passes tags, which group the operations in the generated schema, for example tags=["inventory-warehouses"] (src/cluster_erp/modules/inventory/warehouses/routes.py:33).
Content types¶
| Content | Where | Source |
|---|---|---|
| JSON request and response bodies | every route with a Pydantic body or a response_model |
route decorators in the module pages |
| Multipart form data | 6 routes take an UploadFile: attachment upload and replace, mail draft attachment, party photo, product photo, product model photo |
src/cluster_erp/server/routes/attachments.py:62, src/cluster_erp/modules/mail/messages/routes.py:130, src/cluster_erp/modules/parties/parties/routes.py:187, src/cluster_erp/modules/products_and_services/products/routes.py:216, src/cluster_erp/modules/products_and_services/product_models/routes.py:150 |
| File downloads | routes that return a Response, for example attachment download, document version file, trade document download, privacy export |
src/cluster_erp/server/routes/attachments.py:102, src/cluster_erp/modules/documents/documents/routes.py:240, src/cluster_erp/modules/sales_orders/trade_documents/routes.py:84, src/cluster_erp/modules/privacy/requests/routes.py:153 |
text/calendar |
event iCalendar export | src/cluster_erp/modules/intranet/events/routes.py:307 |
image/svg+xml, application/dxf |
nesting layout output | src/cluster_erp/modules/nesting/nesting_jobs/routes.py:322-394 |
text/plain |
/.well-known/security.txt |
src/cluster_erp/server/app.py:1459-1466 |
| gzip encoding | responses of 1 KB or more | src/cluster_erp/server/app.py:1323 |
The path of one request¶
The diagram follows one authenticated request to a module route. It shows what the code does, not timing. The order in which the framework resolves the dependencies of one route is not stated in the project's code, so the three dependencies appear together.
sequenceDiagram participant Client participant Middleware participant Dependencies participant Handler participant Service participant Database Client->>Middleware: HTTP request Note over Middleware: _security_headers refuses an oversized body with 413 Middleware->>Dependencies: call the route Note over Dependencies: get_db_session, require_app, require_permission Dependencies->>Database: open the tenant session, set the audit context Dependencies->>Handler: user and session, or 401, 403, 422 Handler->>Service: validated schema Service->>Database: query and flush Service-->>Handler: result or AppError Handler-->>Middleware: response model Note over Middleware: commit before the first byte, activity log, security headers Middleware-->>Client: JSON response
The same steps in prose:
| Step | What happens | Source |
|---|---|---|
| Body limit | A Content-Length above max_request_body_bytes gets 413 with code REQUEST_TOO_LARGE. |
src/cluster_erp/server/app.py:1390-1411 |
| Session | get_db_session resolves the tenant database, opens a session, and writes the actor, IP address, client software string, session id, and correlation id into the database session settings. |
src/cluster_erp/server/dependencies.py:160-200, src/cluster_erp/server/dependencies.py:34-72 |
| Entitlement | require_app checks the installed, licensed, and seated state of the module and raises 403 with an entitlement.* code. |
src/cluster_erp/server/entitlements.py:225-273 |
| Permission | require_permission resolves the user, requires every listed permission code, and evaluates ABAC policies. |
src/cluster_erp/modules/auth/guards.py:205-240 |
| Validation | A body or parameter that does not match the schema gets 422 with code VALIDATION_ERROR. |
src/cluster_erp/server/error_handler.py:226-246 |
| Handler and service | The handler builds the service with the session and calls it; services raise AppError for business rule failures. |
src/cluster_erp/modules/inventory/warehouses/routes.py:108-116 |
| Commit | CommitBeforeResponseMiddleware runs the session's commit hook when the response starts. |
src/cluster_erp/server/middleware.py:25-57, src/cluster_erp/server/dependencies.py:168-190 |
| Logging and headers | ActivityLogMiddleware records the request; _security_headers adds the security headers. |
src/cluster_erp/server/middleware.py:424, src/cluster_erp/server/app.py:1412-1429 |
The middleware order and each layer are explained in Request pipeline and middleware.
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| API prefix | api_prefix |
The base path of a module's routes, /api/v1/ followed by the module name. |
API öneki | src/cluster_erp/core/module_base.py:37-38 |
| module router | module_router |
The router a module creates with its API prefix and into which it includes its sub-module routers. | modül yönlendiricisi | src/cluster_erp/modules/inventory/module.py:52 |
Related pages¶
- API reference
- Authentication and headers
- API conventions
- Errors
- Server startup and app factory
- Module lifecycle
Verified against commit 92f8051 on 2026-11-13.