openapi: 3.0.3
info:
  title: MDDB API
  description: |
    MDDB (Markdown Database) is a high-performance, version-controlled markdown database with triple protocol support.

    ## Features
    - Store and manage markdown documents with metadata
    - Full revision history for all documents
    - Multi-language support
    - Fast metadata-based search
    - **Vector search** with embedding providers (OpenAI, Cohere, Voyage AI, Ollama)
    - **Full-text search** with TF-IDF, BM25, BM25F, PMISparse scoring, 7 search modes (simple, boolean, phrase, wildcard, proximity, range, fuzzy), and multi-language stemming (18 languages)
    - **Hybrid search** combining FTS + vector search with alpha blending or RRF fusion
    - **Webhooks** for real-time event notifications
    - **TTL** (time-to-live) support for automatic document expiration
    - **JSON Schema validation** for document metadata
    - **URL import** with YAML frontmatter parsing
    - **Authentication** - JWT tokens and API keys
    - **Authorization** - Collection-level RBAC (Read/Write/Admin)
    - **Memory RAG** - Conversational memory system with session management, message storage, semantic/hybrid recall, and summarization
    - **User Management** - Multi-user with admin roles
    - **Group Permissions** - Organize users into groups
    - Template variable substitution
    - Export capabilities (NDJSON, ZIP)
    - Backup and restore operations
    - **Replication** - Leader-follower replication with binlog streaming
    - **Automation** - Webhooks, triggers (FTS/vector/hybrid + sentiment), crons
    - **Automation Logs** - Execution history with configurable TTL retention

    ## Protocols
    - **HTTP/JSON** - Port 11023 (documented here)
    - **gRPC/Protobuf** - Port 11024 (see gRPC documentation)
    - **GraphQL** - Port 11023/graphql (enable with MDDB_GRAPHQL_ENABLED=true)
    - **MCP** - Port 9000 (Streamable HTTP at `/mcp`, legacy SSE at `/sse`)
    - **HTTP/3 + QUIC** - Port 11443 (extreme mode only)

    ## Per-Protocol Access Modes
    Each protocol can have its own read/write mode: `MDDB_API_MODE`, `MDDB_GRPC_MODE`, `MDDB_MCP_MODE`, `MDDB_HTTP3_MODE`.
    Values: `read`, `write`, `wr`. Default: inherits from `MDDB_MODE`.
    Set `MDDB_MCP_BUILTIN_TOOLS=false` to hide built-in MCP tools.

    ## Authentication
    MDDB supports JWT tokens and API keys for authentication with collection-level RBAC authorization.

    ### JWT Authentication
    ```bash
    # Login to get JWT token
    curl -X POST http://localhost:11023/v1/auth/login \
      -H "Content-Type: application/json" \
      -d '{"username":"admin","password":"secret"}'

    # Use token in requests
    curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:11023/v1/stats
    ```

    ### API Key Authentication
    ```bash
    # Create API key (requires JWT first)
    curl -X POST http://localhost:11023/v1/auth/api-key \
      -H "Authorization: Bearer YOUR_JWT_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"description":"My API key"}'

    # Use API key in requests
    curl -H "X-API-Key: YOUR_API_KEY" http://localhost:11023/v1/stats
    ```

    See authentication endpoints below for user management, groups, and permissions.

  version: "2.9.11"
  contact:
    name: MDDB Team
    url: https://github.com/tradik/mddb
  license:
    name: BSD-3-Clause
    url: https://github.com/tradik/mddb/blob/main/LICENSE

servers:
  - url: http://localhost:11023
    description: Local development server
  - url: http://localhost:11023/v1
    description: Local development server (with version prefix)

tags:
  - name: Health
    description: Health check and monitoring endpoints
  - name: Authentication
    description: User authentication with JWT tokens and API keys
  - name: Users
    description: User management (admin only)
  - name: Groups
    description: Group management and permissions (admin only)
  - name: Embedding Config
    description: Embedding provider configuration management
  - name: Documents
    description: Document management operations
  - name: Search
    description: Search and query operations
  - name: Vector Search
    description: Semantic/vector search operations
  - name: Full-Text Search
    description: Keyword-based full-text search
  - name: Hybrid Search
    description: Combined sparse (FTS) + dense (vector) search with fusion strategies
  - name: Import
    description: Document import from URLs
  - name: TTL
    description: Document time-to-live management
  - name: Webhooks
    description: Webhook registration and management
  - name: Schema Validation
    description: JSON Schema validation for metadata
  - name: Export
    description: Export and backup operations
  - name: Maintenance
    description: Database maintenance operations
  - name: Telemetry
    description: Prometheus-compatible metrics endpoint
  - name: Replication
    description: Leader-follower replication status and monitoring
  - name: Synonyms
    description: FTS synonym dictionary management
  - name: System
    description: System information and endpoint discovery
  - name: MCP
    description: Model Context Protocol 2025-11-25 — Streamable HTTP transport, tools, resources, prompts, completion, logging
  - name: Memory RAG
    description: Conversational memory system for RAG — session management, message storage, semantic/hybrid recall, summarization
  - name: Configuration
    description: Server and MCP configuration
  - name: GraphQL
    description: GraphQL API and interactive playground
  - name: Automation
    description: Triggers, crons, and webhook targets for automated workflows
  - name: Revisions
    description: Document revision history and restore operations
  - name: Collection Config
    description: Per-collection type, description, icon, color, and custom metadata
  - name: Cross-Collection Search
    description: Search across multiple collections using embeddings or text queries
  - name: Temporal Tracking
    description: Document event history, hot-docs leaderboard and activity histograms (requires MDDB_TEMPORAL=true)
  - name: Spell Correction
    description: SymSpell-based FTS spell suggestions, text cleanup, and per-collection custom dictionaries (requires MDDB_SPELL=true)

