Data Model

Database schema and configuration for the PraisonAI Platform

Every workspace, issue, agent, and comment you create is stored in these tables.

Every workspace, issue, agent, and comment you create is stored in these tables.

python
from praisonaiagents import Agent

agent = Agent(name="architect", instructions="Explain platform entities and relationships.")
agent.start("How do workspaces, projects, and issues relate?")

The user maps product concepts to tables; workspaces contain projects, issues, agents, and comments.

Diagram

Core Entities

👤 User

🏢 Workspace

📂 Project

📋 Issue

💬 Comment

🤖 Agent

🏷️ Label

🔗 Dependency

📊 Activity Log

Quick Start

  1. Zero Configuration (Default)
    python
    from praisonai_platform.client import PlatformClient
    
    # In-memory SQLite - data lost on restart
    client = PlatformClient(base_url="http://localhost:8000")
    client.login(email="me@example.com", password="...")
    
    workspace = client.workspaces.create(name="Research")
    issue = client.issues.create(workspace_id=workspace.id, title="Setup database")
  2. Persistent SQLite
    bash
    # Set database URL for persistence
    export DATABASE_URL="sqlite+aiosqlite:///./platform.db"
    
    # Initialize database tables
    python -c "import asyncio; from praisonai_platform.db import init_db; asyncio.run(init_db())"
  3. PostgreSQL Production
    bash
    # Switch to PostgreSQL
    export DATABASE_URL="postgresql+asyncpg://user:pass@host/db"
    
    # Initialize tables
    python -c "import asyncio; from praisonai_platform.db import init_db; asyncio.run(init_db())"

How It Works

Diagram
DBEngineSessionAPIClientDBEngineSessionAPIClientRequestget_db dependencyget_session_factory()get_engine() (cached)AsyncSessionSession yieldedQuery/UpdateResultAuto-commit on successResponse
ComponentPurposeLifecycle
EngineDatabase connection poolCached globally, first call wins
SessionPer-request transactionCreated/disposed per API call
get_dbFastAPI dependencyYields session, auto-commits
init_dbTable creationCall once for persistent databases

Entities

User (users)

Authentication and identity for platform access.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
namestr—Username (unique)
emailstr—Email address (unique)
password_hashstr—Hashed password
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

Workspace (workspaces)

Top-level container for organizing projects and issues.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
namestr—Workspace name
descriptionstrNoneOptional description
settingsdict{}JSON configuration
issue_prefixstr"ISSUE"Issue numbering prefix
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

Member (members)

User membership and roles within workspaces.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
user_idstr—Foreign key to users
workspace_idstr—Foreign key to workspaces
rolestr"member"Role: owner, admin, member
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

Constraints: Unique (user_id, workspace_id)

Project (projects)

Optional grouping for issues within a workspace.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
workspace_idstr—Foreign key to workspaces
namestr—Project name
descriptionstrNoneOptional description
settingsdict{}JSON configuration
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

Issue (issues)

Work items and tasks within a workspace.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
workspace_idstr—Foreign key to workspaces
project_idstrNoneOptional foreign key to projects
titlestr—Issue title
descriptionstrNoneOptional description
statusstr"backlog"Status: backlog, in-progress, done
prioritystr"medium"Priority: low, medium, high, urgent
assignee_idstrNoneOptional foreign key to users
created_by_idstrNoneOptional foreign key to users
issue_numberintNoneAuto-incrementing number
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

Comment (comments)

Discussion threads on issues.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
issue_idstr—Foreign key to issues
author_idstrNoneOptional foreign key to users
contentstr—Comment text
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

Agent (agents)

AI agents assigned to workspaces.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
workspace_idstr—Foreign key to workspaces
namestr—Agent name
descriptionstrNoneOptional description
statusstr"idle"Status: idle, active, error
configdict{}JSON configuration
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

IssueLabel (issue_labels)

Label definitions for categorizing issues.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
workspace_idstr—Foreign key to workspaces
namestr—Label name
colorstr"#000000"Hex color code
descriptionstrNoneOptional description
created_atdatetimeUTC nowCreation timestamp
updated_atdatetimeUTC nowLast update timestamp

