Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Use these from `@astrojs/starlight/components`:

## Resource conventions

- Most resources use `id` as their model identifier; exceptions: `DeliveryChannelPolicy` and `NamedQuery` use `name` as the path element instead. This inconsistency is documented in `identifiers.mdx`.
- Most resources use `id` as their model identifier; the exception is `DeliveryChannelPolicy`, which uses `name` as the path element instead. (`NamedQuery` has a `name` property too, but is addressed by a minted GUID `id`.) This inconsistency is documented in `identifiers.mdx`.
- Domain/range tables follow this format in every property section:

```
Expand Down
64 changes: 62 additions & 2 deletions dlcs-docs-client/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,64 @@
# Code samples for IIIF-CS

1. Create an .env file with your settings, using the example in [example.env](example.env)
2. Run the code samples for each documentation page. Some are split into multiple steps.
Python samples accompanying the API documentation pages. Each `p{NN}_{topic}/`
directory matches a documentation page (numbered by sidebar order); the shared
helpers live in `iiif_cs.py` and `settings.py` in this directory.

## One-time setup

1. Create and activate a virtual environment in this directory, and install the
dependencies:

```
cd dlcs-docs-client
python -m venv .venv
.venv\Scripts\activate # (Windows; on macOS/Linux: source .venv/bin/activate)
pip install requests python-dotenv
```

2. Create a `.env` file **in this directory** with your settings, using the example
in [example.env](example.env).

## Running a sample

Always run from **this directory** (`dlcs-docs-client`), using Python's *module*
form — dots, no `.py`, no leading `.\`:

```
python -m p04_entrypoint.entrypoint
python -m p06_space.create_space
python -m p08_queue.get_batches
```

Tab completion works if you type the path first and then fix it up, but the argument
really is a module name: `p04_entrypoint.entrypoint`, not a file path.

### Why the other obvious invocations fail

| Attempt | Why it fails |
|:---|:---|
| `cd p04_entrypoint` then `python entrypoint.py` | When you run a *script file*, Python puts the **script's own directory** on the import path — not your shell's current directory. `iiif_cs.py` lives one level up, so `ModuleNotFoundError: No module named 'iiif_cs'`. |
| `python p04_entrypoint\entrypoint.py` from here | Same rule: the path entry is `p04_entrypoint\`, not this directory. Same error. |
| `python -m .\p04_entrypoint\entrypoint.py` | `-m` takes a **module name**, not a file path — hence "Relative module names not supported". |
| `python -m entrypoint` from inside `p04_entrypoint` | Would find the module, but `iiif_cs` is still not on the path (and the `.env` wouldn't load — see below). |

`python -m package.module` works because `-m` puts the **current working
directory** first on the import path — so `iiif_cs`, `settings`, and cross-sample
imports (e.g. `p09_batch` importing from `p08_queue`) all resolve.

Two more reasons the working directory must be this one:

- `settings.py` calls `load_dotenv()`, which looks for `.env` relative to the
current working directory.
- Some samples import helpers from sibling sample packages by their
`p{NN}_…` name.

## What the samples are (and aren't)

Deliberately simple, synchronous, no error handling — they exist to show the HTTP
operations as clearly as possible, not to be a client library. Most demonstrate a
flow top-to-bottom under `if __name__ == '__main__':` and print each request and
response as they go. They run against the API named in your `.env`
(`IIIF_CS_API_HOST`) and most create/modify real resources in the documentation
space (`settings.docs_space_id`) — point them at a test/staging customer, not
production content you care about.
32 changes: 32 additions & 0 deletions scratch/api-doc/adjuncts.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,35 @@ The corresponding canvas output (before removal):
}
]
```

---

## label requirement (open question, 2026-06-24)

The adjunct creation field-usage table originally marked `label` as **required** in all four columns (POST/PUT external, POST/PUT from origin), and the `### label` prose said it "is required when supplying the adjunct yourself". The validator (`API/Features/Adjuncts/Validation/HydraAdjunctValidator.cs`) does **not** enforce `label`, so the docs were softened to "recommended" to match current behaviour.

