Files
ARCADIA-Studio/docs/api.rst
T

381 lines
18 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Arcadia Studio model REST API
=============================
This is the HTTP contract for ``oa-server``. The normative engineering model
and source language belong to ``language.rst``. ``openapi.json`` describes the
JSON records and closed command vocabulary. The server uses the same Rust
``Project``, ``Command``, parser/printer and validation implementation as the
desktop.
Identity, revision and writes
-----------------------------
All model routes begin with ``/api/v1``. A hosted project's immutable service
``resource_id`` is different from its editable ``model.id``. Each stored file
contains ``{resource_id, revision, model}``. The revision starts at 1, increments
once per changed accepted transaction, and does not change for a no-op.
Existing-project writes require the exact quoted ETag returned by a project
read, for example::
If-Match: "p-6f7162cc-094c-4f30-9b70-3f6f355f0c7f-r1"
Missing preconditions return 428; stale preconditions return 412. Weak ETags,
wildcards and lists are not accepted on writes. GET of the envelope, model and
source supports ``If-None-Match`` and returns an empty 304 when unchanged.
Use ETags as opaque strings; revisions are unsigned integer counters in JSON.
Every accepted changed write is persisted before the response. A worker captures
a revision-qualified snapshot, then parses and validates its candidate outside
the catalog lock. Commit rechecks the exact ETag and atomically installs the
envelope under the lock. Another accepted edit during preparation therefore
returns 412 even when the original snapshot passed its initial revision check.
Malformed or rejected inputs preserve the accepted model. Incomplete-model
warnings permit work and are returned in ``issues``.
There is no retained revision history, idempotency receipt, tombstone or
server undo. DELETE permanently removes the hosted envelope. Source/JSON
exports contain the current model only. They preserve the model's persistent
aliases, diagrams, artifact references and OA/SA trace data. Artifact revision
strings refer to external artifacts, not past server snapshots.
A lost connection or 504 can occur after an admitted write has begun. That
write may still complete. Read current state before choosing a new action.
Do not automatically retry POST create/import or regenerate random IDs and
assume the original request failed.
Routes
------
Health and schema routes are public. All model routes require the configured
bearer token, if any. Non-loopback binding requires a configured token.
.. list-table:: Endpoints
:header-rows: 1
:widths: 12 41 47
* - Method
- Path
- Behavior
* - GET
- ``/health``, ``/health/live``, ``/health/ready``
- Responding process with successfully opened store.
* - GET
- ``/openapi.json``, ``/api/v1/openapi.json``
- OpenAPI 3.1 contract.
* - POST
- ``/api/v1/projects``
- Create from ``{"name":"..."}``; 201 + Location/ETag.
* - GET
- ``/api/v1/projects``
- Summaries; ``limit``, ``after``, name substring ``q``.
* - GET
- ``/api/v1/projects/{id}``
- Complete current stored envelope.
* - PATCH
- ``/api/v1/projects/{id}``
- Conditional rename using ``{"name":"..."}``.
* - DELETE
- ``/api/v1/projects/{id}``
- Conditional permanent removal; 204.
* - POST
- ``/api/v1/projects/import``
- Raw model JSON or Arcadia source; new service ID.
* - GET / PUT
- ``/api/v1/projects/{id}/model``
- Export or conditionally replace native model JSON.
* - GET / PUT
- ``/api/v1/projects/{id}/source``
- Export or conditionally replace canonical UTF-8 source.
* - GET
- ``/api/v1/projects/{id}/elements``
- Filter by ``kind``, ``layer``, ``alias``, name ``q``.
* - GET
- ``/api/v1/projects/{id}/relations``
- Filter by ``kind``, ``source``, ``target``, ``incident_to``.
* - GET
- ``/api/v1/projects/{id}/artifact-links``
- Artifact links; optional owner ``object`` filter.
* - GET
- ``/api/v1/projects/{id}/traces``
- OA/SA traces; optional endpoint ``object`` filter.
* - POST
- ``/api/v1/projects/{id}/query``
- Bounded directed neighborhood, no mutation.
* - GET / POST
- ``/api/v1/projects/{id}/validation``
- Validate current model or a submitted candidate.
* - POST
- ``/api/v1/projects/{id}/transactions``
- Conditional typed command batch, optional dry run.
* - POST
- ``/api/v1/projects/{id}/transitions/preview``
- Preview a core transition against If-Match; return plan/base_revision.
* - POST
- ``/api/v1/projects/{id}/transitions/apply``
- Conditionally apply that client-held plan and base_revision.
``Content-Type: application/json`` is required for JSON requests.
``text/plain; charset=utf-8`` is used for Arcadia source. The service does not
guess formats from a filename. Unknown DTO fields, invalid UUIDs/enums, duplicate
model map keys and unsupported schemas are rejected. Maximum body size is
8 MiB. Compressed or encoded request bodies and browser Origin requests are
not supported.
Model admission permits at most 5,000 elements plus relations, 20,000 total
persistent records (including the project, views and placements), and 50,000
ordered step references. Source declaration counts and decoded JSON record
counts are checked before structural validation. Legacy import counts the
occurrences and placements migration will generate before validating or
migrating that model. Exceeding these budgets returns ``422 model_limit``;
candidate validation reports the same diagnostic in its 200 response.
Parsing, validation and query processing use snapshot workers, so this work
does not hold the catalog lock or serialize unrelated model preparation.
Import accepts schema-1 JSON through the shared explicit migration adapter,
as well as schema-2 native JSON. Source import uses the shared language parser
and its supported migrations. Export and native JSON replacement use schema 2.
Only documented query parameters are accepted. In particular, appending
``?revision=...`` to model/source export is an error, not historical retrieval.
Queries and pagination
----------------------
List filters combine using AND. Enum spelling is case-sensitive and comes
from the shared schema: examples include ``kind=Activity`` and ``layer=Oa``.
Aliases match exactly; ``q`` is a Unicode-lowercase substring match on the
display name. Empty or invalid enum values are request errors.
Lists are ordered by UUID. ``limit`` defaults to 100 and accepts 1 through
1000. ``after`` is an exclusive last UUID. ``next_after`` is null at the end.
Project-scoped lists return a revision. Include that revision on following
pages to detect a changed model; 409 ``snapshot_changed`` means restart the
query. Supplying a past revision does not retrieve history. The project catalog
is a live list and does not have a multi-page snapshot guarantee.
A neighborhood request is::
{
"roots": ["1b37b9d7-9a95-4a51-8707-010878a82419"],
"direction": "both",
"relation_kinds": ["Allocation", "Interaction"],
"max_depth": 2,
"max_objects": 200,
"revision": 3
}
Roots may identify elements or relations. The service traverses relation
source/target adjacency in the selected direction (incoming/outgoing/both),
preserves distinct parallel relations, and returns ``elements``, ``relations``,
``revision`` and ``truncated``. Empty kind filters permit all relation kinds.
Every returned relation includes its endpoint closure, including the endpoints
of a referenced relation. Closure records count against the object bound but
do not add traversal depth. Model ownership, process occurrence order and
non-endpoint references remain available in the returned records and complete
model; they are not silently treated as additional graph edges.
Use 1–100 roots, depth 0–4, and 1–1000 total returned objects. The cap must fit
the roots and their endpoint closure. A root closure that cannot fit is an
error; further omitted edges set ``truncated: true``. A missing root is 422.
Deterministic UUID iteration makes repeated queries of one snapshot stable.
Transactions
------------
The ``commands`` array contains the shared externally tagged Serde command
representation. It is not RFC 6902 JSON Patch. For example::
{
"commands": [
{"Rename": ["1b37b9d7-9a95-4a51-8707-010878a82419", "Assess assistance"]},
{"Describe": ["1b37b9d7-9a95-4a51-8707-010878a82419", "Review the request."]}
],
"dry_run": true
}
One-field variants use ``{"Delete":"uuid"}``; tuple variants use arrays;
named-field variants use objects. For a new typed OA activity::
{
"CreateElement": {
"id": "1b37b9d7-9a95-4a51-8707-010878a82419",
"alias": "assess",
"name": "Assess assistance",
"description": "Review the request.",
"parent": null,
"body": {"Oa": "Activity"}
}
}
``CreateArtifact``/``EditArtifact`` and ``CreateTrace``/``EditTrace`` use the same
transaction boundary as engineering edits. Artifact URI, revision and fragment
strings are opaque references. No URI is fetched or verified by the service.
Model references and alias uniqueness are checked by the core.
At most 200 commands are allowed, counting nested Batch wrappers. Explicit
creation identities allow later commands in the batch to reference earlier
creations. The shared ``execute_batch`` applies all operations to one candidate
and validates the final state. A rejected operation or final structural error
rejects the whole request. Reference rewrites/deletion cleanup follow the same
core logic as desktop editing.
Dry run still requires ``If-Match``. Its response includes ``revision``,
``dry_run``, ``changed``, ``issues`` and the proposed ``model``. It neither writes
nor reserves IDs. A committed response has the same fields except the model is
omitted. Commit must check the revision again. A no-op is successful with
``changed: false`` and the original ETag.
Contextual process and chain topology
-------------------------------------
Operational processes and system functional chains can combine work
contributions, exchange contributions, explicit controls and references to
reusable sequences. Each contribution is an ordinary ``Occurrence`` element
owned directly by the process/chain, with its stable ID in that owner's
``steps`` list. ``OccurrenceBody`` includes, for example::
{"Action":{"action":"<work UUID>","lifeline":null}}
{"Control":{"kind":"Choice"}}
{"SequenceReference":{"sequence":"<process or chain UUID>"}}
``ControlKind`` is ``Choice``, ``Merge``, ``Fork``, ``Join`` or ``Loop``.
``RelationBody.SequenceLink`` connects contribution IDs in one owner and
contains ``source``, ``target`` and a string ``guard``. Conditions belong to
choice/loop paths; an explicit ``else`` guard can describe the other path.
The readable order of the ``steps`` list remains persistent, while links
express the explicit alternative, parallel and loop topology. The core checks
owner context, work/exchange endpoint agreement and recursive sequence reuse;
engineering diagnostics identify incomplete branch cardinality or paths.
Old exchange-only sequences without explicit links retain their linear meaning.
These records use the same create/edit transaction commands and source/model
replacement routes as other engineering records. For example,
``GET /api/v1/projects/{id}/relations?kind=SequenceLink`` queries the links.
The source representation uses ``sequence @alias`` references. The service
does not execute conditions or simulate a process.
Typed scenarios and message values
----------------------------------
Scenario bodies store an explicit ``viewpoint``. Occurrence Exchange bodies
store ``message_kind``, optional correlated-call ``reply_to`` and contextual
``values``. Message kinds are Asynchronous, Call, Reply, Create, Delete, or
``{"Timer":{"expression":"after 5 s"}}``. Each value record contains a
carried DataField UUID in ``field`` and its textual ``expression``; expressions
do not change the shared exchange item's type or evaluate server-side.
``ScenarioUse`` contains a referenced ``scenario`` and one-to-one lifeline
``bindings`` records with ``referenced`` and ``local`` UUIDs. The core validates
viewpoint/layer compatibility, call/reply order and reversal, lifetime order,
carried fields, binding identity and recursive reuse through the same candidate
boundary used by the desktop. The normative details are in ``language.rst``.
Existing schema-2 files may omit the new fields: missing viewpoint maps to
MixedLegacy and missing message fields to Asynchronous, null and []. Source
exports make those compatibility defaults explicit. This preserves original V2
models while the release schema is being integrated; it does not silently
reinterpret old mixed lifelines as a strict new viewpoint.
Validation
----------
GET returns current-model diagnostics. POST accepts either::
{"format":"json", "model": {"...":"complete native Project record"}}
or::
{"format":"arcadia", "source":"complete source document"}
A well-formed validation request returns 200 with ``valid`` and ``issues`` even
if its candidate is invalid. A malformed request envelope or JSON model record
is a 400. Source diagnostics include one-based line and column according to the
shared language parser. Candidate validation does not replace current state.
Typed state machines and events
-------------------------------
OA and SA Event records use the same ``SharedBody::Event`` and ``EventBody``
contract as source and graphical editing. Signal carries same-layer item
references; Time specifies After/At and an expression; Change specifies a
condition expression. State vertices include Choice, Junction, Fork, Join,
ShallowHistory, DeepHistory, EntryPoint, ExitPoint and Terminate, as well as
State, Mode, Initial and Final. Query these through the ordinary ``kind``
filters. No timer or executable state-machine service is implied.
StateTransition keeps ``trigger``, ``guard`` and ``effect`` prose and adds
``transition_kind`` (External/Local/Internal), ``triggers`` (Event or work UUIDs)
and ``effects`` (work UUIDs). The reference lists use UUIDs in JSON and aliases
in source. Missing new properties in staged schema-2 input hydrate as
External/[]/[] without changing prior text. These defaults are compatibility
behavior pending the distinct release schema, not a versionless expansion of
every future input contract.
Use one ordinary transaction to create an event and edit its referring
transition. Reidentification updates references, and deletion prunes signal
items and effect references. Removing the last typed trigger with no prior
trigger prose leaves a descriptive replacement reminder; it does not silently
introduce a completion transition. Invalid typed references reject the whole
candidate and preserve revision/ETag. All writes retain the same conditional
commit and disk persistence contract as other semantic records.
Cross-layer transitions
-----------------------
Preview accepts the shared ``TransitionRequest`` record, including direction
(``OaToSa`` or ``SaToOa``), sources, dependency scope, mappings, selected fields,
conflict resolutions and optional destination diagram. All fields are explicit
in OpenAPI. At most 100 sources, 200 mappings and 400 field resolutions are
accepted. A conflict-free plan must fit the same 200-command transaction limit
and model-capacity limits.
The preview response is ``{"base_revision":1,"plan":{...}}``. It contains
planned changes, conflicts, warnings and exact commands/IDs. It does not write
the model or persist a server-side plan. Apply accepts that entire response and
requires the original ETag in ``If-Match``. It checks both base_revision and the
core's snapshot fingerprint before executing the shared transition validator.
Stale revisions fail with 412 and unresolved conflicts with 422. Successful
apply increments the revision once, preserving the planned identities.
A supplied plan is a client-owned command proposal. It is not cryptographically
authenticated as an untouched server preview; the same authenticated client
can submit ordinary typed commands. The core fingerprint is a change detector,
not a security digest. There is no plan token, expiration store or receipt.
Error contract
--------------
All errors have ``Content-Type: application/problem+json``. Example::
{
"type":"urn:arcadia:problem:revision_conflict",
"title":"Precondition Failed",
"status":412,
"code":"revision_conflict",
"detail":"Project changed. Reload and review the current model before retrying.",
"current_revision":3
}
``issues`` contain severity, code and message, and may include field,
object_id, line and column. Use
``code`` for client decisions, not the English message. ``X-Request-ID`` is a
response correlation UUID. This is not an idempotency key or receipt address.
* 400: malformed JSON/envelope/query/UUID or unsupported ETag form.
* 401: missing or incorrect configured bearer token; includes WWW-Authenticate.
* 403: browser Origin is unsupported, or unauthenticated Host is not loopback.
* 404: missing project or route.
* 405: unsupported HTTP method.
* 409: requested query revision changed or revision counter exhausted.
* 412: stale write precondition.
* 413: body or serialized model exceeds size limit.
* 415: unsupported Content-Type or Content-Encoding.
* 422: rejected source/model/command, model count limit, or missing graph root.
* 428: missing If-Match.
* 503: work slots full or filesystem/storage unavailable; Retry-After is present.
* 504: request deadline; an admitted write outcome may be unknown.
* 507: fixed store cap of 128 models or 256 MiB serialized envelopes reached.
* 500: unexpected server/worker failure.
Deployment and persistence limitations are documented in ``server.md``.