IssueLabelLink (issue_label_links)

Many-to-many relationship between issues and labels.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
issue_idstr—Foreign key to issues
label_idstr—Foreign key to issue_labels
created_atdatetimeUTC nowCreation timestamp

Constraints: Unique (issue_id, label_id)

IssueDependency (issue_dependencies)

Dependency relationships between issues.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
issue_idstr—Foreign key to issues
depends_on_idstr—Foreign key to issues
dependency_typestr—Type: blocks, blocked_by, related
created_atdatetimeUTC nowCreation timestamp

Constraints: Unique (issue_id, depends_on_id, dependency_type)

ActivityLog (activity_logs)

Audit trail for workspace activities.

ColumnTypeDefaultDescription
idstrUUIDPrimary key
workspace_idstr—Foreign key to workspaces
entity_typestr—Entity type: issue, project, workspace
entity_idstr—ID of the affected entity
actionstr—Action: created, updated, deleted
actor_idstrNoneOptional foreign key to users
detailsdict{}JSON details
created_atdatetimeUTC nowCreation timestamp

Configuration Options

NameWhereDefaultDescription
DATABASE_URLenv varsqlite+aiosqlite:///:memory:SQLAlchemy async URL used by get_engine()
get_engine(database_url=None)praisonai_platform.db—Returns the cached AsyncEngine; first call wins, pass database_url to override env
get_session()praisonai_platform.db—Async generator yielding an AsyncSession per request
init_db()praisonai_platform.db—Creates all tables via Base.metadata.create_all
reset_engine()praisonai_platform.db—Disposes and clears the cached engine (tests / URL switch)

Common Patterns

Running One-Off Queries

python
import asyncio
from praisonai_platform.db import get_session, init_db
from praisonai_platform.db.models import Workspace
from sqlalchemy import select

async def count_workspaces():
    await init_db()  # Ensure tables exist
    async for session in get_session():
        result = await session.execute(select(Workspace))
        workspaces = result.scalars().all()
        print(f"Found {len(workspaces)} workspaces")
        break

asyncio.run(count_workspaces())

Switching to PostgreSQL in Production

bash
# 1. Install driver
pip install asyncpg

# 2. Set database URL
export DATABASE_URL="postgresql+asyncpg://user:password@localhost/platform"

# 3. Initialize tables
python -c "import asyncio; from praisonai_platform.db import init_db; asyncio.run(init_db())"

# 4. Start platform server
python -m praisonai_platform

Resetting Engine in Tests

python
import pytest
from praisonai_platform.db import reset_engine, init_db

@pytest.fixture(autouse=True)
async def clean_db():
    await reset_engine()  # Clear cached engine
    await init_db()       # Create fresh tables
    yield
    await reset_engine()  # Clean up

Best Practices

Initialize Database Once

For non-memory databases, call init_db() once at application startup, not per request. The default in-memory SQLite creates tables automatically.

python
# In your app startup
import asyncio
from praisonai_platform.db import init_db

if __name__ == "__main__":
    asyncio.run(init_db())  # Only for persistent databases
    # Start your server...
Don't Mix Database URLs

The engine is cached globally – if you need to switch DATABASE_URL values, call reset_engine() first to avoid connection pool conflicts.

python
from praisonai_platform.db import reset_engine, get_engine

# Switch from SQLite to Postgres
await reset_engine()
engine = get_engine("postgresql+asyncpg://user:pass@host/db")
Keep SQLite for Development Only

Use SQLite for development and testing, but switch to PostgreSQL for production workloads. SQLite doesn’t handle concurrent writes well in server environments.

bash
# Development
export DATABASE_URL="sqlite+aiosqlite:///./dev.db"

# Production
export DATABASE_URL="postgresql+asyncpg://user:pass@prod-host/platform"
Use Sessions Properly

Always use the get_db dependency in FastAPI routes – it handles session lifecycle, commits, and rollbacks automatically. Don’t create sessions manually.

python
from fastapi import Depends
from praisonai_platform.api.deps import get_db

@app.get("/workspaces")
async def list_workspaces(session: AsyncSession = Depends(get_db)):
    # Session is auto-managed
    return await workspace_service.list_all(session)

Related