Access control in PrintHeritage is enforced at two levels: a global role that travels with your user account and governs platform-wide operations, and a project-level permission that controls your access to specific projects. Both levels use the sameDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/joaomonteir0/printheritage/llms.txt
Use this file to discover all available pages before exploring further.
GlobalRole enum, keeping the permission model uniform and easy to reason about. Every API request is validated against these roles before any data is read or written.
Global Roles
Every user account carries a singleglobal_role value drawn from the GlobalRole enum defined in models.py. New accounts default to VISUALIZER unless a different role is specified at registration.
| Role | Description |
|---|---|
SUPER_ADMIN | Full, unrestricted access to the entire platform. Bypasses all project-level permission checks. Can view audit logs, list all users, and perform any operation on any project. |
GENERAL_ADMIN | Administrative access without audit-log visibility. Bypasses project-level checks and can list all users platform-wide. Cannot access the /audit-logs endpoint. |
PROJECT_ADMIN | Project-scoped administration. Must hold an ACCEPTED ProjectPermission for each project. Can add and delete datasets within permitted projects. |
VISUALIZER | Read-only access. Must hold an ACCEPTED ProjectPermission to view a project. Cannot delete datasets. |
The
global_role on a User record and the access_level on a ProjectPermission record are both typed as the same GlobalRole enum. When a user is added to a project, their current global_role is copied into access_level automatically, but the two values are stored independently and can diverge if a user’s global role is later updated.Role Capabilities at a Glance
| Capability | SUPER_ADMIN | GENERAL_ADMIN | PROJECT_ADMIN | VISUALIZER |
|---|---|---|---|---|
| View audit logs | ✅ | ❌ | ❌ | ❌ |
List all users (GET /users) | ✅ | ✅ | ❌ | ❌ |
| Bypass project-level access checks | ✅ | ✅ | ❌ | ❌ |
| View all projects platform-wide | ✅ | ✅ | ❌ | ❌ |
| Create projects | ✅ | ✅ | ✅ | ✅ |
| Read project data (with permission) | ✅ | ✅ | ✅ | ✅ |
| Add datasets to a project | ✅ | ✅ | ✅ | ❌ |
| Delete datasets from a project | ✅ | ✅ | ✅ | ❌ |
| Invite members to a project | ✅ | ✅ | ✅ | ❌ |
The RoleChecker Guard
Endpoints that require a minimum global role use theRoleChecker dependency from security.py. It accepts a list of permitted roles. SUPER_ADMIN users always pass regardless of what roles are listed:
Project Permissions
TheProjectPermission model records a user’s membership in a specific project. Each row links one user to one project and cannot be duplicated (enforced by a UNIQUE constraint on (user_id, project_id)).
| Field | Type | Description |
|---|---|---|
id | UUID | Auto-generated identifier for the permission record. |
user_id | UUID (FK → users.id) | The member being granted access. |
project_id | UUID (FK → projects.id) | The project this permission applies to. |
invited_by | UUID (FK → users.id) | The user who sent the invitation. Nullable for auto-created owner permissions. |
access_level | GlobalRole | The role this member holds within the project. |
status | PermissionStatus | Invitation lifecycle state: PENDING, ACCEPTED, or REJECTED. |
is_read | Boolean | Whether the user has read the invitation notification. |
is_favorite | Boolean | Whether this user has marked the project as a favorite. |
PermissionStatus
ACCEPTED permissions grant access to project data. PENDING invitations appear in the user’s invitation inbox at GET /invitations and can be acted on via POST /invitations/{id}/accept or POST /invitations/{id}/reject.
How validate_project_access Works
Every project-scoped endpoint calls security.validate_project_access before returning data. The check proceeds as follows:
- If the requesting user’s
global_roleisSUPER_ADMINorGENERAL_ADMIN, access is granted immediately — noProjectPermissionrow is required. - Otherwise, the function queries for an
ACCEPTEDProjectPermissionmatching the user and project. If none exists, a403 Forbiddenerror is raised.
Dataset Deletion Restriction
Deleting a dataset requiresPROJECT_ADMIN or higher. VISUALIZER accounts receive HTTP 403 even when they hold an ACCEPTED project permission:
ACCEPTED ProjectPermission and a sufficiently privileged global_role.