Open question: should the API require `label` when the user supplies the adjunct (the four scenarios above)? If so, add a `Label` NotEmpty rule to the validator and restore "required" in the table and prose. Original prose clause removed:
> It is recommended to always supply this, and is required when supplying the adjunct yourself.

---

## Old-doc prose preserved by the 2026-08-03 provenance re-audit

### `iiifLink` expression semantics (PROV-14) — **restore-candidate**

Explains what the field is *for*; dropped in the port, absent from the new `iiifLink`
section:

> "This property is used when the adjunct is _expressed_ by the platform in the IIIF
> Presentation API, either in the [single asset manifest](asset#manifest) or in a
> [Named Query](named-queries)."

### Content-POST fragments (PROV-15) — **park with the ADJ-01 `content` material**

Small fragments dropped without capture; they belong with the parked content-supply
workflow above (only meaningful if/when the `content` endpoint is built):

- rationale: "removing the need to manage the origin"
- on `publicId`: "or by POSTing binary content to the adjunct's ../content URI"
- field-usage table footnote: "** assumes you will provide content later by binary POST"
- field-usage table row: `content | ignored` (×4 columns)
34 changes: 28 additions & 6 deletions scratch/api-doc/asset-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ These examples belong in the `### Query object` section once supported:
?q={"id":"PHOTO.2.22.36.2.tif"}
```

# Ordering not yet implemented
# Ordering — ⟳ IMPLEMENTED, restore (verified 2026-08-03, DIS-01) — **restore-candidate**

You can order by the value of a field of an asset:

Expand All @@ -18,18 +18,25 @@ You can order by the value of a field of an asset:
?orderBy=height
```

If no ordering is provided the order is undefined.
~~If no ordering is provided the order is undefined.~~ **Answered:** default order is
`Created` (`AssetQueryX.GetPropertyName` falls back to "Created"). Note for the docs:
there is no field whitelist — an unknown field name yields a handled Hydra **500**,
not a 400 (DIS-06); matching is case-insensitive. The `p15` sample now has a
`get_images_ordered` example but its docstring still says "Not yet supported" (stale).

(It is unclear whether the default undefined order is by creation date.)

# More examples (use ordering, not yet implemented)
# More examples — ⟳ now valid (ordering implemented), restore with DIS-01

```
?q={"string1":"my-value","number1":99}&orderBy=width&pageSize=10&page=12
?string1=my-value&orderByDescending=string3&page=9
```

# Multiple values not yet implemented
# Multiple values not yet implemented — ⟳ still true EXCEPT `manifests` (2026-08-03, DIS-03/05)

`manifests` is the one multi-value field that exists today (`?manifests=a,b`
comma-split, or `q` with a string array) — the precedent if this is ever generalised.
For the string1-3 fields below, an array still fails deserialisation → 400
"Could not parse query".

```
?q={"string1":["a","b"]}
Expand All @@ -48,3 +55,18 @@ If no ordering is provided the order is undefined.
```

`id` is the internal _Model Id_ (see [Identifiers](identifiers)), the last part of the URI. This query returns all assets that match that identifier. If used to filter assets on `/customers/{customer}/allImages`, the returned assets could be in any of the customer's spaces (but never any other customer), so even a single value for `id` could return more than one asset. On `/customers/{customer}/spaces/{space}/images`, each requested `id` value can only return 0 or 1 assets, because this value must be unique within a space.

---

# Roadmap rationale (PROV-06, captured 2026-08-03) — **park (design context)**

Old-doc line explaining why the query surface is expected to grow, dropped with the
caution rewrite:

> "We will need a full set of query features for portal use."

# Applicable endpoints (⟳ 2026-08-03, DIS-22)

The batch endpoints also accept the full query syntax and are missing from the live
page's list: `GET .../queue/batches/{batchId}/images` and `.../batches/{batchId}/assets`
support `?q=`, shortcut params, ordering, paging and `include=adjuncts`.
24 changes: 24 additions & 0 deletions scratch/api-doc/asset.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ The `@context` is documented as `https://dlcs.github.io/vocab/context/future.jso
### `## manifest` section

- NOT PORTED: This property is not yet implemented. The old docs described it as "A link to a IIIF Presentation 3 manifest that provides the URLs and additional information for all the _outputs_ of the delivery channels, and any [adjuncts](adjuncts) you have registered (or that the platform has created)."
- Confirmed (2026-06-24): the single-asset manifest exists, and its URI _should_ become the value of a `manifest` property — but it is not yet implemented _as a property_.
- Open question (2026-06-24): possible rename of `manifests` → `scopes`. Not present in protagonist `main` or `develop` as of this date — may be in an unmerged PR. Revisit before next edit to this property.

Need to make bigger use of this feature and encourage linking to it in a viewer - provide a link to viewer in the API? Maybe not that far.

Expand Down Expand Up @@ -133,3 +135,25 @@ Typically, an asset is used in only one Manifest, but not always.

The following sections from the old asset.mdx remain to be ported:

---

## "(First draft) Version 1" `max` / `maxBehaviour` design block (PROV-03, captured 2026-08-03) — **park (design history)**

The old page's trailing design discussion — superseded by the `maxWidth` /
`openFullMax` / `openMaxWidth` three-property model but the only record of *why* that
design exists, and of one unresolved combination case:

> "The effect of setting `max` depends on what you set `maxBehaviour` to: `maxWidth`:
> this is independent of roles... `substitute`: the effect is 'Anyone can see a request
> up to maxWidth but you need a role to see higher'... `thumbnail`: this only applies
> to images with roles... Note that for this choice it's not a width, it's a bounding
> box - like maxUnauthorised."

And the open question:

> "What about the scenario where you want to allow full thumbs up to 400 px, but still
> impose a maxWidth of 512 even for authed users?... Or have a fourth behaviour:
> `maxWidthWithOpenThumbs`..."

Relevant when SPA-01/DIS-18 decide the fate of `openMaxWidth` + substitute.

17 changes: 17 additions & 0 deletions scratch/api-doc/batch.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,20 @@ A batch represents a submitted job of assets. [Collections](collections) of batc
"assets": "https://api.dlcs.io/customers/2/queue/batches/875629/assets",
```

# Old volatility caveat on `images` — resolved (PROV-21, logged 2026-08-03)

The old page prefixed the images/batch-membership paragraph with *"The following
information will likely change"*. It did change: the images/assets split landed
(current-members vs at-creation members), and the new page's settled prose matches
code (`GetBatchImages.cs:10` — current batch members only). Caveat retired; nothing
to restore.

# Batch-size limit: old docs said 100, shipped default is 250 (PROV-05/PROV-18, resolved 2026-08-03)

The old docs stated a fixed limit: *"There is a limit of 100 assets per batch."*
Verified against code: `ApiSettings.MaxBatchSize = 250` (platform-configured).
registering-assets.mdx already says 250; batch.mdx says only "configurable";
collections.mdx still carries the old "e.g., 100" advice. Make all three agree on
"250 by default, platform-configured". The same limit applies to adjunct batches
(`AdjunctBatchPostValidator`).

33 changes: 33 additions & 0 deletions scratch/api-doc/customer.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ I'll need to re-read the RFCs, look at the DB schema etc and then write the hypo

GET is only operation supported on Customer - how do I edit name and displayName?

> Answered (2026-06-24): Customer supports GET and PATCH. PATCH edits **only** `displayName` (`CustomerPatchValidator` rejects `name`; `PatchCustomer` reads only `DisplayName`, per `API/Features/Customer/CustomerController.cs`). `name` is set at creation (POST) and cannot be changed afterwards.
>
> Original live-doc text (customer.mdx), replaced because it was inaccurate — restore/adjust if `name` becomes editable via PATCH:
> "Only the fields `name` and `displayName` are editable."


## spaces

Expand Down Expand Up @@ -272,3 +277,31 @@ See [Access Control](access-control) for details.
| GET | Retrieves all Roles | - | 🔗 hydra:Collection (of vocab:Role) | 200 OK |
| POST | Creates a new Role | vocab:Role | vocab:Role | 201 Created |

---

## Old-doc prose preserved by the 2026-08-03 provenance re-audit

### Pre-seeded default delivery channels (PROV-11) — **restore-candidate**

Dropped when the `defaultDeliveryChannels` example was swapped to `iiif-av`; the fact
that new customers arrive with default channels is now stated nowhere on the page:

> "(You will already have this delivery channel)."

(Also see ACC-19: the new example is internally inconsistent — `iiif-img` channel with
an `iiif-av/default-video` policy, pasted from a working note.)

### Space-level images endpoint shares the extended query syntax (PROV-12) — **park (design intent)**

> "this and /customers/x/spaces/y/images should work the same way, using an extended
> asset query syntax that takes the metadata values, tags, roles, and id(s)."

Ties to DIS-04 (tags/roles/id filters unbuilt). Keep as design intent, not doc copy.

### Pointer to "Managing portal users" (PROV-13) — **needs-decision (ACC-10)**

> "See [Managing portal users](portal-users) for details."

The target page never existed in the old repo either. Whether a portal-users page
should exist is exactly ACC-10's question.

7 changes: 7 additions & 0 deletions scratch/api-doc/delivery-channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ The `policyData` for `iiif-av` currently only supports a fixed set of preset str
# iiif-av: HLS adaptive bitrate not yet available

> In a future version of the API, the platform will support adaptive bitrate outputs in HLS format.

# default iiif-img policy: Image API version deliberately unspecified (PROV-16, captured 2026-08-03)

Old-doc parenthetical dropped in the port — the only statement that the `default`
policy's unspecified Image API version is future-extensible:

> "_(future policy could dictate whether v2, v3 etc)_"
37 changes: 35 additions & 2 deletions scratch/api-doc/entrypoint.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
# Notes (clarified 2026-08-03)

- **`queue`:** the API response is missing a `queue` link — even though the global
`/queue` **endpoint** exists (`QueueController.cs:17`). The EntryPoint model simply
has no `queue` property to emit (`DLCS.HydraModel/EntryPoint.cs:18-55`). So the fix,
if wanted, is cheap: add the link property (DIS-14 option b). *(An earlier
verification note misread this as a false claim about the model — the intended
meaning, endpoint-present/link-missing, is correct.)*
- **Remove `imageOptimisationPolicies` and `thumbnailPolicies`** (DIS-15; emitted,
legacy, undocumented — and `thumbnailPolicies`' description string is a copy-paste
of the `portalRoles` text).
- The model DOES emit `portalRoles`, undocumented (DIS-16).

API response is missing `queue` property - even though it's present
# Old-doc prose preserved by the 2026-08-03 provenance re-audit

Remove `imageOptimisationPolicies` and `thumbnailPolicies`
## `deliveryChannelPolicies` (PROV-01) — **probably to be dropped, not restored**

The API does **not** return a `deliveryChannelPolicies` link, and it probably should
not be documented (the old section header was itself `## DELETE
deliveryChannelPolicies`, wrapped in a Callout questioning whether the global set
should exist). The live entrypoint.mdx JSON example still shows the property and
should lose it (DIS-14). The old prose is preserved here **only** in case the room
decides the feature is wanted after all:

> "A link to a paged [Collection](collections) of further collections of [delivery
> channel policies](delivery-channels). This is a rare example of a Collection of
> Collections, where the returned collections are like sub-folders, for organisational
> use. / These _Delivery Channel policies_ are common settings you can re-use for your
> own assets, as further explained in [Delivery Channels](delivery-channels)."

## "Hardcoded" non-dereferenceable policies (PROV-02) — **restore-candidate**

Real behaviour worth documenting somewhere (delivery-channels page?): `use-original`,
`none` and `default` are valid policy references that exist as hardcoded values
rather than dereferenceable resources.

> "You get some default Delivery Channel **Policies** when your customer is created.
> For thumbs and AV. / You can also refer to \"hardcoded\" but not dereferenceable
> policies use-original, none and default. So what would be in here?"
Loading