Repository navigation
Release: merge development into beta - #4715
Open
github-actions[bot] wants to merge 100 commits into
Open
github-actions[bot] wants to merge 100 commits into
github-actions[bot] wants to merge 100 commits into
Conversation
An example set seeds the records a demo needs, but a task lives in the task engine, not in a register, so no fragment could put one on its objects. A fragment may now declare tasks: a key and the task's fields (title, description, objectUuid, state, assignee, candidateGroups, priority, dueAt, kind, and completedAt and completedBy for a finished one), placeholders allowed. The check refuses an unknown field, a task without a title or object, an assignee or completer the set does not create or adopt, a state the engine does not map and a date that is not one. Install writes each task once through TaskService::import (the trusted path, so a task may be born completed), keyed example-set:<app>/<key>, records its uuid and reports a recorded task that is gone as missing. Remove deletes the tasks before the objects they are on. Assisted-by: ClaudeCode:claude-opus-5-5
…0261020094809 chore(sync): carry beta back into development
A macro bound its flow by uuid, but a flow an app ships in x-openregister-flows gets a uuid minted per installation, so no app could ship a macro. A binding may now name a flow the same schema declares: the save checks the declaration (a manual trigger is required), and a run resolves the name to the stored flow by the import's identity, name and declaring schema. Assisted-by: ClaudeCode:claude-opus-5-5
…trail (#4722) Suspending, reactivating, ending, retaining or archiving an organisation, or editing its name, description or slug, left no entry on the audit trail. Each change now writes one sealed entry keyed by the organisation's uuid in object_uuid, with the acting user: organisation.status_changed from TenantLifecycleService and organisation.updated from the organisation update endpoint. Fail-soft, like the settings and grant auditors. dossiq's organisation History tab reads them through GET /api/audit-trails?object_uuid=. Assisted-by: ClaudeCode:claude-opus-5-5
* feat(flow): a macro run's audit entry lists what it changed
The action.macro audit entry named the action, the flow and the run, but
not what the run did, so a page could not say "2 changes: term
suspended, message sent" (dossiq DqZaakAssistent) without opening the
run. The entry's context now carries `changes`: each completed step that
wrote an object, sent a message or created a task, by its own label and
kind, in run order.
Assisted-by: ClaudeCode:claude-opus-5-5
* feat(flow): name a macro's changes by the node's label
A run's log names a step by its node id ("set-term"), which is not what
a page should print. A flow node may carry a `label` written for people
("termijn opgeschort"); the changes on the action.macro audit entry use
it, and fall back to the id.
Assisted-by: ClaudeCode:claude-opus-5-5
* feat(flow): a labelled app step counts as a macro change
OpenRegister cannot tell what another app's node type does, so a
dossiq step such as suspending the term never counted as a change. A
completed step whose node carries a `label` now counts as kind `step`.
Assisted-by: ClaudeCode:claude-opus-5-5
* fix(flow): macro run changes pass phpmd and the controller test
CI on #4721: phpmd flagged the static MacroRunChanges::fromLog call in
the controller and its cyclomatic complexity of 11, and the controller
test still expected the macro audit context without `changes`. The
changes are now an instance method split into labelsOf() and
changeOf(), the resolver composes them (changesOf()), and the test
expects `changes: []`.
Assisted-by: ClaudeCode:claude-opus-5-5
) PUT/PATCH /api/organisations/{uuid} let any member rename an organisation or change its description; only a change of who holds grant_manage asked for more. Ruben decided members only read it. The update now checks isOrganisationAdmin (a Nextcloud administrator or the organisation's owner) before anything is written, and answers a member 403. The grant_manage-only guard could no longer be reached and goes. Assisted-by: ClaudeCode:claude-opus-5-5
…4724) * feat(example-sets): a fragment may declare saved views Dossiq's search page draws a saved search with a count alert, and a saved view lives in the view table, not a register. A fragment may now declare views (name, description, owner, isPublic, query, presentation, alert) for the set's own accounts: checked before anything is written, written once through ViewService::create (which validates presentation and alert), recorded, proved and deleted on remove. Tasks and views share one path: ExampleSetEngineRows holds the check and install loops, ExampleSetEngineKinds runs every kind for the installer and the remover, and a kind this OpenRegister cannot write refuses its rows instead of skipping them. The cast gains Fatma Kaya, regisseur jeugdteam (group Sociaal domein), the handler of dossiq's jeugdwet example case, and Sanne de Vries lives at Parkstraat 24, as DqContact draws her. Assisted-by: ClaudeCode:claude-opus-5-5 * fix(example-sets): keep Sanne de Vries at Lindelaan 14 portaliq's fragment writes her own cases at that address (Dakkapel Lindelaan 14), so moving her to Parkstraat 24 for the contact board would contradict them. That move waits for a decision. Assisted-by: ClaudeCode:claude-opus-5-5 * test(example-sets): declare the engine-row classes the example-set tests run Every example-set test now builds the installer and remover with the tasks and views writers, so under beStrictAboutCoverageMetadata each test that did not list them was risky and its coverage was dropped, which read as 0% on the changed files in the coverage guard. Assisted-by: ClaudeCode:claude-opus-5-5
* feat(example-sets): a fragment may declare saved views Dossiq's search page draws a saved search with a count alert, and a saved view lives in the view table, not a register. A fragment may now declare views (name, description, owner, isPublic, query, presentation, alert) for the set's own accounts: checked before anything is written, written once through ViewService::create (which validates presentation and alert), recorded, proved and deleted on remove. Tasks and views share one path: ExampleSetEngineRows holds the check and install loops, ExampleSetEngineKinds runs every kind for the installer and the remover, and a kind this OpenRegister cannot write refuses its rows instead of skipping them. The cast gains Fatma Kaya, regisseur jeugdteam (group Sociaal domein), the handler of dossiq's jeugdwet example case, and Sanne de Vries lives at Parkstraat 24, as DqContact draws her. Assisted-by: ClaudeCode:claude-opus-5-5 * fix(example-sets): keep Sanne de Vries at Lindelaan 14 portaliq's fragment writes her own cases at that address (Dakkapel Lindelaan 14), so moving her to Parkstraat 24 for the contact board would contradict them. That move waits for a decision. Assisted-by: ClaudeCode:claude-opus-5-5 * test(example-sets): declare the engine-row classes the example-set tests run Every example-set test now builds the installer and remover with the tasks and views writers, so under beStrictAboutCoverageMetadata each test that did not list them was risky and its coverage was dropped, which read as 0% on the changed files in the coverage guard. Assisted-by: ClaudeCode:claude-opus-5-5 * feat(example-sets): Pieter Jansen joins the Zuiddrecht cast Dossiq's boards draw the cases list as Pieter Jansen, a handler in Vergunningen, and its saved-view boards open the row menu of a view he owns. A fragment may only give a view to an account the set creates or adopts, so he joins the cast with the account id `pieter`, the one the dossiq examples already name as a participant. Assisted-by: ClaudeCode:claude-opus-5-5
…#4737) Spec-only change object-actions-declared-and-run. A declared action (x-openregister-action) gains inputs as JSON Schema, a precondition, surfaces and one body (transition, flow or inline steps lowered to the flow engine). One list endpoint per object merges declared actions with lifecycle transitions; one run path validates inputs, checks the right and runs sync or async; every run writes one action.run audit entry. Includes the migration path for dossiq, pipelinq and learniq verbs and six open questions with recommendations. Assisted-by: ClaudeCode:claude-opus-5-5
…nd one body Generalises the macro binding into ObjectActionDefinition (tasks 1.1-1.5): label, icon, surfaces, inputs (JSON Schema), when (JSONLogic), confirm, mode, next, elevate and exactly one body (transition, flow or steps). A named flow is a body on its own; macro: true stays accepted. Schema save refuses two bodies, an undeclared transition, non-object inputs, invalid JSONLogic, unknown surfaces, bulk with @object defaults, async transitions, async writeOnly inputs, wildcard or ungranted elevate, and elevate saved by a non-administrator. Register-level actions are inherited at read time; a schema entry replaces the inherited one whole and an inherited entry never elevates. Assisted-by: ClaudeCode:claude-opus-5-5
…engine
Tasks 2.4 and the run-context half of 2.3. FlowDefinitionBuilder::lowerSteps()
turns an action's steps into a straight line: manual trigger, the new
openregister.action-inputs step, the steps, an end node carrying next.
ObjectActionStepsFlow stores that document once per content hash as an
inert system flow (disabled, ownerless) and publishes it, so a steps run
is an ordinary run readable at /api/flow-runs/{uuid}.
Schema save refuses a step whose node is unknown, whose config the node
refuses, or that branches, waits or bounds the flow, and says to bind a
flow instead. writeOnly inputs reach the steps through a request-scoped
holder and never enter the stored run context.
Assisted-by: ClaudeCode:claude-opus-5-5
Tasks 2.1-2.3, 2.5, 2.8, 2.9 and 4.1.
- GET /api/objects/{register}/{schema}/{id}/actions lists the runnable
declared actions the caller holds the right to (inherited ones too)
and every lifecycle transition, each with availability and reason;
a transition a declared action names is listed once under its key.
- GET /api/object-actions/{register}/{schema} lists the bulk-surface
actions, right checked at schema level.
- POST .../actions/{action} takes {inputs}: 404 unknown, 403 no right,
409 action-precondition-unmet, 422 invalid inputs (per field) or a
refusing body. transition goes through TransitionEngine::transition(),
flow through FlowService::run(), steps through the new
FlowService::runForAction(). Async answers 202 queued, a suspended sync
run 202 suspended.
- A selection only runs actions offered on bulk.
- Every run writes one action.run audit entry with the inputs digest;
writeOnly inputs are left out of the digest and the stored context.
- available-actions keeps its shape and gains a Deprecation header and
a Link to the new list.
Assisted-by: ClaudeCode:claude-opus-5-5
…bject nodes
Tasks 3.1 and 3.2. openregister.transition takes {action, data?, object?}
and moves the item's object through TransitionEngine::transition() as the
run's identity; a refused move fails the step with the engine's message.
openregister.link-object either creates an object from {register,
schema, data} and writes its uuid into {relation} on the item's object
(appended to a list), or runs the item schema's declared
x-openregister-handoff through HandoffService. An absent implementer
fails the step with not-available instead of succeeding silently.
Both declare their BPMN kind and palette category.
Assisted-by: ClaudeCode:claude-opus-5-5
… action.macro
Task 4.2. GET /api/objects/{register}/{schema}/{id}/actions/history lists
the object's action.run entries and the older action.macro entries as one
kind, newest first, each with its run link, its changes and its outcome.
The caller needs read on the object. Older macro entries are read as they
were written; the hash chain forbids rewriting them.
Assisted-by: ClaudeCode:claude-opus-5-5
…un-action bulk job
Task 2.6. POST /api/object-actions/{register}/{schema}/{action} with more
than 100 ids now answers 202 with a previewed bulk job of the new bulk
action openregister:run-action and the link to commit it, instead of a
400. The preview asks each member the run's own checks (action, right,
when, inputs) through ObjectActionRunner::check(); the commit runs the
action as the person who started the job.
Assisted-by: ClaudeCode:claude-opus-5-5
…tor alone The object action validator already asks the macro validator, so the mapper needs one optional collaborator, not two; this keeps its constructor at nine parameters (phpmd ExcessiveParameterList). Without a validator wired the shape refusals of both still fire, and the save warns when runnable actions were saved unverified. Assisted-by: ClaudeCode:claude-opus-5-5
…ions Psalm NullableReturnStatement: Register::getConfiguration() may be null. Assisted-by: ClaudeCode:claude-opus-5-5
…ct-actions-2-steps
…ookup RecentLensLookupCallSitesTest: an internal find must say whether it is a lookup; this one reads the object only to write the relation back. Assisted-by: ClaudeCode:claude-opus-5-5
…#4739) Assisted-by: ClaudeCode:claude-opus-5-5
…oost feat(example-sets): Buurtvereniging Oost and its chair Marja Verbeek join the cast
feat(example-sets): a fragment may put parties on its objects
The export endpoint dropped every `_`-prefixed parameter as request plumbing, so `export?format=json&_ids[]=a&_ids[]=b` exported every row the caller could read. `_ids`, as a list or a comma-separated string, now narrows the search behind the export to those objects; RBAC and multitenancy still apply to each. Without `_ids` nothing changes. A list page can then export its selected rows (dossiq's case type list, "Selectie exporteren als JSON"). openspec change export-honours-selected-ids. Assisted-by: ClaudeCode:claude-opus-5-5
RecentLensLookupCallSitesTest fails on development: FlowDryRunService::dryRun read the object with _audit false as the ninth positional argument, which the scan cannot see. The call now names its arguments, so the decision is visible and the base is green again. Assisted-by: ClaudeCode:claude-opus-5-5
A fragment's view can now carry `sharedWith`: a list of { user | group,
mode } with mode read (may use) or write (may update), handed to
ViewService::create. A user share must name an account the set creates or
adopts, as an owner must; a share names exactly one target; an unknown
mode is refused. dossiq's Zuiddrecht fragment uses it for Pieter's
"Wacht op inwoner" (board DqFilterDelen: shared with Woo en informatie
and Anouk Bakker).
Assisted-by: ClaudeCode:claude-opus-5-5
…-lookup fix(flows): the dry run's object read says it is a lookup
…et-notes-and-read-states # Conflicts: # lib/Command/ExampleSetInstallCommand.php # lib/Service/ExampleSet/ExampleSetCatalogue.php # lib/Service/ExampleSet/ExampleSetEngineKinds.php # lib/Service/ExampleSet/ExampleSetInstaller.php # lib/Service/ExampleSet/ExampleSetRecord.php # lib/Service/ExampleSet/ExampleSetRemover.php # tests/Unit/Service/ExampleSet/ExampleSetInstallerTest.php # tests/Unit/Service/ExampleSet/ExampleSetTestCase.php
…-read-states feat(example-sets): notes and read states
Boards DqContact, PqKlant and PqBriefOpstellen draw her BRP first names as "Sanne Johanna"; the cast had only her given name. The cast gains `firstNames`, which her BRP row's voornamen now quotes. Her given name stays "Sanne" (the portal greets her by it) and her initials stay "S." (the case lists draw "S. de Vries"). Her birth date stays 14 March 1988: MijnGegevens, PqKlant, PqBriefOpstellen and PtGegevensPdf draw 1988, only DqContact draws 1986. Assisted-by: ClaudeCode:claude-opus-5-5
…ept-objects fix(example-sets): a later install attaches the files a kept object gained
…ion-quota-and-members feat(example-sets): a cast organisation may declare its quota and its members
…and-organisation feat(example-sets): a fragment may give a task its engine key and organisation
feat(example-sets): a saved view may declare its shares
…-first-names feat(example-sets): Sanne de Vries's first names are Sanne Johanna
LqCfPrivacyverzoek opens a data-subject request from OpenRegister's shared data-subject-requests register, which learniq reads through the objects API, and the demo instance holds none. The Zuiddrecht cast file now writes one: a parent's erasure request for a former pupil, in progress, handled by Pieter, with its statutory term still running. Assisted-by: ClaudeCode:claude-opus-5-5
…ure-request feat(example-sets): a data-subject request in the Zuiddrecht set
The archiving page (#4796) and every board-look widget since 2.72 need a current library. The one break is in the unit tests: the library's formatters now reach @nextcloud/initial-state, pure ESM that jest does not transform, so the Connections page spec mocks it the way it already mocks @nextcloud/auth. Assisted-by: ClaudeCode:claude-opus-5-5
chore(deps): @conduction/nextcloud-vue 2.72.0 to ^2.129.0
Bumps [smalot/pdfparser](https://github.com/smalot/pdfparser) from 2.13.0 to 2.13.1. - [Release notes](https://github.com/smalot/pdfparser/releases) - [Commits](smalot/pdfparser@v2.13.0...v2.13.1) --- updated-dependencies: - dependency-name: smalot/pdfparser dependency-version: 2.13.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [nextcloud/ocp](https://github.com/nextcloud-deps/ocp) from 35.0.1 to 35.0.2. - [Commits](nextcloud-deps/ocp@v35.0.1...v35.0.2) --- updated-dependencies: - dependency-name: nextcloud/ocp dependency-version: 35.0.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [marked](https://github.com/markedjs/marked) from 18.0.14 to 18.1.1. - [Release notes](https://github.com/markedjs/marked/releases) - [Commits](markedjs/marked@v18.0.14...v18.1.1) --- updated-dependencies: - dependency-name: marked dependency-version: 18.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…4729) Bumps [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom) from 30.5.1 to 30.5.2. - [Release notes](https://github.com/jestjs/jest/releases) - [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/jestjs/jest/commits/v30.5.2/packages/jest-environment-jsdom) --- updated-dependencies: - dependency-name: jest-environment-jsdom dependency-version: 30.5.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [theodo-group/llphant](https://github.com/LLPhant/LLPhant) from 1.0.6 to 1.0.7. - [Release notes](https://github.com/LLPhant/LLPhant/releases) - [Commits](LLPhant/LLPhant@1.0.6...1.0.7) --- updated-dependencies: - dependency-name: theodo-group/llphant dependency-version: 1.0.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@vue/test-utils](https://github.com/vuejs/test-utils) from 2.5.0 to 2.5.1. - [Release notes](https://github.com/vuejs/test-utils/releases) - [Commits](vuejs/test-utils@v2.5.0...v2.5.1) --- updated-dependencies: - dependency-name: "@vue/test-utils" dependency-version: 2.5.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
#4805) * feat(tasks): the task subject context carries the subject's identifier A task row's subject now carries identifier, the subject object's own human number (a case's "2026-0074"), read in the same batch as its title, so a task list can show it under the title (dossiq board DqTaken). Assisted-by: ClaudeCode:claude-opus-5-5 * fix(tasks): a single task read carries its subject context GET /api/flow-tasks/{uuid} and the verb responses built the row with no subject; they now use TaskInboxService::enrich, the inbox row with its subject, so a task page can name its case (dossiq DqTaak "bij zaak 2026-0074"). Assisted-by: ClaudeCode:claude-opus-5-5
…bjects (#4800) * feat(organisations): an organisation quota limits its users and its objects dossiq's DqTenant draws "Zaken 1.240 van 5.000" and "Gebruikers 24 van 50". An organisation gains userQuota, objectQuota and objectQuotaSchema (the slug of the schema the object quota counts; none counts every schema), nullable as the other quotas. quota answers users, objects and objectsSchema; usage.objects counts the organisation's live objects of that schema, only with an object quota, null when it could not be counted. The update endpoint and example-set quotas accept them; the Zuiddrecht set gives Gemeente Waterland 50 users and 5,000 cases. Generic: OpenRegister knows no cases, the app names the schema. Assisted-by: ClaudeCode:claude-opus-5-5 * chore(organisations): move the app version so the quota migration runs on upgrade Assisted-by: ClaudeCode:claude-opus-5-5 * fix(organisations): the quota migration hands back the schema on every path check:strict: SchemaReuseHygieneTest requires every changeSchema() return to be $schema, so the shared snapshot is kept. Assisted-by: ClaudeCode:claude-opus-5-5
* feat(example-sets): a fragment may ship flows An example set could not ship a flow, so the apps' flow pages showed whatever flow was lying around (board DqFlow). A fragment's flows part declares flows of its app with their steps' places on the canvas: checked first, stored switched off and published like a shipped flow, proved on reinstall and removed with the set. FlowService::deleteStored holds the delete cascade for a caller that already decided. Assisted-by: ClaudeCode:claude-opus-5-5 * fix(flows): say why FlowService has a public method more than phpmd's ten check:strict's phpmd counted deleteStored() as the eleventh public method. It is delete()'s cascade without the caller check, for an example set removing the flow it wrote. Assisted-by: ClaudeCode:claude-opus-5-5
…lug once (#4809) dossiq's user settings listed "Mijn dagelijkse werkoverzicht" twice: the instance holds two workDigest schema rows for dossiq, an older 1.0.0 that an import left behind (in no register, no objects) and the current 1.0.1. Preferences are keyed by the slug, so the second row could only repeat the first. The list now reads one schema per owning app and slug, the highest version, then the highest id. Assisted-by: ClaudeCode:claude-opus-5-5
…#4810) A read audit entry says who opened a record; on a family or health case that is itself personal data. Administrators always see read entries; anyone else only when in a group the new setting audit.readEventsVisibleTo lists (JSON, empty by default, security relevant). ObjectHistoryForReaders drops read entries before paging and answers readEventsVisible; the admin history answers true; the readable feed leaves them out. Fails closed on a missing user, an unreadable setting or a failing group lookup. Assisted-by: ClaudeCode:claude-opus-5-5
#4811) {{view:<key>.uuid}} stands for the uuid of a saved view the same fragment declares, and a fragment's user preferences are now written after its views. The check accepts the placeholder with a stand-in. dossiq's Zuiddrecht set uses it to put Pieter's "Termijn deze week" in his menu (board DqFilterInMenu). Assisted-by: ClaudeCode:claude-opus-5-5
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated PR to sync development changes to beta for beta release.
Merging this PR will trigger the beta release workflow.