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

# Data Model

> Database schema and configuration for the PraisonAI Platform

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

```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
```

## 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>
