The projects module serves projects with production roll-up and earned value reads, schedules, kick-offs, meetings, actions, fixtures, project items, activities with relations and material links, and the project board. All 64 endpoints sit under /api/v1/projects. For business meaning see the Projects module page.
Group facts¶
| Item | Value | Source |
|---|---|---|
| Base path | /api/v1/projects |
src/cluster_erp/core/module_base.py:37-38, src/cluster_erp/modules/projects/module.py:67 |
| Routers | 9 router objects in 9 files; listed in the section Endpoint summary | src/cluster_erp/modules/projects/module.py:35 |
| Endpoints | 64, counted from the route decorators and add_api_route calls of the routers that register_routes mounts |
src/cluster_erp/modules/projects/actions/routes.py, src/cluster_erp/modules/projects/activities/routes.py, src/cluster_erp/modules/projects/board_routes.py ... |
| Authentication | Bearer header or session cookie, resolved by get_current_user; see Authentication and headers |
src/cluster_erp/modules/auth/guards.py:85-167 |
| Permission guard | 64 of 64 routes declare require_permission |
src/cluster_erp/modules/auth/guards.py:205-240 |
| App entitlement gate | require_app("projects") on every mounted router |
src/cluster_erp/modules/projects/module.py:78 |
| Error format | JSON body {"error": {...}}; see Errors |
src/cluster_erp/server/error_handler.py:33-46 |
Endpoint summary¶
One row per sub-module folder. The router prefix is added to the base path.
| Sub-module | Routers | Endpoints | Router source |
|---|---|---|---|
projects |
router (/projects) |
9 | src/cluster_erp/modules/projects/projects/routes.py:28 |
schedules |
router (/schedules) |
7 | src/cluster_erp/modules/projects/schedules/routes.py:19 |
kickoffs |
router (/kickoffs) |
7 | src/cluster_erp/modules/projects/kickoffs/routes.py:20 |
meetings |
router (/meetings) |
6 | src/cluster_erp/modules/projects/meetings/routes.py:20 |
actions |
router (/actions) |
8 | src/cluster_erp/modules/projects/actions/routes.py:22 |
fixtures |
router (/fixtures) |
7 | src/cluster_erp/modules/projects/fixtures/routes.py:21 |
items |
router (/project-items) |
7 | src/cluster_erp/modules/projects/items/routes.py:22 |
activities |
router (/activities) |
12 | src/cluster_erp/modules/projects/activities/routes.py:24 |
board_routes |
router (/project-board) |
1 | src/cluster_erp/modules/projects/board_routes.py:17 |
Projects endpoints¶
Project records, production roll-up, earned value (EVM), and status transition.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/projects/ |
list_projects |
project.read |
none | search, status, customer_id, project_manager_id, limit, offset |
dict |
200 (default) | src/cluster_erp/modules/projects/projects/routes.py:40 |
POST |
/api/v1/projects/projects/ |
create_project |
project.create |
ProjectCreate |
none | ProjectRead |
201 |
src/cluster_erp/modules/projects/projects/routes.py:76 |
GET |
/api/v1/projects/projects/{project_id} |
get_project |
project.read |
none | none | ProjectRead |
200 (default) | src/cluster_erp/modules/projects/projects/routes.py:88 |
GET |
/api/v1/projects/projects/{project_id}/production-rollup |
project_production_rollup |
project.read |
none | none | dict |
200 (default) | src/cluster_erp/modules/projects/projects/routes.py:102 |
GET |
/api/v1/projects/projects/{project_id}/evm |
project_evm |
project.read |
none | none | dict |
200 (default) | src/cluster_erp/modules/projects/projects/routes.py:125 |
PUT |
/api/v1/projects/projects/{project_id} |
update_project |
project.update |
ProjectUpdate |
none | ProjectRead |
200 (default) | src/cluster_erp/modules/projects/projects/routes.py:270 |
POST |
/api/v1/projects/projects/{project_id}/transition |
transition_project |
project.update |
TransitionRequest |
none | ProjectRead |
200 (default) | src/cluster_erp/modules/projects/projects/routes.py:285 |
DELETE |
/api/v1/projects/projects/{project_id} |
delete_project |
project.delete |
none | none | none | 204 |
src/cluster_erp/modules/projects/projects/routes.py:298 |
POST |
/api/v1/projects/projects/bulk-delete |
bulk_delete_projects |
project.bulk_delete |
BulkDeleteRequest |
none | BulkDeleteResponse |
200 (default) | src/cluster_erp/modules/projects/projects/routes.py:310 |
Schedules endpoints¶
Schedules of a project, publish, and share with the customer.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/schedules/by-project/{project_id} |
list_schedules_by_project |
project.read |
none | none | list[ScheduleRead] |
200 (default) | src/cluster_erp/modules/projects/schedules/routes.py:22 |
POST |
/api/v1/projects/schedules/ |
create_schedule |
project.update |
ScheduleCreate |
none | ScheduleRead |
201 |
src/cluster_erp/modules/projects/schedules/routes.py:34 |
GET |
/api/v1/projects/schedules/{schedule_id} |
get_schedule |
project.read |
none | none | ScheduleRead |
200 (default) | src/cluster_erp/modules/projects/schedules/routes.py:46 |
PUT |
/api/v1/projects/schedules/{schedule_id} |
update_schedule |
project.update |
ScheduleUpdate |
none | ScheduleRead |
200 (default) | src/cluster_erp/modules/projects/schedules/routes.py:60 |
POST |
/api/v1/projects/schedules/{schedule_id}/publish |
publish_schedule |
project.update |
none | none | ScheduleRead |
200 (default) | src/cluster_erp/modules/projects/schedules/routes.py:75 |
POST |
/api/v1/projects/schedules/{schedule_id}/share-with-customer |
share_schedule_with_customer |
project.update |
none | none | ScheduleRead |
200 (default) | src/cluster_erp/modules/projects/schedules/routes.py:87 |
DELETE |
/api/v1/projects/schedules/{schedule_id} |
delete_schedule |
project.update |
none | none | none | 204 |
src/cluster_erp/modules/projects/schedules/routes.py:99 |
Kick-offs endpoints¶
The kick-off of a project, its checklist, and mark held.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/kickoffs/by-project/{project_id} |
get_kickoff_by_project |
project.read |
none | none | KickoffRead \| None |
200 (default) | src/cluster_erp/modules/projects/kickoffs/routes.py:23 |
POST |
/api/v1/projects/kickoffs/ |
create_kickoff |
meeting.record |
KickoffCreate |
none | KickoffRead |
201 |
src/cluster_erp/modules/projects/kickoffs/routes.py:37 |
GET |
/api/v1/projects/kickoffs/{kickoff_id} |
get_kickoff |
project.read |
none | none | KickoffRead |
200 (default) | src/cluster_erp/modules/projects/kickoffs/routes.py:49 |
PUT |
/api/v1/projects/kickoffs/{kickoff_id} |
update_kickoff |
meeting.record |
KickoffUpdate |
none | KickoffRead |
200 (default) | src/cluster_erp/modules/projects/kickoffs/routes.py:63 |
POST |
/api/v1/projects/kickoffs/{kickoff_id}/checklist |
update_checklist |
meeting.record |
list[ChecklistItemUpdate] |
none | KickoffRead |
200 (default) | src/cluster_erp/modules/projects/kickoffs/routes.py:76 |
POST |
/api/v1/projects/kickoffs/{kickoff_id}/mark-held |
mark_held |
meeting.record |
none | none | KickoffRead |
200 (default) | src/cluster_erp/modules/projects/kickoffs/routes.py:89 |
DELETE |
/api/v1/projects/kickoffs/{kickoff_id} |
delete_kickoff |
meeting.record |
none | none | none | 204 |
src/cluster_erp/modules/projects/kickoffs/routes.py:101 |
Meetings endpoints¶
Meetings of a project.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/meetings/by-project/{project_id} |
list_meetings_by_project |
project.read |
none | none | list[MeetingRead] |
200 (default) | src/cluster_erp/modules/projects/meetings/routes.py:23 |
POST |
/api/v1/projects/meetings/ |
create_meeting |
meeting.record |
MeetingCreate |
none | MeetingRead |
201 |
src/cluster_erp/modules/projects/meetings/routes.py:35 |
GET |
/api/v1/projects/meetings/{meeting_id} |
get_meeting |
project.read |
none | none | MeetingRead |
200 (default) | src/cluster_erp/modules/projects/meetings/routes.py:47 |
PUT |
/api/v1/projects/meetings/{meeting_id} |
update_meeting |
meeting.record |
MeetingUpdate |
none | MeetingRead |
200 (default) | src/cluster_erp/modules/projects/meetings/routes.py:61 |
DELETE |
/api/v1/projects/meetings/{meeting_id} |
delete_meeting |
meeting.record |
none | none | none | 204 |
src/cluster_erp/modules/projects/meetings/routes.py:74 |
POST |
/api/v1/projects/meetings/bulk-delete |
bulk_delete_meetings |
meeting.record |
BulkDeleteRequest |
none | BulkDeleteResponse |
200 (default) | src/cluster_erp/modules/projects/meetings/routes.py:85 |
Actions endpoints¶
Actions of a project, overdue actions, and transition.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/actions/by-project/{project_id} |
list_by_project |
project.read |
none | status |
list[ActionListRead] |
200 (default) | src/cluster_erp/modules/projects/actions/routes.py:25 |
GET |
/api/v1/projects/actions/overdue |
list_overdue |
project.read |
none | none | list[ActionListRead] |
200 (default) | src/cluster_erp/modules/projects/actions/routes.py:38 |
POST |
/api/v1/projects/actions/ |
create_action |
action.assign |
ActionCreate |
none | ActionRead |
201 |
src/cluster_erp/modules/projects/actions/routes.py:49 |
GET |
/api/v1/projects/actions/{action_id} |
get_action |
project.read |
none | none | ActionRead |
200 (default) | src/cluster_erp/modules/projects/actions/routes.py:61 |
PUT |
/api/v1/projects/actions/{action_id} |
update_action |
project.update |
ActionUpdate |
none | ActionRead |
200 (default) | src/cluster_erp/modules/projects/actions/routes.py:75 |
POST |
/api/v1/projects/actions/{action_id}/transition |
transition_action |
action.assign |
ActionTransition |
none | ActionRead |
200 (default) | src/cluster_erp/modules/projects/actions/routes.py:88 |
DELETE |
/api/v1/projects/actions/{action_id} |
delete_action |
project.update |
none | none | none | 204 |
src/cluster_erp/modules/projects/actions/routes.py:101 |
POST |
/api/v1/projects/actions/bulk-delete |
bulk_delete_actions |
project.update |
BulkDeleteRequest |
none | BulkDeleteResponse |
200 (default) | src/cluster_erp/modules/projects/actions/routes.py:113 |
Fixtures endpoints¶
Fixtures of a project and transition.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/fixtures/by-project/{project_id} |
list_by_project |
project.read |
none | none | list[FixtureRead] |
200 (default) | src/cluster_erp/modules/projects/fixtures/routes.py:24 |
POST |
/api/v1/projects/fixtures/ |
create_fixture |
project.update |
FixtureCreate |
none | FixtureRead |
201 |
src/cluster_erp/modules/projects/fixtures/routes.py:36 |
GET |
/api/v1/projects/fixtures/{fixture_id} |
get_fixture |
project.read |
none | none | FixtureRead |
200 (default) | src/cluster_erp/modules/projects/fixtures/routes.py:48 |
PUT |
/api/v1/projects/fixtures/{fixture_id} |
update_fixture |
project.update |
FixtureUpdate |
none | FixtureRead |
200 (default) | src/cluster_erp/modules/projects/fixtures/routes.py:62 |
POST |
/api/v1/projects/fixtures/{fixture_id}/transition |
transition_fixture |
project.update |
FixtureTransition |
none | FixtureRead |
200 (default) | src/cluster_erp/modules/projects/fixtures/routes.py:75 |
DELETE |
/api/v1/projects/fixtures/{fixture_id} |
delete_fixture |
project.update |
none | none | none | 204 |
src/cluster_erp/modules/projects/fixtures/routes.py:88 |
POST |
/api/v1/projects/fixtures/bulk-delete |
bulk_delete_fixtures |
project.update |
BulkDeleteRequest |
none | BulkDeleteResponse |
200 (default) | src/cluster_erp/modules/projects/fixtures/routes.py:100 |
Project items endpoints¶
Items of a project and production order creation for an item.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/project-items/by-project/{project_id} |
list_by_project |
project.read |
none | none | list[ProjectItemRead] |
200 (default) | src/cluster_erp/modules/projects/items/routes.py:25 |
POST |
/api/v1/projects/project-items/ |
create_project_item |
project.update |
ProjectItemCreate |
none | ProjectItemRead |
201 |
src/cluster_erp/modules/projects/items/routes.py:37 |
GET |
/api/v1/projects/project-items/{item_id} |
get_project_item |
project.read |
none | none | ProjectItemRead |
200 (default) | src/cluster_erp/modules/projects/items/routes.py:49 |
PUT |
/api/v1/projects/project-items/{item_id} |
update_project_item |
project.update |
ProjectItemUpdate |
none | ProjectItemRead |
200 (default) | src/cluster_erp/modules/projects/items/routes.py:63 |
DELETE |
/api/v1/projects/project-items/{item_id} |
delete_project_item |
project.update |
none | none | none | 204 |
src/cluster_erp/modules/projects/items/routes.py:76 |
POST |
/api/v1/projects/project-items/{item_id}/create-production-order |
create_production_order_for_item |
CreateProductionOrderForProject.REQUIRED_PERMISSION |
none | none | dict |
200 (default) | src/cluster_erp/modules/projects/items/routes.py:88 |
POST |
/api/v1/projects/project-items/bulk-delete |
bulk_delete_project_items |
project.update |
BulkDeleteRequest |
none | BulkDeleteResponse |
200 (default) | src/cluster_erp/modules/projects/items/routes.py:139 |
Activities endpoints¶
Activities by schedule and by project, relations, and material links.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/activities/by-schedule/{schedule_id} |
list_activities |
project.read |
none | none | dict |
200 (default) | src/cluster_erp/modules/projects/activities/routes.py:27 |
GET |
/api/v1/projects/activities/for-project |
list_activities_for_project |
project.read |
none | project_id |
dict |
200 (default) | src/cluster_erp/modules/projects/activities/routes.py:43 |
GET |
/api/v1/projects/activities/by-project/{project_id} |
list_activities_by_project |
project.read |
none | none | dict |
200 (default) | src/cluster_erp/modules/projects/activities/routes.py:55 |
GET |
/api/v1/projects/activities/{activity_id} |
get_activity |
project.read |
none | none | ActivityRead |
200 (default) | src/cluster_erp/modules/projects/activities/routes.py:90 |
POST |
/api/v1/projects/activities/ |
create_activity |
project.update |
ActivityCreate |
none | ActivityRead |
201 |
src/cluster_erp/modules/projects/activities/routes.py:105 |
PUT |
/api/v1/projects/activities/{activity_id} |
update_activity |
project.update |
ActivityUpdate |
none | ActivityRead |
200 (default) | src/cluster_erp/modules/projects/activities/routes.py:117 |
DELETE |
/api/v1/projects/activities/{activity_id} |
delete_activity |
project.update |
none | none | none | 204 |
src/cluster_erp/modules/projects/activities/routes.py:132 |
POST |
/api/v1/projects/activities/relations |
add_relation |
project.update |
RelationCreate |
none | RelationRead |
201 |
src/cluster_erp/modules/projects/activities/routes.py:144 |
DELETE |
/api/v1/projects/activities/relations/{relation_id} |
delete_relation |
project.update |
none | none | none | 204 |
src/cluster_erp/modules/projects/activities/routes.py:156 |
GET |
/api/v1/projects/activities/{activity_id}/materials |
list_material_links |
project.read |
none | none | dict |
200 (default) | src/cluster_erp/modules/projects/activities/routes.py:168 |
POST |
/api/v1/projects/activities/materials |
add_material_link |
project.update |
MaterialLinkCreate |
none | MaterialLinkRead |
201 |
src/cluster_erp/modules/projects/activities/routes.py:180 |
DELETE |
/api/v1/projects/activities/materials/{link_id} |
delete_material_link |
project.update |
none | none | none | 204 |
src/cluster_erp/modules/projects/activities/routes.py:192 |
Project board endpoints¶
One read model for the project board, defined in src/cluster_erp/modules/projects/board_routes.py.
| Method | Path | Handler | Permission | Request | Query | Response | Status | Source |
|---|---|---|---|---|---|---|---|---|
GET |
/api/v1/projects/project-board/ |
get_project_board |
project.read |
none | date_from, date_to, scope |
dict |
200 (default) | src/cluster_erp/modules/projects/board_routes.py:20 |
Error codes¶
The table lists the error codes that code under src/cluster_erp/modules/projects/ raises, found by a syntax-tree scan for AppError(...), the factories in src/cluster_erp/core/errors.py (not_found, conflict, protected, permission_denied, privilege_escalation, check_version), and HTTPException(...). A status of 400 is the AppError default (src/cluster_erp/core/errors.py:23). Guard errors (401, 403), the entitlement codes, and validation errors (422) apply to every route and are listed on Errors.
| Code | HTTP status | Raised in | First site |
|---|---|---|---|
CONCURRENCY_VERSION_CONFLICT |
409 |
activities |
src/cluster_erp/modules/projects/activities/services.py:128 |
PROJECTS_ITEM_NO_PRODUCT |
422 |
items |
src/cluster_erp/modules/projects/items/routes.py:119 |
PROJECT_ACTION_ALREADY_CLOSED |
400 |
actions |
src/cluster_erp/modules/projects/actions/services.py:161 |
PROJECT_ACTION_INVALID_TRANSITION |
400 |
actions |
src/cluster_erp/modules/projects/actions/services.py:167 |
PROJECT_ACTIVITY_CYCLE |
422 |
activities |
src/cluster_erp/modules/projects/activities/services.py:186 |
PROJECT_ACTIVITY_INVALID |
404, 422 |
activities |
src/cluster_erp/modules/projects/activities/services.py:100 |
PROJECT_FIXTURE_INVALID_TRANSITION |
400 |
fixtures |
src/cluster_erp/modules/projects/fixtures/services.py:139 |
PROJECT_INVALID_STATUS |
400 |
projects |
src/cluster_erp/modules/projects/projects/services.py:305 |
PROJECT_SCHEDULE_NOT_DRAFT |
400 |
schedules |
src/cluster_erp/modules/projects/schedules/services.py:78 |
RESOURCE_NOT_FOUND |
404 |
actions, activities, fixtures, items, kickoffs, meetings, projects, schedules |
src/cluster_erp/modules/projects/actions/routes.py:71 |
Events emitted¶
The table lists the contract classes that code under src/cluster_erp/modules/projects/ passes directly to EventBus.emit, found by a syntax-tree scan. Events built in a variable first are not counted. The contracts are described in Contracts reference.
| Contract | Sites | First site |
|---|---|---|
ProjectActionCreated |
1 | src/cluster_erp/modules/projects/actions/services.py:93 |
ProjectActivityChanged |
1 | src/cluster_erp/modules/projects/activities/services.py:49 |
ProjectClosed |
1 | src/cluster_erp/modules/projects/projects/services.py:279 |
ProjectCreated |
1 | src/cluster_erp/modules/projects/projects/services.py:142 |
ProjectFixtureRequired |
1 | src/cluster_erp/modules/projects/fixtures/services.py:76 |
ProjectKickoffCompleted |
2 | src/cluster_erp/modules/projects/kickoffs/services.py:113 |
ProjectSchedulePublished |
1 | src/cluster_erp/modules/projects/schedules/services.py:138 |
ProjectScheduleShared |
1 | src/cluster_erp/modules/projects/schedules/services.py:162 |
ProjectStatusChanged |
1 | src/cluster_erp/modules/projects/projects/services.py:261 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.