license: built full stack, test and documentation
Some checks failed
docs / build (push) Has been cancelled
docs / deploy (push) Has been cancelled

This commit is contained in:
Giuseppe Naponiello
2026-07-03 12:47:47 +02:00
parent f8206b5840
commit 271acacb1d
39 changed files with 4078 additions and 57 deletions

17
docs/developer/index.md Normal file
View File

@@ -0,0 +1,17 @@
# Developer guide
Architecture, data model and API of the Dynamic Collection platform, for
developers and integrators.
At a glance: an API-only **Laravel** backend (Sanctum + Fortify, MySQL,
Redis/Horizon), a **Vite + TypeScript** multi-page frontend with islands
(Tailwind v4 + daisyUI, Leaflet, 3DHOP), and a **Linked Art** provider
exposing records for harvesting by the Swedish national aggregator
(KSamsök 2).
## Chapters
- **[Licenses](licenses.md)** — the license vocabulary: data model, seeding,
legal text files, REUSE constraints and API endpoints.
*More chapters will follow as the platform takes shape.*

View File

@@ -0,0 +1,67 @@
# Licenses
The license vocabulary: data model, seeding, legal text files and API. For
the user-facing overview see the [User guide](../user/licenses.md).
## Data model
Licenses are a controlled vocabulary (table `licenses`, model
`App\Models\Lists\License`), created and populated at install time by the
`LicenseSeeder`**not** by the v1 ETL.
| Column | Meaning |
|---|---|
| `name` | Official full name (e.g. *Attribution 4.0 International*) |
| `acronym` | Display label shown in the UI (e.g. *CC BY 4.0*) |
| `spdx_id` | [SPDX](https://spdx.org/licenses/) identifier for export and interoperability; `NULL` for entries outside the SPDX License List — never invent one |
| `kind` | Backed enum `App\Enums\LicenseKind`: `license`, `mark` or `rights_statement` |
| `description` | One-sentence explanation shown in the forms |
| `uri` | Canonical URI (creativecommons.org / rightsstatements.org), also used in the Linked Art JSON-LD |
| `file` | File name of the legal text bundled in media download zips; `NULL` where no legal text exists |
| `for_record` / `for_media` | Scope flags: records only accept open licenses (CC0, CC BY), media accept everything |
| `sort_order` | Ordering in selects, from the most open to the most restrictive |
| `active` | Soft retirement: an inactive license disappears from forms but stays valid for content already using it |
Scope and `active` filtering happens in the form selects **and** is
re-validated server side; an edit form must still include the currently
assigned license even when it is inactive or out of scope.
## Seeding and legacy ids
The seeder ships 11 entries: Public Domain Mark + the CC 4.0 family + the
three most common rights statements (*InC*, *InC-EDU*, *CNE*). Ids **13 are
fixed** and match the legacy v1 database (1 = PDM, 2 = CC0, 3 = CC BY) so the
ETL maps artifact/media foreign keys 1:1 without translation. Further entries
can be added by administrators at runtime.
## Legal texts and downloads
The official CC legal texts live in
**`backend/storage/app/public/licenses/`**, named after their SPDX id
(e.g. `CC-BY-4.0.txt`). They are versioned in the repository — an exception
in `storage/app/public/.gitignore` — so they exist from the first clone. From
there the backend bundles them into media download zips, and the frontend can
link them directly (`/storage/licenses/…`, via `php artisan storage:link`).
Marks and rights statements have no legal text (`file` is `NULL`): the zip
only carries their canonical URI.
!!! warning "REUSE"
The root `LICENSES/` directory is reserved for the licenses **of the
repository**: [REUSE](https://reuse.software) fails the lint on license
texts not referenced by any file ("unused license"), and duplicate SPDX
file names anywhere under `LICENSES/` crash the tool. That is why the
downloadable texts live under `backend/storage/`. Their provenance is
annotated in `REUSE.toml`: Creative Commons dedicates the text of its
licenses to the public domain (CC0), which is also why `LICENSES/`
contains `CC0-1.0.txt`.
## API
| Endpoint | Access | Purpose |
|---|---|---|
| `GET /api/licenses` | public | list; filters `scope=record\|media`, `active=0\|1` |
| `GET /api/licenses/{id}` | public | detail |
| `GET /api/licenses/{id}/usage` | authenticated | is the license in use? |
| `POST /api/licenses` | admin | create an entry |
| `PUT/PATCH /api/licenses/{id}` | admin | update (partial updates supported, e.g. only `active`) |
| `DELETE /api/licenses/{id}` | admin | delete; blocked with `409` when the entry is in use |