paths:
  /health:
    get:
      tags:
        - Health
      summary: Health check
      description: Simple health check endpoint that verifies database connectivity
      operationId: getHealth
      responses:
        "200":
          description: Service is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: healthy
                  mode:
                    type: string
                    enum: [read, write, wr]
                    example: wr
        "503":
          description: Service is unhealthy
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/health:
    get:
      tags:
        - Health
      summary: Health check (versioned)
      description: Alias for /health endpoint
      operationId: getHealthV1
      responses:
        "200":
          description: Service is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: healthy
                  mode:
                    type: string
                    enum: [read, write, wr]
                    example: wr
        "503":
          description: Service is unhealthy
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/stats:
    get:
      tags:
        - Health
      summary: Server statistics
      description: Get detailed server and database statistics
      operationId: getStats
      responses:
        "200":
          description: Statistics retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Stats"

  /v1/add:
    post:
      tags:
        - Documents
      summary: Add or update document
      description: |
        Add a new document or update an existing one. If a document with the same collection, key, and language exists, it will be updated and a new revision will be created.
      operationId: addDocument
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddRequest"
      responses:
        "200":
          description: Document added/updated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/add-batch:
    post:
      tags:
        - Documents
      summary: Batch add documents
      description: |
        Add multiple documents to a collection in a single request. Uses the optimized batch processor for high throughput.
        Fires all post-commit hooks (embedding, FTS indexing, webhooks, TTL, automation triggers).
      operationId: addBatch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddBatchRequest"
      responses:
        "200":
          description: Batch result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddBatchResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/ingest:
    post:
      tags:
        - Documents
      summary: Bulk ingest documents
      description: |
        Advanced bulk ingest endpoint for scraping pipelines and data import workflows.
        Supports URL key derivation, YAML frontmatter extraction, content deduplication,
        auto-metadata injection, and collection auto-configuration.
      operationId: ingestDocuments
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/IngestRequest"
      responses:
        "200":
          description: Ingest result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IngestResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/upload:
    post:
      tags:
        - Documents
      summary: Upload files with auto-conversion to Markdown
      description: |
        Upload files via multipart/form-data. Files are auto-converted
        to Markdown and stored as documents. Supports single and batch upload.

        Supported formats: `.md`, `.txt`, `.html`, `.htm`, `.pdf`, `.docx`, `.odt`, `.rtf`, `.yaml`, `.yml`, `.log`, `.lex`, `.tex`, `.latex`.
        Default (md/txt) is stored as-is with frontmatter extraction; others are converted.
        ODT and DOCX are ZIP-based with XML extraction. RTF is parsed to plain text.
        LaTeX/TeX is converted (sections, formatting, environments). YAML/LOG/LEX are wrapped in code blocks.
      operationId: uploadFile
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - collection
                - lang
              properties:
                file:
                  type: string
                  format: binary
                  description: Single file to upload
                "files[]":
                  type: array
                  items:
                    type: string
                    format: binary
                  description: Multiple files to upload
                collection:
                  type: string
                  description: Target collection name
                lang:
                  type: string
                  description: Document language code (e.g. en_US)
                key:
                  type: string
                  description: Document key (derived from filename if empty)
                meta:
                  type: string
                  description: JSON-encoded metadata map
                ttl:
                  type: integer
                  description: Time-to-live in seconds
                maxSize:
                  type: integer
                  description: Per-file size limit in bytes (default 10MB, max 100MB)
      responses:
        "200":
          description: File(s) uploaded and stored
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/UploadResponse"
                  - $ref: "#/components/schemas/UploadBatchResponse"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/get:
    post:
      tags:
        - Documents
      summary: Get document
      description: |
        Retrieve a document by collection, key, and language. Supports template variable substitution using the `env` parameter.
      operationId: getDocument
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GetRequest"
      responses:
        "200":
          description: Document retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Document not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/search:
    post:
      tags:
        - Search
      summary: Search documents
      description: |
        Search documents with metadata filtering, sorting, and pagination.

        **Filtering:** AND logic between different metadata keys, OR logic between values of the same key.

        **Sorting:** Sort by `addedAt`, `updatedAt`, or `key`.
      operationId: searchDocuments
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchRequest"
      responses:
        "200":
          description: Search results
          headers:
            X-Total-Count:
              description: Total number of matching documents (before pagination)
              schema:
                type: integer
                example: 234
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Document"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/delete:
    post:
      tags:
        - Documents
      summary: Delete document
      description: Delete a specific document by collection, key, and language
      operationId: deleteDocument
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeleteRequest"
      responses:
        "200":
          description: Document deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted:
                    type: boolean
                    example: true
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/delete-batch:
    post:
      tags:
        - Documents
      summary: Batch delete documents
      description: Delete multiple documents in a single request
      operationId: deleteDocumentsBatch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
                - documents
              properties:
                collection:
                  type: string
                  description: Target collection
                  example: blog
                documents:
                  type: array
                  items:
                    type: object
                    properties:
                      key:
                        type: string
                      lang:
                        type: string
                  example:
                    - key: post-1
                      lang: en
                    - key: post-2
                      lang: en
      responses:
        "200":
          description: Batch delete result
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted:
                    type: integer
                    example: 2
                  not_found:
                    type: integer
                    example: 0
                  failed:
                    type: integer
                    example: 0
                  errors:
                    type: array
                    items:
                      type: string
                    nullable: true
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/delete-collection:
    post:
      tags:
        - Documents
      summary: Delete collection
      description: Delete all documents in a collection
      operationId: deleteCollection
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeleteCollectionRequest"
      responses:
        "200":
          description: Collection deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted:
                    type: integer
                    description: Number of documents deleted
                    example: 42
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/export:
    post:
      tags:
        - Export
      summary: Export documents
      description: |
        Export documents in NDJSON or ZIP format with optional metadata filtering.

        **NDJSON:** Newline-delimited JSON, one document per line.

        **ZIP:** Archive with markdown files named `{key}.{lang}.md`.
      operationId: exportDocuments
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExportRequest"
      responses:
        "200":
          description: Export file
          content:
            application/x-ndjson:
              schema:
                type: string
                format: binary
            application/zip:
              schema:
                type: string
                format: binary
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/backup:
    get:
      tags:
        - Export
      summary: Create backup
      description: Create a backup of the database file
      operationId: createBackup
      parameters:
        - name: to
          in: query
          required: true
          description: Destination path for backup file
          schema:
            type: string
            example: backup-20250109.db
      responses:
        "200":
          description: Backup created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  backup:
                    type: string
                    example: backup-20250109.db
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/restore:
    post:
      tags:
        - Export
      summary: Restore from backup
      description: Restore database from a backup file
      operationId: restoreBackup
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - from
              properties:
                from:
                  type: string
                  description: Path to backup file
                  example: backup-20250109.db
      responses:
        "200":
          description: Database restored successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  restored:
                    type: string
                    example: backup-20250109.db
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/truncate:
    post:
      tags:
        - Maintenance
      summary: Truncate revision history
      description: |
        Remove old revisions to save disk space. Keeps the latest N revisions per document.

        **Warning:** This operation is irreversible.
      operationId: truncateRevisions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TruncateRequest"
      responses:
        "200":
          description: Revisions truncated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted:
                    type: integer
                    description: Number of revisions deleted
                    example: 150
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/vector-search:
    post:
      tags:
        - Vector Search
      summary: Semantic vector search
      description: |
        Search documents by semantic similarity using vector embeddings.

        Provide either a `query` string (which will be embedded automatically using the configured provider) or a raw `queryVector` array of floats.

        Results are ranked by cosine similarity score. Use `threshold` to filter out low-relevance results. Use `filterMeta` to narrow results by metadata before ranking.

        Use `algorithm` to select the search strategy: `flat` (exact), `hnsw` (fast approximate), `ivf` (clustered), or `pq` (compressed). See [Search Algorithms](SEARCH.md) for details.
      operationId: vectorSearch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VectorSearchRequest"
      responses:
        "200":
          description: Vector search results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VectorSearchResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "503":
          description: Vector index is still loading
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/vector-reindex:
    post:
      tags:
        - Vector Search
      summary: Reindex collection embeddings
      description: |
        Trigger re-embedding of all documents in a collection. This is a write-protected endpoint.

        Use `force: true` to re-embed all documents even if their content has not changed since the last embedding.
      operationId: vectorReindex
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VectorReindexRequest"
      responses:
        "200":
          description: Reindex completed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VectorReindexResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/vector-stats:
    get:
      tags:
        - Vector Search
      summary: Vector search statistics
      description: Get the current status of the vector search subsystem, including provider info, index readiness, and per-collection embedding counts.
      operationId: vectorStats
      responses:
        "200":
          description: Vector stats retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VectorStatsResponse"

  /v1/geo-search:
    post:
      tags:
        - Geo Search
      summary: Radius search (R-tree or geohash)
      description: |
        Find documents within `radiusMeters` of a (lat, lng) point. Documents
        must have `geo_lat`+`geo_lng`, `geo_hash`, or a resolvable
        `geo_postcode`+`geo_country` in their metadata. Results are sorted by
        ascending distance and composable with `filterMeta`.
      operationId: geoSearch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [collection, lat, lng, radiusMeters]
              properties:
                collection: { type: string }
                lat: { type: number, format: double }
                lng: { type: number, format: double }
                radiusMeters: { type: number, format: double }
                topK: { type: integer, default: 10 }
                algorithm:
                  { type: string, enum: [rtree, geohash], default: rtree }
                filterMeta:
                  {
                    type: object,
                    additionalProperties:
                      { type: array, items: { type: string } },
                  }
                includeContent: { type: boolean, default: false }
      responses:
        "200": { description: OK }
        "400": { description: Invalid request }
        "503": { description: Index still loading }

  /v1/geo-within:
    post:
      tags:
        - Geo Search
      summary: Bounding-box search
      description: Find documents inside an axis-aligned bbox. Does not cross the anti-meridian.
      operationId: geoWithin
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [collection, minLat, maxLat, minLng, maxLng]
              properties:
                collection: { type: string }
                minLat: { type: number }
                maxLat: { type: number }
                minLng: { type: number }
                maxLng: { type: number }
                filterMeta:
                  {
                    type: object,
                    additionalProperties:
                      { type: array, items: { type: string } },
                  }
                includeContent: { type: boolean }
      responses:
        "200": { description: OK }

  /v1/geo-reindex:
    post:
      tags:
        - Geo Search
      summary: Force-rebuild geo indexes
      description: Rebuild both R-tree and geohash indexes from the persisted `geo` bucket. Optionally load one or more postcode CSVs first.
      operationId: geoReindex
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                collection:
                  {
                    type: string,
                    description: "Empty = rebuild all collections",
                  }
                loadPostcodes:
                  type: array
                  items:
                    type: object
                    properties:
                      country: { type: string }
                      csvPath: { type: string }
      responses:
        "200": { description: OK }

  /v1/geo-stats:
    get:
      tags:
        - Geo Search
      summary: Geo index statistics
      operationId: geoStats
      responses:
        "200": { description: OK }

  /v1/geo-encode:
    post:
      tags:
        - Geo Search
      summary: Encode (lat, lng) → geohash string
      operationId: geoEncode
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [lat, lng]
              properties:
                lat: { type: number }
                lng: { type: number }
                precision:
                  { type: integer, minimum: 1, maximum: 12, default: 12 }
      responses:
        "200": { description: OK }

  /v1/geo-decode:
    post:
      tags:
        - Geo Search
      summary: Decode geohash → centroid + bbox
      operationId: geoDecode
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [geohash]
              properties:
                geohash: { type: string }
      responses:
        "200": { description: OK }

  /v1/fts:
    post:
      tags:
        - Full-Text Search
      summary: Full-text search
      description: |
        Perform full-text search across documents in a collection. Supports 7 search modes with auto-detection and multi-language stemming (18 languages).

        **Search modes** (`mode` parameter, default `auto`):
        - `simple`: Classic keyword search scored by algorithm (TF-IDF, BM25, BM25F, PMISparse)
        - `boolean`: AND/OR/NOT operators, `+required`, `-excluded` terms
        - `phrase`: Exact word sequence matching using `"quoted phrases"`
        - `wildcard`: Pattern matching with `*` (any chars) and `?` (single char)
        - `proximity`: Terms within N words — `"term1 term2"~5`
        - `auto` (default): Auto-detects mode from query syntax (quotes → phrase, operators → boolean, etc.)

        **Algorithms** (for simple/boolean modes):
        - `tfidf` (default): Classic TF-IDF scoring
        - `bm25`: Okapi BM25 with document length normalization (k1=1.2, b=0.75)
        - `bm25f`: BM25F field-weighted scoring — applies different weights to title, metadata, and content fields
        - `pmisparse`: PMISparse — BM25 + PMI query expansion

        **Range filtering:** Use `rangeMeta` to filter by numeric, date, or string ranges on metadata fields.

        **In-graph filtering:** Use `filterMeta` to narrow results by metadata before scoring, same as vector search.
      operationId: fullTextSearch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FTSSearchRequest"
      responses:
        "200":
          description: Full-text search results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FTSSearchResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/fts-reindex:
    post:
      tags:
        - Full-Text Search
      summary: Reindex FTS for a collection
      description: |
        Re-indexes all documents in a collection using their stored `lang` field for language-aware stemming and stop words.
        Use this after enabling multi-language support to update existing documents indexed with the default English pipeline.
      operationId: ftsReindex
      parameters:
        - name: collection
          in: query
          required: true
          schema:
            type: string
          description: Collection name to reindex
      responses:
        "200":
          description: Reindex completed
          content:
            application/json:
              schema:
                type: object
                properties:
                  reindexed:
                    type: integer
                    description: Number of documents reindexed
                  collection:
                    type: string
        "400":
          description: Missing collection parameter
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/fts-languages:
    get:
      tags:
        - Full-Text Search
      summary: List supported FTS languages
      description: Returns all supported languages for multi-language FTS with their codes, names, and the configured default language.
      operationId: ftsLanguages
      responses:
        "200":
          description: Supported languages
          content:
            application/json:
              schema:
                type: object
                properties:
                  languages:
                    type: array
                    items:
                      type: object
                      properties:
                        code:
                          type: string
                          example: en
                        name:
                          type: string
                          example: English
                  defaultLang:
                    type: string
                    example: en

  /v1/hybrid-search:
    post:
      tags:
        - Hybrid Search
      summary: Hybrid sparse+dense search
      description: |
        Combine FTS (keyword) and vector (semantic) search into a single query. Returns results ranked by a fused score.

        **Fusion strategies:**
        - `alpha` (default): Weighted alpha blending — `combined = (1-alpha) * normalizedFTS + alpha * vectorScore`. Alpha=0 is pure keyword, alpha=1 is pure semantic.
        - `rrf`: Reciprocal Rank Fusion — `score = 1/(k + rank_fts) + 1/(k + rank_vector)`. Rank-based, no alpha needed.

        **FTS algorithms:** `bm25` (default), `bm25f` (field-weighted).

        **Vector algorithms:** `flat` (default), `hnsw`, `ivf`, `pq`, `sq`.

        Use `filterMeta` to pre-filter by metadata before both FTS and vector scoring.
      operationId: hybridSearch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/HybridSearchRequest"
      responses:
        "200":
          description: Hybrid search results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HybridSearchResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/import-url:
    post:
      tags:
        - Import
      summary: Import document from URL
      description: |
        Fetch content from a URL, parse YAML frontmatter if present, merge metadata, and store the document. This is a write-protected endpoint.

        If `key` is not provided, it is derived from the URL path. YAML frontmatter metadata from the fetched content is merged with the `meta` parameter.
      operationId: importUrl
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ImportURLRequest"
      responses:
        "200":
          description: Document imported successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/import-wiki:
    post:
      tags:
        - Import
      summary: Import Wikipedia XML dump
      description: |
        Stream and import MediaWiki XML dumps (`.xml` or `.xml.bz2`) into a collection.
        Automatically converts wikitext to Markdown. Streams the XML — does not load the entire file into memory.
        Supports namespace filtering, redirect skipping, and batch processing with progress logging.
      operationId: importWiki
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
                - collection
                - lang
              properties:
                file:
                  type: string
                  format: binary
                  description: Wikipedia XML dump file (.xml or .xml.bz2)
                collection:
                  type: string
                  description: Target collection name
                lang:
                  type: string
                  description: Language code (e.g. en, de, pl)
                namespaces:
                  type: string
                  description: "Comma-separated namespace IDs (default: 0 = articles only)"
                skipRedirects:
                  type: string
                  enum: ["true", "false"]
                  description: Skip redirect pages
                skipFts:
                  type: string
                  enum: ["true", "false"]
                  description: Skip FTS indexing for faster bulk import
                maxPages:
                  type: string
                  description: Maximum number of pages to import
                batchSize:
                  type: string
                  description: "Pages per batch commit (default: 500)"
          application/octet-stream:
            schema:
              type: string
              format: binary
          application/x-bzip2:
            schema:
              type: string
              format: binary
      parameters:
        - name: collection
          in: query
          schema:
            type: string
          description: Target collection (for octet-stream/bzip2 uploads)
        - name: lang
          in: query
          schema:
            type: string
          description: Language code (for octet-stream/bzip2 uploads)
        - name: namespaces
          in: query
          schema:
            type: string
          description: "Comma-separated namespace IDs (default: 0)"
        - name: skipRedirects
          in: query
          schema:
            type: string
        - name: skipFts
          in: query
          schema:
            type: string
        - name: maxPages
          in: query
          schema:
            type: integer
        - name: batchSize
          in: query
          schema:
            type: integer
        - name: filename
          in: query
          schema:
            type: string
          description: Filename hint for compression detection (e.g. dump.xml.bz2)
      responses:
        "200":
          description: Import completed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WikiImportResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/set-ttl:
    post:
      tags:
        - TTL
      summary: Set document TTL
      description: |
        Set a time-to-live (TTL) on a document. After the TTL expires, the document will be automatically deleted. This is a write-protected endpoint.

        Set `ttl` to `0` to remove the TTL and make the document permanent again.
      operationId: setTTL
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SetTTLRequest"
      responses:
        "200":
          description: TTL set successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/webhooks:
    get:
      tags:
        - Webhooks
      summary: List webhooks
      description: List all registered webhooks.
      operationId: listWebhooks
      responses:
        "200":
          description: List of registered webhooks
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Webhook"
    post:
      tags:
        - Webhooks
      summary: Register webhook
      description: |
        Register a new webhook to receive event notifications. This is a write-protected endpoint.

        If `collection` is empty, the webhook will receive events for all collections.
      operationId: registerWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegisterWebhookRequest"
      responses:
        "200":
          description: Webhook registered successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/webhooks/delete:
    post:
      tags:
        - Webhooks
      summary: Delete webhook
      description: Delete a registered webhook by its ID. This is a write-protected endpoint.
      operationId: deleteWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeleteWebhookRequest"
      responses:
        "200":
          description: Webhook deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: deleted
                  id:
                    type: string
                    example: abc123
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/schema/set:
    post:
      tags:
        - Schema Validation
      summary: Set collection schema
      description: |
        Set a JSON Schema for a collection's metadata validation. This is a write-protected endpoint.

        Once set, all documents added to the collection will have their metadata validated against this schema.
      operationId: setSchema
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SetSchemaRequest"
      responses:
        "200":
          description: Schema set successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  collection:
                    type: string
                    example: blog
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/schema/get:
    post:
      tags:
        - Schema Validation
      summary: Get collection schema
      description: Retrieve the JSON Schema currently set for a collection.
      operationId: getSchema
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
              properties:
                collection:
                  type: string
                  description: Collection name
                  example: blog
      responses:
        "200":
          description: Schema retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SchemaResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/schema/delete:
    post:
      tags:
        - Schema Validation
      summary: Delete collection schema
      description: Remove the JSON Schema for a collection, disabling metadata validation. This is a write-protected endpoint.
      operationId: deleteSchema
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
              properties:
                collection:
                  type: string
                  description: Collection name
                  example: blog
      responses:
        "200":
          description: Schema deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  collection:
                    type: string
                    example: blog
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Read-only mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/schema/list:
    post:
      tags:
        - Schema Validation
      summary: List all schemas
      description: List all JSON Schemas set across all collections.
      operationId: listSchemas
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
      responses:
        "200":
          description: List of schemas
          content:
            application/json:
              schema:
                type: object
                properties:
                  schemas:
                    type: array
                    items:
                      type: object
                      properties:
                        collection:
                          type: string
                          example: blog
                        schema:
                          type: string
                          description: JSON Schema string
                          example: '{"type":"object","required":["author"]}'

  /v1/validate:
    post:
      tags:
        - Schema Validation
      summary: Validate metadata against schema
      description: |
        Validate a metadata object against the JSON Schema set for a collection.

        This is a dry-run validation that does not modify any data. Useful for pre-validating metadata before adding a document.
      operationId: validateMetadata
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ValidateRequest"
      responses:
        "200":
          description: Validation result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidateResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /metrics:
    get:
      tags:
        - Telemetry
      summary: Prometheus metrics
      description: |
        Returns server telemetry in Prometheus text exposition format.

        Includes HTTP request counters, latency histograms, database statistics,
        vector search status, and Go runtime metrics. Enabled by default
        (set `MDDB_METRICS=false` to disable).

        See [Telemetry documentation](TELEMETRY.md) for Grafana dashboards and alerting rules.
      operationId: getMetrics
      responses:
        "200":
          description: Prometheus metrics
          content:
            text/plain:
              schema:
                type: string
                example: |
                  # HELP mddb_uptime_seconds Time since server start in seconds.
                  # TYPE mddb_uptime_seconds gauge
                  mddb_uptime_seconds 3621.4
                  # HELP mddb_http_requests_total Total number of HTTP requests.
                  # TYPE mddb_http_requests_total counter
                  mddb_http_requests_total{method="POST",path="/v1/add",status="200"} 1523
        "404":
          description: Metrics disabled (MDDB_METRICS=false)

  /v1/replication/status:
    get:
      tags:
        - Replication
      summary: Replication status
      description: |
        Returns the replication status of this node, including role, LSN, binlog stats,
        and connected followers (leader only).

        Available for all roles: standalone, leader, and follower.

        ### Replication Architecture
        MDDB uses a pull-based, single-leader replication model. Wait for the `healthy` flag to determine if the node is fully synced.

        ```mermaid
        graph LR
            L[Leader] -->|Binlog Stream| F1[Follower 1]
            L -->|Binlog Stream| F2[Follower 2]
        ```

        See [Replication documentation](REPLICATION.md) for full setup instructions and monitoring.
      operationId: getReplicationStatus
      responses:
        "200":
          description: Replication status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReplicationStatusResponse"

  /v1/synonyms:
    get:
      tags:
        - Synonyms
      summary: List synonyms
      description: List all synonym entries for a collection. Synonyms are used to expand FTS queries with related terms.
      operationId: listSynonyms
      parameters:
        - name: collection
          in: query
          required: true
          description: Collection name
          schema:
            type: string
            example: blog
      responses:
        "200":
          description: Synonym list retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SynonymListResponse"
        "400":
          description: Invalid request (missing collection parameter)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Synonyms
      summary: Add or update synonym group
      description: |
        Add or update a synonym mapping for a term in a collection. Synonyms are bidirectional --
        if "big" has synonym "large", then querying "large" will also expand to include "big".
      operationId: setSynonym
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SynonymRequest"
      responses:
        "200":
          description: Synonym group set successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Synonyms
      summary: Delete synonym group
      description: Delete a synonym mapping for a term in a collection.
      operationId: deleteSynonym
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SynonymDeleteRequest"
      responses:
        "200":
          description: Synonym group deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/stopwords:
    get:
      tags:
        - Stop Words
      summary: List stop words
      description: List all stop word entries (default + custom) for a collection. Stop words are excluded from FTS indexing.
      operationId: listStopWords
      parameters:
        - name: collection
          in: query
          required: true
          description: Collection name
          schema:
            type: string
            example: blog
      responses:
        "200":
          description: Stop word list retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                    example: blog
                  entries:
                    type: array
                    items:
                      type: object
                      properties:
                        word:
                          type: string
                          example: the
                        isDefault:
                          type: boolean
                          example: true
                  total:
                    type: integer
                    example: 35
                  defaults:
                    type: integer
                    example: 33
                  custom:
                    type: integer
                    example: 2
        "400":
          description: Invalid request (missing collection parameter)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Stop Words
      summary: Add custom stop words
      description: Add custom stop words to a collection. These words will be excluded from FTS indexing.
      operationId: addStopWords
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
                - words
              properties:
                collection:
                  type: string
                  example: blog
                words:
                  type: array
                  items:
                    type: string
                  example: ["foo", "bar"]
      responses:
        "200":
          description: Stop words added successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  added:
                    type: integer
                    example: 2
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Stop Words
      summary: Delete custom stop words
      description: Delete custom stop words from a collection. Default stop words cannot be deleted.
      operationId: deleteStopWords
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
                - words
              properties:
                collection:
                  type: string
                  example: blog
                words:
                  type: array
                  items:
                    type: string
                  example: ["foo"]
      responses:
        "200":
          description: Stop words deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  deleted:
                    type: integer
                    example: 1
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/embedding-configs:
    get:
      tags:
        - Embedding Config
      summary: List embedding configurations
      description: List all embedding model configurations.
      operationId: listEmbeddingConfigs
      responses:
        "200":
          description: List of embedding configurations
          content:
            application/json:
              schema:
                type: object
                properties:
                  configs:
                    type: array
                    items:
                      $ref: "#/components/schemas/EmbeddingConfig"
    post:
      tags:
        - Embedding Config
      summary: Create embedding configuration
      description: |
        Create a new embedding model configuration. Required fields: id, name, provider, model, dimensions.

        Supported providers: `openai`, `ollama`, `cohere`, `voyage`.
      operationId: createEmbeddingConfig
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmbeddingConfig"
      responses:
        "201":
          description: Embedding configuration created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmbeddingConfig"
        "400":
          description: Invalid request (missing required fields or invalid provider)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/embedding-configs/{id}:
    get:
      tags:
        - Embedding Config
      summary: Get embedding configuration
      description: Retrieve a specific embedding configuration by ID.
      operationId: getEmbeddingConfig
      parameters:
        - name: id
          in: path
          required: true
          description: Embedding configuration ID
          schema:
            type: string
            example: openai-small
      responses:
        "200":
          description: Embedding configuration retrieved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmbeddingConfig"
        "404":
          description: Configuration not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    put:
      tags:
        - Embedding Config
      summary: Update embedding configuration
      description: |
        Update an existing embedding configuration. The ID in the path is used (body ID is ignored).

        Supported providers: `openai`, `ollama`, `cohere`, `voyage`.
      operationId: updateEmbeddingConfig
      parameters:
        - name: id
          in: path
          required: true
          description: Embedding configuration ID
          schema:
            type: string
            example: openai-small
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmbeddingConfig"
      responses:
        "200":
          description: Embedding configuration updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmbeddingConfig"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Embedding Config
      summary: Delete embedding configuration
      description: Delete an embedding configuration. Cannot delete the default configuration.
      operationId: deleteEmbeddingConfig
      parameters:
        - name: id
          in: path
          required: true
          description: Embedding configuration ID
          schema:
            type: string
            example: openai-small
      responses:
        "204":
          description: Embedding configuration deleted
        "400":
          description: Cannot delete default config
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Configuration not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/embedding-configs/set-default:
    post:
      tags:
        - Embedding Config
      summary: Set default embedding configuration
      description: |
        Set an embedding configuration as the default. This will unset any previously default configuration
        and reinitialize the embedding system with the new default config.
      operationId: setDefaultEmbeddingConfig
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - id
              properties:
                id:
                  type: string
                  description: ID of the embedding configuration to set as default
                  example: openai-small
      responses:
        "200":
          description: Default configuration updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: default config updated
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Configuration not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/system/info:
    get:
      tags:
        - System
      summary: System information
      description: |
        Returns detailed system information including hostname, OS, architecture, CPU count,
        Go version, memory statistics, goroutine count, CPU usage, and network interfaces.
      operationId: getSystemInfo
      responses:
        "200":
          description: System information retrieved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SystemInfoResponse"

  /v1/config:
    get:
      tags:
        - Configuration
      summary: Server configuration
      description: |
        Returns the current server configuration including version, database path, mode,
        protocol statuses, authentication state, and vector/chunk configuration.
      operationId: getConfig
      responses:
        "200":
          description: Server configuration retrieved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ConfigResponse"

  /v1/mcp/config:
    get:
      tags:
        - Configuration
      summary: MCP YAML configuration
      description: |
        Returns a YAML configuration template for the MCP (Model Context Protocol) server.
        Includes gRPC and REST connection settings and example custom tool configurations.
      operationId: getMCPConfig
      responses:
        "200":
          description: MCP configuration in YAML format
          content:
            text/yaml:
              schema:
                type: string
                example: |
                  mcp:
                    # listenAddress: "0.0.0.0:9000"
                  mddb:
                    grpcAddress: "localhost:11024"
                    restBaseUrl: "http://localhost:11023"
                    transportMode: "grpc_with_rest_fallback"
                    timeoutSeconds: 2
                    maxRetries: 1

  /v1/endpoints:
    get:
      tags:
        - System
      summary: List all endpoints
      description: |
        Returns a comprehensive list of all available HTTP endpoints, gRPC methods, and MCP tools
        supported by this server instance.
      operationId: listEndpoints
      responses:
        "200":
          description: Endpoint list retrieved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EndpointsResponse"

  /v1/auth/login:
    post:
      tags:
        - Authentication
      summary: Login
      description: |
        Authenticate with username and password to receive a JWT token.
        The token should be included in subsequent requests via the `Authorization: Bearer <token>` header.
      operationId: authLogin
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/LoginRequest"
      responses:
        "200":
          description: Login successful
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LoginResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Invalid credentials
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/register:
    post:
      tags:
        - Users
      summary: Register new user
      description: Create a new user account. Requires admin authentication.
      operationId: authRegister
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegisterRequest"
      responses:
        "200":
          description: User registered successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegisterResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: User already exists
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/api-key:
    post:
      tags:
        - Authentication
      summary: Create API key
      description: |
        Create a new API key for the authenticated user. The key is returned only once in the response.
        Use the `X-API-Key` header to authenticate with the key in subsequent requests.
      operationId: authCreateAPIKey
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateAPIKeyRequest"
      responses:
        "200":
          description: API key created (key shown only once)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateAPIKeyResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/api-keys:
    get:
      tags:
        - Authentication
      summary: List API keys
      description: List all API keys for the authenticated user (key values are not included, only hashes).
      operationId: authListAPIKeys
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of API keys
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListAPIKeysResponse"
        "401":
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/api-keys/{keyHash}:
    delete:
      tags:
        - Authentication
      summary: Delete API key
      description: Delete an API key by its hash. Users can only delete their own API keys.
      operationId: authDeleteAPIKey
      security:
        - BearerAuth: []
      parameters:
        - name: keyHash
          in: path
          required: true
          description: SHA256 hash of the API key
          schema:
            type: string
            example: a1b2c3d4e5f6...
      responses:
        "200":
          description: API key deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: deleted
        "400":
          description: Key hash required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden (can only delete own keys)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: API key not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/me:
    post:
      tags:
        - Authentication
      summary: Get current user info
      description: Returns information about the currently authenticated user.
      operationId: authGetMe
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Current user info
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetMeResponse"
        "401":
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: User not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/permissions:
    get:
      tags:
        - Users
      summary: Get user permissions
      description: Get all permissions for a specific user. Requires admin authentication.
      operationId: authGetPermissions
      security:
        - BearerAuth: []
      parameters:
        - name: username
          in: query
          required: true
          description: Username to get permissions for
          schema:
            type: string
            example: alice
      responses:
        "200":
          description: User permissions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Permission"
        "400":
          description: Username parameter required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Users
      summary: Set user permissions
      description: Set permissions for a user on a specific collection. Requires admin authentication.
      operationId: authSetPermissions
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SetPermissionRequest"
      responses:
        "200":
          description: Permission set successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SetPermissionResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/users:
    get:
      tags:
        - Users
      summary: List all users
      description: List all user accounts with their details. Requires admin authentication.
      operationId: authListUsers
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of users
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsersListResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/users/{username}:
    delete:
      tags:
        - Users
      summary: Delete user
      description: Delete (disable) a user account. Requires admin authentication.
      operationId: authDeleteUser
      security:
        - BearerAuth: []
      parameters:
        - name: username
          in: path
          required: true
          description: Username to delete
          schema:
            type: string
            example: alice
      responses:
        "200":
          description: User deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: deleted
        "400":
          description: Username required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: User not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/groups:
    get:
      tags:
        - Groups
      summary: List all groups
      description: List all user groups. Requires admin authentication.
      operationId: authListGroups
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of groups
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GroupsListResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Groups
      summary: Create group
      description: Create a new user group. Requires admin authentication.
      operationId: authCreateGroup
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateGroupRequest"
      responses:
        "201":
          description: Group created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Group"
        "400":
          description: Invalid request (missing name or group already exists)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/groups/{name}:
    get:
      tags:
        - Groups
      summary: Get group details
      description: Retrieve details for a specific group. Requires admin authentication.
      operationId: authGetGroup
      security:
        - BearerAuth: []
      parameters:
        - name: name
          in: path
          required: true
          description: Group name
          schema:
            type: string
            example: developers
      responses:
        "200":
          description: Group details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Group"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Group not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    put:
      tags:
        - Groups
      summary: Update group
      description: Update a group's description and member list. Requires admin authentication.
      operationId: authUpdateGroup
      security:
        - BearerAuth: []
      parameters:
        - name: name
          in: path
          required: true
          description: Group name
          schema:
            type: string
            example: developers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateGroupRequest"
      responses:
        "200":
          description: Group updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Group"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Group not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Groups
      summary: Delete group
      description: Delete a group and all its associated permissions. Requires admin authentication.
      operationId: authDeleteGroup
      security:
        - BearerAuth: []
      parameters:
        - name: name
          in: path
          required: true
          description: Group name
          schema:
            type: string
            example: developers
      responses:
        "200":
          description: Group deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: deleted
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Group not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/auth/group-permissions:
    get:
      tags:
        - Groups
      summary: Get group permissions
      description: Get all permissions for a specific group. Requires admin authentication.
      operationId: authGetGroupPermissions
      security:
        - BearerAuth: []
      parameters:
        - name: group
          in: query
          required: true
          description: Group name
          schema:
            type: string
            example: developers
      responses:
        "200":
          description: Group permissions
          content:
            application/json:
              schema:
                type: object
                properties:
                  permissions:
                    type: array
                    items:
                      $ref: "#/components/schemas/GroupPermission"
        "400":
          description: Group parameter required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Groups
      summary: Set group permission
      description: Set a collection-level permission for a group. Requires admin authentication.
      operationId: authSetGroupPermission
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GroupPermission"
      responses:
        "200":
          description: Permission set
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: permission set
        "400":
          description: Invalid request (missing fields or group not found)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Admin access required
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /graphql:
    post:
      tags:
        - GraphQL
      summary: GraphQL API endpoint
      description: |
        Execute GraphQL queries and mutations against the MDDB API.
        Requires `MDDB_GRAPHQL_ENABLED=true` environment variable.

        Supports queries for documents, search, vector search, full-text search, and hybrid search.
        Supports mutations for adding, deleting, and managing documents.
      operationId: graphqlQuery
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - query
              properties:
                query:
                  type: string
                  description: GraphQL query or mutation string
                  example: "{ stats { totalDocuments } }"
                variables:
                  type: object
                  additionalProperties: true
                  description: GraphQL variables
                operationName:
                  type: string
                  description: Name of the operation to execute (if query contains multiple)
      responses:
        "200":
          description: GraphQL response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: Query result data
                  errors:
                    type: array
                    items:
                      type: object
                      properties:
                        message:
                          type: string
                        path:
                          type: array
                          items:
                            type: string
                    description: GraphQL errors (if any)

  /playground:
    get:
      tags:
        - GraphQL
      summary: GraphQL Playground
      description: |
        Interactive GraphQL Playground UI for exploring and testing the MDDB GraphQL API.
        Requires `MDDB_GRAPHQL_ENABLED=true` environment variable.
      operationId: graphqlPlayground
      responses:
        "200":
          description: GraphQL Playground HTML page
          content:
            text/html:
              schema:
                type: string

  /v1/automation:
    get:
      tags: [Automation]
      summary: List automation rules
      description: Returns all automation rules (webhooks, triggers, crons). Optionally filter by type.
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [webhook, trigger, cron]
          description: Filter by rule type
      responses:
        "200":
          description: List of automation rules
          content:
            application/json:
              schema:
                type: object
                properties:
                  rules:
                    type: array
                    items:
                      $ref: "#/components/schemas/AutomationRule"
                  total:
                    type: integer
    post:
      tags: [Automation]
      summary: Create automation rule
      description: Create a new webhook target, trigger, or cron rule.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AutomationRule"
      responses:
        "201":
          description: Rule created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationRule"
        "400":
          description: Validation error

  /v1/automation/{id}:
    get:
      tags: [Automation]
      summary: Get automation rule
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Automation rule
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationRule"
        "404":
          description: Not found
    put:
      tags: [Automation]
      summary: Update automation rule
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AutomationRule"
      responses:
        "200":
          description: Rule updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AutomationRule"
    delete:
      tags: [Automation]
      summary: Delete automation rule
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Rule deleted

  /v1/automation/{id}/test:
    post:
      tags: [Automation]
      summary: Test trigger (dry run)
      description: Execute a trigger's search and return matching documents without firing the webhook.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Test results
          content:
            application/json:
              schema:
                type: object
                properties:
                  trigger:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      searchType:
                        type: string
                      query:
                        type: string
                      threshold:
                        type: number
                  matches:
                    type: array
                    items:
                      $ref: "#/components/schemas/TriggerMatch"
                  total:
                    type: integer

  /v1/automation-logs:
    get:
      tags: [Automation]
      summary: List automation execution logs
      description: Returns automation execution logs ordered newest-first with cursor-based pagination. Requires MDDB_AUTOMATION_LOGS != "disable".
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 500
          description: Max entries per page
        - name: cursor
          in: query
          schema:
            type: string
          description: Pagination cursor from previous response
        - name: ruleId
          in: query
          schema:
            type: string
          description: Filter by rule ID
        - name: status
          in: query
          schema:
            type: string
            enum: [success, error, skipped]
          description: Filter by execution status
      responses:
        "200":
          description: Automation logs
          content:
            application/json:
              schema:
                type: object
                properties:
                  logs:
                    type: array
                    items:
                      $ref: "#/components/schemas/AutomationLogEntry"
                  total:
                    type: integer
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean

  /v1/meta-keys:
    get:
      tags:
        - Search
      summary: List metadata keys and values for a collection
      description: Returns all unique metadata keys and their unique values for a given collection. Useful for building filter UIs.
      parameters:
        - name: collection
          in: query
          required: true
          schema:
            type: string
          description: Collection name
      responses:
        "200":
          description: Metadata keys with their unique values
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
                example:
                  meta:
                    tag: ["go", "rust", "python"]
                    author: ["alice", "bob"]
        "400":
          description: Missing collection parameter

  /v1/checksum:
    get:
      tags:
        - Collections
      summary: Get collection checksum
      description: Returns a CRC32-based checksum for a collection that changes whenever documents are added, updated, or deleted. Useful for cache invalidation - clients can poll this lightweight endpoint to detect changes without downloading all documents.
      parameters:
        - name: collection
          in: query
          required: true
          schema:
            type: string
          description: Collection name
      responses:
        "200":
          description: Collection checksum and document count
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                  checksum:
                    type: string
                    description: 8-character hex CRC32 checksum
                  documentCount:
                    type: integer
                example:
                  collection: "blog"
                  checksum: "a1b2c3d4"
                  documentCount: 42
        "400":
          description: Missing collection parameter

  /v1/update:
    patch:
      tags:
        - Documents
      summary: Partial document update
      description: |
        Update document metadata and/or content independently.
        Only provided fields are updated; omitted fields remain unchanged.
        Use `meta: {}` to clear all metadata.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
                - key
                - lang
              properties:
                collection:
                  type: string
                key:
                  type: string
                lang:
                  type: string
                meta:
                  type: object
                  description: "If provided, replaces all metadata. Use {} to clear."
                  additionalProperties:
                    type: array
                    items:
                      type: string
                contentMd:
                  type: string
                  description: "If provided, replaces document content."
                ttl:
                  type: integer
                  description: "If provided, updates TTL in seconds. 0 = no expiry."
            examples:
              meta-only:
                summary: Update only metadata
                value:
                  collection: "blog"
                  key: "p1"
                  lang: "en"
                  meta:
                    tag: ["go", "updated"]
              content-only:
                summary: Update only content
                value:
                  collection: "blog"
                  key: "p1"
                  lang: "en"
                  contentMd: "# New Content"
      responses:
        "200":
          description: Updated document
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          description: Missing required fields or no fields to update
        "404":
          description: Document not found
        "405":
          description: Method not allowed

  /v1/doc-meta:
    get:
      tags:
        - Documents
      summary: Get document metadata only
      description: Returns metadata for a document without content. Lightweight read useful for checking tags without transferring document body.
      parameters:
        - name: collection
          in: query
          required: true
          schema:
            type: string
          description: Collection name
        - name: key
          in: query
          required: true
          schema:
            type: string
          description: Document key
        - name: lang
          in: query
          schema:
            type: string
            default: "en"
          description: Language code (defaults to "en")
      responses:
        "200":
          description: Document metadata
          content:
            application/json:
              schema:
                type: object
                properties:
                  key:
                    type: string
                  lang:
                    type: string
                  meta:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
                  addedAt:
                    type: integer
                  updatedAt:
                    type: integer
                  expiresAt:
                    type: integer
                example:
                  key: "p1"
                  lang: "en"
                  meta:
                    tag: ["go", "rust"]
                    author: ["alice"]
                  addedAt: 1709600000
                  updatedAt: 1709610000
        "400":
          description: Missing required parameters
        "404":
          description: Document not found

  /v1/classify:
    post:
      tags:
        - Classification
      summary: Zero-shot document classification
      description: |
        Classify a document or text against candidate labels using embedding similarity.
        Provide either a document reference (collection + key + lang) or raw text, plus an array of candidate labels.
        Returns labels ranked by cosine similarity to the document/text embedding.
        Requires an embedding provider to be configured.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - labels
              properties:
                collection:
                  type: string
                  description: Collection name (for document reference)
                key:
                  type: string
                  description: Document key (for document reference)
                lang:
                  type: string
                  description: Language code (for document reference, defaults to "en")
                text:
                  type: string
                  description: Raw text to classify (alternative to document reference)
                labels:
                  type: array
                  items:
                    type: string
                  description: Candidate labels to rank by similarity (max 100)
                topK:
                  type: integer
                  description: Return top K labels (0 = all, default is all)
                multi:
                  type: boolean
                  description: If true, return all labels above threshold
                threshold:
                  type: number
                  description: Minimum similarity score (default 0.0)
            example:
              text: "Go is a statically typed, compiled language designed at Google"
              labels: ["programming", "cooking", "sports", "music"]
      responses:
        "200":
          description: Classification results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        label:
                          type: string
                        score:
                          type: number
                  model:
                    type: string
                  dimensions:
                    type: integer
              example:
                results:
                  - label: "programming"
                    score: 0.87
                  - label: "music"
                    score: 0.21
                  - label: "sports"
                    score: 0.18
                  - label: "cooking"
                    score: 0.12
                model: "text-embedding-3-small"
                dimensions: 1536
        "400":
          description: Missing labels, invalid request, or no embedding provider
        "404":
          description: Referenced document not found

  /v1/revisions:
    post:
      tags:
        - Revisions
      summary: List document revision history
      description: |
        Returns the revision history for a specific document, ordered by timestamp descending.
        Each revision includes the content and metadata at that point in time.
      operationId: listRevisions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
                - key
                - lang
              properties:
                collection:
                  type: string
                  description: Collection name
                  example: blog
                key:
                  type: string
                  description: Document key
                  example: hello-world
                lang:
                  type: string
                  description: Language code
                  example: en_US
      responses:
        "200":
          description: Revision history retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                    example: blog
                  key:
                    type: string
                    example: hello-world
                  lang:
                    type: string
                    example: en_US
                  revisions:
                    type: array
                    items:
                      $ref: "#/components/schemas/RevisionEntry"
                  total:
                    type: integer
                    description: Total number of revisions
                    example: 3
        "400":
          description: Missing required fields
        "404":
          description: Document not found

  /v1/revisions/restore:
    post:
      tags:
        - Revisions
      summary: Restore a document to a previous revision
      description: |
        Restores a document to the state it was in at a specific revision timestamp.
        The restored content becomes the current version of the document.
      operationId: restoreRevision
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
                - key
                - lang
                - timestamp
              properties:
                collection:
                  type: string
                  description: Collection name
                  example: blog
                key:
                  type: string
                  description: Document key
                  example: hello-world
                lang:
                  type: string
                  description: Language code
                  example: en_US
                timestamp:
                  type: integer
                  format: int64
                  description: Unix timestamp of the revision to restore
                  example: 1704844800
      responses:
        "200":
          description: Document restored successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          description: Missing required fields or invalid timestamp
        "404":
          description: Document or revision not found

  /mcp:
    post:
      tags:
        - MCP
      summary: MCP Streamable HTTP endpoint (2025-11-25)
      description: |
        Streamable HTTP transport for MCP protocol 2025-11-25. Accepts JSON-RPC requests.
        Supported methods: initialize, tools/list, tools/call, resources/list, resources/read,
        prompts/list, prompts/get, completion/complete, logging/setLevel, ping.
        Notifications (no id) return 202 Accepted.
        Session management via MCP-Session-Id header.
        Available on MCP port (default 9000).
      operationId: mcpStreamableHTTP
      parameters:
        - name: MCP-Session-Id
          in: header
          description: Session identifier (assigned by server at initialize)
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                jsonrpc:
                  type: string
                  example: "2.0"
                id:
                  type: integer
                  example: 1
                method:
                  type: string
                  example: "tools/list"
                params:
                  type: object
      responses:
        "200":
          description: JSON-RPC response
          headers:
            MCP-Session-Id:
              description: Session identifier (present on initialize response)
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
        "202":
          description: Notification accepted (no response body)
    get:
      tags:
        - MCP
      summary: MCP SSE stream for server-initiated messages
      description: |
        Open an SSE stream for receiving server-initiated messages (notifications, progress).
        Requires MCP-Session-Id header from a previous initialize call.
      operationId: mcpStreamableSSE
      parameters:
        - name: MCP-Session-Id
          in: header
          required: true
          schema:
            type: string
      responses:
        "200":
          description: SSE event stream
          content:
            text/event-stream:
              schema:
                type: string
    delete:
      tags:
        - MCP
      summary: Terminate MCP session
      description: Close an active MCP Streamable HTTP session.
      operationId: mcpTerminateSession
      parameters:
        - name: MCP-Session-Id
          in: header
          required: true
          schema:
            type: string
      responses:
        "204":
          description: Session terminated

  /v1/events:
    get:
      tags:
        - Real-Time
      summary: Server-Sent Events stream
      description: |
        Subscribe to real-time document change events via SSE.
        Events: doc.added, doc.updated, doc.deleted.
        Default enabled (MDDB_SSE_ENABLED=false to disable).
      operationId: sseEvents
      parameters:
        - name: collection
          in: query
          description: Filter events to a specific collection (optional)
          schema:
            type: string
      responses:
        "200":
          description: SSE event stream
          content:
            text/event-stream:
              schema:
                type: string

  /v1/collection-config:
    get:
      tags:
        - Collection Config
      summary: Get collection configuration
      description: Get the configuration for a specific collection including type, description, icon, color, and custom metadata.
      operationId: getCollectionConfig
      parameters:
        - name: collection
          in: query
          required: true
          schema:
            type: string
          description: Collection name
          example: blog
      responses:
        "200":
          description: Collection configuration retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                    example: blog
                  config:
                    $ref: "#/components/schemas/CollectionConfig"
                  configured:
                    type: boolean
                    description: Whether the collection has been explicitly configured
                    example: true
        "400":
          description: Missing collection parameter
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    put:
      tags:
        - Collection Config
      summary: Set collection configuration
      description: Set or update the configuration for a collection.
      operationId: setCollectionConfig
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
              properties:
                collection:
                  type: string
                  description: Collection name
                  example: blog
                type:
                  type: string
                  description: Collection type
                  example: website
                description:
                  type: string
                  description: Collection description
                  example: Blog posts and articles
                icon:
                  type: string
                  description: Collection icon (emoji or icon name)
                  example: "\uD83C\uDF10"
                color:
                  type: string
                  description: Collection color (hex code)
                  example: "#3B82F6"
                customMeta:
                  type: object
                  additionalProperties: true
                  description: Custom key-value metadata for the collection
                storageBackend:
                  type: string
                  enum: [boltdb, memory, s3]
                  description: "Storage backend for this collection. Default: boltdb"
                  example: boltdb
                storageConfig:
                  $ref: "#/components/schemas/StorageConfigDef"
                quantization:
                  type: string
                  enum: [float32, int8, int4]
                  description: "Vector quantization level for this collection. int8 gives 4x compression (~1% recall drop), int4 gives 8x compression (~2-3% recall drop). Default: float32 (no quantization). Requires vector-reindex after changing."
                  example: int8
      responses:
        "200":
          description: Collection configuration set successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  collection:
                    type: string
                    example: blog
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Collection Config
      summary: Delete collection configuration
      description: Delete the configuration for a specific collection.
      operationId: deleteCollectionConfig
      parameters:
        - name: collection
          in: query
          required: true
          schema:
            type: string
          description: Collection name
          example: blog
      responses:
        "200":
          description: Collection configuration deleted successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  collection:
                    type: string
                    example: blog
        "400":
          description: Missing collection parameter
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/collection-configs:
    get:
      tags:
        - Collection Config
      summary: List all collection configurations
      description: Get all collection configurations.
      operationId: listCollectionConfigs
      responses:
        "200":
          description: All collection configurations retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  configs:
                    type: array
                    items:
                      type: object
                      properties:
                        collection:
                          type: string
                          example: blog
                        config:
                          $ref: "#/components/schemas/CollectionConfig"
                  total:
                    type: integer
                    description: Total number of configured collections
                    example: 3

  /v1/aggregate:
    post:
      tags:
        - Aggregations
      summary: Aggregate metadata facets and date histograms
      description: |
        Compute metadata value counts (facets) and date histograms for a collection.
        Supports optional metadata pre-filtering to scope the aggregation.
      operationId: aggregate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AggregateRequest"
      responses:
        "200":
          description: Aggregation results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AggregateResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/cross-search:
    post:
      tags:
        - Cross-Collection Search
      summary: Cross-collection vector search
      description: |
        Search across multiple collections using a source document's embedding vector or a text query.
        Useful for finding related content across different collection types (e.g., images matching blog post content).
      operationId: crossSearch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CrossSearchRequest"
      responses:
        "200":
          description: Cross-collection search results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CrossSearchResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/find-duplicates:
    post:
      tags:
        - Duplicate Detection
      summary: Find duplicate and similar documents
      description: |
        Scans a collection for duplicate and similar documents using content hashes and embedding vectors.
        Exact mode groups documents with identical content hashes. Similar mode compares embedding vectors
        pairwise and clusters documents above the similarity threshold using transitive clustering.
      operationId: findDuplicates
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FindDuplicatesRequest"
      responses:
        "200":
          description: Duplicate detection results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FindDuplicatesResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/memory/session:
    post:
      tags: [Memory RAG]
      summary: Create a new memory session
      description: Start a new conversation session for storing and recalling messages.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [userId]
              properties:
                userId:
                  type: string
                  description: User identifier
                scenario:
                  type: string
                  description: Session context/scenario
                title:
                  type: string
                  description: Human-readable title
                meta:
                  type: object
                  additionalProperties:
                    type: string
                ttl:
                  type: integer
                  description: TTL in seconds (default 30 days)
      responses:
        "200":
          description: Session created
          content:
            application/json:
              schema:
                type: object
                properties:
                  sessionId:
                    type: string
                  userId:
                    type: string
                  scenario:
                    type: string
                  title:
                    type: string
                  createdAt:
                    type: integer
                  expiresAt:
                    type: integer

  /v1/memory/message:
    post:
      tags: [Memory RAG]
      summary: Add a message to a session
      description: Store a message in a memory session. Messages are auto-embedded for semantic recall.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [sessionId, role, content]
              properties:
                sessionId:
                  type: string
                role:
                  type: string
                  enum: [user, assistant, system, tool]
                content:
                  type: string
                meta:
                  type: object
                  additionalProperties:
                    type: string
      responses:
        "200":
          description: Message added
          content:
            application/json:
              schema:
                type: object
                properties:
                  messageId:
                    type: string
                  sessionId:
                    type: string
                  role:
                    type: string
                  createdAt:
                    type: integer
                  embedded:
                    type: boolean

  /v1/memory/recall:
    post:
      tags: [Memory RAG]
      summary: Recall relevant messages
      description: Semantically recall relevant messages from past conversations using hybrid search (vector + keyword).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [query]
              properties:
                query:
                  type: string
                userId:
                  type: string
                sessionId:
                  type: string
                role:
                  type: string
                topK:
                  type: integer
                  default: 10
                threshold:
                  type: number
                strategy:
                  type: string
                  enum: [hybrid, semantic, keyword]
                  default: hybrid
                alpha:
                  type: number
                includeContent:
                  type: boolean
                filterMeta:
                  type: object
      responses:
        "200":
          description: Recall results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        document:
                          $ref: "#/components/schemas/Document"
                        score:
                          type: number
                        rank:
                          type: integer
                        sessionId:
                          type: string
                        role:
                          type: string
                        matchStrategy:
                          type: string
                  total:
                    type: integer
                  strategy:
                    type: string
                  query:
                    type: string

  /v1/memory/summarize:
    post:
      tags: [Memory RAG]
      summary: Summarize a session
      description: Generate and store a summary of a session's conversation.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [sessionId]
              properties:
                sessionId:
                  type: string
                userId:
                  type: string
      responses:
        "200":
          description: Summary generated
          content:
            application/json:
              schema:
                type: object
                properties:
                  summaryId:
                    type: string
                  sessionId:
                    type: string
                  summary:
                    type: string
                  createdAt:
                    type: integer
                  messages:
                    type: integer

  /v1/memory/sessions:
    post:
      tags: [Memory RAG]
      summary: List memory sessions
      description: List sessions with optional user/scenario filtering and pagination.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                userId:
                  type: string
                scenario:
                  type: string
                limit:
                  type: integer
                  default: 50
                offset:
                  type: integer
                sort:
                  type: string
                  enum: [createdAt, updatedAt]
                  default: createdAt
                asc:
                  type: boolean
      responses:
        "200":
          description: Session list
          content:
            application/json:
              schema:
                type: object
                properties:
                  sessions:
                    type: array
                    items:
                      type: object
                      properties:
                        sessionId:
                          type: string
                        userId:
                          type: string
                        scenario:
                          type: string
                        title:
                          type: string
                        createdAt:
                          type: integer
                        updatedAt:
                          type: integer
                        expiresAt:
                          type: integer
                        messageCount:
                          type: integer
                  total:
                    type: integer

  /v1/memory/history:
    post:
      tags: [Memory RAG]
      summary: Get session message history
      description: Retrieve chronologically ordered message history for a session.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [sessionId]
              properties:
                sessionId:
                  type: string
                limit:
                  type: integer
                  default: 100
                offset:
                  type: integer
      responses:
        "200":
          description: Message history
          content:
            application/json:
              schema:
                type: object
                properties:
                  messages:
                    type: array
                    items:
                      $ref: "#/components/schemas/Document"
                  total:
                    type: integer

  /v1/temporal/query:
    post:
      tags: [Temporal Tracking]
      summary: Query document event history
      description: Returns create/update/access events for a specific document within a time range. Requires MDDB_TEMPORAL=true.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [collection, key, lang]
              properties:
                collection:
                  type: string
                key:
                  type: string
                lang:
                  type: string
                eventType:
                  type: string
                  enum: [create, update, access]
                  description: Filter by event type; omit for all events
                from:
                  type: integer
                  format: int64
                  description: Unix timestamp; defaults to 30 days ago
                to:
                  type: integer
                  format: int64
                  description: Unix timestamp; defaults to now
                limit:
                  type: integer
                  default: 100
      responses:
        "200":
          description: Event history
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                  docId:
                    type: string
                  events:
                    type: array
                    items:
                      $ref: "#/components/schemas/TemporalEvent"
                  total:
                    type: integer
        "400":
          description: Missing required fields or temporal not available

  /v1/temporal/hot:
    post:
      tags: [Temporal Tracking]
      summary: Hot documents leaderboard
      description: Returns the top-N most accessed documents in a collection. Requires MDDB_TEMPORAL=true.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [collection]
              properties:
                collection:
                  type: string
                topN:
                  type: integer
                  default: 10
                since:
                  type: integer
                  format: int64
                  description: Unix timestamp to filter events from
      responses:
        "200":
          description: Hot documents list
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                  entries:
                    type: array
                    items:
                      type: object
                      properties:
                        docId:
                          type: string
                        accessCount:
                          type: integer
                          format: int64
                        lastAccessAt:
                          type: integer
                          format: int64
                        document:
                          $ref: "#/components/schemas/Document"
        "400":
          description: Missing required field or temporal not available

  /v1/temporal/histogram:
    post:
      tags: [Temporal Tracking]
      summary: Event frequency histogram
      description: Returns a bucketed histogram of event frequency for a collection. Requires MDDB_TEMPORAL=true.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [collection]
              properties:
                collection:
                  type: string
                eventType:
                  type: string
                  default: access
                  enum: [create, update, access]
                interval:
                  type: string
                  default: day
                  enum: [day, week, month]
                from:
                  type: integer
                  format: int64
                to:
                  type: integer
                  format: int64
      responses:
        "200":
          description: Histogram buckets
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                  eventType:
                    type: string
                  interval:
                    type: string
                  buckets:
                    type: array
                    items:
                      type: object
                      properties:
                        from:
                          type: integer
                          format: int64
                        to:
                          type: integer
                          format: int64
                        count:
                          type: integer
        "400":
          description: Missing required field or temporal not available

  /v1/spell-suggest:
    post:
      tags: [Spell Correction]
      summary: Spell correction suggestions
      description: Returns per-token spell suggestions and a corrected version of the input text. Requires MDDB_SPELL=true.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [text, lang]
              properties:
                collection:
                  type: string
                  description: Optional — scope suggestions to collection dictionary
                text:
                  type: string
                lang:
                  type: string
                  example: en
                maxSuggestions:
                  type: integer
                  default: 5
      responses:
        "200":
          description: Spell suggestions
          content:
            application/json:
              schema:
                type: object
                properties:
                  originalText:
                    type: string
                  suggestedText:
                    type: string
                  tokenSuggestions:
                    type: array
                    items:
                      type: object
                      properties:
                        token:
                          type: string
                        suggestions:
                          type: array
                          items:
                            type: string
        "503":
          description: Spell index still loading — retry

  /v1/spell-cleanup:
    post:
      tags: [Spell Correction]
      summary: Apply spell corrections to text
      description: Applies the best corrections to each token and returns the cleaned text. Requires MDDB_SPELL=true.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [text, lang]
              properties:
                collection:
                  type: string
                text:
                  type: string
                lang:
                  type: string
      responses:
        "200":
          description: Cleaned text
          content:
            application/json:
              schema:
                type: object
                properties:
                  original:
                    type: string
                  cleaned:
                    type: string
                  correctionsApplied:
                    type: integer
        "503":
          description: Spell index still loading — retry

  /v1/spell-dictionary:
    get:
      tags: [Spell Correction]
      summary: List custom dictionary words
      description: Returns words in the custom dictionary for the given collection and language.
      parameters:
        - in: query
          name: collection
          schema:
            type: string
        - in: query
          name: lang
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Dictionary words
          content:
            application/json:
              schema:
                type: object
                properties:
                  collection:
                    type: string
                  lang:
                    type: string
                  words:
                    type: array
                    items:
                      type: string
    put:
      tags: [Spell Correction]
      summary: Add words to custom dictionary
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [lang, words]
              properties:
                collection:
                  type: string
                lang:
                  type: string
                words:
                  type: array
                  items:
                    type: string
                frequency:
                  type: integer
                  default: 100
                  description: Boost frequency for added words
      responses:
        "200":
          description: Words added
          content:
            application/json:
              schema:
                type: object
                properties:
                  added:
                    type: integer
    delete:
      tags: [Spell Correction]
      summary: Remove words from custom dictionary
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [lang, words]
              properties:
                collection:
                  type: string
                lang:
                  type: string
                words:
                  type: array
                  items:
                    type: string
      responses:
        "200":
          description: Words removed
          content:
            application/json:
              schema:
                type: object
                properties:
                  removed:
                    type: integer

