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.