Getting started
Run the documents service against the local Azurite emulator and walk the two-step upload with curl.
Prerequisites
Follow Local development. The documents service needs the
Azure Blob Storage emulator as well as Postgres, and ./localenv up starts both:
./localenv up documents-api- API: localhost:8102
- Swagger UI: localhost:8102/api-docs
- Database:
postgres://postgres:postgres@localhost:5433/documents - Blob emulator:
localhost:10000
Local catalog entries all point at the one Azurite instance and differ by container name. A catalog
entry may own several containers, in which case a request names the one it wants. The service creates
every configured container on startup and sets emulator CORS so a browser upload from the review
console works; curl does not need that. Credentials come from
services/documents/process-compose.yaml; the deployed equivalents are
described in Operations.
Authorization is not wired yet — endpoints are open aside from Idempotency-Key on writes.
Upload a document
Ask for a write SAS
curl -s -X POST localhost:8102/v1/documents/sas \
-H 'Content-Type: application/json' \
-d '{"filename":"lease.pdf","visibility":"private","storage_account":"default-private"}' | jqThe response carries sas_url, sas_expires_at, the container it signed for, and the blob_name
the service chose. Keep the URL, the container, and the blob name.
default-private owns one container, so the request can leave container out. An account configured
with several requires it — add "container":"project-storage" to the body.
PUT the bytes to the SAS URL
curl -s -X PUT "$SAS_URL" \
-H 'x-ms-blob-type: BlockBlob' \
-H 'Content-Type: application/pdf' \
--data-binary @lease.pdfx-ms-blob-type is required by Azure for a block blob upload. Nothing reaches the documents
service here.
Record the document
curl -s -X POST localhost:8102/v1/documents \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"data": {
"filename": "lease.pdf",
"visibility": "private",
"storage_account": "default-private",
"blob_name": "'"$BLOB_NAME"'",
"content_type": "application/pdf",
"references": [
{"ref_type":"lease","ref_id":"L-1","ref_category":"signed-copy","is_external":false}
],
"metadata": [{"meta_name":"pages","meta_value":"12"}]
}
}' | jqThe service confirms the blob exists before it writes the row, so a create that skipped step two
returns 422 and stores nothing.
Read it back
curl -s localhost:8102/v1/documents/{id} | jqThe response is the document plus a freshly signed read sas_url. Fetch the bytes with that URL
directly; the service never proxies them.
Find documents by reference
curl -s 'localhost:8102/v1/documents?ref_type=lease&ref_id=L-1' | jqEach returned document carries all of its references and metadata, not only the one that matched. See API for every filter and ADR 0014 for the pagination shape.
Watch the fanout
In another terminal:
./localenv up documents-documentslistenerCreating or updating a document logs an event received line from
documents-documents-queue-listener, carrying the same requestId the API returned in
X-Request-Id. See
ADR 0017.
Generate OpenAPI
go run ./services/documents/cmd/api -openapi > /tmp/documents-openapi.yamlThe checked-in spec is services/documents/openapi.yaml.