> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Model

> Database schema and configuration for the PraisonAI Platform

<Note>
  Platform is now a separate repository - install with `pip install praisonai-platform` as before, and see the [PraisonAI-Platform repo](https://github.com/MervinPraison/PraisonAI-Platform) for source and issues. Details: [Where Platform Lives](/docs/features/platform/where-platform-lives).
</Note>

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

<Note>
  Updated for **PraisonAI Platform PR #1591**: issues support `parent_issue_id`, workspace-scoped `number`/`identifier`, and kanban `position`; comments support `parent_id` threading; projects use `title`, `icon`, `status` (default `planned`), and `lead_type`/`lead_id`; agents use `owner_type`/`owner_id`, `runtime_mode`/`runtime_config`, and default status `offline`.
</Note>

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

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Core Entities"
        A[👤 User] --> B[🏢 Workspace]
        B --> C[📂 Project]
        C --> D[📋 Issue]
        D --> E[💬 Comment]
        B --> F[🤖 Agent]
        D --> G[🏷️ Label]
        D --> H[🔗 Dependency]
        B --> I[📊 Activity Log]
    end
    
    classDef user fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef workspace fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef entity fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef system fill:#F59E0B,stroke:#7C90A0,color:#fff
    
    class A user
    class B workspace
    class C,D,E,F,G,H entity
    class I system
    classDef agent fill:#8B0000,color:#fff
    classDef tool fill:#189AB4,color:#fff
```

## Quick Start

<Steps>
  <Step title="Zero Configuration (Default)">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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")
    ```
  </Step>

  <Step title="Persistent SQLite">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # 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())"
    ```
  </Step>

  <Step title="PostgreSQL Production">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # 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())"
    ```
  </Step>
</Steps>

***

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Client
    participant API
    participant Session
    participant Engine
    participant DB
    
    Client->>API: Request
    API->>Session: get_db dependency
    Session->>Engine: get_session_factory()
    Engine->>Engine: get_engine() (cached)
    Engine->>Session: AsyncSession
    Session-->>API: Session yielded
    API->>DB: Query/Update
    DB-->>API: Result
    API->>Session: Auto-commit on success
    API-->>Client: Response
```

| Component | Purpose | Lifecycle |
| - | - | - |
| **Engine** | Database connection pool | Cached globally, first call wins |
| **Session** | Per-request transaction | Created/disposed per API call |
| **get\_db** | FastAPI dependency | Yields session, auto-commits |
| **init\_db** | Table creation | Call once for persistent databases |

***

## Entities

### User (users)

Authentication and identity for platform access.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `name` | `str` | — | Username (unique) |
| `email` | `str` | — | Email address (unique) |
| `password_hash` | `str` | — | Hashed password |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

### Workspace (workspaces)

Top-level container for organizing projects and issues.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `name` | `str` | — | Workspace name |
| `description` | `str` | `None` | Optional description |
| `settings` | `dict` | `{}` | JSON configuration |
| `issue_prefix` | `str` | `"ISSUE"` | Issue numbering prefix |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

### Member (members)

User membership and roles within workspaces.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `user_id` | `str` | — | Foreign key to users |
| `workspace_id` | `str` | — | Foreign key to workspaces |
| `role` | `str` | `"member"` | Role: `owner`, `admin`, `member` |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

**Constraints:** Unique (user\_id, workspace\_id)

### Project (projects)

Optional grouping for issues within a workspace.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `workspace_id` | `str` | — | Foreign key to workspaces |
| `name` | `str` | — | Project name |
| `description` | `str` | `None` | Optional description |
| `settings` | `dict` | `{}` | JSON configuration |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

### Issue (issues)

Work items and tasks within a workspace.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `workspace_id` | `str` | — | Foreign key to workspaces |
| `project_id` | `str` | `None` | Optional foreign key to projects |
| `title` | `str` | — | Issue title |
| `description` | `str` | `None` | Optional description |
| `status` | `str` | `"backlog"` | Status: backlog, in-progress, done |
| `priority` | `str` | `"medium"` | Priority: low, medium, high, urgent |
| `assignee_id` | `str` | `None` | Optional foreign key to users |
| `created_by_id` | `str` | `None` | Optional foreign key to users |
| `issue_number` | `int` | `None` | Auto-incrementing number |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

### Comment (comments)

Discussion threads on issues.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `issue_id` | `str` | — | Foreign key to issues |
| `author_id` | `str` | `None` | Optional foreign key to users |
| `content` | `str` | — | Comment text |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

### Agent (agents)

AI agents assigned to workspaces.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `workspace_id` | `str` | — | Foreign key to workspaces |
| `name` | `str` | — | Agent name |
| `description` | `str` | `None` | Optional description |
| `status` | `str` | `"idle"` | Status: idle, active, error |
| `config` | `dict` | `{}` | JSON configuration |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

### IssueLabel (issue\_labels)

Label definitions for categorizing issues.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `workspace_id` | `str` | — | Foreign key to workspaces |
| `name` | `str` | — | Label name |
| `color` | `str` | `"#000000"` | Hex color code |
| `description` | `str` | `None` | Optional description |
| `created_at` | `datetime` | UTC now | Creation timestamp |
| `updated_at` | `datetime` | UTC now | Last update timestamp |

### IssueLabelLink (issue\_label\_links)

Many-to-many relationship between issues and labels.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `issue_id` | `str` | — | Foreign key to issues |
| `label_id` | `str` | — | Foreign key to issue\_labels |
| `created_at` | `datetime` | UTC now | Creation timestamp |

**Constraints:** Unique (issue\_id, label\_id)

### IssueDependency (issue\_dependencies)

Dependency relationships between issues.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `issue_id` | `str` | — | Foreign key to issues |
| `depends_on_id` | `str` | — | Foreign key to issues |
| `dependency_type` | `str` | — | Type: `blocks`, `blocked_by`, `related` |
| `created_at` | `datetime` | UTC now | Creation timestamp |

**Constraints:** Unique (issue\_id, depends\_on\_id, dependency\_type)

### ActivityLog (activity\_logs)

Audit trail for workspace activities.

| Column | Type | Default | Description |
| - | - | - | - |
| `id` | `str` | UUID | Primary key |
| `workspace_id` | `str` | — | Foreign key to workspaces |
| `entity_type` | `str` | — | Entity type: issue, project, workspace |
| `entity_id` | `str` | — | ID of the affected entity |
| `action` | `str` | — | Action: created, updated, deleted |
| `actor_id` | `str` | `None` | Optional foreign key to users |
| `details` | `dict` | `{}` | JSON details |
| `created_at` | `datetime` | UTC now | Creation timestamp |

***

## Configuration Options

| Name | Where | Default | Description |
| - | - | - | - |
| `DATABASE_URL` | env var | `sqlite+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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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

<AccordionGroup>
  <Accordion title="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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # 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...
    ```
  </Accordion>

  <Accordion title="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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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")
    ```
  </Accordion>

  <Accordion title="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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # Development
    export DATABASE_URL="sqlite+aiosqlite:///./dev.db"

    # Production
    export DATABASE_URL="postgresql+asyncpg://user:pass@prod-host/platform"
    ```
  </Accordion>

  <Accordion title="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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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)
    ```
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Workspaces" icon="building" href="/docs/features/platform/workspaces">
    Manage teams and organize work
  </Card>

  <Card title="Issues" icon="circle-check" href="/docs/features/platform/issues">
    Track and manage work items
  </Card>

  <Card title="Agents" icon="robot" href="/docs/features/platform/agents">
    Deploy AI agents to workspaces
  </Card>

  <Card title="Authentication" icon="shield" href="/docs/features/platform/authentication">
    User authentication and sessions
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.