Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/IvanchoDev89/maleku-system/llms.txt

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

Maleku System uses a Role-Based Access Control (RBAC) model to govern every action a user can perform on the platform. All users are assigned exactly one role — stored in the role column of the users table — chosen from six values defined in the UserRole enum: client, vendor, agent, customer_service, admin, and super_admin. Roles are not strictly hierarchical: agent and customer_service are lateral operational roles with narrowly scoped permissions, while super_admin has unconditional access to all resources. Permission checks are enforced via FastAPI dependency injection at the endpoint level using the require_role(), require_permission(), and require_verified_email() guards defined in app/core/security.py.

Roles

client

The default role assigned to every newly registered user. Clients can browse listings, search destinations, create bookings, cancel their own bookings, read blog and destination content, and leave reviews on completed stays or tours.

vendor

Vendors can create and manage their own listings (properties, tours, vehicles, boats, transportation), view their personal analytics dashboard, and receive payouts via Stripe Connect. They also inherit client-level read permissions for listings and content.

agent

A lateral operational role for travel agents. Agents can create, read, update, and cancel bookings on behalf of clients, and read properties, tours, and chat threads. Agents do not have vendor or admin capabilities.

customer_service

A narrow support role that can read and update bookings, cancel bookings, and participate in chat. Customer service staff have no access to listings, analytics, or administrative functions.

admin

Admins handle platform-wide operations: approving vendor accounts, moderating content (blog posts, destinations), viewing audit logs, exporting booking reports, and managing bookings across all vendors. Admins can read user records but cannot change roles or delete accounts.

super_admin

Super Admins have unconditional access to every endpoint on the platform. In addition to all admin capabilities, they can change user roles, permanently delete accounts, impersonate other users, access system settings, run compliance checks on vendors, and export any data set.
Vendors must be verified by a Super Admin before their listings appear publicly on the platform. The is_verified flag on the Vendor model controls this gate. Until verification, listings are visible in the vendor’s own dashboard but are excluded from public search and listing pages.

Permission Matrix

The table below summarises what each role can do across the main resource categories. Permission combinations are defined in DEFAULT_ROLE_PERMISSIONS inside app/core/security.py and can be customised per-role by a Super Admin via the role_permissions database table.
Resourceclientvendoragentcustomer_serviceadminsuper_admin
PropertiesReadCreate, Read, Update, DeleteReadRead, Create, Update, FeatureFull + Delete
ToursReadCreate, Read, Update, DeleteReadRead, Create, UpdateFull + Delete
BookingsCreate, Read, CancelRead, UpdateCreate, Read, Update, CancelRead, Update, CancelRead, Create, Update, Cancel, ExportFull + Refund
Content (CMS)ReadRead, Create, UpdateFull CRUD + publishFull CRUD + publish + SEO
ChatRead, CreateRead, CreateRead, CreateRead, CreateRead, CreateFull
User ManagementReadCreate, Read, Update, Delete, Impersonate, Block, Export
VendorsRead, ApproveFull + Suspend, Export
AnalyticsRead, ReportsRead, Export, Reports
Audit LogsRead (system.logs)Full access + export
System SettingsSettings, Maintenance, Backup, Logs, Permissions

Authentication Guards

All permission logic is enforced through three FastAPI dependency functions in app/core/security.py:

require_role(*roles)

Checks that current_user.role is one of the provided roles. If not, a 403 Forbidden is raised with a detail message listing the required roles. Used directly on endpoints that need a hard role boundary:
# Only SUPER_ADMIN may verify a vendor
current_user: User = Depends(require_role(UserRole.SUPER_ADMIN))

require_superadmin()

A convenience wrapper around require_role(UserRole.SUPER_ADMIN). Used across all /api/v1/superadmin/ routes for consistent enforcement:
current_user: User = Depends(require_superadmin())

require_permission(module, action)

A finer-grained guard that checks whether the user’s role is allowed to perform action on module. It first queries the role_permissions table in the database — allowing a Super Admin to customise permissions at runtime — and falls back to DEFAULT_ROLE_PERMISSIONS if no database row exists. SUPER_ADMIN bypasses the check entirely:
# Example: require the "export" action on "bookings"
current_user: User = Depends(require_permission("bookings", "export"))

require_verified_email()

Wraps get_current_active_user and additionally checks current_user.is_verified. Any request from an unverified user is rejected with 403 Forbidden and the message “Email verification required. Please verify your email before proceeding.” This guard is applied to all booking-creation endpoints.

JWT Token Lifecycle

Maleku System issues two tokens on every successful login, both signed with HS256 using settings.SECRET_KEY.
Token TypePayload type fieldDefault ExpiryConfig Key
Access Tokenaccess60 minutesACCESS_TOKEN_EXPIRE_MINUTES
Refresh Tokenrefresh7 daysREFRESH_TOKEN_EXPIRE_DAYS
Verification Tokenverification24 hoursHardcoded in create_verification_token()
Password Reset Tokenpassword_reset1 hourHardcoded in create_password_reset_token()
# Creating an access token (from app/core/security.py)
def create_access_token(subject: str | Any, expires_delta: timedelta | None = None) -> str:
    if expires_delta:
        expire = datetime.now(UTC) + expires_delta
    else:
        expire = datetime.now(UTC) + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)

    to_encode = {"exp": expire, "sub": str(subject), "type": "access"}
    return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
Token blacklisting — when a user logs out (or changes their password), the access token is added to a Redis-backed blacklist via token_blacklist. Every incoming request goes through get_current_user(), which calls token_blacklist.is_blacklisted(token) before decoding. Additionally, token_blacklist.is_user_tokens_blacklisted() checks against the token’s iat claim to invalidate all tokens issued before the last password change.

Email Verification

Every new user account starts with is_verified = False. A time-limited verification token (24-hour expiry) is sent to the user’s email address via create_verification_token(). Until the user clicks the verification link:
  • They can log in and browse public content.
  • They cannot create bookings — the require_verified_email() dependency blocks the attempt with HTTP 403.
The is_verified flag lives on the User model:
# From app/models/user.py
is_verified = Column(Boolean, default=False, nullable=False)
email_verification_token = Column(String(255), nullable=True)
email_verification_expires = Column(DateTime(timezone=True), nullable=True)
A Super Admin can manually flip is_verified to True via the PUT /api/v1/superadmin/users/{user_id} endpoint. Users created directly by a Super Admin are pre-verified (is_verified=True) and skip the email flow.

Build docs developers (and LLMs) love