Skip to content
Draft
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
venv/
venv/
site/
29 changes: 29 additions & 0 deletions docs/api/api-catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# API Catalog

Every EOEPCA+ deployment exposes a machine-readable directory of its services at
`/.well-known/api-catalog`. User clients treat this as the only supported way to
discover endpoints, authentication, and deployment metadata, they MUST NOT
hard-code service URLs or assume a fixed hostname layout.

[RFC 9727](https://www.rfc-editor.org/rfc/rfc9727) well-known URI,
[RFC 9264](https://www.rfc-editor.org/rfc/rfc9264) Linkset JSON
(`application/linkset+json`). Services are link targets keyed by link relation
type (`rel`); relation URIs and extension properties are in
[schema/v1.json](schema/v1.json).

- **Schema:** [schema/v1.json](schema/v1.json)
- **Example:** [schema/example.json](schema/example.json), reference deployment to inspect or validate against

```bash
check-jsonschema --schemafile docs/api/schema/v1.json docs/api/schema/example.json
```

Deployments MUST serve a document that validates against the current schema.
Clients SHOULD fetch `service-desc` from the catalog for the live schema URL.
Look services up by `rel`. Absent `eoepca:auth`, means unauthenticated access
is possible.

## Versioning

`eoepca:schema_version` is SemVer. Changes within a MAJOR are additive only. On a
MAJOR bump the previous schema stays at
6 changes: 0 additions & 6 deletions docs/api/endpoint-specification.md

This file was deleted.

182 changes: 182 additions & 0 deletions docs/api/schema/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
{
"$schema": "https://eoepca.org/schemas/discovery/v1.json",

"linkset": [
{
"anchor": "https://develop.eoepca.org/.well-known/api-catalog",
"profile": [
"https://www.rfc-editor.org/info/rfc9727",
"https://eoepca.org/profiles/discovery/v1"
],

"eoepca:schema_version": "0.0.1",
"eoepca:description": "EOEPCA+ reference deployment on CloudFerro.",
"eoepca:attribution": "ESA / EOEPCA+",
"eoepca:deployment": {
"name": "EOEPCA+ Develop",
"environment": "develop",
"git_revision": "a1b2c3d",
"generated_at": "2026-06-03T08:14:00Z"
},

"self": [
{
"href": "https://develop.eoepca.org/.well-known/api-catalog",
"type": "application/linkset+json",
"profile": "https://www.rfc-editor.org/info/rfc9727"
}
],
"service-desc": [
{
"href": "https://eoepca.org/schemas/discovery/v1.json",
"type": "application/schema+json"
}
],
"service-doc": [
{
"href": "https://eoepca.readthedocs.io/",
"type": "text/html"
}
],

"http://openid.net/specs/connect/1.0/issuer": [
{
"href": "https://iam-auth.develop.eoepca.org/realms/eoepca",
"title": "Keycloak",
"service-desc": "https://iam-auth.develop.eoepca.org/realms/eoepca/.well-known/openid-configuration",
"eoepca:realm": "eoepca",
"eoepca:default_client_id": "demo"
}
],

"https://eoepca.org/rel/workspace-api": [
{
"href": "https://workspace-api.develop.eoepca.org",
"type": "application/json",
"title": "Workspace API",
"eoepca:auth": "oidc",
"eoepca:api_version": "2.1",
"eoepca:naming": { "pattern": "ws-{username}", "prefix": "ws" }
}
],

"data": [
{
"href": "https://resource-catalogue.develop.eoepca.org",
"type": "application/json",
"title": "Resource catalogue (open)",
"conformsTo": [
"https://api.stacspec.org/v1.0.0/core",
"https://api.stacspec.org/v1.0.0/item-search",
"http://www.opengis.net/spec/ogcapi-records-1/1.0/conf/core"
],
"eoepca:auth": "none"
},
{
"href": "https://resource-catalogue-protected.develop.eoepca.org",
"type": "application/json",
"title": "Resource catalogue (protected)",
"eoepca:auth": "oidc-uma"
},
{
"href": "https://eoapi.develop.eoepca.org/stac",
"type": "application/json",
"title": "eoAPI STAC",
"conformsTo": [
"https://api.stacspec.org/v1.0.0/core",
"https://api.stacspec.org/v1.0.0/item-search"
],
"eoepca:auth": "oidc-write",
"eoepca:api_version": "1.0.0"
},
{
"href": "https://eoapi.develop.eoepca.org/vector",
"type": "application/json",
"title": "eoAPI vector (TiPg)",
"conformsTo": ["http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core"]
}
],

"https://eoepca.org/rel/harvester": [
{
"href": "https://registration-harvester-api.develop.eoepca.org/flowable-rest",
"type": "application/json",
"title": "Harvester (Flowable)",
"eoepca:engine": "flowable"
}
],

"http://www.opengis.net/def/rel/ogc/1.0/processes": [
{
"href": "https://zoostd.develop.eoepca.org/ogc-api",
"type": "application/json",
"title": "Processing (ZOO-DRU standard)",
"eoepca:flavor": "zoo-dru-std",
"eoepca:auth": "oidc-uma",
"eoepca:api_version": "OGC API Processes Part 1 / 1.0"
},
{
"href": "https://zookeda.develop.eoepca.org/ogc-api",
"type": "application/json",
"title": "Processing (ZOO-DRU KEDA)",
"eoepca:flavor": "zoo-dru-keda",
"eoepca:auth": "oidc-uma",
"eoepca:api_version": "OGC API Processes Part 1 / 1.0"
}
],

"https://eoepca.org/rel/openeo": [
{
"href": "https://eoapi.develop.eoepca.org/openeo",
"type": "application/json",
"title": "TiTiler-OpenEO",
"eoepca:backend_id": "titiler-openeo",
"eoepca:api_version": "1.2.0"
},
{
"href": "https://openeofed.develop.eoepca.org",
"type": "application/json",
"title": "OpenEO Federation",
"eoepca:backend_id": "federation",
"eoepca:role": "aggregator",
"eoepca:api_version": "1.2.0"
}
],

"https://eoepca.org/rel/datacube-access": [
{
"href": "https://datacube-access.develop.eoepca.org",
"type": "text/html",
"title": "Datacube Access"
}
],

"https://eoepca.org/rel/resource-health": [
{
"href": "https://resource-health.develop.eoepca.org",
"type": "text/html",
"title": "Resource Health",
"eoepca:apis": { "healthchecks": "/api/healthchecks/v1", "telemetry": "/api/telemetry/v1" }
}
],

"https://eoepca.org/rel/notifications": [
{
"href": "https://notifications.develop.eoepca.org",
"type": "application/json",
"title": "CloudEvents broker",
"eoepca:knative_subdomain": "na.develop.eoepca.org"
}
],

"https://eoepca.org/rel/s3": [
{
"href": "https://minio.develop.eoepca.org",
"title": "MinIO S3 endpoint",
"eoepca:region": "eoepca-demo",
"eoepca:virtual_hosting": false
}
]
}
]
}
106 changes: 106 additions & 0 deletions docs/api/schema/v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://eoepca.org/schemas/discovery/v1.json",
"title": "EOEPCA+ API Catalog (RFC 9727)",
"description": "Schema for the document at `/.well-known/api-catalog`. RFC 9727 well-known URI, RFC 9264 Linkset format (`application/linkset+json`). Service URLs are link targets keyed by `rel`.",
"type": "object",
"required": ["linkset"],
"additionalProperties": true,
"properties": {
"$schema": { "type": "string", "format": "uri" },
"linkset": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/LinkContext" },
"contains": {
"type": "object",
"required": ["anchor"],
"properties": {
"anchor": { "type": "string", "pattern": "/\\.well-known/api-catalog$" }
}
}
}
},
"$defs": {
"LinkContext": {
"type": "object",
"required": ["anchor"],
"properties": {
"anchor": { "type": "string", "format": "uri" },
"profile": {
"type": ["string", "array"],
"items": { "type": "string", "format": "uri" }
},
"eoepca:schema_version": { "type": "string", "pattern": "^1\\.[0-9]+\\.[0-9]+$" },
"eoepca:description": { "type": "string" },
"eoepca:attribution": { "type": "string" },
"eoepca:deployment": { "$ref": "#/$defs/Deployment" }
},
"additionalProperties": { "$ref": "#/$defs/TargetArray" }
},
"TargetArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/Target" }
},
"Target": {
"type": "object",
"required": ["href"],
"additionalProperties": true,
"properties": {
"href": { "type": "string", "format": "uri-reference" },
"type": { "type": "string" },
"title": { "type": "string" },
"profile": {
"type": ["string", "array"],
"items": { "type": "string", "format": "uri" }
},
"service-desc": { "type": "string", "format": "uri" },
"conformsTo": {
"type": "array",
"items": { "type": "string", "format": "uri" }
},
"eoepca:auth": { "$ref": "#/$defs/AuthMode" },
"eoepca:api_version": { "type": "string" },
"eoepca:realm": { "type": "string" },
"eoepca:default_client_id": { "type": "string" },
"eoepca:naming": { "$ref": "#/$defs/NamingPattern" },
"eoepca:engine": { "type": "string", "enum": ["flowable", "operaton", "camunda"] },
"eoepca:flavor": { "type": "string", "enum": ["zoo-dru-std", "zoo-dru-keda", "zoo-dru-wes"] },
"eoepca:backend_id": { "type": "string" },
"eoepca:role": { "type": "string", "enum": ["backend", "aggregator"] },
"eoepca:region": { "type": "string" },
"eoepca:virtual_hosting": { "type": "boolean" },
"eoepca:knative_subdomain": { "type": "string" },
"eoepca:apis": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
},
"AuthMode": {
"type": "string",
"enum": ["none", "oidc", "oidc-write", "oidc-uma"],
"description": "none: open. oidc: bearer required. oidc-write: open for GET/HEAD/OPTIONS. oidc-uma: bearer + UMA ticket."
},
"NamingPattern": {
"type": "object",
"required": ["pattern"],
"additionalProperties": true,
"properties": {
"pattern": { "type": "string" },
"prefix": { "type": "string" }
}
},
"Deployment": {
"type": "object",
"additionalProperties": true,
"properties": {
"name": { "type": "string" },
"environment": { "type": "string" },
"git_revision": { "type": "string" },
"generated_at": { "type": "string", "format": "date-time" }
}
}
}
}
45 changes: 42 additions & 3 deletions docs/design/overview.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
# Architecture

