feat: expose membership and job APIs

This commit is contained in:
Lucas Winther committed 2026-09-26 11:23:00 +02:00
1 parent ad192365a1
commit 734ba404c8
12 files changed
+624 -19

No files matched your search

+7 -2
View File
@@ -6,7 +6,8 @@ How `recoll-modern` is built today. Update in the same commit as any structural
The Python service scaffold, SQLite schema, collection and membership repositories, document
discovery/identity modules, durable job worker, engine adapter, authentication service, and initial
HTTP shell are built. Membership, search and job resource routes remain to be added. Recoll behaviour
HTTP shell, membership routes, and job routes are built. Search and document retrieval remain to be
added. Recoll behaviour
below was verified against a real container.
The goal: a self-hosted service that wraps Recoll's indexing and full-text search behind (a) a modern
@@ -31,7 +32,7 @@ web UI and (b) an MCP server, running in Docker, with several independent collec
| `helper/` | C reader run by Recoll's `metadatacmds` for each indexed file |
| `src/recoll_modern/engine/` | Shared Protocol, deterministic fake, and isolated Recoll Python/indexer adapter |
| `src/recoll_modern/domain/auth.py`, `storage/auth.py` | Argon2 password checks, seeded administrator, hashed server-side sessions and CSRF verification |
| `src/recoll_modern/api/` | HTTP auth, health, file browsing, collection metadata, prefix/proxy handling and JSON errors |
| `src/recoll_modern/api/` | HTTP auth, health, file browsing, collection/membership/rule/job resources, prefix/proxy handling and JSON errors |
| `tests/` | Automated service tests |
Discovery produces content hashes and root-relative paths without writing to the document volume.
@@ -104,6 +105,10 @@ Core routes use a server-side session cookie and CSRF token; `GET /auth/session`
the database only stores hashes. Forwarded scheme, host and prefix are applied only for configured
proxy networks.
Membership, rule, and reindex writes create versioned, durable jobs. The worker updates SQLite
provenance, exports the membership map, and forces affected paths through the engine. Document listing
derives effective membership from SQLite and includes direct and rule provenance.
The resource groups are auth, health, read-only file browsing, collections and membership sources,
directory rules, scoped search, document text/original retrieval, and indexing jobs. Search callers
select returned fields; only `document_id` is unconditional, and inline full text is bounded. Every
+5 -5
View File
@@ -15,12 +15,12 @@ Where the workflow stands (`AGENTS.md` -> Workflow: brainstorm -> spec -> plan -
selectable search fields, subpath hosting and the packaging seam for deferred desktop spec 005.
- Plan `docs/plans/001-search-engine-api.md`: **approved 2026-09-18.** Its listed Python runtime and
development dependencies are approved. Execution follows the plan task by task.
- Plan Tasks 1–3 are complete and independently reviewed. Tasks 4–10 add discovery, content-hash
- Plan Tasks 1–3 are complete and independently reviewed. Tasks 4–11 add discovery, content-hash
identity, additive membership, durable jobs, the atomic membership map, the engine boundary,
session authentication and the HTTP shell. Their checkboxes are current in the plan. The next task
is membership, rule and job routes.
session authentication, the HTTP shell, and membership/rule/job routes. Their checkboxes are current
in the plan. The next task is scoped search and document retrieval.
The next action is Task 11, "Expose membership, rule, and job APIs." Do not repeat Tasks 1–10.
The next action is Task 12, "Expose scoped search and document retrieval." Do not repeat Tasks 1–11.
Things a resuming agent will otherwise get wrong:
@@ -49,7 +49,7 @@ Things a resuming agent will otherwise get wrong:
then record the verified ones in `AGENTS.md`.
- [ ] Dockerfile + compose: Recoll in the image, document volume mounted `:ro`, writable volumes for
the index and SQLite.
- [ ] Write the `metadatacmds` membership helper as a fast-starting non-Python program, fed by a flat
- [x] Write the `metadatacmds` membership helper as a fast-starting non-Python program, fed by a flat
map exported from SQLite. A `python3` helper made a 400-file index 9x slower; Recoll spawns it
once per file per index run.
- [ ] Re-measure indexing overhead against real documents (PDF, EPUB) rather than small text files —
+4 -4
View File
@@ -787,7 +787,7 @@ git commit -m "feat: add authenticated HTTP service"
- Consumes: Task 5 membership plans and Task 6 job repository
- Produces: spec endpoints under `/collections/{id}/memberships`, `/directory-rules`, and `/jobs`
- [ ] **Step 1: Write failing request/response tests**
- [x] **Step 1: Write failing request/response tests**
```python
def test_persistent_directory_request_enqueues_replayable_job(client: TestClient) -> None:
@@ -808,11 +808,11 @@ def test_removing_rule_preserves_overlapping_membership(client: TestClient) -> N
Cover invalid source combinations, exclusions outside source, default best-effort, strict atomicity, effective provenance, per-file overrides, patching rule exclusions, non-retryable jobs, and 50/200 pagination.
- [ ] **Step 2: Run tests and observe failure**
- [x] **Step 2: Run tests and observe failure**
Run: `uv run pytest tests/api/test_memberships.py tests/api/test_jobs.py -v`
- [ ] **Step 3: Implement validated schemas and routes**
- [x] **Step 3: Implement validated schemas and routes**
Use discriminated Pydantic models `FileSource(type="file", path)` and
`DirectorySource(type="directory", path, mode, excluded_directories)`. Reject mode/exclusions on files
@@ -823,7 +823,7 @@ effective membership plus `direct`, contributing rule IDs, and override state. I
collection IDs and uses the whole document root when neither is present. Retry accepts failed or
completed-with-errors jobs only.
- [ ] **Step 4: Verify and commit**
- [x] **Step 4: Verify and commit**
Run: `uv run pytest tests/api/test_memberships.py tests/api/test_jobs.py -v && uv run ruff check . && uv run mypy src tests`