Skip to content

Creating Tables

Kloudmint doesn't run migrations or own your database -- it works directly with your project's own SQLAlchemy models and Base. There are two kinds of tables involved: your own domain tables (Customers, Orders, whatever your app is about) and the Role/Permission tables kloudmint needs for RBAC.

1. Your own domain models -- nothing kloudmint-specific

Define these exactly as you normally would in SQLAlchemy:

# models.py
from sqlalchemy import Column, Integer, String, Numeric
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class Product(Base):
    __tablename__ = "products"

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    price = Column(Numeric(10, 2), nullable=False)

If a model will be shown in the admin as a related field (e.g. an Order.customer dropdown), give it a __str__ method -- otherwise the admin shows a raw <Customer object at 0x...> instead of a name:

class Customer(Base):
    ...
    def __str__(self) -> str:
        return self.full_name

2. The Role / Permission tables -- generated by kloudmint

Call create_rbac_models(Base) once, binding Role/Permission onto your app's own Base (same Base as your domain models, so they live in the same database):

from kloudmint.models import create_rbac_models

Role, Permission = create_rbac_models(Base)

This gives you two classes with these columns:

Model Columns
Role id, name
Permission id, role_id, resource, action

3. Actually creating the tables in the database

Kloudmint doesn't run this for you -- use whichever approach your project already uses:

Quick / prototyping (what the example apps use):

Base.metadata.create_all(engine)

Production projects (recommended): use Alembic so table changes are versioned:

alembic revision --autogenerate -m "add roles and permissions tables"
alembic upgrade head

Alembic will pick up Role/Permission automatically as long as they're defined on the same Base your env.py points target_metadata at.

4. Seeding an initial role + admin user

You need at least one role with permissions and one user pointing at it before you can log in. A minimal seed script:

def seed():
    Base.metadata.create_all(engine)

    with SessionLocal() as db:
        role = Role(name="super_admin")
        db.add(role)
        db.flush()

        for resource in ["Product", "Role", "Permission"]:
            for action in ["index", "show", "create", "update", "destroy"]:
                db.add(Permission(role_id=role.id, resource=resource, action=action))

        user = User(email="admin@example.com", role_id=role.id)
        user.set_password(initial_password)  # read from an env var / prompt; never hard-code
        db.add(user)

        db.commit()

See examples/basic_app/seed.py for a complete, runnable version.