Subcomponent architecture and interfaces.
User clients are thin orchestration layers over EOEPCA+ platform services. The
platform advertises those services through a single discovery document; clients
never embed deployment-specific URLs.

!!! warning
Work in progress... :construction_worker:
## Discovery layer

```
User client EOEPCA+ deployment
─────────── ──────────────────

1. GET /.well-known/api-catalog
─────────────────────────────► Linkset JSON
(rel → href + metadata)

2. Pick rel (workspace-api, data, openeo, …)
Read eoepca:auth, eoepca:naming, conformsTo

3. Authenticate via OIDC issuer link
(eoepca:default_client_id from catalog)

4. Call target service API
─────────────────────────────► Workspace, STAC, OpenEO, …
```

The catalog is specified in [API Catalog](../api/api-catalog.md) ([schema/v1.json](../api/schema/v1.json)).

## Design principles

- **Rel-based lookup** — clients select services by registered `rel` URIs, not
by position or informal key names.
- **Server decides auth** — `eoepca:auth` in the catalog is a hint; a 401 from the service means you need credentials.
- **Additive evolution** — new rels and properties are MINOR changes; removing
or renaming rels is MAJOR and follows the catalog versioning rules.
- **Cache-friendly** — deployments MUST emit a stable ETag tied to
`eoepca:deployment.git_revision` so clients can revalidate cheaply.

## Interfaces

| Interface | Role |
|---|---|
| `/.well-known/api-catalog` | Platform → client; full service directory. |
| OIDC issuer (`openid issuer` rel) | Client ↔ Keycloak; token acquisition. |
| Per-service APIs | Client ↔ individual building blocks; discovered via catalog. |
Loading