Adds the REST API surface that Daedalus calls to manage workspace
lifecycle and dispatch file ingestion. All endpoints under /library/api/:
POST /workspaces/ create workspace (idempotent on
workspace_id; library_type frozen)
GET /workspaces/{workspace_id}/ workspace status with item/chunk
counts
DELETE /workspaces/{workspace_id}/ delete workspace + reachable
content; concept-safe (orphan-only
Concept GC; concepts referenced
elsewhere are preserved)
POST /ingest/ queue a file for ingest. Idempotent
on (library, source_ref, hash):
same triple → return existing job;
new hash → supersede.
GET /jobs/{job_id}/ poll job status
POST /jobs/{job_id}/retry/ re-dispatch a failed job
GET /jobs/?status=&library_uid= list recent jobs
Workspace-Library lookup uses the unique workspace_id index added in the
schema commit. Concept GC runs as a separate transaction after item/chunk
delete so partial failures don't leave the global graph corrupted.
Tests cover serializer validation, IngestJob ORM behavior, the
(library, source_ref, hash) idempotency query pattern, and auth
boundaries on every new endpoint. Cypher correctness is validated by
manual end-to-end testing — no live Neo4j in unit tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
44 lines
1.8 KiB
Python
44 lines
1.8 KiB
Python
"""
|
|
URL patterns for the library DRF API.
|
|
"""
|
|
|
|
from django.urls import path
|
|
|
|
from . import views, workspaces
|
|
|
|
app_name = "library-api"
|
|
|
|
urlpatterns = [
|
|
# Libraries
|
|
path("libraries/", views.library_list_create, name="library-list"),
|
|
path("libraries/<str:uid>/", views.library_detail, name="library-detail"),
|
|
# Collections
|
|
path("collections/", views.collection_list_create, name="collection-list"),
|
|
path("collections/<str:uid>/", views.collection_detail, name="collection-detail"),
|
|
# Items
|
|
path("items/", views.item_list_create, name="item-list"),
|
|
path("items/upload/", views.item_upload, name="item-upload"),
|
|
path("items/<str:uid>/", views.item_detail, name="item-detail"),
|
|
path("items/<str:uid>/reembed/", views.item_reembed, name="item-reembed"),
|
|
path("items/<str:uid>/status/", views.item_status, name="item-status"),
|
|
# Search (Phase 3)
|
|
path("search/", views.search, name="search"),
|
|
path("search/vector/", views.search_vector, name="search-vector"),
|
|
path("search/fulltext/", views.search_fulltext, name="search-fulltext"),
|
|
# Concepts (Phase 3)
|
|
path("concepts/", views.concept_list, name="concept-list"),
|
|
path("concepts/<str:uid>/graph/", views.concept_graph, name="concept-graph"),
|
|
# Workspaces (Daedalus integration)
|
|
path("workspaces/", workspaces.workspace_create, name="workspace-create"),
|
|
path(
|
|
"workspaces/<str:workspace_id>/",
|
|
workspaces.workspace_detail_or_delete,
|
|
name="workspace-detail",
|
|
),
|
|
# Ingest (Daedalus integration)
|
|
path("ingest/", views.ingest_create, name="ingest-create"),
|
|
path("jobs/", views.ingest_job_list, name="ingest-job-list"),
|
|
path("jobs/<str:job_id>/", views.ingest_job_detail, name="ingest-job-detail"),
|
|
path("jobs/<str:job_id>/retry/", views.ingest_job_retry, name="ingest-job-retry"),
|
|
]
|