Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
4136f66
chore(release): sync beta back into development
github-actions[bot] Aug 31, 2026
1fc9ef7
fix(composer): declare ext-xsl so dependabot can resolve (#3201)
rubenvdlinde Aug 31, 2026
fa6b38a
chore(release): sync main back into development
github-actions[bot] Aug 31, 2026
34f1905
Merge pull request #3210 from ConductionNL/sync/main-to-development-2…
rubenvdlinde Aug 31, 2026
07f2713
Merge pull request #3203 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Aug 31, 2026
8fa9618
chore(deps): take @conduction/nextcloud-vue 2.27.2 (#3214)
rubenvdlinde Aug 31, 2026
36809e1
chore(deps): bump zod from 4.4.3 to 4.5.2 (#3206)
dependabot[bot] Aug 31, 2026
df087fb
chore(deps): bump marked from 12.0.2 to 18.0.11 (#3207)
dependabot[bot] Aug 31, 2026
9c1d3a2
chore(sync): carry beta back into development
github-actions[bot] Aug 31, 2026
c6cb8e0
Merge pull request #3222 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Aug 31, 2026
e27bde1
docs(license): state the apexcharts licence accurately in the overrid…
rubenvdlinde Aug 31, 2026
40da9a4
chore(release): 2.0.9-unstable.20260831133308 (#3225)
github-actions[bot] Aug 31, 2026
b1f17ad
chore(release): sync main back into development
github-actions[bot] Aug 31, 2026
0485aea
chore(sync): carry beta back into development
github-actions[bot] Aug 31, 2026
10a4525
Merge pull request #3229 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Aug 31, 2026
e6acacc
fix(deps): make the npm overrides follow their direct dependency (#3232)
rubenvdlinde Aug 31, 2026
b957cae
fix(db): bind catch(Exception) to a class that exists, and drop dead …
rubenvdlinde Aug 31, 2026
015a254
Merge pull request #3227 from ConductionNL/sync/main-to-development-2…
rubenvdlinde Aug 31, 2026
07b58b0
fix(db): remove an impossible lastInsertId fallback and a duplicate g…
rubenvdlinde Aug 31, 2026
f26b368
fix(archival): call a mapper method that exists, and correct a @throw…
rubenvdlinde Aug 31, 2026
5c5a734
docs(license): correct the apexcharts MIT boundary and record the OEM…
rubenvdlinde Aug 31, 2026
290b35d
fix(chat): send temperature through modelOptions, where LLPhant reads…
rubenvdlinde Aug 31, 2026
99aaccc
docs(cache): declare the warmup_breakdown key the stats array actuall…
rubenvdlinde Aug 31, 2026
ce8b4f4
chore(release): 2.0.11-unstable.20260831184325 (#3246)
github-actions[bot] Aug 31, 2026
e10e5bc
feat(schemas): let an app retire a schema from its descriptor (#3248)
rubenvdlinde Aug 31, 2026
842ba50
feat(organisation): carry the four chain-partner fields it lacked (#3…
rubenvdlinde Aug 31, 2026
67cc872
spec(flow-portal-task): a portal-task node that asks a party outside …
rubenvdlinde Sep 1, 2026
37dd618
chore(n8n): retire the n8n register descriptor (#3251)
rubenvdlinde Sep 1, 2026
72fa00a
spec(flow-runs-subject-scope): the case page's view of the engine (#3…
rubenvdlinde Sep 1, 2026
6fc19be
chore(release): 2.0.12-unstable.20260901050305 (#3256)
github-actions[bot] Sep 1, 2026
9ef9ff8
feat(flow): a case page's view of the engine, scoped to one subject (…
rubenvdlinde Sep 1, 2026
5e0df04
feat(flow): send-notification, send-email and send-talk-message nodes…
rubenvdlinde Sep 1, 2026
b42da68
chore(deps): nextcloud-vue 2.28.0, and an npm override that resolves …
rubenvdlinde Sep 1, 2026
40bab56
fix(controllers): name the register before the schema
rubenvdlinde Sep 1, 2026
293736f
chore(lint): let the linter see tests/ and scripts/ (#3265)
rubenvdlinde Sep 1, 2026
d99e3bc
Merge pull request #3266 from ConductionNL/fix/resolve-register-befor…
rubenvdlinde Sep 1, 2026
ddbbeba
feat(flow): the task entity — a suspension becomes a queryable row (#…
rubenvdlinde Sep 1, 2026
6e2e2af
feat(flow): parallel streams — independent branches of one run advanc…
rubenvdlinde Sep 1, 2026
63da91d
fix(controllers): two more inverted call sites, and a guard that can …
rubenvdlinde Sep 1, 2026
6a48669
Merge pull request #3277 from ConductionNL/fix/register-order-any-rec…
rubenvdlinde Sep 1, 2026
90a37fe
feat(flow): the openregister.user-task node puts a person into the gr…
rubenvdlinde Sep 1, 2026
cfad0da
feat(router): move openregister off hash routing, and stop the catch-…
rubenvdlinde Sep 1, 2026
985d351
feat(flow): task inbox projections, notifications you can answer, a V…
rubenvdlinde Sep 1, 2026
a099d56
feat(flow): the case layer — CMMN semantics as rows on the object (fl…
rubenvdlinde Sep 1, 2026
ca4f2e6
chore(sync): carry beta back into development
github-actions[bot] Sep 1, 2026
2fffbe9
Merge pull request #3294 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Sep 1, 2026
f9c4b10
feat(flow): the portal-task node, the external performer type and the…
rubenvdlinde Sep 1, 2026
562724a
feat(flow): task forms, the fields a user task's completion supplies …
rubenvdlinde Sep 1, 2026
9e6bb06
fix(flow): imported flows fire (id/slug seam) and can be adopted (#3285)
rubenvdlinde Sep 1, 2026
7a12cf6
feat(flow): durable business timers, one clock for SLA, opschorting a…
rubenvdlinde Sep 1, 2026
44843c6
fix(e2e): give occ a maxBuffer so the worker scenarios stop self-skip…
rubenvdlinde Sep 1, 2026
027ed41
fix(e2e): follow the router off hash routing in the three specs that …
rubenvdlinde Sep 1, 2026
d075694
build(guard): fail the build when two Dexie versions ship in one chun…
rubenvdlinde Sep 1, 2026
82ed322
feat(approval): consolidate the approval engine onto ordered task seq…
rubenvdlinde Sep 1, 2026
14bd30f
fix(flow): resume reads the live subject, routed items reach their br…
rubenvdlinde Sep 1, 2026
9b32ca0
chore(release): 2.0.14-unstable.20260901212512 (#3314)
rubenvdlinde Sep 1, 2026
cfa9647
fix(e2e): repair the two specs history routing broke on development (…
rubenvdlinde Sep 1, 2026
865d212
feat(tasks): wire the fleet task inbox into the UI (#3315)
rubenvdlinde Sep 2, 2026
eeedb7b
fix(flow): a resume answers only the node whose slot it answers, and …
rubenvdlinde Sep 2, 2026
81e3dd1
fix(flow): the await-signal answer lands in the item's record, not be…
rubenvdlinde Sep 2, 2026
d1594cc
feat(flow): a decision-table node puts rule evaluation into the graph…
rubenvdlinde Sep 2, 2026
24a7516
feat(flow): the engine owns the two seams every consumer was rebuildi…
rubenvdlinde Sep 2, 2026
2839ab9
fix(search): count only the chunk owners the caller can actually see …
rubenvdlinde Sep 2, 2026
17a4478
test(e2e): the VTODO deep link serves the shell, it no longer redirec…
rubenvdlinde Sep 2, 2026
2c23de6
fix(tenant): follow the merge before the UUID becomes a scope (#3336)
rubenvdlinde Sep 2, 2026
246222d
feat(tasks): task expiry enforcement and configurable timeout/reject …
rubenvdlinde Sep 2, 2026
501136a
Takes nextcloud-vue 2.31.1 so a hovered KPI tile stops drawing a card…
rubenvdlinde Sep 2, 2026
8783ce6
fix(federation): a federated create may not address an existing object
Sep 3, 2026
2740ada
style(dsar): drop the else phpmd flagged
Sep 3, 2026
709a855
docs(federation): the @spec tag gate-16 asked for
Sep 3, 2026
85e8321
Merge pull request #3345 from ConductionNL/fix/federated-create-canno…
rubenvdlinde Sep 3, 2026
63ad6ff
feat(quality): the quality assessment is @self metadata, not object data
Sep 3, 2026
1eb6823
Merge pull request #3348 from ConductionNL/feat/quality-is-self-metadata
rubenvdlinde Sep 3, 2026
4309cec
feat(flow): a user task arms its own deadline (#3350)
rubenvdlinde Sep 3, 2026
7b576fb
fix(tests): three extraction tests asserted nothing and could not fai…
rubenvdlinde Sep 3, 2026
2accc47
fix: two silent setters, and the warnings that were pointing at them …
rubenvdlinde Sep 3, 2026
afb1f00
feat(organisations): adopt a leaf app's organisations without losing …
rubenvdlinde Sep 3, 2026
6e8bc8f
feat(files): a publication window on the file, so an attachment needs…
rubenvdlinde Sep 3, 2026
925c204
fix(flow): the heartbeat recovers a missed signal instead of rolling …
rubenvdlinde Sep 3, 2026
f3f4abc
feat(tasks): find the newest sequence for a template, across every an…
rubenvdlinde Sep 3, 2026
b8eb72e
test(flow): cover the heartbeat recovery paths that no test executed …
rubenvdlinde Sep 3, 2026
8781660
feat(organisations): project the organisation as an object so a $ref …
rubenvdlinde Sep 3, 2026
0961e89
fix(deferral): register the shutdown flush through a closure, and tes…
rubenvdlinde Sep 3, 2026
c130aa2
fix(nav): let users reach Personal settings again (#3367)
rubenvdlinde Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .license-overrides.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"@fortawesome/free-solid-svg-icons": "License is (CC-BY-4.0 AND MIT) — both are approved open-source licenses, compound AND expression not parsed by checker",
"smalot/pdfparser": "License is LGPL-3.0 — equivalent to LGPL-3.0-only which is on the allowlist, SPDX identifier variation not recognized by checker",
"apexcharts": "License is MIT — license-checker misreads logo URL as custom license, see https://github.com/apexcharts/apexcharts.js/blob/main/LICENSE",
"apexcharts": "NOT MIT. The last MIT release is 5.0.0 -- 5.1.0 onward is the ApexCharts dual-license (Community free only below USD 2M annual revenue; sublicensing under different terms not permitted). This app declares ^7.0.0. Conduction confirmed 2026-08-31 it is below USD 2M, so it qualifies for the Community tier. 🔴 UNRESOLVED: an OEM/Redistribution licence is separately required when embedding ApexCharts in a product used by other people, and is only waived for STATIC charts users cannot interact with -- RegisterDetail.vue and SchemaDetails.vue both set toolbar.show and zoom.enabled, and this app ships to third parties via the Nextcloud App Store. Escalated to the maintainers; do not read this override as a clearance for redistribution.",
"dompdf/dompdf": "License is LGPL-2.1 — equivalent to LGPL-2.1-or-later which is on the allowlist; configured hermetically (isRemoteEnabled=false / isPhpEnabled=false) at the single instantiation site PdfReportWriter:69"
}
56 changes: 55 additions & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Open Register drijft apps zoals OpenCatalogi, Procest, Pipelinq en Software Cata

Vrij en open source onder de EUPL-licentie.
]]></description>
<version>2.0.12</version>
<version>2.0.14-unstable.20260901212512</version>
<licence>EUPL-1.2</licence>
<author mail="info@conduction.nl" homepage="https://www.conduction.nl/">Conduction</author>
<namespace>OpenRegister</namespace>
Expand Down Expand Up @@ -142,9 +142,11 @@ Vrij en open source onder de EUPL-licentie.
<job>OCA\OpenRegister\BackgroundJob\DsarRetentionSweepJob</job>
<job>OCA\OpenRegister\BackgroundJob\ReportRenderJob</job>
<job>OCA\OpenRegister\BackgroundJob\NotificationQueueFlushJob</job>
<job>OCA\OpenRegister\BackgroundJob\TaskScheduledNotificationJob</job>
<job>OCA\OpenRegister\BackgroundJob\ArchivalRetentionTask</job>
<job>OCA\OpenRegister\BackgroundJob\FlowRunWorker</job>
<job>OCA\OpenRegister\BackgroundJob\FlowScheduleWorker</job>
<job>OCA\OpenRegister\BackgroundJob\FlowTimerWorker</job>
<job>OCA\OpenRegister\BackgroundJob\HandoffQueueDrainJob</job>
<job>OCA\OpenRegister\BackgroundJob\TemporalCalculationSweepJob</job>
<job>OCA\OpenRegister\BackgroundJob\DsarDpiaDetectionJob</job>
Expand Down Expand Up @@ -240,6 +242,42 @@ Vrij en open source onder de EUPL-licentie.
Post-migration, because it needs the flow_* columns the schema
migration adds. -->
<step>OCA\OpenRegister\Repair\RechainAuditTrailForFlowAttribution</step>
<!-- Task fixtures (flow-task-entity, ADR-001): the five seed
groups from the change's design.md, idempotent on uuid.
OPT-IN: runs only when app config openregister/seed_demo_tasks
is true, so a production instance never receives demo rows;
a demo instance and the test environment switch it on.
Post-migration because the step needs the openregister_tasks
tables its own change's migration creates. -->
<step>OCA\OpenRegister\Repair\SeedTaskFixtures</step>
<!-- Business timers (flow-business-timers, ADR-001): the flow-timers
register with its working-calendar and escalation-ladder schemas
and seeded defaults (nl-national, nl-termijn-default), idempotent
with force: false so administrator edits survive. Then the
invariant check, which COUNTS orphaned or inconsistent timers and
reports them rather than cancelling them. Post-migration because
both need the openregister_flow_timers tables. -->
<step>OCA\OpenRegister\Repair\SeedFlowTimerRegister</step>
<step>OCA\OpenRegister\Repair\CheckFlowTimerInvariants</step>
<!-- Approval consolidation (flow-approval-consolidation): moves
every approval chain, step set and in-flight decision onto
task sequences, verifies the reconciliation and FAILS LOUDLY
on any mismatch. Idempotent on the reconciliation columns.
Post-migration because it needs openregister_task_sequences
and the sequence columns on openregister_tasks. The legacy
tables are kept; rollback is the
openregister:approval:rollback-to-steps command. -->
<step>OCA\OpenRegister\Repair\MigrateApprovalChainsToTasks</step>
<step>OCA\OpenRegister\Repair\SeedCaseFixtures</step>
<!-- Business timers (flow-business-timers, ADR-001): the flow-timers
register with its working-calendar and escalation-ladder schemas
and seeded defaults (nl-national, nl-termijn-default), idempotent
with force: false so administrator edits survive. Then the
invariant check, which COUNTS orphaned or inconsistent timers and
reports them rather than cancelling them. Post-migration because
both need the openregister_flow_timers tables. -->
<step>OCA\OpenRegister\Repair\SeedFlowTimerRegister</step>
<step>OCA\OpenRegister\Repair\CheckFlowTimerInvariants</step>
</post-migration>
<install>
<step>OCA\OpenRegister\Repair\ReconcileDeclaredBackgroundJobs</step>
Expand Down Expand Up @@ -281,6 +319,7 @@ Vrij en open source onder de EUPL-licentie.
<step>OCA\OpenRegister\Repair\SeedVocabularyRegister</step>
<step>OCA\OpenRegister\Repair\RegisterOpenRegisterWithDoriath</step>
<step>OCA\OpenRegister\Repair\SeedZgwZakenMigrationPack</step>
<step>OCA\OpenRegister\Repair\SeedFlowTimerRegister</step>
</install>
</repair-steps>

Expand All @@ -295,6 +334,9 @@ Vrij en open source onder de EUPL-licentie.
<!-- App-rename repair: re-points registers and schemas at a new owning
app id. Only a DB connection, so the DI graph stays light. -->
<command>OCA\OpenRegister\Command\MigrateSchemaApplicationCommand</command>
<!-- The approval consolidation's reverse repair: an operator-run
rollback tool, deliberately NOT a repair step. -->
<command>OCA\OpenRegister\Command\RollbackApprovalMigrationCommand</command>
<command>OCA\OpenRegister\Command\RechainAuditTrailCommand</command>
<!-- Read-only report: which RBAC groups this instance declares, and whether
anyone belongs to them. Provisioning guarantees a declared group EXISTS;
Expand All @@ -310,6 +352,8 @@ Vrij en open source onder de EUPL-licentie.
<!-- field-level-object-encryption: encrypt existing plaintext values of a newly-flagged property. -->
<command>OCA\OpenRegister\Command\EncryptFieldCommand</command>
<command>OCA\OpenRegister\Command\DedupeRegistersCommand</command>
<command>OCA\OpenRegister\Command\AdoptLeafOrganisationsCommand</command>
<command>OCA\OpenRegister\Command\PruneRetiredSchemasCommand</command>
<command>OCA\OpenRegister\Command\RelinkRegisterSchemasCommand</command>
<command>OCA\OpenRegister\Command\ReconcileMagicTablesCommand</command>
<command>OCA\OpenRegister\Command\DedupeConfigurationsCommand</command>
Expand Down Expand Up @@ -363,4 +407,14 @@ Vrij en open source onder de EUPL-licentie.
<contactsmenu>
<provider>OCA\OpenRegister\Contacts\ContactsMenuProvider</provider>
</contactsmenu>
<!-- The in-band write-back hook for projected task VTODOs
(flow-task-inbox-projections, design D-6). apps/dav's PluginManager
loads it into the Sabre server; it acts only on VTODOs carrying
X-OPENREGISTER-TASK and refuses an unauthorized edit with a DAV 403
before the client records it. -->
<sabre>
<plugins>
<plugin>OCA\OpenRegister\Dav\TaskVtodoWriteBackPlugin</plugin>
</plugins>
</sabre>
</info>
106 changes: 96 additions & 10 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@
// The VERSION number is `\d+`, not `[^/]+`. Without that,
// `/versions/publish` would match `version` with the literal string
// "publish" and return a 404 for a route that exists.
// Adoption: the CALLER becomes the owner of a shipped, ownerless flow.
// A deliberate act with its own verb — `owner` is not an editable field
// on PUT, so this is the only path from imported to dispatchable.
['name' => 'flow#adopt', 'url' => '/api/flows/{id}/adopt', 'verb' => 'POST', 'requirements' => ['id' => '[^/]+']],
['name' => 'flow#versions', 'url' => '/api/flows/{id}/versions', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']],
['name' => 'flow#version', 'url' => '/api/flows/{id}/versions/{version}', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+', 'version' => '\d+']],
['name' => 'flow#publish', 'url' => '/api/flows/{id}/publish', 'verb' => 'POST', 'requirements' => ['id' => '[^/]+']],
Expand Down Expand Up @@ -1253,16 +1257,6 @@
['name' => 'scheduledWorkflow#update', 'url' => '/api/scheduled-workflows/{id}', 'verb' => 'PUT', 'requirements' => ['id' => '\d+']],
['name' => 'scheduledWorkflow#destroy', 'url' => '/api/scheduled-workflows/{id}', 'verb' => 'DELETE', 'requirements' => ['id' => '\d+']],

// Approval Chains - multi-step approval definitions and per-object progress.
['name' => 'approval#index', 'url' => '/api/approval-chains', 'verb' => 'GET'],
['name' => 'approval#show', 'url' => '/api/approval-chains/{id}', 'verb' => 'GET', 'requirements' => ['id' => '\d+']],
['name' => 'approval#create', 'url' => '/api/approval-chains', 'verb' => 'POST'],
['name' => 'approval#update', 'url' => '/api/approval-chains/{id}', 'verb' => 'PUT', 'requirements' => ['id' => '\d+']],
['name' => 'approval#destroy', 'url' => '/api/approval-chains/{id}', 'verb' => 'DELETE', 'requirements' => ['id' => '\d+']],
['name' => 'approval#objects', 'url' => '/api/approval-chains/{id}/objects', 'verb' => 'GET', 'requirements' => ['id' => '\d+']],
['name' => 'approval#steps', 'url' => '/api/approval-steps', 'verb' => 'GET'],
['name' => 'approval#approve', 'url' => '/api/approval-steps/{id}/approve', 'verb' => 'POST', 'requirements' => ['id' => '\d+']],
['name' => 'approval#reject', 'url' => '/api/approval-steps/{id}/reject', 'verb' => 'POST', 'requirements' => ['id' => '\d+']],

// MCP Discovery - Tiered API discovery for AI agents.
// CORS preflight (OPTIONS) is handled automatically by the @CORS annotation.
Expand Down Expand Up @@ -1338,12 +1332,85 @@
// resolves routes in declaration order, so a later registration would be
// answered by `show('active')` → 404 for every request.
['name' => 'flowRun#active', 'url' => '/api/flow-runs/active', 'verb' => 'GET'],
// Finished runs on ONE subject object (flow-runs-subject-scope): the case
// page's run history. `subject` is REQUIRED (400 without it) and the read is
// organisation-scoped like `active`. Same ordering rule: it MUST stay above
// the `{uuid}` route or `show('completed')` answers it with a 404.
['name' => 'flowRun#completedForSubject', 'url' => '/api/flow-runs/completed', 'verb' => 'GET'],
['name' => 'flowRun#show', 'url' => '/api/flow-runs/{uuid}', 'verb' => 'GET', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'flowRun#objects', 'url' => '/api/flow-runs/{uuid}/objects', 'verb' => 'GET', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'flowRun#retry', 'url' => '/api/flow-runs/{uuid}/retry', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'flowRun#resume', 'url' => '/api/flow-runs/{uuid}/resume', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
// Correlation-addressed signal delivery (flow-approval-consolidation):
// same authority as resume, addressed by business key instead of run
// uuid, fail-closed on zero and on more than one match. Registered on
// a literal segment so it can never shadow, or be shadowed by, the
// uuid-addressed routes.
['name' => 'flowRun#signalByKey', 'url' => '/api/flow-run-signals/{key}', 'verb' => 'POST', 'requirements' => ['key' => '[^/]+']],
// Interactive test run (or-flow-partial-run): run synchronously with optional startAt + pins + seed.
['name' => 'flowRun#test', 'url' => '/api/flow-runs/test', 'verb' => 'POST'],
// The fleet-generic task (flow-task-entity): the inbox and the
// lifecycle verbs. Named for the `flow-tasks` CAPABILITY, not for a
// flow requirement — a standalone task with run_uuid null is served
// here identically. `/api/tasks` itself belongs to the older CalDAV
// VTODO leaf (tasks#allUserTasks above), which is a different thing.
// Every verb's real authorization is TaskAuthorizationService inside
// the service; the route attribute is never the whole check.
// The one stable "open this task" address (flow-task-inbox-projections):
// the VTODO URL, the notification buttons and the rule actions all
// resolve here. It serves the SPA SHELL (history-mode router), and the
// SPA's `flow-task-detail` route (src/main.js) renders the task; the bare
// `/flow-tasks` inbox list needs no entry of its own because
// `dashboard#catchAll` below already shells every non-api sub-path.
['name' => 'task#open', 'url' => '/flow-tasks/{uuid}', 'verb' => 'GET', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#index', 'url' => '/api/flow-tasks', 'verb' => 'GET'],
['name' => 'task#create', 'url' => '/api/flow-tasks', 'verb' => 'POST'],
['name' => 'task#show', 'url' => '/api/flow-tasks/{uuid}', 'verb' => 'GET', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#audit', 'url' => '/api/flow-tasks/{uuid}/audit', 'verb' => 'GET', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#offer', 'url' => '/api/flow-tasks/{uuid}/offer', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#claim', 'url' => '/api/flow-tasks/{uuid}/claim', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#unclaim', 'url' => '/api/flow-tasks/{uuid}/unclaim', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#assign', 'url' => '/api/flow-tasks/{uuid}/assign', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#reassign', 'url' => '/api/flow-tasks/{uuid}/reassign', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#delegate', 'url' => '/api/flow-tasks/{uuid}/delegate', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#resolve', 'url' => '/api/flow-tasks/{uuid}/resolve', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#complete', 'url' => '/api/flow-tasks/{uuid}/complete', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#cancel', 'url' => '/api/flow-tasks/{uuid}/cancel', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'task#checkItem', 'url' => '/api/flow-tasks/{uuid}/checklist/{itemId}', 'verb' => 'PATCH', 'requirements' => ['uuid' => '[^/]+', 'itemId' => '[^/]+']],

// The portal seam (flow-portal-task): a party OUTSIDE the instance,
// authenticated at portaliq's edge, acts here under a signed
// X-Portal-Subject assertion, never a Nextcloud session. The subject
// routes are PublicPage by design and authorized inside the service
// against the task's STORED party reference. The delivery routes are
// the operator's (administrator): portaliq settles what it sent.
// `deliveries` is registered before `{uuid}` so the literal wins.
['name' => 'portalTask#index', 'url' => '/api/portal-tasks', 'verb' => 'GET'],
['name' => 'portalTask#deliveries', 'url' => '/api/portal-tasks/deliveries', 'verb' => 'GET'],
['name' => 'portalTask#deliveryDelivered', 'url' => '/api/portal-tasks/deliveries/{uuid}/delivered', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'portalTask#deliveryFailed', 'url' => '/api/portal-tasks/deliveries/{uuid}/failed', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'portalTask#show', 'url' => '/api/portal-tasks/{uuid}', 'verb' => 'GET', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'portalTask#complete', 'url' => '/api/portal-tasks/{uuid}/complete', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],

// The case layer (flow-cmmn-case-semantics): a plan of stages, human
// items and milestones anchored to an OpenRegister OBJECT. There is no
// case id: every plan route is keyed by the anchoring object's uuid, and
// the item verbs by the plan item's uuid. No CMMN XML route exists; the
// zaaktype import takes a document that is already in a register.
// Every verb's real authorization is CasePlanAuthorizationService
// inside the service; the route attribute is never the whole check.
// The two literal routes stay ABOVE `{objectUuid}` or they are swallowed.
['name' => 'case#items', 'url' => '/api/cases/items', 'verb' => 'GET'],
['name' => 'case#skeletonFromZaaktype', 'url' => '/api/cases/skeleton-from-zaaktype', 'verb' => 'POST'],
['name' => 'case#transition', 'url' => '/api/cases/items/{uuid}/transition', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'case#enable', 'url' => '/api/cases/items/{uuid}/enable', 'verb' => 'POST', 'requirements' => ['uuid' => '[^/]+']],
['name' => 'case#show', 'url' => '/api/cases/{objectUuid}', 'verb' => 'GET', 'requirements' => ['objectUuid' => '[^/]+']],
['name' => 'case#create', 'url' => '/api/cases/{objectUuid}', 'verb' => 'POST', 'requirements' => ['objectUuid' => '[^/]+']],
['name' => 'case#destroy', 'url' => '/api/cases/{objectUuid}', 'verb' => 'DELETE', 'requirements' => ['objectUuid' => '[^/]+']],
['name' => 'case#evaluate', 'url' => '/api/cases/{objectUuid}/evaluate', 'verb' => 'POST', 'requirements' => ['objectUuid' => '[^/]+']],
['name' => 'case#enableable', 'url' => '/api/cases/{objectUuid}/enableable', 'verb' => 'GET', 'requirements' => ['objectUuid' => '[^/]+']],
['name' => 'case#attach', 'url' => '/api/cases/{objectUuid}/items', 'verb' => 'POST', 'requirements' => ['objectUuid' => '[^/]+']],
['name' => 'case#complete', 'url' => '/api/cases/{objectUuid}/complete', 'verb' => 'POST', 'requirements' => ['objectUuid' => '[^/]+']],
// Delegation grants (or-delegation-grants): the consent surface. A grant
// store with no way to answer is a store that only ever says no, so these
// are what make every delegation refusal recoverable.
Expand All @@ -1366,5 +1433,24 @@
['name' => 'federatedConfig#publicKey', 'url' => '/api/federated-config/public-key', 'verb' => 'GET'],
['name' => 'federatedConfig#trust', 'url' => '/api/federated-config/trust', 'verb' => 'GET'],
['name' => 'federatedConfig#setTrust', 'url' => '/api/federated-config/trust', 'verb' => 'PUT'],

// SPA catch-all — MUST stay last so every explicit route above keeps
// priority over the /{path} fallback. Without it only `/` served the
// shell, so any deep link (/registers, /schemas, a detail route) never
// reached the SPA at all — the #133 regression that forced this app back
// onto hash routing. Spelled inline rather than via
// \OCA\OpenRegister\AppHost\Routes::standard() because this file also
// declares a `resources` block the builder does not carry, and because
// this IS openregister — guarding a call to its own class would be odd.
// ⚠️ `(?!api/)` is load-bearing. Nextcloud's RouteParser processes the
// `routes` array BEFORE the `resources` array
// (RouteParser::parseDefaultRoutes), and Symfony matches in insertion
// order — so even as the LAST entry here this route still registers
// ahead of all nine `api/...` resource routes below. Without the
// lookahead `.+` (which matches slashes) would swallow
// GET /api/registers, /api/schemas and the rest, answering the SPA
// shell instead of JSON. The SPA never needs an `api/` path.
['name' => 'dashboard#catchAll', 'url' => '/{path}', 'verb' => 'GET',
'requirements' => ['path' => '(?!api/).+'], 'defaults' => ['path' => '']],
],
];
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@
"optimize-autoloader": true,
"sort-packages": true,
"platform": {
"php": "8.3"
"php": "8.3",
"ext-xsl": "1"
}
},
"extra": {
Expand Down
Loading
Loading