DocType: MockDocA

# MockDocA

**Source**: [verify_selective_migrations.py](file:///builds/castlecraft/framework-m/scripts/verify_selective_migrations.py)

## Fields

_No fields defined._

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Todo

# Todo

Todo DocType for testing.

**Source**: [run_server.py](file:///builds/castlecraft/framework-m/libs/framework-m/examples/run_server.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| title | str |  | Todo title | - |
| completed | bool |  | - | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| Employee | ✓ |  | ✓ | ✓ |
| Guest |  |  | ✓ |  |
| Manager | ✓ |  | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: ScheduledJob

# ScheduledJob

Persistent scheduled job configuration.

    Stores cron job definitions that are loaded by the worker
    process at startup, enabling dynamic job scheduling.

    Attributes:
        name: Unique job identifier
        function: Dotted path to job function (e.g., 'myapp.jobs.send_email')
        cron_expression: Cron syntax string (e.g., '0 9 * * *')
        enabled: Whether the job is active
        last_run: Timestamp of last execution (updated by worker)
        next_run: Timestamp of next scheduled run (calculated)

**Source**: [scheduled_job.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/scheduled_job.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| name | str | ✓ | Unique job identifier | minLen: 1, maxLen: 255 |
| function | str | ✓ | Dotted path to job function (e.g., 'myapp.jobs.send_email') | minLen: 1 |
| cron_expression | str | ✓ | Cron syntax (e.g., '0 9 * * *' for daily at 9 AM) | minLen: 1 |
| enabled | bool |  | Whether the job is active and should be scheduled | - |
| last_run | datetime | None |  | Timestamp of last execution (set by worker) | - |
| next_run | datetime | None |  | Timestamp of next scheduled run (calculated) | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| Employee |  |  | ✓ |  |
| Manager | ✓ |  | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Todo

# Todo

A simple todo item.

    Attributes:
        title: The title/name of the todo item
        description: Optional description of the todo
        completed: Whether the todo is completed
        priority: Priority level (Low, Medium, High)

**Source**: [todo.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/todo.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| title | str |  | Title of the todo item | minLen: 1, maxLen: 200 |
| description | str | None |  | Optional description | maxLen: 1000 |
| completed | bool |  | Whether the todo is completed | - |
| priority | str |  | Priority level | pattern: `^(Low|Medium|High)$` |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Translation

# Translation

Translation for multilingual text.

    Attributes:
        source_text: Original text in default language (usually English)
        translated_text: Translated text in target locale
        locale: Target locale code (e.g., "fr", "es", "hi", "ta")
        context: Optional context for disambiguation (e.g., "button", "label", "error")

    Constraints:
        Unique: (source_text, locale, context) - prevents duplicate translations

    Example:
        # Simple translation
        t1 = Translation(
            source_text="Save",
            translated_text="Enregistrer",
            locale="fr",
        )

        # Context-aware translation
        t2 = Translation(
            source_text="Save",
            translated_text="Sauvegarder",
            locale="fr",
            context="button",
        )

**Source**: [translation.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/translation.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| source_text | str |  | Original text in default language | minLen: 1, maxLen: 1000 |
| translated_text | str |  | Translated text in target locale | minLen: 1, maxLen: 1000 |
| locale | str |  | Target locale code (e.g., 'fr', 'es', 'hi') | minLen: 2, maxLen: 10, pattern: `^[a-z]{2}(_[A-Z]{2})?$` |
| context | str | None |  | Optional context for disambiguation | maxLen: 100 |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: ErrorLog

# ErrorLog

Error log entry DocType.

    Stores information about system errors for debugging.
    Errors are captured by the global exception handler.

    Attributes:
        title: Short description of the error
        error_type: Exception class name (e.g., "ValueError")
        error_message: Full error message
        traceback: Stack trace for debugging
        request_url: URL that triggered the error
        user_id: User who triggered the error
        request_id: Request ID for correlation
        timestamp: When the error occurred
        context: Additional context (headers, params, etc.)

    Example:
        log = ErrorLog(
            title="Validation failed",
            error_type="ValidationError",
            error_message="Field 'email' is invalid",
        )

**Source**: [error_log.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/error_log.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| title | str | ✓ | Short description of the error | maxLen: 255 |
| error_type | str | ✓ | Exception class name (e.g., ValueError) | - |
| error_message | str | ✓ | Full error message | - |
| traceback | str | None |  | Full stack trace for debugging | - |
| request_url | str | None |  | URL that triggered the error | - |
| user_id | str | None |  | User who triggered the error | - |
| request_id | str | None |  | Request ID for log correlation | - |
| timestamp | datetime |  | When the error occurred (UTC) | - |
| context | dict[str, Any] | None |  | Additional context: headers, params, etc. | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| System Manager | ✓ |  | ✓ |  |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: WorkflowState

# WorkflowState

Tracks the current workflow state of a document.

    Attributes:
        workflow: Name of the workflow
        doctype: The DocType of the document in workflow
        document_name: The name/ID of the document
        current_state: Current state name in the workflow
        updated_at: When the state was last updated

**Source**: [workflow_state.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/workflow_state.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| workflow | str |  | Workflow name | - |
| doctype | str |  | Target DocType | - |
| document_name | str |  | Document ID | - |
| current_state | str |  | Current workflow state | - |
| updated_at | datetime |  | Last state update timestamp | - |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: TenantTranslation

# TenantTranslation

Tenant-specific translation overrides.

    Allows tenants to customize translations to match their terminology,
    industry, or brand voice. Overrides system translations when present.

    Attributes:
        tenant_id: Tenant identifier (from TenantContext)
        source_text: Original text to translate (1-1000 characters)
        translated_text: Translated text in target locale (1-1000 characters)
        locale: Locale code (e.g., "en", "hi", "ta", "es_MX")
        context: Optional context for disambiguation (e.g., "button", "field_label")

    Constraints:
        - Unique combination of (tenant_id, source_text, locale, context)
        - locale must match pattern: 2 lowercase letters, optionally followed by
          underscore and 2 uppercase letters (e.g., "en", "en_US", "pt_BR")

    Example:
        # Healthcare tenant uses "Patient" instead of "Customer"
        TenantTranslation(
            tenant_id="healthcare-corp",
            source_text="Customer",
            translated_text="Patient",
            locale="en",
            context="field_label"
        )

        # Retail tenant uses "Client" in French
        TenantTranslation(
            tenant_id="retail-corp",
            source_text="Customer",
            translated_text="Client",
            locale="fr",
            context="field_label"
        )

**Source**: [tenant_translation.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/tenant_translation.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| tenant_id | str |  | Tenant identifier from TenantContext | minLen: 1, maxLen: 100 |
| source_text | str |  | Original text to translate | minLen: 1, maxLen: 1000 |
| translated_text | str |  | Translated text in target locale | minLen: 1, maxLen: 1000 |
| locale | str |  | Locale code (e.g., 'en', 'hi', 'ta', 'es_MX') | minLen: 2, maxLen: 10, pattern: `^[a-z]{2}(_[A-Z]{2})?$` |
| context | str | None |  | Optional context for disambiguation (e.g., 'button', 'field_label') | maxLen: 100 |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Notification

# Notification

Notification DocType.

    Stores in-app notifications for users.

    Attributes:
        user_id: Recipient user ID
        subject: Notification subject/title
        message: Full notification message
        notification_type: Type of notification (info, success, etc.)
        read: Whether the notification has been read
        doctype: Related DocType (optional)
        document_id: Related document ID (optional)
        timestamp: When the notification was created
        from_user: User who triggered the notification (optional)
        metadata: Additional notification data

    Example:
        notification = Notification(
            user_id="user-001",
            subject="New Comment",
            message="John commented on your invoice.",
        )

**Source**: [notification.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/notification.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| user_id | str | ✓ | Recipient user ID | - |
| subject | str | ✓ | Notification subject/title | maxLen: 255 |
| message | str | ✓ | Full notification message | - |
| notification_type | str |  | Notification type (info, success, warning, error, etc.) | - |
| read | bool |  | Whether the notification has been read | - |
| doctype | str | None |  | Related DocType (e.g., Invoice) | - |
| document_id | str | None |  | Related document ID | - |
| timestamp | datetime |  | When the notification was created (UTC) | - |
| from_user | str | None |  | User who triggered the notification | - |
| metadata | dict[str, Any] | None |  | Additional notification data | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| All |  | ✓ | ✓ | ✓ |
| System Manager | ✓ |  |  |  |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: LocalUser

# LocalUser

SQL-backed user for Indie mode (Mode A).

    Stores credentials and profile information locally.
    Default implementation for rapid development.

    Attributes:
        email: Unique email address (login identifier)
        password_hash: Argon2 hash of password (excluded from serialization)
        full_name: Optional display name
        is_active: Whether user can log in (default True)

    Security:
        - password_hash is excluded from model_dump() and model_dump_json()
        - Never store plaintext passwords
        - Use argon2 for hashing (see LocalIdentityAdapter)

    Example:
        user = LocalUser(
            email="john@example.com",
            password_hash="$argon2id$v=19$...",
            full_name="John Doe",
        )

**Source**: [user.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/user.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| email | str |  | Unique email address | - |
| password_hash | str |  | Argon2 password hash | - |
| full_name | str | None |  | User's display name | - |
| is_active | bool |  | Whether user can log in | - |
| locale | str | None |  | User's preferred locale (e.g., 'en', 'hi', 'ta') | maxLen: 10 |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: ApiKey

# ApiKey

API key for scripts and integrations.

    Attributes:
        key_hash: Argon2 hash of the API key (excluded from serialization)
        user_id: Owner of the key
        name: Human-readable label for the key
        scopes: Optional permission scopes (e.g., ["read", "write"])
        expires_at: Optional expiration date
        last_used_at: Last time the key was used (for auditing)
        is_active: Whether the key is currently active

    Security:
        - key_hash is excluded from model_dump() and model_dump_json()
        - Never store or return plaintext keys
        - Raw key is only shown once at creation time

    Example:
        key = ApiKey(
            key_hash="$argon2id$v=19$...",
            user_id="user-123",
            name="Production Deployment",
            scopes=["deploy"],
            expires_at=datetime(2025, 12, 31),
        )

**Source**: [api_key.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/api_key.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| key_hash | str |  | Argon2 hash of the API key | - |
| user_id | str |  | Owner user ID | - |
| name | str |  | Human-readable key label | - |
| scopes | list[str] |  | Permission scopes for this key | - |
| expires_at | datetime | None |  | Key expiration date (None = never expires) | - |
| last_used_at | datetime | None |  | Last time the key was used | - |
| is_active | bool |  | Whether the key is active | - |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: RecentDocument

# RecentDocument

RecentDocument DocType.

    Tracks recently viewed documents per user for quick navigation.

    Attributes:
        user_id: User who viewed the document
        doctype: DocType of the viewed document
        document_id: ID of the viewed document
        document_name: Display name of the document
        route: URL route to the document
        viewed_at: When the document was last viewed

**Source**: [recent_document.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/recent_document.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| user_id | str | ✓ | User who viewed the document | - |
| doctype | str | ✓ | DocType of the viewed document | - |
| document_id | str | ✓ | ID of the viewed document | - |
| document_name | str | ✓ | Display name of the document | - |
| route | str | None |  | URL route to the document | - |
| viewed_at | datetime |  | When the document was last viewed | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| All | ✓ | ✓ | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: SystemSettings

# SystemSettings

System settings singleton DocType.

    Stores global application configuration. Only one instance exists.

    Attributes:
        name: Always "System Settings"
        app_name: Application display name
        timezone: Default timezone (e.g., "UTC", "America/New_York")
        date_format: Date format string (e.g., "YYYY-MM-DD")
        time_format: Time format string (e.g., "HH:mm:ss")
        language: Default language code (e.g., "en")
        enable_signup: Allow new user registration
        session_expiry: Session timeout in minutes
        maintenance_mode: If True, only admins can access

    Example:
        settings = SystemSettings(
            app_name="My App",
            timezone="America/New_York",
        )

**Source**: [system_settings.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/system_settings.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| name | str |  | Always 'System Settings | - |
| app_name | str |  | Application display name | maxLen: 255 |
| timezone | str |  | Default timezone (e.g., UTC, America/New_York) | - |
| date_format | str |  | Date format (e.g., YYYY-MM-DD, DD/MM/YYYY) | - |
| time_format | str |  | Time format (e.g., HH:mm:ss, hh:mm A) | - |
| language | str |  | Default language code (e.g., en, es, fr) | minLen: 2, maxLen: 10 |
| enable_signup | bool |  | Allow new user registration | - |
| session_expiry | int |  | Session timeout in minutes | min: 1, max: 525600 |
| maintenance_mode | bool |  | If True, only admins can access the application | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| All |  |  | ✓ |  |
| System Manager | ✓ |  |  | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: DocumentShare

# DocumentShare

Explicit share of a document with a user or role.

    Enables fine-grained document-level sharing beyond the default
    owner-based or team-based RLS.

    Attributes:
        doctype_name: The DocType being shared (e.g., "Invoice")
        doc_id: Document identifier (e.g., "INV-001" or UUID)
        shared_with: User ID or Role name to share with
        share_type: Whether sharing with USER or ROLE
        granted_permissions: List of permissions granted (e.g., ["read", "write"])
        note: Optional note explaining why the share was created

**Source**: [document_share.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/document_share.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| doctype_name | str |  | DocType name of the shared document | - |
| doc_id | str |  | ID or name of the document being shared | - |
| shared_with | str |  | User ID or Role name to share with | - |
| share_type | ShareType |  | Whether sharing with a user or role | - |
| granted_permissions | list[str] |  | Permissions granted: read, write, delete, etc. | - |
| note | str | None |  | Reason for sharing (for audit) | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| Employee | ✓ |  | ✓ | ✓ |
| Manager | ✓ |  | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: EmailQueue

# EmailQueue

Email queue DocType.

    Stores outbound emails for asynchronous processing.

    Attributes:
        to: List of recipient email addresses
        cc: Carbon copy recipients
        bcc: Blind carbon copy recipients
        subject: Email subject line
        body: Email body (HTML)
        text_body: Plain text alternative
        status: Queue status (Queued, Sending, Sent, Failed)
        priority: Email priority (low, normal, high)
        error: Error message if failed
        retry_count: Number of retry attempts
        max_retries: Maximum retry attempts
        queued_at: When the email was queued
        sent_at: When the email was sent
        from_address: Sender email address
        reply_to: Reply-to address
        attachments: Attachment metadata
        reference_doctype: Related DocType (optional)
        reference_id: Related document ID (optional)

    Example:
        email = EmailQueue(
            to=["user@example.com"],
            subject="Invoice",
            body="
Your invoice is attached.
",
        )

**Source**: [email_queue.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/email_queue.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| to | list[str] | ✓ | Recipient email addresses | minLen: 1 |
| subject | str | ✓ | Email subject line | maxLen: 500 |
| body | str | ✓ | Email body (HTML) | - |
| cc | list[str] | None |  | Carbon copy recipients | - |
| bcc | list[str] | None |  | Blind carbon copy recipients | - |
| text_body | str | None |  | Plain text alternative | - |
| status | str |  | Queue status (Queued, Sending, Sent, Failed) | - |
| priority | str |  | Email priority (low, normal, high) | - |
| error | str | None |  | Error message if failed | - |
| retry_count | int |  | Number of retry attempts | min: 0 |
| max_retries | int |  | Maximum retry attempts | min: 0, max: 10 |
| queued_at | datetime |  | When the email was queued (UTC) | - |
| sent_at | datetime | None |  | When the email was sent (UTC) | - |
| from_address | str | None |  | Sender email address (uses default if not specified) | - |
| reply_to | str | None |  | Reply-to address | - |
| attachments | list[dict[str, Any]] | None |  | Attachment metadata (file_id, filename, content_type) | - |
| reference_doctype | str | None |  | Related DocType (e.g., Invoice) | - |
| reference_id | str | None |  | Related document ID | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| System Manager | ✓ | ✓ | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Webhook

# Webhook

Outgoing webhook configuration.

    Defines webhooks that listen to events and deliver HTTP
    notifications to external endpoints with optional filtering.

    Attributes:
        name: Unique webhook identifier
        event: Event to listen to (e.g., "doc.created", "doc.updated")
        doctype_filter: Optional DocType filter (e.g., "Invoice")
        condition: Optional JMESPath/SimpleEval expression to filter events
        url: Webhook endpoint URL
        method: HTTP method (POST or PUT)
        headers: Custom HTTP headers to send
        payload_transform: Optional Jinja2 template to transform event payload
        enabled: Whether the webhook is active
        secret: Secret for HMAC-SHA256 signature verification

**Source**: [webhook.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/webhook.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| name | str | ✓ | Unique webhook identifier | minLen: 1, maxLen: 255 |
| event | str | ✓ | Event to listen to (e.g., 'doc.created') | minLen: 1 |
| doctype_filter | str | None |  | Filter by DocType (e.g., 'Invoice', 'Order') | - |
| condition | str | None |  | JMESPath or SimpleEval expression to filter events (e.g., 'status == `paid`') | - |
| url | str | ✓ | Webhook endpoint URL | minLen: 1 |
| method | str |  | HTTP method (POST or PUT) | - |
| headers | dict[str, Any] |  | Custom HTTP headers to send with request | - |
| payload_transform | str | None |  | Jinja2 template to transform event payload (e.g., \'{"text": "{{ doc.name }}"}\') | - |
| enabled | bool |  | Whether the webhook is active | - |
| secret | str | None |  | Secret for HMAC-SHA256 signature (X-Webhook-Signature header) | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| Manager |  |  | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: CustomPermission

# CustomPermission

Database-stored permission override.

    Allows admins to override code-first permissions with database rules.
    Evaluated in the RbacPermissionAdapter alongside Meta.permissions.

    Evaluation Priority:
    1. Explicit DENY rules are checked first (deny wins)
    2. If no deny, explicit ALLOW rules are checked
    3. If no explicit rule, fall back to code-first Meta.permissions

    Attributes:
        for_user: Optional user ID this rule applies to
        for_role: Optional role name this rule applies to
        doctype_name: The DocType this permission applies to ("*" for all)
        action: The action (read, write, create, delete, submit, etc.)
        effect: Whether to ALLOW or DENY the permission
        enabled: Whether this rule is active
        priority: Rule priority (higher = evaluated first)
        description: Human-readable description of why this rule exists

**Source**: [custom_permission.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/custom_permission.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| for_user | str | None |  | User ID this rule applies to (None = all users) | - |
| for_role | str | None |  | Role name this rule applies to (None = all roles) | - |
| doctype_name | str |  | DocType name or '*' for all DocTypes | - |
| action | str |  | Action: read, write, create, delete, submit, cancel, amend | - |
| effect | PermissionEffect |  | Whether to allow or deny this permission | - |
| enabled | bool |  | Whether this rule is active | - |
| priority | int |  | Rule priority (higher = evaluated first) | - |
| description | str | None |  | Why this rule exists (for audit) | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| System |  |  | ✓ |  |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Workflow

# Workflow

Defines a complete workflow configuration.

    Attributes:
        doctype: The target DocType this workflow applies to
        initial_state: The starting state for new documents
        states: List of state definitions with metadata
        is_active: Whether this workflow is currently active

**Source**: [workflow.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/workflow.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| doctype | str |  | Target DocType for this workflow | - |
| initial_state | str |  | Initial state for new documents | - |
| states | list[dict[str, str]] |  | State definitions with name and optional metadata | - |
| is_active | bool |  | Whether workflow is active | - |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: SocialAccount

# SocialAccount

Links OAuth2/OIDC provider identity to local user.

    Attributes:
        provider: OAuth2 provider name (google, github, microsoft, oidc)
        provider_user_id: Unique ID from the provider
        user_id: Local user ID this account belongs to
        display_name: Display name from provider (for UI)
        email: Email from provider (for lookup, optional)
        last_login_at: Last time this social account was used

    Security:
        - No sensitive data (tokens, secrets) stored here
        - Only identity linking information
        - Tokens are handled by OAuth2 flow, not persisted

    Example:
        # User signs in with Google
        account = SocialAccount(
            provider="google",
            provider_user_id="1234567890",
            user_id="user-001",
            display_name="John Doe",
        )

**Source**: [social_account.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/social_account.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| provider | str |  | OAuth2 provider (google, github, microsoft, oidc) | - |
| provider_user_id | str |  | Unique user ID from the provider | - |
| user_id | str |  | Local user ID this account belongs to | - |
| display_name | str |  | Display name from provider | - |
| email | str | None |  | Email from provider (for lookup) | - |
| last_login_at | datetime | None |  | Last time this social account was used for login | - |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: WebhookLog

# WebhookLog

Webhook delivery audit log.

    Records each webhook delivery attempt with status, response,
    and error information for debugging and auditing.

    Attributes:
        webhook: Reference to the Webhook DocType name
        event: The event that triggered the webhook
        status: Delivery status ('success' or 'failed')
        response_code: HTTP response status code
        response_body: HTTP response body (truncated)
        error: Error message if delivery failed
        timestamp: When the delivery was attempted

**Source**: [webhook_log.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/webhook_log.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| webhook | str | ✓ | Reference to Webhook name | minLen: 1 |
| event | str | ✓ | Event that triggered the webhook (e.g., 'doc.created') | minLen: 1 |
| status | str | ✓ | Delivery status: 'success' or 'failed | - |
| response_code | int | ✓ | HTTP response status code | - |
| response_body | str | None |  | HTTP response body (may be truncated) | - |
| error | str | None |  | Error message if delivery failed | - |
| timestamp | datetime |  | When the delivery was attempted | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| Manager |  |  | ✓ |  |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: File

# File

File attachment DocType.

    Stores metadata about uploaded files. Actual file content
    is stored via StorageAdapter (local, S3, GCS, etc.).

    Attributes:
        file_name: Original filename as uploaded
        file_url: Storage URL/path for retrieval
        file_size: Size in bytes
        content_type: MIME type (e.g., "application/pdf")
        attached_to_doctype: DocType this file is attached to
        attached_to_name: Document ID this file is attached to
        is_private: If True, requires authentication to access

    Example:
        file = File(
            file_name="report.pdf",
            file_url="/files/2024/01/report-abc123.pdf",
            file_size=51200,
            content_type="application/pdf",
            is_private=True,
        )

**Source**: [file.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/file.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| file_name | str |  | Original filename | - |
| file_url | str |  | Storage URL/path | - |
| file_size | int |  | File size in bytes | - |
| content_type | str |  | MIME type | - |
| attached_to_doctype | str | None |  | DocType this file is attached to | - |
| attached_to_name | str | None |  | Document ID this file is attached to | - |
| is_private | bool |  | If True, requires authentication | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Guest |  |  | ✓ |  |
| User | ✓ | ✓ | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Session

# Session

Database-backed user session.

    Attributes:
        session_id: Unique session identifier (used as cookie value)
        user_id: User this session belongs to
        expires_at: When the session expires
        ip_address: Client IP address for security auditing
        user_agent: Client user agent for display

    Security:
        - session_id should be cryptographically random
        - Check expires_at before accepting session
        - Track ip_address/user_agent for security alerts

**Source**: [session.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/session.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| session_id | str |  | Unique session identifier | - |
| user_id | str |  | User this session belongs to | - |
| expires_at | datetime |  | Session expiration time | - |
| ip_address | str | None |  | Client IP address | - |
| user_agent | str | None |  | Client user agent string | - |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: JobLog

# JobLog

Background job execution log.

    Records job execution status and results for monitoring,
    debugging, and audit purposes.

    Attributes:
        job_id: Unique job identifier from job queue
        job_name: Name of the job function
        status: Current status (queued/running/success/failed)
        enqueued_at: When the job was added to queue
        started_at: When the job started executing
        completed_at: When the job finished
        error: Error message if job failed
        result: Job result data if successful

**Source**: [job_log.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/job_log.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| job_id | str | ✓ | Unique job identifier from job queue | minLen: 1 |
| job_name | str | ✓ | Name of the job function | minLen: 1 |
| status | str | ✓ | Job status: queued, running, success, or failed | - |
| enqueued_at | datetime |  | When the job was added to queue | - |
| started_at | datetime | None |  | When the job started executing | - |
| completed_at | datetime | None |  | When the job finished (success or failure) | - |
| error | str | None |  | Error message if job failed | - |
| result | dict[str, Any] | None |  | Job result data if successful | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| Employee |  |  | ✓ |  |
| Manager |  |  | ✓ |  |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: ActivityLog

# ActivityLog

Activity log entry DocType.

    Stores an immutable audit record of a user action on a document.
    Once created, activity logs should never be modified or deleted.

    Attributes:
        user_id: ID of the user who performed the action
        action: Type of action ("create", "read", "update", "delete")
        doctype: Name of the affected DocType
        document_id: ID of the affected document
        timestamp: When the action occurred (auto-set)
        changes: Field changes for updates (old/new values)
        metadata: Additional context (request_id, ip, user_agent)

    Example:
        log = ActivityLog(
            user_id="user-001",
            action="create",
            doctype="Todo",
            document_id="TODO-001",
        )

**Source**: [activity_log.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/activity_log.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| user_id | str | ✓ | ID of the user who performed the action | minLen: 1 |
| action | str | ✓ | Type of action: create, read, update, delete | pattern: `^(create|read|update|delete)$` |
| doctype | str | ✓ | Name of the affected DocType | minLen: 1 |
| document_id | str | ✓ | ID of the affected document | minLen: 1 |
| timestamp | datetime |  | When the action occurred (UTC) | - |
| changes | dict[str, Any] | None |  | Field changes for updates: {field: {old: x, new: y}} | - |
| metadata | dict[str, Any] | None |  | Additional context: request_id, ip, user_agent, etc. | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| All |  |  | ✓ |  |
| System Manager | ✓ |  | ✓ |  |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: Report

# Report

CQRS report configuration.

    Defines reports that support zero-cliff scalability from
    startup (Code Reports) to enterprise (Analytics with OLAP).

    Attributes:
        name: Unique report identifier
        report_type: Report execution mode (Code Report or Analytics Report)
        data_source: Data source adapter (SQL, Elastic, ClickHouse)
        query: Report query (SQL file path, SQL query, or Elastic DSL)
        enabled: Whether the report is active

**Source**: [report.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/report.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| name | str | ✓ | Unique report identifier | minLen: 1, maxLen: 255 |
| report_type | str | ✓ | Report execution mode: 'Code Report' (indie) or 'Analytics Report' (enterprise) | - |
| data_source | str | None |  | Data source adapter: SQL, Elastic, ClickHouse (for Analytics Reports) | - |
| query | str | None |  | Report query: SQL file path, SQL query, or Elastic DSL JSON | - |
| enabled | bool |  | Whether the report is active | - |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| Admin | ✓ | ✓ | ✓ | ✓ |
| Employee |  |  | ✓ |  |
| Manager | ✓ |  | ✓ | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: WorkflowTransition

# WorkflowTransition

Defines an allowed transition in a workflow.

    Attributes:
        workflow: Name of the workflow this transition belongs to
        from_state: Source state name
        to_state: Destination state name
        action: Action name that triggers this transition
        allowed_roles: List of roles permitted to perform this transition
        condition: Optional Python expression to evaluate before allowing transition

**Source**: [workflow_transition.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/workflow_transition.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| workflow | str |  | Workflow name | - |
| from_state | str |  | Source state | - |
| to_state | str |  | Destination state | - |
| action | str |  | Transition action name | - |
| allowed_roles | list[str] |  | Roles allowed to perform this transition | - |
| condition | str | None |  | Optional Python expression for conditional transitions | - |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: PrintFormat

# PrintFormat

Print format configuration DocType.

    Stores print template configuration for a DocType.

    Attributes:
        name: Display name for the format
        doctype: Target DocType this format applies to
        template: Path to Jinja2 template file
        is_default: If True, this is the default format for the DocType
        css: Optional custom CSS for styling
        header_html: Optional custom header HTML
        footer_html: Optional custom footer HTML
        page_size: Page size for PDF (A4, Letter, etc.)
        orientation: Page orientation (portrait, landscape)

    Example:
        format = PrintFormat(
            name="Invoice Pro Forma",
            doctype="Invoice",
            template="invoice_proforma.html",
        )

**Source**: [print_format.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/doctypes/print_format.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| name | str | ✓ | Display name for the print format | minLen: 1, maxLen: 255 |
| doctype | str | ✓ | Target DocType this format applies to | minLen: 1 |
| template | str | ✓ | Path to Jinja2 template file | minLen: 1 |
| is_default | bool |  | If True, this is the default format for the DocType | - |
| css | str | None |  | Optional custom CSS for styling | - |
| header_html | str | None |  | Optional custom header HTML | - |
| footer_html | str | None |  | Optional custom footer HTML | - |
| page_size | str |  | Page size for PDF (A4, Letter, Legal) | pattern: `^(A4|Letter|Legal|A3|A5)$` |
| orientation | str |  | Page orientation (portrait, landscape) | pattern: `^(portrait|landscape)$` |

## Permissions

| Role | Create | Delete | Read | Write |
|------|------|------|------|------|
| All |  |  | ✓ |  |
| System Manager | ✓ | ✓ |  | ✓ |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


DocType: NamingCounter

# NamingCounter

Counter storage for naming series.

    Stores the current counter value for each prefix, enabling
    persistent and queryable counter management.

    Example:
        # Counter for INV-2026- prefix
        counter = NamingCounter(prefix="INV-2026-", current=42)

        # Next invoice will be INV-2026-0043

    Note:
        Uses optimistic updates - no SELECT FOR UPDATE needed.
        On conflict, retry with incremented value.

**Source**: [naming_counter.py](file:///builds/castlecraft/framework-m/libs/framework-m-core/src/framework_m_core/domain/naming_counter.py)

## Fields

| Field | Type | Required | Description | Validators |
|-------|------|----------|-------------|------------|
| prefix | str |  | Naming series prefix | - |
| current | int |  | Current counter value | - |

## Configuration

| Setting | Value |
|---------|-------|
| Submittable | `False` |
| Track Changes | `True` |

## Controller

Controller hooks are implemented in `*_controller.py` files.
Available lifecycle hooks:

- `validate()` - Called before save, raise exceptions for validation errors
- `before_insert()` - Called before inserting a new document
- `after_insert()` - Called after successfully inserting
- `before_save()` - Called before saving (insert or update)
- `after_save()` - Called after saving
- `before_delete()` - Called before deleting
- `after_delete()` - Called after deleting


Document: docs/intro.md

---
sidebar_position: 1
---

# Introduction

[![Pipeline Status](https://gitlab.com/castlecraft/framework-m/badges/main/pipeline.svg)](https://gitlab.com/castlecraft/framework-m/-/pipelines)
[![Python](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Status: Pre-Alpha](https://img.shields.io/badge/status-pre--alpha-orange)](https://gitlab.com/castlecraft/framework-m)

Welcome to the **Framework M** documentation.

> **Build once. Scale forever.**

Framework M is a modular, metadata-driven full-stack framework designed for building scalable enterprise applications. It bridges the gap between rapid development velocity and enterprise-grade architecture.

:::tip Core Philosophical Pillars
The **"M"** in Framework M represents our three architectural foundations:

- **Modular**: Built on **Hexagonal Architecture** (Ports & Adapters). Build a **Modular Monolith** for velocity and transparently decompose into **Microservices** for scale without a rewrite.
- **Multi-Tenant**: Native, first-class support for multi-tenancy is baked into every layer—from the database to the API.
- **Metadata-Driven**: Application behavior is defined by **DocTypes** (metadata) to accelerate development. This enables automatic CRUD, UI, and workflows with modern type safety.
:::

## Why Framework M?

Batteries-included frameworks deliver incredible initial velocity, but often lead to a "productivity cliff" when scale, enterprise integration, or complex deployment requirements arise.

Framework M is designed to provide **Zero Cliff Architecture**. You get the same rapid development experience—DocTypes, automatic CRUD, permissions, workflows—but built on enterprise-grade foundations from day one.

## Quick Navigation

- **[Quick Start](user/getting-started.md)**: Get up and running in minutes.
- **[Developer Guide](developer/index.md)**: Deep dive into the framework architecture.
- **[Architecture](developer/architecture.md)**: Understand Hexagonal Architecture & Ports/Adapters.
- **[Defining DocTypes](developer/defining-doctypes.md)**: Learn about metadata-driven development.
- **[ADRs](adr/)**: Understand the "why" behind our architecture decisions.
- **[Checklists](/checklists/)**: Track the implementation progress of the framework.

---

*For technical documentation and deployment details, please refer to the [README](https://gitlab.com/castlecraft/framework-m).*


Document: docs/developer/frontend-testing.md

---
title: Frontend Testing
sidebar_position: 11
---

# Frontend Testing Guide

Complete testing documentation for the Framework M frontend application.

## Table of Contents

- [Overview](#overview)
- [Test Infrastructure](#test-infrastructure)
- [Unit Tests](#unit-tests)
- [Integration Tests](#integration-tests)
- [E2E Tests](#e2e-tests)
- [Running Tests](#running-tests)
- [Writing New Tests](#writing-new-tests)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)

## Overview

The frontend uses a comprehensive testing strategy with three layers:

1. **Unit Tests** - Test individual components in isolation
2. **Integration Tests** - Test component interactions and workflows
3. **E2E Tests** - Test complete user workflows across browsers

### Technology Stack

- **Test Runner**: [Vitest](https://vitest.dev/) - Vite-native test runner
- **Component Testing**: [@testing-library/react](https://testing-library.com/react) - User-centric testing utilities
- **User Interactions**: [@testing-library/user-event](https://testing-library.com/docs/user-event/intro) - Realistic user interactions
- **Assertions**: [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) - DOM matchers
- **DOM Environment**: [happy-dom](https://github.com/capricorn86/happy-dom) - Fast DOM implementation
- **E2E Testing**: [Playwright](https://playwright.dev/) - Cross-browser automation

## Test Infrastructure

### Configuration Files

#### `vitest.config.ts`

```typescript
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  test: {
    environment: "happy-dom",
    globals: true,
    setupFiles: ["./src/setupTests.ts"],
    css: true,
    coverage: {
      provider: "v8",
      reporter: ["text", "json", "html"],
    },
  },
});
```

#### `src/setupTests.ts`

Global test setup that runs before all tests:

- Imports `@testing-library/jest-dom` matchers
- Mocks `window.matchMedia` (for theme detection)
- Mocks `localStorage` and `sessionStorage`
- Mocks `IntersectionObserver` and `ResizeObserver`
- Auto-cleanup after each test

#### `playwright.config.ts`

E2E test configuration:

- Tests in `tests/e2e/` directory
- Runs against `http://localhost:5173`
- Auto-starts dev server
- Tests on Chromium, Firefox, and WebKit
- Screenshots and videos on failure

## Unit Tests

### Location

Unit tests are colocated with components in `__tests__` directories:

```
src/
├── components/
│   ├── __tests__/
│   │   ├── ThemeToggle.test.tsx
│   │   ├── AutoForm.test.tsx
│   │   └── AutoTable.test.tsx
│   ├── ThemeToggle.tsx
│   └── ...
```

### Example: Component Test

```typescript
import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";
import { ThemeToggle } from "../ThemeToggle";
import { ThemeProvider } from "../../contexts/ThemeContext";

describe("ThemeToggle", () => {
  it("toggles theme when clicked", async () => {
    const user = userEvent.setup();

    render(
      <ThemeProvider>
        <ThemeToggle />
      </ThemeProvider>
    );

    const button = screen.getByRole("button");
    expect(button).toHaveAttribute("aria-label", "Switch to dark mode");

    await user.click(button);

    expect(button).toHaveAttribute("aria-label", "Switch to light mode");
    expect(window.localStorage.getItem("framework-m-theme")).toBe("dark");
  });
});
```

### Covered Components

#### `ThemeToggle.test.tsx` (6 tests)

- ✅ Renders toggle button
- ✅ Shows correct icon based on theme
- ✅ Toggles theme on click
- ✅ Persists to localStorage
- ✅ Applies dark class to document
- ✅ Keyboard accessible

#### `AutoForm.test.tsx` (12 tests)

- ✅ Renders fields from JSON Schema
- ✅ Submit button visibility
- ✅ onChange/onSubmit callbacks
- ✅ Validation for required fields
- ✅ Pre-fills initial data
- ✅ Readonly and disabled modes
- ✅ Boolean fields as checkboxes
- ✅ Enum fields as selects

#### `AutoTable.test.tsx` (11 tests)

- ✅ Renders columns from schema
- ✅ Displays data from Refine useList
- ✅ Loading state
- ✅ Row selection
- ✅ onRowClick callback
- ✅ Column sorting
- ✅ Pagination controls
- ✅ Formats booleans, dates, nulls

## Integration Tests

### Location

Integration tests are in `src/__tests__/integration/`:

```
src/
└── __tests__/
    └── integration/
        ├── crud-flow.test.tsx
        └── theme-persistence.test.tsx
```

### Example: CRUD Flow Test

```typescript
describe("CRUD Flow Integration", () => {
  it("completes full CRUD workflow", async () => {
    // 1. READ: List view shows records
    expect(screen.getByText("Test Todo 1")).toBeInTheDocument();

    // 2. CREATE: Navigate to create form
    await user.click(screen.getByText("Create New"));
    await user.click(screen.getByText("Save"));
    expect(mockDataProvider.create).toHaveBeenCalled();

    // 3. UPDATE: Edit existing record
    await user.click(screen.getByText("Test Todo 1"));
    await user.click(screen.getByText("Update"));
    expect(mockDataProvider.update).toHaveBeenCalled();

    // 4. DELETE: Remove record
    await user.click(screen.getByText("Delete"));
    expect(mockDataProvider.deleteOne).toHaveBeenCalled();
  });
});
```

### Covered Workflows

#### `crud-flow.test.tsx` (3 tests)

- ✅ Full CRUD workflow (Create → Read → Update → Delete)
- ✅ Validation errors during create
- ✅ Network error handling

#### `theme-persistence.test.tsx` (7 tests)

- ✅ Theme persists to localStorage
- ✅ Restores theme on mount
- ✅ Applies dark class to document
- ✅ System preference detection
- ✅ Saved theme overrides system
- ✅ System preference change listener
- ✅ Theme consistency across components

## E2E Tests

### Location

E2E tests are in `tests/e2e/`:

```
tests/
└── e2e/
    ├── login.spec.ts
    ├── create-record.spec.ts
    └── cross-browser.spec.ts
```

### Example: Login Test

```typescript
import { test, expect } from "@playwright/test";

test.describe("User Login", () => {
  test("should successfully log in", async ({ page }) => {
    await page.goto("/login");

    await page.getByLabel(/email/i).fill("test@example.com");
    await page.getByLabel(/password/i).fill("password123");
    await page.getByRole("button", { name: /login/i }).click();

    await expect(page).toHaveURL(/\/app\/dashboard/);
    await expect(page.getByRole("button", { name: /logout/i })).toBeVisible();
  });
});
```

### Covered Scenarios

#### `login.spec.ts` (7 tests)

- ✅ Display login form
- ✅ Validation errors for empty form
- ✅ Error for invalid credentials
- ✅ Successful login
- ✅ Session persistence on reload
- ✅ Logout functionality
- ✅ Keyboard navigation

#### `create-record.spec.ts` (9 tests)

- ✅ Navigate to create form
- ✅ Display form fields from metadata
- ✅ Required field validation
- ✅ Create record successfully
- ✅ Cancel creation
- ✅ Network error handling
- ✅ Edit after creation
- ✅ Auto-save drafts
- ✅ Real-time validation

#### `cross-browser.spec.ts` (10 tests)

- ✅ Theme toggle across browsers
- ✅ Navigation between views
- ✅ Search functionality
- ✅ Bulk actions
- ✅ Form validation consistency
- ✅ Locale switching
- ✅ Responsive design (mobile)
- ✅ Keyboard shortcuts
- ✅ Page transitions
- ✅ Error states

## Running Tests

### Unit & Integration Tests

```bash
# Run all tests once
pnpm test --run

# Run tests in watch mode
pnpm test

# Run with UI
pnpm test:ui

# Run with coverage
pnpm test:coverage
```

### E2E Tests

```bash
# Run all E2E tests
pnpm test:e2e

# Run with Playwright UI
pnpm test:e2e:ui

# Run in headed mode (see browser)
pnpm test:e2e:headed

# Run specific browser
pnpm test:e2e --project=chromium
pnpm test:e2e --project=firefox
pnpm test:e2e --project=webkit

# Run specific test file
pnpm test:e2e tests/e2e/login.spec.ts
```

### CI/CD

Tests run automatically in CI:

```yaml
# .github/workflows/test.yml
- name: Run unit tests
  run: pnpm test --run

- name: Run E2E tests
  run: pnpm test:e2e
```

## Writing New Tests

### Unit Test Template

```typescript
import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";
import { YourComponent } from "../YourComponent";

describe("YourComponent", () => {
  it("should do something", async () => {
    const user = userEvent.setup();
    const handleClick = vi.fn();

    render(<YourComponent onClick={handleClick} />);

    const button = screen.getByRole("button");
    await user.click(button);

    expect(handleClick).toHaveBeenCalled();
  });
});
```

### Integration Test Template

```typescript
import { describe, it, expect, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import { BrowserRouter } from "react-router";
import { Refine } from "@refinedev/core";

describe("Feature Integration", () => {
  beforeEach(() => {
    // Setup test environment
  });

  it("completes workflow", async () => {
    render(
      <BrowserRouter>
        <Refine dataProvider={mockDataProvider}>
          <YourFeature />
        </Refine>
      </BrowserRouter>
    );

    // Test workflow steps
    await waitFor(() => {
      expect(screen.getByText("Expected Result")).toBeInTheDocument();
    });
  });
});
```

### E2E Test Template

```typescript
import { test, expect } from "@playwright/test";

test.describe("Feature E2E", () => {
  test.beforeEach(async ({ page }) => {
    await page.goto("/your-page");
  });

  test("should work as expected", async ({ page }) => {
    await page.getByRole("button", { name: /action/i }).click();
    await expect(page).toHaveURL(/expected-url/);
    await expect(page.getByText("Success")).toBeVisible();
  });
});
```

## Best Practices

### General

1. **Test User Behavior**: Test what users see and do, not implementation details
2. **Accessible Queries**: Use `getByRole`, `getByLabelText` over `getByTestId`
3. **Async Actions**: Always `await` user interactions
4. **Isolation**: Each test should be independent
5. **Cleanup**: Use `beforeEach` and `afterEach` for setup/teardown

### Unit Tests

- Mock external dependencies (API calls, contexts)
- Test one component at a time
- Cover edge cases (empty state, errors, loading)
- Test accessibility (ARIA attributes, keyboard navigation)

### Integration Tests

- Test component interactions
- Use real providers when possible
- Mock only external APIs
- Test complete workflows

### E2E Tests

- Test critical user journeys
- Use realistic test data
- Handle timing issues with `waitFor`
- Test across browsers
- Keep tests fast (avoid unnecessary waits)

## Troubleshooting

### Common Issues

#### "Cannot find module" errors

```bash
# Install dependencies
pnpm install
```

#### Tests timeout

```typescript
// Increase timeout for slow tests
test("slow test", async () => {
  // ...
}, 10000); // 10 seconds
```

#### "Element not found" errors

```typescript
// Wait for element to appear
await waitFor(() => {
  expect(screen.getByText("Hello")).toBeInTheDocument();
});

// Or use findBy (waits automatically)
const element = await screen.findByText("Hello");
```

#### E2E tests fail locally

```bash
# Ensure dev server is running
pnpm dev

# Or let Playwright start it automatically (configured in playwright.config.ts)
pnpm test:e2e
```

#### Browser not installed

```bash
# Install Playwright browsers
pnpm exec playwright install
```

### Debug Mode

#### Vitest

```bash
# Run tests in debug mode
pnpm test --inspect-brk

# Open Chrome DevTools → chrome://inspect
```

#### Playwright

```bash
# Run with UI mode (recommended)
pnpm test:e2e:ui

# Run in headed mode
pnpm test:e2e:headed

# Debug specific test
pnpm exec playwright test --debug login.spec.ts
```

### Coverage Reports

```bash
# Generate coverage report
pnpm test:coverage

# Open HTML report
open coverage/index.html
```

Coverage is configured in `vitest.config.ts`:

- Text output to terminal
- JSON for CI integration
- HTML for detailed viewing

### CI/CD Integration

Tests run on every push and PR:

- Unit tests: Fast feedback (< 30s)
- E2E tests: Comprehensive validation (2-5 min)
- Coverage reports uploaded to CI

## Test Statistics

Current test coverage:

- **Unit Tests**: 29 tests across 3 files
- **Integration Tests**: 10 tests across 2 files
- **E2E Tests**: 26 tests across 3 files
- **Total**: 65 tests

### Coverage Metrics

- Components: 85%+ coverage
- Critical paths: 100% coverage
- Edge cases: Well tested

## Next Steps

To improve test coverage:

1. Add tests for remaining components (LocaleSwitcher, WorkflowActions, etc.)
2. Increase integration test scenarios
3. Add visual regression tests (Playwright + Snapshots)
4. Performance testing (Lighthouse CI)
5. Accessibility testing (axe-core integration)

## References

- [Vitest Documentation](https://vitest.dev/)
- [Testing Library](https://testing-library.com/)
- [Playwright Documentation](https://playwright.dev/)
- [React Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)


Document: docs/developer/studio-setup.md

---
title: Studio Setup
sidebar_position: 10
---

# Studio Setup Guide

## Running Studio

The Studio provides a visual interface for designing DocTypes and managing your Framework M application.

### Single Command

```bash
m studio --port 9999
```

This starts the Studio server with both the UI and API on a single port.

### URL Structure

The Studio uses a **path prefix architecture** for clean separation:

- **UI**: `http://127.0.0.1:9999/studio/ui/`
  - Main interface for designing DocTypes
  - All frontend routes are under `/studio/ui/*`

- **API**: `http://127.0.0.1:9999/studio/api/`
  - Backend endpoints for data operations
  - All API routes are under `/studio/api/*`

- **Root**: `http://127.0.0.1:9999/`
  - Automatically redirects to `/studio/ui/`

### Development Mode

For frontend development with hot reload:

**Terminal 1 - API Server:**

```bash
m studio --port 9999
```

**Terminal 2 - Frontend Dev Server:**

```bash
cd apps/studio/studio_ui
pnpm dev
```

The Vite dev server runs on `http://localhost:5173` with API proxying to port 9999.

### Git Noise and Local Builds

**Avoid running `pnpm build` locally during development.**

Running `pnpm build` updates the static assets in `apps/studio/src/framework_m_studio/static/`. Since Vite includes hashes in filenames (e.g., `index-a1b2c3.js`), every build modifies tracked files, creating unnecessary git noise.

**Best Practice:**

- Use `pnpm dev` for frontend development.
- **Rely on CI/CD** for release builds. The pipeline automatically rebuilds the UI assets for PyPI packages.
- Local `pnpm build` is only necessary to verify production artifacts locally or update the repository snapshot.

## Architecture

### Path Prefix Separation

The Studio implements complete separation between UI and API routes:

```
/studio/ui/*     → React SPA (HTML pages)
/studio/api/*    → JSON API endpoints
/studio          → Redirects to /studio/ui/
```

This architecture:

- ✅ Prevents route collisions
- ✅ Enables clean URLs (no hash fragments)
- ✅ Works with single-command deployment
- ✅ Supports proper Content-Type headers

### Static Assets

Static assets (JS, CSS, images) are served at:

```
/studio/ui/assets/*
```

The Vite build process outputs to `apps/studio/src/framework_m_studio/static/` which is included in the Python package.

## API Endpoints

### Health Check

```bash
curl http://127.0.0.1:9999/studio/api/health
```

### List DocTypes

```bash
curl http://127.0.0.1:9999/studio/api/doctypes
```

### Get DocType

```bash
curl http://127.0.0.1:9999/studio/api/doctype/User
```

### Field Types

```bash
curl http://127.0.0.1:9999/studio/api/field-types
```

## Building for Production

### Build Frontend

```bash
cd apps/studio/studio_ui
pnpm build
```

This outputs to `../src/framework_m_studio/static/` which is packaged with the Python distribution.

### Package Python

```bash
cd apps/studio
uv build
```

The built wheel includes the static frontend assets.

## Troubleshooting

### UI Downloads Instead of Rendering

If the browser downloads HTML files instead of rendering them, check:

1. **Content-Type Headers**: Ensure responses have `Content-Type: text/html; charset=utf-8`
2. **Route Handlers**: Verify return type is `Response` not union types
3. **Browser Cache**: Clear browser cache and hard reload (Ctrl+Shift+R)

### 404 Errors on Deep Links

If refreshing a page like `/studio/ui/doctypes/edit/User` gives 404:

1. **Check Route Handler**: Ensure `/studio/ui/{path:path}` wildcard route exists
2. **SPA Fallback**: Verify the handler returns `index.html` for non-file paths
3. **Base Path**: Confirm React Router uses `basename="/studio/ui"`

### API Calls Failing

If API calls return errors:

1. **CORS**: Check CORS configuration allows your origin
2. **Path Prefix**: Ensure API calls use `/studio/api/*` prefix
3. **Server Running**: Verify `m studio` is running on the correct port


Document: docs/developer/architecture.md

# Architecture

A guide to understanding Framework M's architecture and project structure.

## Overview

Framework M uses **Hexagonal Architecture** (Ports & Adapters) to maintain clean separation between business logic and infrastructure.

```
┌─────────────────────────────────────────────────────────────┐
│                    Primary Adapters                         │
│              (HTTP, CLI, Background Jobs)                   │
└─────────────────────────────┬───────────────────────────────┘
                              │
                    ┌─────────▼──────────┐
                    │    Core Domain     │
                    │  (DocTypes, Logic) │
                    └─────────┬──────────┘
                              │
┌─────────────────────────────▼───────────────────────────────┐
│                   Secondary Adapters                        │
│        (Database, Cache, Storage, Events, etc.)             │
└─────────────────────────────────────────────────────────────┘
```

## Project Structure (Monorepo)

Framework M is split into focused packages to enable flexibility and lean production deployments.

### Core Packages (`libs/`)

1.  **`framework-m-core`**: The absolute minimum kernel.
    -   All **Protocols** (Interfaces) for Repository, EventBus, Cache, etc.
    -   Pydantic-based DocType metadata engine.
    -   Dependency Injection container.
    -   **Zero adapters** (infrastructure-free).

2.  **`framework-m-standard`**: The standard battery of adapters.
    -   **SQLAlchemy** adapters (PostgreSQL/SQLite).
    -   **NATS** adapters for Event Bus and WebSockets.
    -   **Redis** adapters for Caching.
    -   **Litestar** web integration.
    -   RBAC Permission system.

3.  **`framework-m`**: The meta-package.
    -   Bundles `core` + `standard`.
    -   Recommended for most developers and "Indie" deployments.

### Developer Tools (`apps/`)

-   **`framework-m-studio`**: Visual DocType builder and CLI scaffolding.
    -   Contains `m new:app`, `m new:doctype`.
    -   Documentation generators.
    -   Studio UI (React + Refine).

---

## Detailed Directory Map

```
libs/
├── framework-m-core/
│   └── src/framework_m_core/
│       ├── domain/              # Base protocols
│       ├── interfaces/          # Protocol definitions (Ports)
│       └── registry.py          # MetaRegistry
│
├── framework-m-standard/
│   └── src/framework_m_standard/
│       ├── adapters/            # Concrete implementations
│       │   ├── db/              # SQLAlchemy
│       │   ├── eventbus/        # NATS
│       │   └── web/             # Litestar
│       └── cli/                 # Standard commands (migrate, start)
│
apps/
└── studio/                      # Studio UI & Scaffolding
    └── src/framework_m_studio/
        ├── cli/                 # Dev commands (new, codegen, docs)
        └── docs_generator.py    # Documentation engine
```

## Key Modules

| Module | Purpose | Location |
|------|---------|----------|
| `framework_m_core.domain` | Base classes for DocTypes/Controllers | `framework-m-core` |
| `framework_m_core.interfaces` | System-wide Protocols (contracts) | `framework-m-core` |
| `framework_m_standard.adapters.db` | SQLAlchemy & GenericRepository | `framework-m-standard` |
| `framework_m_standard.adapters.web` | Litestar app factory & Auto-CRUD | `framework-m-standard` |
| `framework_m_studio.cli.new` | Code generation and app templates | `framework-m-studio` |

## Protocol-Based Design

Framework M defines **Protocols** (interfaces) for all infrastructure concerns:

- See [Protocol Reference](../developer/generated/index.md)

This allows you to:
1. **Swap implementations** without changing business logic
2. **Test in isolation** with mock adapters
3. **Deploy differently** (e.g., Redis vs memory cache)

## Controller Hooks

Business logic lives in Controllers, not DocTypes. See [Defining DocTypes](./defining-doctypes.md) for hook examples.

## CLI Commands

Framework M provides CLI tools for development. Run `m --help` for available commands.

## Apps Structure

User applications live in `apps/`:

```
your_app/
├── src/
│   └── your_app/             # Namespaced package
│       └── doctypes/
│           └── your_doctype/
│               ├── __init__.py
│               ├── doctype.py      # Schema
│               └── controller.py   # Business logic
├── pyproject.toml
└── README.md
```

## Next Steps

- [Creating Apps](./creating-apps.md) - Build your first app
- [Defining DocTypes](./defining-doctypes.md) - Advanced patterns