Define your schema and auto-generate standardized permission scopes for every entity.
The Challenge
In large-scale FastAPI applications, managing authorization often becomes a "string-guessing" game. Developers manually define permission strings like "product:view" or "order:delete" in routers, while the models remain unaware of these scopes. This leads to permission drift, where a table is renamed or a scope is mistyped, resulting in silent authorization failures or security loopholes.
The ZCore Elegance
ZCore's Base is a thin extension of SQLAlchemy's DeclarativeBase. It provides a centralized .actions() method that dynamically generates a structured Actions object based on the __tablename__. These actions are then used by ZCore routers and security layers to enforce consistent authorization without hardcoded strings.
from zcore import Base
from sqlalchemy.orm import Mapped, mapped_column
import uuid
class Product(Base):
__tablename__ = "products"
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
name: Mapped[str] = mapped_column()
# ZCore automatically provides:
# Product.actions().CREATE -> "products:create"
# Product.actions().VIEW -> "products:view"
# Product.actions().DELETE -> "products:delete"
# Product.actions().LISTVIEW -> "products:listview"
# Standard SQLAlchemy models don't know about permissions.
# You are forced to manually manage strings elsewhere:
class Product(Base):
__tablename__ = "products"
id: Mapped[uuid.UUID] = mapped_column(primary_key=True)
# In your security layer:
PRODUCT_CREATE = "products:create" # Manual string
PRODUCT_VIEW = "products:view" # Manual string
# High risk of typos and zero link to the actual model class.
Boundaries & Integration
ZCore does not hide SQLAlchemy; it empowers it.
- Standard SQLA 2.0: Because
Baseinherits fromDeclarativeBase, you use the modernMappedandmapped_columnsyntax exactly as documented in SQLAlchemy 2.0. - Bypass: If you do not wish to use ZCore's authorization system, you can still use the
Baseclass for standard migrations and queries without ever calling.actions(). - Custom Engines: While
db_managerprovides a pre-configuredAsyncEngine, you can still create your own SQLAlchemy engine and bind ZCore models to it—they are 100% compatible with standardAsyncSessionoperations.
Under-the-Hood Spec
1. The Actions Dataclass
The Actions object is an immutable, frozen dataclass [setup.py]. When Base.actions() is called, ZCore iterates over the internal fields of the Actions class and interpolates the __tablename__ to create unique, namespaced permission keys. This ensures that permission names are always derived directly from the source of truth—the database schema.
2. Intelligent Connection Pooling
The DatabaseManager.init_app method contains specific logic for SQLite vs. server-based databases (PostgreSQL/MySQL) [setup.py]. For SQLite, it disables pool_size and max_overflow to prevent locking issues common with file-based databases, while enabling high-performance connection pooling and pool_pre_ping for production-grade relational servers.
3. Lifecycle Awareness
ZCore models are designed to be used with the db_manager.session() context manager. This manager ensures that if an exception occurs during a database operation, session.rollback() is invoked automatically before the error is propagated, keeping your database state clean without manual try/except blocks in every service.