# Engine API (Delta) ## ADDED Requirements ### Requirement: Note mutation endpoint The engine SHALL provide a `PATCH /api/v1/notes/{id}` endpoint for updating existing notes in place. See the `note-mutation` spec for full details. #### Scenario: Note update endpoint exists - **WHEN** a client sends `PATCH /api/v1/notes/42` with body `{"text": "new content"}` - **THEN** the engine SHALL process the update synchronously and return the updated document --- ### Requirement: Document updated_at tracking The engine SHALL track when documents are modified via an `updated_at` column. This column SHALL be NULL for documents that have never been updated. #### Scenario: New document has no updated_at - **WHEN** a document is first ingested - **THEN** `updated_at` SHALL be NULL and `created_at` SHALL be set to the ingestion timestamp #### Scenario: Note update sets updated_at - **WHEN** a note is updated via `PATCH /api/v1/notes/{id}` - **THEN** `updated_at` SHALL be set to the current timestamp #### Scenario: Tag change sets updated_at - **WHEN** tags are modified via `PUT /api/v1/documents/{id}/tags` - **THEN** `updated_at` SHALL be set to the current timestamp #### Scenario: Schema migration for updated_at - **WHEN** the engine starts against a v2 database without an `updated_at` column - **THEN** the engine SHALL automatically add `ALTER TABLE documents ADD COLUMN updated_at TEXT` and all existing documents SHALL have `updated_at = NULL` ## MODIFIED Requirements ### Requirement: Document management The engine SHALL provide endpoints to list, inspect, remove, and download original files for ingested documents. #### Scenario: List documents - **WHEN** a client sends `GET /api/v1/documents` - **THEN** the engine SHALL return a JSON array of documents with id, title, doc_type, tags, chunk_count, created_at, and updated_at #### Scenario: List documents with filters - **WHEN** a client sends `GET /api/v1/documents?type=pdf&tags=manual` - **THEN** the engine SHALL return only documents matching all specified filters #### Scenario: List documents sorted by most recent - **WHEN** a client requests documents sorted by date - **THEN** the engine SHALL use `COALESCE(updated_at, created_at)` for ordering, so un-mutated documents sort by creation time and mutated documents sort by their last update #### Scenario: Get document details - **WHEN** a client sends `GET /api/v1/documents/{id}` - **THEN** the engine SHALL return the full document record including all chunks, their text content, `updated_at`, and whether the original file is available (`has_file: true/false`) #### Scenario: Download original file - **WHEN** a client sends `GET /api/v1/documents/{id}/file` - **THEN** the engine SHALL return the original file with appropriate Content-Type and `Content-Disposition: attachment; filename="{original_filename}"` headers, or HTTP 404 if the file is not available #### Scenario: Remove a document - **WHEN** a client sends `DELETE /api/v1/documents/{id}` - **THEN** the engine SHALL delete the document, all its chunks, associated embeddings, tag associations, and the stored original file from disk, and return HTTP 200 with a confirmation #### Scenario: Remove non-existent document - **WHEN** a client sends `DELETE /api/v1/documents/{id}` with a non-existent ID - **THEN** the engine SHALL return HTTP 404 ### Requirement: Engine status and reindex The engine SHALL provide status information and support re-embedding all chunks. The `version` field in the status response SHALL always be present and SHALL reflect the engine's release version as read from the `VERSION` file. This field is the contract used by clients for compatibility checking. #### Scenario: Get engine status - **WHEN** a client sends `GET /api/v1/status` - **THEN** the engine SHALL return JSON with `version` (string, from VERSION file), model_name, embedding_dim, GPU device info, database stats (document count by type, total chunks, DB size), and queue stats (queued/processing job count) #### Scenario: Trigger reindex - **WHEN** a client sends `POST /api/v1/reindex` - **THEN** the engine SHALL re-embed all existing chunks using the `enriched_text` column and the currently loaded model, and return progress information. This operation SHALL NOT block search queries.