components:
  schemas:
    WikiImportResponse:
      type: object
      properties:
        imported:
          type: integer
          description: Number of pages successfully imported
        skipped:
          type: integer
          description: Number of pages skipped (wrong namespace, redirects, empty)
        failed:
          type: integer
          description: Number of pages that failed to import
        errors:
          type: array
          items:
            type: string
          description: Error messages (capped at 10)
        collection:
          type: string
          description: Target collection name
        durationMs:
          type: integer
          format: int64
          description: Total import duration in milliseconds
    TemporalEvent:
      type: object
      properties:
        docId:
          type: string
        collection:
          type: string
        eventType:
          type: string
          enum: [create, update, access]
        timestamp:
          type: integer
          format: int64
    Document:
      type: object
      properties:
        id:
          type: string
          description: Auto-generated document ID
          example: doc|blog|hello-world|en_US
        key:
          type: string
          description: Document key (unique within collection and language)
          example: hello-world
        lang:
          type: string
          description: Language code (e.g., en_US, pl_PL, de_DE)
          example: en_US
        meta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata key-value pairs (values are arrays)
          example:
            category: [blog, tutorial]
            author: [John Doe]
            tags: [markdown, database]
        contentMd:
          type: string
          description: Markdown content
          example: "# Hello World\n\nWelcome to MDDB!"
        addedAt:
          type: integer
          format: int64
          description: Unix timestamp when document was created
          example: 1704844800
        updatedAt:
          type: integer
          format: int64
          description: Unix timestamp when document was last updated
          example: 1704931200

    AddRequest:
      type: object
      required:
        - collection
        - key
        - lang
        - contentMd
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        key:
          type: string
          description: Document key
          example: hello-world
        lang:
          type: string
          description: Language code
          example: en_US
        meta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata key-value pairs
          example:
            category: [blog]
            author: [John Doe]
        contentMd:
          type: string
          description: Markdown content
          example: "# Hello World\n\nWelcome to MDDB!"

    AddBatchRequest:
      type: object
      required:
        - collection
        - documents
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        documents:
          type: array
          items:
            $ref: "#/components/schemas/AddBatchDocument"
          description: Documents to add

    AddBatchDocument:
      type: object
      required:
        - key
        - lang
        - contentMd
      properties:
        key:
          type: string
          description: Document key
          example: post1
        lang:
          type: string
          description: Language code
          example: en
        contentMd:
          type: string
          description: Markdown content
          example: "# Hello World"
        meta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata key-value pairs
          example:
            category: [blog]
        saveRevision:
          type: boolean
          description: Whether to save a revision
          default: false

    AddBatchResponse:
      type: object
      properties:
        added:
          type: integer
          description: Number of documents added
          example: 2
        updated:
          type: integer
          description: Number of documents updated
          example: 0
        failed:
          type: integer
          description: Number of documents that failed
          example: 0
        errors:
          type: array
          items:
            type: string
          description: Error messages for failed documents

    IngestRequest:
      type: object
      required:
        - collection
        - documents
      properties:
        collection:
          type: string
          description: Collection name
          example: imported
        documents:
          type: array
          items:
            $ref: "#/components/schemas/IngestDocument"
          description: Documents to ingest
        options:
          $ref: "#/components/schemas/IngestOptions"

    IngestDocument:
      type: object
      required:
        - lang
        - contentMd
      properties:
        url:
          type: string
          format: uri
          description: Source URL (used for key derivation and auto-injected as source_url metadata)
          example: https://example.com/page1
        key:
          type: string
          description: Document key (derived from URL if empty)
          example: page1
        lang:
          type: string
          description: Language code
          example: en
        contentMd:
          type: string
          description: Markdown content
          example: "# Page 1\n\nContent here."
        meta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata key-value pairs
        extractFrontmatter:
          type: boolean
          description: Parse YAML frontmatter from content and merge into metadata
          default: false
        scrapedAt:
          type: integer
          format: int64
          description: Unix timestamp of when the content was scraped (auto-injected as scraped_at metadata)
          example: 1709500000
        scraper:
          type: string
          description: Scraper identifier (auto-injected as scraper metadata)
          example: my-crawler
        ttl:
          type: integer
          format: int64
          description: Time-to-live in seconds
          example: 86400

    IngestOptions:
      type: object
      properties:
        skipDuplicates:
          type: boolean
          description: Skip documents whose content hasn't changed (CRC32 hash comparison)
          default: false
        skipEmbeddings:
          type: boolean
          description: Skip embedding generation for this batch
          default: false
        skipFts:
          type: boolean
          description: Skip FTS indexing for this batch
          default: false
        skipWebhooks:
          type: boolean
          description: Skip webhook firing for this batch
          default: false
        autoConfigureCollection:
          type: boolean
          description: Auto-configure collection as "scraping" type if it doesn't exist
          default: false
        saveRevision:
          type: boolean
          description: Save revision history for all documents in this batch
          default: false

    IngestResponse:
      type: object
      properties:
        added:
          type: integer
          description: Number of documents added
          example: 2
        updated:
          type: integer
          description: Number of documents updated
          example: 0
        skipped:
          type: integer
          description: Number of documents skipped (deduplication)
          example: 0
        failed:
          type: integer
          description: Number of documents that failed
          example: 0
        errors:
          type: array
          items:
            type: string
          description: Error messages for failed documents
        collection:
          type: string
          description: Collection name
          example: imported
        durationMs:
          type: integer
          format: int64
          description: Total processing time in milliseconds
          example: 45

    GetRequest:
      type: object
      required:
        - collection
        - key
        - lang
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        key:
          type: string
          description: Document key
          example: hello-world
        lang:
          type: string
          description: Language code
          example: en_US
        env:
          type: object
          additionalProperties:
            type: string
          description: Template variables for substitution
          example:
            siteName: My Blog
            year: "2025"

    SearchRequest:
      type: object
      required:
        - collection
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        filterMeta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata filters (AND between keys, OR between values)
          example:
            category: [blog, tutorial]
            status: [published]
        sort:
          type: string
          enum: [addedAt, updatedAt, key]
          description: Sort field
          example: updatedAt
        asc:
          type: boolean
          description: Sort ascending (default false)
          example: false
        limit:
          type: integer
          description: Maximum number of results
          example: 10
        offset:
          type: integer
          description: Number of results to skip
          example: 0

    DeleteRequest:
      type: object
      required:
        - collection
        - key
        - lang
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        key:
          type: string
          description: Document key
          example: hello-world
        lang:
          type: string
          description: Language code
          example: en_US

    DeleteCollectionRequest:
      type: object
      required:
        - collection
      properties:
        collection:
          type: string
          description: Collection name to delete
          example: blog

    ExportRequest:
      type: object
      required:
        - collection
        - format
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        filterMeta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Optional metadata filters
          example:
            status: [published]
        format:
          type: string
          enum: [ndjson, zip]
          description: Export format
          example: ndjson

    TruncateRequest:
      type: object
      required:
        - collection
        - keepRevs
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        keepRevs:
          type: integer
          description: Number of revisions to keep per document (0 = delete all history)
          example: 3
        dropCache:
          type: boolean
          description: Clear document cache after truncation
          example: true

    Stats:
      type: object
      properties:
        databasePath:
          type: string
          example: /data/mddb.db
        databaseSize:
          type: integer
          format: int64
          description: Database file size in bytes
          example: 10485760
        mode:
          type: string
          enum: [read, write, wr]
          example: wr
        collections:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                example: blog
              documentCount:
                type: integer
                example: 42
              revisionCount:
                type: integer
                example: 156
              metaIndexCount:
                type: integer
                example: 84
              checksum:
                type: string
                description: 8-character hex CRC32 checksum of the collection
                example: a1b2c3d4
        totalDocuments:
          type: integer
          example: 42
        totalRevisions:
          type: integer
          example: 156
        totalMetaIndices:
          type: integer
          example: 84
        uptime:
          type: string
          example: 2h15m30s

    VectorSearchRequest:
      type: object
      required:
        - collection
      properties:
        collection:
          type: string
          description: Collection name to search
          example: blog
        query:
          type: string
          description: Natural language query string (required if queryVector is not provided)
          example: How to set up a CI/CD pipeline?
        queryVector:
          type: array
          items:
            type: number
            format: float
          description: Raw embedding vector (optional, use instead of query for pre-computed embeddings)
        topK:
          type: integer
          description: Number of top results to return (default 5)
          default: 5
          example: 5
        threshold:
          type: number
          format: float
          description: Minimum cosine similarity score (0.0 to 1.0)
          minimum: 0
          maximum: 1
          example: 0.7
        filterMeta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata filters to narrow results before ranking
          example:
            category: [devops, tutorial]
        includeContent:
          type: boolean
          description: Whether to include document content in results (default false)
          default: false
          example: false
        algorithm:
          type: string
          enum: [flat, hnsw, ivf, pq, opq, sq, bq]
          description: |
            Search algorithm to use (default "flat").
            - **flat**: Exact brute-force cosine similarity (most accurate, slower for large datasets)
            - **hnsw**: Hierarchical Navigable Small World graph (fast approximate, best general-purpose)
            - **ivf**: Inverted File Index with k-means clustering (good for large datasets)
            - **pq**: Product Quantization (compressed, lowest memory, slightly less accurate)
          default: flat
          example: flat
        distanceMetric:
          type: string
          enum: [cosine, dot_product, euclidean]
          description: Distance metric for similarity computation
          default: cosine
          example: cosine

    VectorSearchResponse:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: "#/components/schemas/VectorSearchResultItem"
        total:
          type: integer
          description: Number of results returned
          example: 5
        model:
          type: string
          description: Embedding model used
          example: text-embedding-3-small
        dimensions:
          type: integer
          description: Embedding vector dimensions
          example: 1536
        algorithm:
          type: string
          description: Algorithm used for this search
          example: flat
        distanceMetric:
          type: string
          description: Distance metric used for this search
          example: cosine
        searchStats:
          $ref: "#/components/schemas/SearchStats"

    VectorSearchResultItem:
      type: object
      properties:
        document:
          $ref: "#/components/schemas/Document"
        score:
          type: number
          format: float
          description: Cosine similarity score (0.0 to 1.0)
          example: 0.92
        rank:
          type: integer
          description: Result rank (1-based)
          example: 1

    VectorReindexRequest:
      type: object
      required:
        - collection
      properties:
        collection:
          type: string
          description: Collection name to reindex
          example: blog
        force:
          type: boolean
          description: If true, re-embed even if content is unchanged
          default: false
          example: false

    VectorReindexResponse:
      type: object
      properties:
        embedded:
          type: integer
          description: Number of documents embedded
          example: 42
        skipped:
          type: integer
          description: Number of documents skipped (content unchanged)
          example: 10
        failed:
          type: integer
          description: Number of documents that failed to embed
          example: 0
        totalChunks:
          type: integer
          description: Total number of chunks embedded across all documents
          example: 128
        errors:
          type: array
          items:
            type: string
          description: Error messages for failed embeddings

    VectorStatsResponse:
      type: object
      properties:
        enabled:
          type: boolean
          description: Whether vector search is enabled
          example: true
        provider:
          type: string
          description: Embedding provider name
          example: text-embedding-3-small
        model:
          type: string
          description: Embedding model name
          example: text-embedding-3-small
        dimensions:
          type: integer
          description: Embedding vector dimensions
          example: 1536
        index_ready:
          type: boolean
          description: Whether the vector index is loaded and ready
          example: true
        collections:
          type: object
          additionalProperties:
            type: object
            properties:
              total_documents:
                type: integer
                description: Total documents in collection
                example: 100
              embedded_documents:
                type: integer
                description: Documents with embeddings
                example: 95
              total_chunks:
                type: integer
                description: Total embedding chunks (including multi-chunk documents)
                example: 280
          description: Per-collection embedding statistics
          example:
            blog:
              total_documents: 100
              embedded_documents: 95
              total_chunks: 280
        chunking:
          type: object
          properties:
            enabled:
              type: boolean
              description: Whether document chunking is enabled
              example: true
            chunkSize:
              type: integer
              description: Maximum characters per chunk
              example: 1500
          description: Chunking configuration

    FTSSearchRequest:
      type: object
      required:
        - collection
        - query
      properties:
        collection:
          type: string
          description: Collection name to search
          example: blog
        query:
          type: string
          description: Full-text search query string
          example: cancel subscription
        limit:
          type: integer
          description: Maximum number of results (default 50)
          default: 50
          example: 50
        algorithm:
          type: string
          enum: [tfidf, bm25, bm25f, pmisparse]
          description: |
            Scoring algorithm to use (default "tfidf").
            - **tfidf**: Classic TF-IDF scoring
            - **bm25**: Okapi BM25 with document length normalization (k1=1.2, b=0.75)
            - **bm25f**: BM25F field-weighted scoring — applies different weights to title, metadata, and content
            - **pmisparse**: PMISparse — BM25 + PMI query expansion (invented by Tradik Limited)
          default: tfidf
          example: bm25
        fuzzy:
          type: integer
          enum: [0, 1, 2]
          description: |
            Typo tolerance level (default 0).
            - **0**: Off — exact term matching only
            - **1**: Low — matches terms within 1 edit distance (e.g. "javascrip" → "javascript")
            - **2**: Medium — matches terms within 2 edit distances
          default: 0
          example: 0
        filterMeta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata filters to narrow results before scoring (AND between keys, OR between values)
          example:
            category: [tutorial]
        fieldWeights:
          type: object
          additionalProperties:
            type: number
          description: Field weights for BM25F algorithm (keys are "title", "meta", "content")
          example:
            title: 3.0
            meta: 2.0
            content: 1.0
        disableStem:
          type: boolean
          description: Disable stemming for this query
          default: false
        disableSynonyms:
          type: boolean
          description: Disable synonym expansion for this query
          default: false
        mode:
          type: string
          enum: [auto, simple, boolean, phrase, wildcard, proximity]
          description: |
            Search mode (default "auto"). Auto-detect parses the query to determine the appropriate mode.
            - **auto**: Auto-detect from query syntax
            - **simple**: Classic keyword search
            - **boolean**: AND/OR/NOT operators, +required, -excluded
            - **phrase**: Exact word sequence (`"quoted phrases"`)
            - **wildcard**: Pattern matching (`*` any chars, `?` single char)
            - **proximity**: Terms within N words (`"term1 term2"~5`)
          default: auto
          example: auto
        distance:
          type: integer
          description: Maximum word distance for proximity search (default 5)
          default: 5
          example: 5
        lang:
          type: string
          description: |
            Language code for query tokenization (e.g., "en", "pl", "de"). Uses language-specific stemmer and stop words.
            Language codes are normalized: "en_US" → "en", "pl_PL" → "pl". Falls back to server default if omitted.
          example: en
        rangeMeta:
          type: array
          description: Range filters on metadata or timestamp fields
          items:
            $ref: "#/components/schemas/RangeFilter"

    RangeFilter:
      type: object
      properties:
        field:
          type: string
          description: Field name — metadata key, or built-in "addedAt" / "updatedAt"
          example: price
        gte:
          type: string
          description: Greater than or equal (numeric, date string, or unix timestamp)
          example: "10"
        lte:
          type: string
          description: Less than or equal
          example: "100"
        gt:
          type: string
          description: Greater than
        lt:
          type: string
          description: Less than

    FTSSearchResponse:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: "#/components/schemas/FTSResultItem"
        total:
          type: integer
          description: Number of results returned
          example: 3
        algorithm:
          type: string
          description: Algorithm used for this search
          example: tfidf
        mode:
          type: string
          description: Search mode used (simple, boolean, phrase, wildcard, proximity)
          example: simple
        lang:
          type: string
          description: Language used for query tokenization
          example: en
        fuzzy:
          type: integer
          description: Typo tolerance level used
          example: 0
        searchStats:
          $ref: "#/components/schemas/SearchStats"

    FTSResultItem:
      type: object
      properties:
        document:
          $ref: "#/components/schemas/Document"
        score:
          type: number
          format: float
          description: TF-IDF relevance score
          example: 2.45
        matchedTerms:
          type: array
          items:
            type: string
          description: Terms from the query that matched
          example: [cancel, subscription]

    ImportURLRequest:
      type: object
      required:
        - collection
        - url
        - lang
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        url:
          type: string
          format: uri
          description: URL to fetch content from
          example: https://example.com/post.md
        key:
          type: string
          description: Document key (derived from URL if empty)
          example: my-post
        lang:
          type: string
          description: Language code
          example: en_US
        meta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Additional metadata to merge with frontmatter
          example:
            source: [imported]
        ttl:
          type: integer
          description: Time-to-live in seconds (0 = no expiration)
          example: 3600

    SetTTLRequest:
      type: object
      required:
        - collection
        - key
        - lang
        - ttl
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        key:
          type: string
          description: Document key
          example: hello-world
        lang:
          type: string
          description: Language code
          example: en_US
        ttl:
          type: integer
          description: Time-to-live in seconds (0 = remove TTL)
          example: 3600

    Webhook:
      type: object
      properties:
        id:
          type: string
          description: Unique webhook ID
          example: abc123
        url:
          type: string
          format: uri
          description: Webhook callback URL
          example: https://example.com/hook
        events:
          type: array
          items:
            type: string
            enum: [doc.added, doc.updated, doc.deleted]
          description: Event types to listen for
          example: [doc.added, doc.updated]
        collection:
          type: string
          description: Collection filter (empty = all collections)
          example: blog
        createdAt:
          type: integer
          format: int64
          description: Unix timestamp when the webhook was created
          example: 1704844800

    RegisterWebhookRequest:
      type: object
      required:
        - url
        - events
      properties:
        url:
          type: string
          format: uri
          description: Webhook callback URL
          example: https://example.com/hook
        events:
          type: array
          items:
            type: string
            enum: [doc.added, doc.updated, doc.deleted]
          description: Event types to listen for
          example: [doc.added, doc.updated]
        collection:
          type: string
          description: Collection filter (empty = all collections)
          example: blog

    DeleteWebhookRequest:
      type: object
      required:
        - id
      properties:
        id:
          type: string
          description: Webhook ID to delete
          example: abc123

    SetSchemaRequest:
      type: object
      required:
        - collection
        - schema
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        schema:
          type: string
          description: JSON Schema string for metadata validation
          example: '{"type":"object","required":["author"],"properties":{"author":{"type":"array","items":{"type":"string"}}}}'

    SchemaResponse:
      type: object
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        schema:
          type: string
          description: JSON Schema string
          example: '{"type":"object","required":["author"]}'
        enabled:
          type: boolean
          description: Whether schema validation is enabled for this collection
          example: true

    ValidateRequest:
      type: object
      required:
        - collection
        - meta
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        meta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata to validate against the collection schema
          example:
            category: [blog]
            author: [John Doe]

    ValidateResponse:
      type: object
      properties:
        valid:
          type: boolean
          description: Whether the metadata is valid according to the schema
          example: true
        errors:
          type: array
          items:
            type: string
          description: Validation error messages (empty if valid)
          example: []

    ReplicationStatusResponse:
      type: object
      properties:
        node_id:
          type: string
          description: Unique node identifier
          example: leader-1
        role:
          type: string
          enum: [standalone, leader, follower]
          description: Replication role of this node
          example: leader
        current_lsn:
          type: integer
          format: uint64
          description: Current Log Sequence Number
          example: 45230
        binlog_oldest_lsn:
          type: integer
          format: uint64
          description: Oldest LSN still in the binlog (leader only)
          example: 40000
        binlog_size_bytes:
          type: integer
          format: int64
          description: Binlog file size in bytes (leader only)
          example: 15728640
        leader_addr:
          type: string
          description: Address of the leader node (follower only)
          example: leader:11024
        replication_lag_ms:
          type: integer
          format: int64
          description: Replication lag in milliseconds (follower only)
          example: 12
        healthy:
          type: boolean
          description: Whether this node is healthy
          example: true
        followers:
          type: array
          items:
            $ref: "#/components/schemas/FollowerInfo"
          description: Connected followers (leader only)
        uptime_seconds:
          type: integer
          format: int64
          description: Node uptime in seconds
          example: 86400

    FollowerInfo:
      type: object
      properties:
        follower_id:
          type: string
          description: Follower node identifier
          example: follower-1
        address:
          type: string
          description: Follower network address
          example: "10.0.0.2:11034"
        confirmed_lsn:
          type: integer
          format: uint64
          description: Last LSN confirmed by this follower
          example: 45228
        lag_ms:
          type: integer
          format: int64
          description: Estimated replication lag in milliseconds
          example: 12
        last_seen_at:
          type: integer
          format: int64
          description: Unix timestamp of last communication
          example: 1709500000
        status:
          type: string
          enum: [healthy, warning, unhealthy]
          description: "Follower health status (healthy: <1s lag, warning: 1-30s, unhealthy: >30s)"
          example: healthy

    HybridSearchRequest:
      type: object
      required:
        - collection
        - query
      properties:
        collection:
          type: string
          description: Collection name to search
          example: blog
        query:
          type: string
          description: Search query string (used for both FTS and embedding)
          example: how to deploy with Docker
        topK:
          type: integer
          description: Number of top results to return (default 10)
          default: 10
          example: 10
        algorithm:
          type: string
          enum: [bm25, bm25f]
          description: FTS algorithm (default "bm25")
          default: bm25
          example: bm25
        vectorAlgorithm:
          type: string
          enum: [flat, hnsw, ivf, pq, opq, sq, bq]
          description: Vector search algorithm (default "flat")
          default: flat
          example: flat
        strategy:
          type: string
          enum: [alpha, rrf]
          description: |
            Fusion strategy (default "alpha").
            - **alpha**: Weighted blending — `combined = (1-alpha) * normalizedFTS + alpha * vectorScore`
            - **rrf**: Reciprocal Rank Fusion — `score = 1/(k + rank_fts) + 1/(k + rank_vector)`
          default: alpha
          example: alpha
        alpha:
          type: number
          format: float
          description: Alpha blending weight (0=keyword only, 1=semantic only, default 0.5). Only used with "alpha" strategy.
          minimum: 0
          maximum: 1
          default: 0.5
          example: 0.5
        rrfK:
          type: integer
          description: RRF parameter k (default 60). Only used with "rrf" strategy.
          default: 60
          example: 60
        fuzzy:
          type: integer
          enum: [0, 1, 2]
          description: Typo tolerance for FTS (0=off, 1=1 edit, 2=2 edits)
          default: 0
          example: 0
        threshold:
          type: number
          format: float
          description: Minimum vector similarity score (0.0 to 1.0)
          minimum: 0
          maximum: 1
          example: 0.0
        filterMeta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata filters applied to both FTS and vector results
          example:
            category: [tutorial]
        includeContent:
          type: boolean
          description: Include document content in results
          default: false
        fieldWeights:
          type: object
          additionalProperties:
            type: number
          description: Field weights for BM25F (keys are "title", "meta", "content")
          example:
            title: 3.0
            meta: 2.0
            content: 1.0
        disableStem:
          type: boolean
          description: Disable stemming for FTS
          default: false
        disableSynonyms:
          type: boolean
          description: Disable synonym expansion for FTS
          default: false
        distanceMetric:
          type: string
          enum: [cosine, dot_product, euclidean]
          description: Distance metric for similarity computation
          default: cosine
          example: cosine

    HybridSearchResponse:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: "#/components/schemas/HybridSearchResultItem"
        total:
          type: integer
          description: Number of results returned
          example: 5
        strategy:
          type: string
          description: Fusion strategy used
          example: alpha
        alpha:
          type: number
          description: Alpha value used (only for alpha strategy)
          example: 0.5
        rrfK:
          type: integer
          description: RRF k value used (only for rrf strategy)
          example: 60
        ftsAlgorithm:
          type: string
          description: FTS algorithm used
          example: bm25
        vectorAlgorithm:
          type: string
          description: Vector algorithm used
          example: flat
        distanceMetric:
          type: string
          description: Distance metric used for this search
          example: cosine
        searchStats:
          $ref: "#/components/schemas/SearchStats"

    HybridSearchResultItem:
      type: object
      properties:
        document:
          $ref: "#/components/schemas/Document"
        combinedScore:
          type: number
          format: float
          description: Fused score from both FTS and vector
          example: 0.78
        ftsScore:
          type: number
          format: float
          description: Normalized FTS score component
          example: 0.65
        vectorScore:
          type: number
          format: float
          description: Vector similarity score component
          example: 0.91
        matchedTerms:
          type: array
          items:
            type: string
          description: FTS matched terms
          example: [deploy, docker]
        rank:
          type: integer
          description: Result rank (1-based)
          example: 1

    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: Error message
          example: document not found

    UploadResponse:
      type: object
      properties:
        key:
          type: string
          description: Document key
        format:
          type: string
          description: Detected file format (md, txt, html, pdf, docx, odt, rtf, yaml, tex, log, lex)
        converted:
          type: boolean
          description: Whether the file was converted to markdown
        document:
          $ref: "#/components/schemas/Document"

    UploadBatchResponse:
      type: object
      properties:
        added:
          type: integer
        updated:
          type: integer
        failed:
          type: integer
        errors:
          type: array
          items:
            type: string
        results:
          type: array
          items:
            $ref: "#/components/schemas/UploadResponse"

    SynonymRequest:
      type: object
      required:
        - collection
        - term
        - synonyms
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        term:
          type: string
          description: Base term for the synonym group
          example: big
        synonyms:
          type: array
          items:
            type: string
          description: List of synonyms for the term
          example: [large, huge, enormous]

    SynonymDeleteRequest:
      type: object
      required:
        - collection
        - term
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        term:
          type: string
          description: Term whose synonyms to delete
          example: big

    SynonymEntry:
      type: object
      properties:
        term:
          type: string
          description: Base term
          example: big
        synonyms:
          type: array
          items:
            type: string
          description: List of synonyms
          example: [large, huge, enormous]

    SynonymListResponse:
      type: object
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        entries:
          type: array
          items:
            $ref: "#/components/schemas/SynonymEntry"
        total:
          type: integer
          description: Total number of synonym entries
          example: 10

    EmbeddingConfig:
      type: object
      required:
        - id
        - name
        - provider
        - model
        - dimensions
      properties:
        id:
          type: string
          description: Unique identifier
          example: openai-small
        name:
          type: string
          description: Display name
          example: OpenAI Small
        provider:
          type: string
          enum: [openai, ollama, cohere, voyage]
          description: Embedding provider
          example: openai
        model:
          type: string
          description: Model name
          example: text-embedding-3-small
        dimensions:
          type: integer
          description: Embedding vector dimensions
          example: 1536
        apiKey:
          type: string
          description: API key (for OpenAI, Cohere, Voyage)
          example: sk-...
        apiUrl:
          type: string
          description: API URL (for Ollama or custom endpoints)
          example: http://localhost:11434
        isDefault:
          type: boolean
          description: Whether this is the default configuration
          example: false
        createdAt:
          type: integer
          format: int64
          description: Creation timestamp (Unix seconds)
          example: 1704844800

    SystemInfoResponse:
      type: object
      properties:
        hostname:
          type: string
          description: Server hostname
          example: mddb-server
        os:
          type: string
          description: Operating system
          example: linux
        arch:
          type: string
          description: CPU architecture
          example: amd64
        numCPU:
          type: integer
          description: Number of logical CPUs
          example: 8
        goVersion:
          type: string
          description: Go runtime version
          example: go1.26.2
        version:
          type: string
          description: MDDB server version
          example: 2.9.11
        uptimeSeconds:
          type: integer
          format: int64
          description: Server uptime in seconds
          example: 86400
        memoryTotal:
          type: integer
          format: uint64
          description: Total allocated memory in bytes (cumulative)
          example: 104857600
        memoryUsed:
          type: integer
          format: uint64
          description: Currently allocated memory in bytes
          example: 52428800
        memorySystem:
          type: integer
          format: uint64
          description: System memory obtained from OS in bytes
          example: 73400320
        memoryHeap:
          type: integer
          format: uint64
          description: Heap memory in use in bytes
          example: 41943040
        numGoroutines:
          type: integer
          description: Number of active goroutines
          example: 42
        cpuUsagePercent:
          type: number
          format: float
          description: CPU usage percentage (0-100)
          example: 12.5
        network:
          type: array
          items:
            $ref: "#/components/schemas/NetworkInterface"

    NetworkInterface:
      type: object
      properties:
        name:
          type: string
          description: Interface name
          example: eth0
        addresses:
          type: array
          items:
            type: string
          description: IP addresses assigned to this interface
          example: ["192.168.1.10/24", "fe80::1/64"]
        flags:
          type: string
          description: Interface flags
          example: up|broadcast|multicast

    ConfigResponse:
      type: object
      properties:
        version:
          type: string
          description: MDDB server version
          example: 2.9.11
        databasePath:
          type: string
          description: Path to the database file
          example: /data/mddb.db
        mode:
          type: string
          description: Server mode
          example: wr
        panelMode:
          type: string
          description: Panel mode (internal or external)
          example: internal
        protocols:
          type: object
          properties:
            http:
              type: object
              properties:
                enabled:
                  type: boolean
                  example: true
                addr:
                  type: string
                  example: ":11023"
            grpc:
              type: object
              properties:
                enabled:
                  type: boolean
                  example: true
                addr:
                  type: string
                  example: ":11024"
            mcp:
              type: object
              properties:
                enabled:
                  type: boolean
                  example: false
                addr:
                  type: string
                  example: ""
                stdio:
                  type: boolean
                  example: false
            http3:
              type: object
              properties:
                enabled:
                  type: boolean
                  example: false
                addr:
                  type: string
                  example: ""
        authEnabled:
          type: boolean
          description: Whether authentication is enabled
          example: false
        metricsEnabled:
          type: boolean
          description: Whether Prometheus metrics are enabled
          example: true
        searchStatsEnabled:
          type: boolean
          description: Whether search statistics are included in search responses
          example: false
        replicationRole:
          type: string
          description: Replication role of this node
          example: standalone
        vectorConfig:
          type: object
          description: Vector search configuration (if enabled)
          properties:
            enabled:
              type: boolean
              example: true
            provider:
              type: string
              example: openai
            model:
              type: string
              example: text-embedding-3-small
            dimensions:
              type: integer
              example: 1536
            apiUrl:
              type: string
              example: https://api.openai.com/v1
        chunkConfig:
          type: object
          description: Document chunking configuration
          properties:
            enabled:
              type: boolean
              example: true
            chunkSize:
              type: integer
              example: 1500

    EndpointsResponse:
      type: object
      properties:
        http:
          type: array
          items:
            type: object
            properties:
              method:
                type: string
                description: HTTP method(s)
                example: POST
              path:
                type: string
                description: URL path
                example: /v1/add
              description:
                type: string
                description: Endpoint description
                example: Add/update document
              requiresAuth:
                type: boolean
                description: Whether authentication is required
                example: true
        grpc:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                description: gRPC method name
                example: Add
              description:
                type: string
                description: Method description
                example: Add/update document
        mcp:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                description: MCP tool name
                example: add_document
              description:
                type: string
                description: Tool description
                example: Add/update document
              inputSchema:
                type: object
                description: JSON Schema for the tool input

    LoginRequest:
      type: object
      required:
        - username
        - password
      properties:
        username:
          type: string
          description: Username
          example: admin
        password:
          type: string
          description: Password
          example: secret

    LoginResponse:
      type: object
      properties:
        token:
          type: string
          description: JWT token
          example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
        expiresAt:
          type: integer
          format: int64
          description: Token expiration timestamp (Unix seconds)
          example: 1704931200

    RegisterRequest:
      type: object
      required:
        - username
        - password
      properties:
        username:
          type: string
          description: Username for the new user
          example: alice
        password:
          type: string
          description: Password for the new user
          example: securepassword123

    RegisterResponse:
      type: object
      properties:
        username:
          type: string
          description: Created username
          example: alice
        createdAt:
          type: integer
          format: int64
          description: Account creation timestamp (Unix seconds)
          example: 1704844800

    CreateAPIKeyRequest:
      type: object
      properties:
        description:
          type: string
          description: Optional label for the API key
          example: CI/CD pipeline key
        expiresAt:
          type: integer
          format: int64
          description: Expiration timestamp (Unix seconds, 0 = never)
          example: 0

    CreateAPIKeyResponse:
      type: object
      properties:
        key:
          type: string
          description: The API key value (shown only once)
          example: mddb_live_a1b2c3d4e5f6...
        description:
          type: string
          description: API key description
          example: CI/CD pipeline key
        expiresAt:
          type: integer
          format: int64
          description: Expiration timestamp (Unix seconds, 0 = never)
          example: 0
        createdAt:
          type: integer
          format: int64
          description: Creation timestamp (Unix seconds)
          example: 1704844800

    ListAPIKeysResponse:
      type: object
      properties:
        keys:
          type: array
          items:
            type: object
            properties:
              keyHash:
                type: string
                description: SHA256 hash of the API key (for deletion)
                example: a1b2c3d4e5f6...
              description:
                type: string
                description: API key description
                example: CI/CD pipeline key
              createdAt:
                type: integer
                format: int64
                description: Creation timestamp (Unix seconds)
                example: 1704844800
              expiresAt:
                type: integer
                format: int64
                description: Expiration timestamp (Unix seconds, 0 = never)
                example: 0

    GetMeResponse:
      type: object
      properties:
        username:
          type: string
          description: Current user's username
          example: admin
        admin:
          type: boolean
          description: Whether the user has admin privileges
          example: true
        createdAt:
          type: integer
          format: int64
          description: Account creation timestamp (Unix seconds)
          example: 1704844800

    Permission:
      type: object
      properties:
        username:
          type: string
          description: Username
          example: alice
        collection:
          type: string
          description: Collection name ("*" for all collections)
          example: blog
        read:
          type: boolean
          description: Read permission
          example: true
        write:
          type: boolean
          description: Write permission
          example: true
        admin:
          type: boolean
          description: Admin permission
          example: false

    SetPermissionRequest:
      type: object
      required:
        - username
        - collection
      properties:
        username:
          type: string
          description: Username
          example: alice
        collection:
          type: string
          description: Collection name ("*" for all collections)
          example: blog
        read:
          type: boolean
          description: Read permission
          example: true
        write:
          type: boolean
          description: Write permission
          example: true
        admin:
          type: boolean
          description: Admin permission
          example: false

    SetPermissionResponse:
      type: object
      properties:
        status:
          type: string
          example: ok

    UsersListResponse:
      type: object
      properties:
        users:
          type: array
          items:
            type: object
            properties:
              username:
                type: string
                description: Username
                example: alice
              createdAt:
                type: integer
                format: int64
                description: Account creation timestamp (Unix seconds)
                example: 1704844800
              disabled:
                type: boolean
                description: Whether the user is disabled
                example: false
              admin:
                type: boolean
                description: Whether the user has admin privileges
                example: false
              groups:
                type: array
                items:
                  type: string
                description: Groups the user belongs to
                example: [developers, editors]

    Group:
      type: object
      properties:
        name:
          type: string
          description: Group name
          example: developers
        description:
          type: string
          description: Group description
          example: Development team
        members:
          type: array
          items:
            type: string
          description: List of usernames in the group
          example: [alice, bob]
        createdAt:
          type: integer
          format: int64
          description: Creation timestamp (Unix seconds)
          example: 1704844800

    CreateGroupRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          description: Group name
          example: developers
        description:
          type: string
          description: Group description
          example: Development team
        members:
          type: array
          items:
            type: string
          description: Initial list of member usernames
          example: [alice, bob]

    UpdateGroupRequest:
      type: object
      properties:
        description:
          type: string
          description: Updated group description
          example: Development team (updated)
        members:
          type: array
          items:
            type: string
          description: Updated list of member usernames
          example: [alice, bob, charlie]

    GroupsListResponse:
      type: object
      properties:
        groups:
          type: array
          items:
            $ref: "#/components/schemas/Group"

    GroupPermission:
      type: object
      required:
        - groupName
        - collection
      properties:
        groupName:
          type: string
          description: Group name
          example: developers
        collection:
          type: string
          description: Collection name ("*" for all collections)
          example: blog
        read:
          type: boolean
          description: Read permission
          example: true
        write:
          type: boolean
          description: Write permission
          example: true
        admin:
          type: boolean
          description: Admin permission
          example: false

    AutomationRule:
      type: object
      required: [type, name]
      properties:
        id:
          type: string
          readOnly: true
        type:
          type: string
          enum: [webhook, trigger, cron]
        name:
          type: string
        enabled:
          type: boolean
          default: true
        createdAt:
          type: integer
          readOnly: true
        updatedAt:
          type: integer
          readOnly: true
        url:
          type: string
          description: Webhook URL (type=webhook)
        method:
          type: string
          enum: [POST, GET, PUT]
          default: POST
          description: HTTP method (type=webhook)
        headers:
          type: object
          additionalProperties:
            type: string
          description: Custom HTTP headers (type=webhook)
        collection:
          type: string
          description: Target collection (type=trigger)
        searchType:
          type: string
          enum: [fts, vector, hybrid]
          description: Search type (type=trigger)
        query:
          type: string
          description: Search query (type=trigger)
        threshold:
          type: number
          minimum: 0
          maximum: 100
          description: Minimum score threshold 0-100 (type=trigger)
        webhookId:
          type: string
          description: Target webhook ID (type=trigger, type=cron)
        searchParams:
          type: object
          description: Extra search parameters (type=trigger)
        events:
          type: array
          items:
            type: string
            enum: [insert, update, delete]
          description: Events that fire the trigger (type=trigger, default ["insert","update"])
        sentimentEnabled:
          type: boolean
          description: Enable keyword-based sentiment condition (type=trigger)
        sentimentMin:
          type: number
          minimum: -1.0
          maximum: 1.0
          description: Minimum sentiment score -1.0 to 1.0 (type=trigger)
        sentimentMax:
          type: number
          minimum: -1.0
          maximum: 1.0
          description: Maximum sentiment score -1.0 to 1.0 (type=trigger)
        conditionLogic:
          type: string
          enum: [and, or]
          default: and
          description: How to combine search + sentiment conditions (type=trigger)
        schedule:
          type: string
          description: Cron expression e.g. "0 9 * * *" (type=cron)
        triggerId:
          type: string
          description: Target trigger ID (type=cron)
        lastRun:
          type: integer
          readOnly: true
          description: Last execution timestamp (type=cron)
        nextRun:
          type: integer
          readOnly: true
          description: Next scheduled execution (type=cron)

    TriggerMatch:
      type: object
      properties:
        docId:
          type: string
        collection:
          type: string
        score:
          type: number

    AutomationLogEntry:
      type: object
      properties:
        id:
          type: string
        timestamp:
          type: integer
        ruleId:
          type: string
        ruleName:
          type: string
        ruleType:
          type: string
          enum: [trigger, cron]
        webhookId:
          type: string
        webhookUrl:
          type: string
        status:
          type: string
          enum: [success, error, skipped]
        httpStatus:
          type: integer
        durationMs:
          type: integer
        error:
          type: string
        attempt:
          type: integer

    SearchStats:
      type: object
      description: Statistics about a search execution
      properties:
        durationMs:
          type: integer
          description: Search execution time in milliseconds
          example: 12
        queryTerms:
          type: array
          items:
            type: string
          description: Tokenized query terms
          example: [cancel, subscription]
        indexSize:
          type: integer
          description: Documents in search scope
          example: 150
        totalTokens:
          type: integer
          description: Number of tokens in query
          example: 2

    RevisionEntry:
      type: object
      properties:
        timestamp:
          type: integer
          format: int64
          description: Unix timestamp of the revision
          example: 1704844800
        updatedAt:
          type: integer
          format: int64
          description: Unix timestamp when the revision was saved
          example: 1704844800
        contentMd:
          type: string
          description: Markdown content at this revision
          example: "# Hello World\n\nOriginal content."
        meta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata at this revision
          example:
            category: [blog]
            author: [John Doe]

    CollectionConfig:
      type: object
      properties:
        type:
          type: string
          description: Collection type (e.g., default, website, images, audio, documents)
          example: website
        description:
          type: string
          description: Collection description
          example: Blog posts and articles
        icon:
          type: string
          description: Collection icon (emoji or icon name)
          example: "\uD83C\uDF10"
        color:
          type: string
          description: Collection color (hex code)
          example: "#3B82F6"
        customMeta:
          type: object
          additionalProperties: true
          description: Custom key-value metadata for the collection
        storageBackend:
          type: string
          enum: [boltdb, memory, s3]
          description: "Storage backend for this collection (default: boltdb). Use 'memory' for ephemeral data or 's3' for S3-compatible object storage."
          example: boltdb
        storageConfig:
          $ref: "#/components/schemas/StorageConfigDef"
        quantization:
          type: string
          enum: [float32, int8, int4]
          description: "Vector quantization level. int8 = 4x compression, int4 = 8x compression. Default: float32."
          example: float32

    StorageConfigDef:
      type: object
      description: Backend-specific configuration for non-default storage backends (required when storageBackend is 's3').
      properties:
        endpoint:
          type: string
          description: S3-compatible endpoint URL
          example: s3.amazonaws.com
        bucket:
          type: string
          description: S3 bucket name
          example: my-mddb-bucket
        region:
          type: string
          description: AWS region
          example: us-east-1
        accessKey:
          type: string
          description: Access key for authentication
          example: AKIAIOSFODNN7EXAMPLE
        secretKey:
          type: string
          description: Secret key for authentication
          example: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
        prefix:
          type: string
          description: Key prefix within the bucket
          example: mddb/
        useTLS:
          type: boolean
          description: Use HTTPS for S3 connections
          example: true

    AggregateRequest:
      type: object
      required:
        - collection
      properties:
        collection:
          type: string
          description: Collection name
          example: blog
        filterMeta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Optional metadata pre-filter (AND over keys, OR over values)
        facets:
          type: array
          items:
            type: object
            required:
              - field
            properties:
              field:
                type: string
                description: Metadata key to aggregate
                example: category
              orderBy:
                type: string
                enum: [count, value]
                description: Sort order for facet buckets (default count descending)
                example: count
        histograms:
          type: array
          items:
            type: object
            required:
              - field
            properties:
              field:
                type: string
                description: Time field to histogram (addedAt or updatedAt)
                example: addedAt
              interval:
                type: string
                enum: [day, week, month, year]
                description: Histogram bucket interval (default month)
                example: month
        maxFacetSize:
          type: integer
          description: Maximum number of values per facet (default 50)
          example: 50

    AggregateResponse:
      type: object
      properties:
        collection:
          type: string
          example: blog
        totalDocs:
          type: integer
          description: Total documents matching the filter (or all docs if no filter)
          example: 42
        facets:
          type: object
          additionalProperties:
            type: array
            items:
              type: object
              properties:
                value:
                  type: string
                count:
                  type: integer
          description: Facet results keyed by metadata field name
        histograms:
          type: object
          additionalProperties:
            type: array
            items:
              type: object
              properties:
                key:
                  type: string
                  description: Formatted date label
                from:
                  type: integer
                  description: Unix timestamp start
                to:
                  type: integer
                  description: Unix timestamp end (exclusive)
                count:
                  type: integer
          description: Histogram results keyed by field name
        durationMs:
          type: integer
          description: Query execution time in milliseconds
          example: 3

    CrossSearchRequest:
      type: object
      properties:
        sourceCollection:
          type: string
          description: Collection containing the source document (for document-as-query)
          example: content
        sourceDocID:
          type: string
          description: ID of the source document whose embedding to use as query
          example: post-123
        query:
          type: string
          description: Text query (alternative to sourceCollection/sourceDocID)
          example: machine learning tutorial
        queryVector:
          type: array
          items:
            type: number
          description: Pre-computed query vector (alternative to query or source document)
        targetCollections:
          type: array
          items:
            type: string
          description: Collections to search in
          example: ["images", "audio"]
        topK:
          type: integer
          description: Number of results to return
          default: 10
          example: 10
        threshold:
          type: number
          description: Minimum similarity score
          default: 0.0
          example: 0.5
        algorithm:
          type: string
          description: Vector search algorithm
          enum: [flat, hnsw, ivf, pq, opq, sq, bq]
          default: flat
          example: flat
        distanceMetric:
          type: string
          description: Distance metric for similarity computation
          enum: [cosine, dot_product, euclidean]
          default: cosine
          example: cosine
        filterMeta:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Metadata filters applied to target documents
        includeContent:
          type: boolean
          description: Include document content in results
          default: false
          example: false

    CrossSearchResponse:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: "#/components/schemas/CrossSearchResultItem"
        total:
          type: integer
          description: Total number of results
          example: 5
        sourceCollection:
          type: string
          description: Source collection (if document-as-query was used)
          example: content
        sourceDocID:
          type: string
          description: Source document ID (if document-as-query was used)
          example: post-123
        targetCollections:
          type: array
          items:
            type: string
          description: Collections that were searched
          example: ["images", "audio"]
        algorithm:
          type: string
          description: Vector search algorithm used
          example: flat
        distanceMetric:
          type: string
          description: Distance metric used
          example: cosine
        searchStats:
          $ref: "#/components/schemas/SearchStats"

    CrossSearchResultItem:
      type: object
      properties:
        collection:
          type: string
          description: Collection the result came from
          example: images
        document:
          $ref: "#/components/schemas/Document"
        score:
          type: number
          format: float
          description: Similarity score
          example: 0.89
        rank:
          type: integer
          description: Result rank (1-based)
          example: 1

    FindDuplicatesRequest:
      type: object
      required:
        - collection
      properties:
        collection:
          type: string
          description: Collection to scan
        mode:
          type: string
          enum: [exact, similar, both]
          default: both
          description: "Detection mode: exact (content hash), similar (embedding similarity), or both"
        threshold:
          type: number
          minimum: 0
          maximum: 1
          default: 0.9
          description: Similarity threshold for similar mode
        maxDocs:
          type: integer
          default: 5000
          description: Maximum documents to process (safety bound)
        distanceMetric:
          type: string
          enum: [cosine, dot_product, euclidean]
          default: cosine
        includeContent:
          type: boolean
          default: false
    FindDuplicatesResponse:
      type: object
      properties:
        collection:
          type: string
        mode:
          type: string
        threshold:
          type: number
        distanceMetric:
          type: string
        totalDocuments:
          type: integer
        totalEmbedded:
          type: integer
        exactGroups:
          type: array
          items:
            $ref: "#/components/schemas/DuplicateGroup"
        similarGroups:
          type: array
          items:
            $ref: "#/components/schemas/DuplicateGroup"
        exactDuplicates:
          type: integer
        similarPairs:
          type: integer
        searchStats:
          $ref: "#/components/schemas/SearchStats"
    DuplicateGroup:
      type: object
      properties:
        groupId:
          type: integer
        type:
          type: string
          enum: [exact, similar]
        documents:
          type: array
          items:
            $ref: "#/components/schemas/DuplicateDocInfo"
        score:
          type: number
          description: Average similarity score for the group
    DuplicateDocInfo:
      type: object
      properties:
        docId:
          type: string
        key:
          type: string
        contentHash:
          type: string
        contentMd:
          type: string
        score:
          type: number
          description: Max similarity to another document in the group

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token obtained from POST /v1/auth/login
    APIKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key obtained from POST /v1/auth/api-key
