@smartkomm/plexus-cli 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +826 -2
  2. package/dist/cli.mjs +483 -0
  3. package/dist/skill/.managed-by-plexus-cli +1 -0
  4. package/dist/skill/SKILL.md +185 -0
  5. package/dist/skill/references/accounts/email-changes.md +46 -0
  6. package/dist/skill/references/applications/inspect-process-store.md +61 -0
  7. package/dist/skill/references/applications/start-a-test-application.md +66 -0
  8. package/dist/skill/references/audit/answer-access-request.md +115 -0
  9. package/dist/skill/references/config/attach-a-template.md +117 -0
  10. package/dist/skill/references/config/init-tenant.md +121 -0
  11. package/dist/skill/references/config/onboard-tenant.md +71 -0
  12. package/dist/skill/references/config/rename-program-stage.md +99 -0
  13. package/dist/skill/references/config/set-tenant-branding.md +150 -0
  14. package/dist/skill/references/config/set-tenant-terms.md +50 -0
  15. package/dist/skill/references/config/set-up-billing-catalog.md +73 -0
  16. package/dist/skill/references/config/update-tenant-config.md +170 -0
  17. package/dist/skill/references/config/wipe-tenant-config.md +107 -0
  18. package/dist/skill/references/export/create-named-export.md +47 -0
  19. package/dist/skill/references/feedback/create-and-triage-feedback.md +69 -0
  20. package/dist/skill/references/feedback/manage-feedback-tags.md +57 -0
  21. package/dist/skill/references/finance/change-contract-grant.md +36 -0
  22. package/dist/skill/references/finance/record-submission-date.md +33 -0
  23. package/dist/skill/references/interessenten/list-interessenten.md +54 -0
  24. package/dist/skill/references/notifications/debug-mail-delivery.md +77 -0
  25. package/dist/skill/references/notifications/mail-level.md +90 -0
  26. package/dist/skill/references/notifications/reword-a-letter.md +155 -0
  27. package/dist/skill/references/notifications/trace-a-login.md +50 -0
  28. package/dist/skill/references/offer/add-workflow-node.md +268 -0
  29. package/dist/skill/references/offer/addresses.md +129 -0
  30. package/dist/skill/references/offer/appointment-task.md +79 -0
  31. package/dist/skill/references/offer/assignment-rule.md +195 -0
  32. package/dist/skill/references/offer/attach-form-to-workflow.md +79 -0
  33. package/dist/skill/references/offer/author-form-scenarios.md +97 -0
  34. package/dist/skill/references/offer/author-manifest-meta.md +94 -0
  35. package/dist/skill/references/offer/author-smartform.md +102 -0
  36. package/dist/skill/references/offer/bind-node-input.md +76 -0
  37. package/dist/skill/references/offer/completeness-check.md +137 -0
  38. package/dist/skill/references/offer/countersign-node.md +91 -0
  39. package/dist/skill/references/offer/create-pedagogy-unit.md +55 -0
  40. package/dist/skill/references/offer/declare-node-reads.md +99 -0
  41. package/dist/skill/references/offer/edit-live-tenant-offer.md +144 -0
  42. package/dist/skill/references/offer/edit-smartform.md +121 -0
  43. package/dist/skill/references/offer/edit-workflow-node.md +126 -0
  44. package/dist/skill/references/offer/engage-push-node.md +147 -0
  45. package/dist/skill/references/offer/insert-and-rewire-node.md +67 -0
  46. package/dist/skill/references/offer/node-tasks.md +162 -0
  47. package/dist/skill/references/offer/optional-assessment.md +65 -0
  48. package/dist/skill/references/offer/publish-offer-bundle.md +117 -0
  49. package/dist/skill/references/offer/set-offer-capacities.md +78 -0
  50. package/dist/skill/references/offer/staff-input-if-node.md +112 -0
  51. package/dist/skill/references/offer/task-appointment-result.md +69 -0
  52. package/dist/skill/references/offer/task-family-request.md +69 -0
  53. package/dist/skill/references/offer/task-result-files.md +52 -0
  54. package/dist/skill/references/offer/template-document-node.md +113 -0
  55. package/dist/skill/references/offer/workflow-default-channels.md +69 -0
  56. package/dist/skill/references/resolver/manage-contract-resolver.md +159 -0
  57. package/dist/skill/references/retention/erase-due-applications.md +99 -0
  58. package/dist/skill/references/retention/erase-due-parties.md +107 -0
  59. package/dist/skill/references/roles/migrate-parent-assignments.md +31 -0
  60. package/dist/skill/references/signing/README.md +113 -0
  61. package/dist/skill/references/signing/connect-a-school.md +90 -0
  62. package/dist/skill/references/signing/rotate-the-key.md +41 -0
  63. package/dist/skill/references/stammdaten/purge-deleted-person.md +68 -0
  64. package/dist/skill/references/stripe/connect-a-school.md +107 -0
  65. package/dist/skill/references/stripe/request-and-verify-a-payment.md +78 -0
  66. package/dist/skill/references/test-actions/drive-a-test-application.md +59 -0
  67. package/dist/skill/references/users/add-platform-admin.md +59 -0
  68. package/dist/skill/references/users/add-platform-user.md +59 -0
  69. package/dist/skill/references/users/add-tenant-admin.md +75 -0
  70. package/dist/skill/references/users/change-login-email.md +55 -0
  71. package/dist/skill/references/users/cli-access-for-tenant-admin.md +117 -0
  72. package/dist/skill/references/users/delete-permission-group.md +76 -0
  73. package/dist/skill/references/users/grant-cross-tenant-access.md +57 -0
  74. package/dist/skill/references/users/grant-feedback-assignable.md +43 -0
  75. package/dist/skill/references/users/set-password.md +57 -0
  76. package/dist/skill/references/users/use-test-account.md +79 -0
  77. package/dist/skill/references/worker-ops/debug-worker-jobs.md +90 -0
  78. package/dist/skill/references/worker-ops/verify-migrations.md +51 -0
  79. package/dist/spec.snapshot.json +145815 -0
  80. package/package.json +53 -4
@@ -0,0 +1,59 @@
1
+ # Drive a test application through test mode
2
+
3
+ **When to use:** walk a test application through an offer from the terminal — load a form
4
+ scenario and submit it, fill the file fields, submit a form — exactly what the cockpit's
5
+ test-mode popover („Testmodus") does. Replaces raw `call workflow:listTestActions` /
6
+ `runTestAction`.
7
+
8
+ ## Prerequisites
9
+ - `--tenant` set, and `--env` named on the command line for `run` (it writes; prod also
10
+ needs `--allow-prod`); the application is a **test application** (started in test
11
+ mode) and the caller holds `testActions.run`. Otherwise both verbs refuse with that reason.
12
+ - The application id — start one with `applications start-test`
13
+ ([Start a test application](../applications/start-a-test-application.md)) or list them with
14
+ `applications list --offer <slug> --test-only`.
15
+ - The form's scenarios exist — see [Author a form's test scenarios](../offer/author-form-scenarios.md).
16
+
17
+ ## Steps
18
+ ```bash
19
+ # What the application's current node(s) offer:
20
+ plexus-cli --env staging --tenant test test-actions list --application <applicationId>
21
+
22
+ # Load a scenario and submit (files are stubbed with openable PDFs first):
23
+ plexus-cli --env staging --tenant test test-actions run --application <applicationId> \
24
+ --action load-scenario:joint-reduced-fee
25
+
26
+ # Only load the values, no submit:
27
+ plexus-cli --env staging --tenant test test-actions run --application <applicationId> \
28
+ --action load-scenario:joint-reduced-fee --no-auto-submit
29
+
30
+ # Fill every file field, then submit once the fill has landed:
31
+ plexus-cli --env staging --tenant test test-actions run --application <applicationId> --action auto-fill-files
32
+ plexus-cli --env staging --tenant test test-actions list --application <applicationId> # submit-form no longer disabled?
33
+ plexus-cli --env staging --tenant test test-actions run --application <applicationId> --action submit-form
34
+
35
+ # Application-wide actions (listed under „(Bewerbung)“), e.g. become responsible:
36
+ plexus-cli --env staging --tenant test test-actions run --application <applicationId> --action takeResponsibility
37
+ ```
38
+
39
+ Without `--node` the CLI asks every current node of the application and runs the action
40
+ on the one that offers it. Two current nodes offering the same action (parallel branches)
41
+ → it stops and asks for `--node`.
42
+
43
+ ## Verify
44
+ `run` prints the action and the node it ran on. File fills — and the submit a scenario
45
+ does after them — run as a scheduled action and land a moment later; `test-actions list`
46
+ then shows what the next node offers.
47
+
48
+ ## Idempotency / gotchas
49
+ - A disabled action is refused with its reason before the server is asked
50
+ (`submit-form … disabled: missingRequired (3)` — a required field is still empty).
51
+ - `load-scenario:<id>` submits by default, like the popover's „Automatisch absenden" checkbox.
52
+ - Not a test application, or no `testActions.run`: refused with that reason (never an empty
53
+ list). An unknown `--node`: refused with the node id.
54
+ - The UI label of `auto-fill-files` is „File-Felder mit Dummy füllen“.
55
+ - Real applications are never driven this way; the server refuses test actions outside
56
+ test mode.
57
+
58
+ ## Related
59
+ - [Author a form's test scenarios](../offer/author-form-scenarios.md) · [Use a tenant's test account](../users/use-test-account.md)
@@ -0,0 +1,59 @@
1
+ # Add a platform admin
2
+
3
+ **When to use:** you need a **tenant-less platform operator** (full `_platform.*`
4
+ set, reaches every tenant) with a working login — e.g. onboarding a new operator or
5
+ agent.
6
+
7
+ ## Prerequisites
8
+ - **Env:** target with `--env <local|staging|prod>`. **No `--tenant`** — a platform
9
+ admin is tenant-less by definition.
10
+ - **Auth:** your **own platform-admin token** (needs `_platform.users.manage`); a
11
+ Convex admin key is **not** sufficient. Confirm with
12
+ `plexus-cli --env <env> whoami`.
13
+ - **Inputs:** the new admin's email + display name. The email must **not** already
14
+ have tenant access (the `_platform.* XOR tenant-access` invariant).
15
+ - **Tooling:** an installed `plexus-cli`; `plexus-cli users --help` lists the user
16
+ commands.
17
+
18
+ ## Steps
19
+ ```bash
20
+ plexus-cli --env <env> users provision-platform-admin <email> \
21
+ --name "Vorname Nachname" \
22
+ --output creds.csv --quiet
23
+ ```
24
+
25
+ - The server **generates the password and returns it once**. `--output creds.csv`
26
+ captures the `email,password` row; `--quiet` keeps it out of stdout. To set a known
27
+ password, pass `--password "…"`.
28
+
29
+ ## Verify
30
+ ```bash
31
+ plexus-cli --env <env> users show <email>
32
+ ```
33
+
34
+ Success: a `platform: …` line lists the full `_platform.*` permission set and the
35
+ user has **no** tenant rows. `plexus-cli --env <env> platform users` lists them too.
36
+
37
+ ## Hand the credentials over
38
+
39
+ Same three-line format as every other credential handover — URL, email, password,
40
+ bare, one block per account. See
41
+ [Add a tenant admin](./add-tenant-admin.md) → "Hand the credentials over".
42
+
43
+ ## Idempotency / gotchas
44
+ - **Idempotent — re-running rotates the password** (does not duplicate the account).
45
+ - **Refuses an email that already has tenant access** (the `_platform.* XOR
46
+ tenant-access` invariant). For a per-tenant account use
47
+ [Add a tenant admin](./add-tenant-admin.md) instead.
48
+ - Contrast `users create <email> --platform-admin`, which also mints a credential
49
+ (no verb leaves an identity that cannot log in) but takes **no display
50
+ name** and never rotates an existing password. `provision-platform-admin` is the
51
+ named path, and re-running it deliberately resets the login.
52
+ - Runtime-only account — **not** part of the demo seed (real personal passwords
53
+ never are); a destructive reseed won't recreate it. Re-run if ever reseeded.
54
+
55
+ ## Related
56
+ - [Add a tenant admin](./add-tenant-admin.md) — the per-tenant twin (`users provision`).
57
+ - Command reference: `plexus-cli users provision-platform-admin --help` and
58
+ `plexus-cli users create --help` (the create-vs-provision distinction above).
59
+ - Connection and token: `plexus-cli config show`, `plexus-cli whoami`.
@@ -0,0 +1,59 @@
1
+ # Add a platform user
2
+
3
+ **When to use:** you need a **tenant-less platform operator** with a limited,
4
+ explicit `_platform.*` permission set and a working login.
5
+
6
+ ## Prerequisites
7
+ - **Env:** target with `--env <local|staging|prod>`. **No `--tenant`** — a platform
8
+ user is tenant-less by definition.
9
+ - **Auth:** your **own platform-admin token** (needs `_platform.users.manage`); a
10
+ Convex admin key is **not** sufficient. Confirm with
11
+ `plexus-cli --env <env> whoami`.
12
+ - **Inputs:** the user's email, display name, and exact platform permissions. The
13
+ email must **not** already have tenant access (the `_platform.* XOR tenant-access`
14
+ invariant).
15
+ - **Tooling:** an installed `plexus-cli`; `plexus-cli users --help` lists the user
16
+ commands.
17
+
18
+ ## Steps
19
+ ```bash
20
+ plexus-cli --env <env> users provision-platform-user <email> \
21
+ --name "Vorname Nachname" \
22
+ --permission _platform.schema.read \
23
+ --output creds.csv --quiet
24
+ ```
25
+
26
+ - Repeat `--permission` for every `_platform.*` permission the user should hold.
27
+ - The server **generates the password and returns it once**. `--output creds.csv`
28
+ captures the `email,password` row; `--quiet` keeps it out of stdout. To set a known
29
+ password, pass `--password "..."`.
30
+
31
+ ## Verify
32
+ ```bash
33
+ plexus-cli --env <env> users show <email>
34
+ ```
35
+
36
+ Success: a `platform: ...` line lists exactly the requested `_platform.*`
37
+ permissions and the user has **no** tenant rows.
38
+
39
+ ## Hand the credentials over
40
+
41
+ Same three-line format as every other credential handover — URL, email, password,
42
+ bare, one block per account. See
43
+ [Add a tenant admin](./add-tenant-admin.md) → "Hand the credentials over".
44
+
45
+ ## Idempotency / gotchas
46
+ - **Idempotent — re-running rotates the password** and resets the platform
47
+ permission list to exactly the repeated `--permission` values.
48
+ - **Refuses an email that already has tenant access** (the `_platform.* XOR
49
+ tenant-access` invariant). A limited platform user cannot also be a tenant user.
50
+ - For full platform operators, use [Add a platform admin](./add-platform-admin.md)
51
+ instead. That command grants the full `_platform.*` set.
52
+ - Runtime-only account — **not** part of the demo seed (real personal passwords
53
+ never are); a destructive reseed won't recreate it. Re-run if ever reseeded.
54
+
55
+ ## Related
56
+ - [Add a platform admin](./add-platform-admin.md) — full `_platform.*` operators.
57
+ - [Set (rotate) a user's password](./set-password.md) — rotate an existing
58
+ credential without changing access.
59
+ - Connection and token: `plexus-cli config show`, `plexus-cli whoami`.
@@ -0,0 +1,75 @@
1
+ # Add a tenant admin
2
+
3
+ **When to use:** a staff member should administer **one tenant** with a working
4
+ login — a ready-to-use account (credential + full tenant-admin access), not just a
5
+ permission grant.
6
+
7
+ ## Prerequisites
8
+ - **Env / tenant:** target with `--env <local|staging|prod>` **and** `--tenant <slug>`
9
+ (this is tenant-scoped). Run `plexus-cli --env <env> tenants` to see the slugs you
10
+ reach.
11
+ - **Auth:** a token whose identity may manage users in that tenant (a platform-admin
12
+ token, or tenant access with `_platform.users.manage`). Confirm with
13
+ `plexus-cli --env <env> whoami`.
14
+ - **Inputs:** the new user's email + display name.
15
+ - **Tooling:** an installed `plexus-cli`; `plexus-cli users --help` lists the user
16
+ commands.
17
+
18
+ ## Steps
19
+ ```bash
20
+ plexus-cli --env <env> --tenant <slug> users provision <email> \
21
+ --name "Vorname Nachname" --group tenant_admin \
22
+ --output creds.csv --quiet
23
+ ```
24
+
25
+ - `--group tenant_admin` is the **default**, so it may be omitted; it's shown here to
26
+ be explicit. Pass a different permission-group key (see
27
+ `plexus-cli --env <env> --tenant <slug> users groups`) for a non-admin staff account.
28
+ - The server **generates the password and returns it once**. `--output creds.csv`
29
+ appends the `email,password` row to a file; `--quiet` keeps it out of stdout. To set
30
+ a known password instead, pass `--password "…"` (and drop `--quiet` if you want to
31
+ see it echoed).
32
+
33
+ ## Verify
34
+ ```bash
35
+ plexus-cli --env <env> users show <email>
36
+ ```
37
+
38
+ Success: the user lists the `<slug>` tenant with groups `tenant_admin, applicant`.
39
+ (`users show` is a global lookup across every tenant the user belongs to — no
40
+ `--tenant` needed; the email match is case-insensitive.)
41
+
42
+ ## Hand the credentials over — always this format
43
+
44
+ Three bare lines, nothing else: URL, email, password. No table, no markdown link,
45
+ no labels. One block per account, so the recipient can copy each line straight
46
+ into the login form.
47
+
48
+ ```
49
+ https://plexus.swop.schule/
50
+ ada@example.com
51
+ <the generated password>
52
+ ```
53
+
54
+ Use the app URL of the env you provisioned in. Write the URL bare: a markdown link renders as a terminal escape
55
+ sequence, and the address never reaches the visible text.
56
+
57
+ ## Idempotency / gotchas
58
+ - **Re-running rotates the password** (it re-provisions the credential) and re-emits
59
+ it — re-run only if you intend to reset the login.
60
+ - The password is shown **once**; if you didn't capture it, re-run with `--output …`
61
+ to mint a fresh one.
62
+ - This both **grants tenant access and creates a login credential** — contrast
63
+ `users add` / `users set-group`, which only adjust access and group membership for
64
+ a user who already exists. `users add` REFUSES an unknown address (it
65
+ has no name or password channel, so any identity it created could never log in);
66
+ provision the account first, here.
67
+ - The backend lowercases the email; the login address is the lowercased form.
68
+ - Runtime-only account — it is **not** part of the demo seed, so a destructive reseed
69
+ won't recreate it; re-run this playbook if the tenant is ever reseeded.
70
+
71
+ ## Related
72
+ - [Add a platform admin](./add-platform-admin.md) — the tenant-less platform twin
73
+ (`users provision-platform-admin`).
74
+ - Command reference: `plexus-cli users --help`.
75
+ - Connection and token: `plexus-cli config show`, `plexus-cli whoami`.
@@ -0,0 +1,55 @@
1
+ # Change a user's login e-mail
2
+
3
+ **When to use:** an account's login address has to move — above all a made-up
4
+ test account on a real, deliverable domain (`test100@<domain>.com`) that must go to a
5
+ reserved one (`test100@<domain>.test`) so no mail can ever reach a stranger.
6
+
7
+ ## Prerequisites
8
+ - A platform token with `_platform.users.manage` for the target env.
9
+ - The account exists (`plexus-cli --env <env> users show <email>`).
10
+ - The new address is free: the verb refuses one held by another account, in the
11
+ plan already.
12
+
13
+ ## Steps
14
+ ```bash
15
+ # 1. Plan — runs every check, writes nothing
16
+ plexus-cli --env <env> users set-email <old@domain> --to <new@domain>
17
+
18
+ # 2. Apply
19
+ plexus-cli --env <env> users set-email <old@domain> --to <new@domain> --confirm
20
+ ```
21
+
22
+ For a test account, keep the local part and replace the domain's TLD with
23
+ `.test` (RFC 2606/6761): `test100@<domain>.com` → `test100@<domain>.test`,
24
+ `ada@<schule>.de` → `ada@<schule>.test`.
25
+
26
+ ## Verify
27
+ ```bash
28
+ plexus-cli --env <env> users show <new@domain> # same userId, same tenants
29
+ plexus-cli --env <env> users show <old@domain> # → No user with email …
30
+ ```
31
+
32
+ ## Idempotency / gotchas
33
+ - Re-running with the address already moved prints "no change".
34
+ - One identity, every tenant: an account shared by several tenants moves in all
35
+ of them at once. (Staff editing the party's E-Mail field cannot do this — that
36
+ path refuses a shared identity and points here.)
37
+ - The password is untouched; set one afterwards with `users set-password` if needed.
38
+ - **Mailbox proof** is reset (the holder re-confirms via a mailed link before
39
+ they can move a process again) — except for a reserved test address (`.test`,
40
+ `.example`, `.invalid`, `.localhost`, `example.com/.net/.org`): no mailbox
41
+ exists there, so the proof stays as it was (`proof: unchanged`), and no mode ever transmits
42
+ such an address (`skipped: reserved_address`).
43
+ - **Config-declared accounts** (a staff roster in tenant config): re-export the
44
+ tenant config afterwards (`plexus-cli --env <env> --tenant <slug> config export`).
45
+ Applying an older export that still names the old address re-creates an
46
+ identity on it — config accounts are matched by e-mail.
47
+ - Only the login changes. Old addresses in history (sent deliveries, value
48
+ history, contract snapshots) stay as they were; a queued delivery to the old
49
+ address ends `skipped: recipient_changed`.
50
+ - An account-LESS party's e-mail (a contact, a second parent) is a stored value,
51
+ not a login — change it with `plexus-cli call parties:updateValue …` instead.
52
+
53
+ ## Related
54
+ - [Set (rotate) a user's password](./set-password.md)
55
+ - [Debug a mail delivery](../notifications/debug-mail-delivery.md)
@@ -0,0 +1,117 @@
1
+ # CLI access for a tenant admin
2
+
3
+ **When to use:** a school's own administrator (no platform rights) should run
4
+ `plexus-cli` for **exactly their tenant**: export, plan and apply its config
5
+ (`config export|apply|set`) and its admission offers (`offer …`). Example: the
6
+ administrator of one school group onboarding their own offers.
7
+
8
+ The person gets a `plx_…` token that acts **as them**. It reaches exactly the
9
+ tenants their own login reaches — no other tenant, no platform surface. **A token
10
+ works only while its owner holds `administration.apiTokens.manage`** (platform:
11
+ `_platform.apiTokens.manage`): every CLI call asks the right again, and the
12
+ change that takes the right away revokes the person's tokens.
13
+
14
+ ## Prerequisites
15
+ - **The person is a tenant member with a login.** No login yet →
16
+ [Add a tenant admin](./add-tenant-admin.md) first.
17
+ - **Every `tenant_admin` holds the three CLI rights** — `administration.apiTokens.manage`
18
+ (mint a token), `administration.config.read` / `.manage` (config, held
19
+ **tenant-wide**). They are part of the derived `tenant_admin` and reach existing
20
+ tenants on every deploy; nothing to grant. Someone outside `tenant_admin` needs a
21
+ group holding them.
22
+ - **Offer commands** need `bewerbungsmanagement.forms.configure` (in `tenant_admin`).
23
+ A config change to groups or members also needs
24
+ `administration.permissions.manage` / `.users.manage` (in `tenant_admin`).
25
+ - **Your auth (issuing for them):** a platform token with `_platform.users.manage`
26
+ **and** `_platform.apiTokens.manage` — the token acts as the person.
27
+ - `--env` is required for the write; prod also needs `--allow-prod`.
28
+
29
+ ## Steps
30
+
31
+ **0 — check the person is a `tenant_admin`:**
32
+
33
+ ```bash
34
+ plexus-cli --env <env> users show <email> # groups: tenant_admin, …
35
+ ```
36
+
37
+ **A — the administrator mints it themselves:** in the app, *Einstellungen →
38
+ API-Token* („Token erstellen"), or with a token they already have:
39
+ `plexus-cli --env <env> tokens create laptop`.
40
+
41
+ **B — the platform issues it for them** (to hand over directly):
42
+
43
+ ```bash
44
+ plexus-cli --env <env> tokens create cli --for <email> --output /tmp/token-<slug>.csv --quiet
45
+ ```
46
+
47
+ - The token is shown **once**. `--output` appends `email,token` to the CSV (a file
48
+ with a different header, e.g. a password file, is refused); `--quiet` keeps it out
49
+ of stdout. Without `--output`, it is printed.
50
+ - Refused when the address has no account (`kein Konto`), no login, or holds
51
+ `administration.apiTokens.manage` in no tenant (`in keinem Mandanten`) — including
52
+ platform operators, who are tenant-less.
53
+ - The token records who issued it.
54
+
55
+ **The administrator's setup** (`~/.config/agent-tools/plexus.yml`; see SKILL.md →
56
+ Connect, or `plexus-cli --help`). The platform operator provides the staging URLs:
57
+
58
+ ```yaml
59
+ plexus:
60
+ default_env: staging
61
+ default_tenant: <slug>
62
+ environments:
63
+ staging: { convex_url: "https://<staging-convex-url>", site_url: "https://<staging-site-url>", token: "plx_…" }
64
+ # Required even without a prod token: every write compares its target with
65
+ # the prod URL (refused otherwise: "names no environments.prod.convex_url").
66
+ prod: { convex_url: "https://db.plexus.swop.schule", site_url: "https://actions.db.plexus.swop.schule" }
67
+ ```
68
+
69
+ ## Verify
70
+
71
+ As the administrator's token:
72
+
73
+ ```bash
74
+ plexus-cli --env <env> whoami
75
+ plexus-cli --env <env> config export --tenant <slug> --out ./<slug>/config.json # passes
76
+ plexus-cli --env <env> config export --tenant <other-slug> --out /tmp/x.json # FORBIDDEN / NOT_FOUND
77
+ plexus-cli --env <env> config apply --tenant <slug> --from snapshot:./<slug>/config.json # dry run passes
78
+ ```
79
+
80
+ ## What a tenant-scoped apply refuses (FORBIDDEN, naming the field)
81
+ - a tenant that does not exist (no onboarding), `--from blueprint`, `--allow-destructive`;
82
+ - any `tenant.*` setting except `branding`, `brandingAssets`, `notificationChrome`
83
+ differing from live — modules (`enabledModules` decides the permission allowlist),
84
+ `defaultApplicantGroupKey`, `mailLevel`, `magicLinkLogin`, terms, …;
85
+ - the import `source`;
86
+ - a `foundation.users` address that is not an **active** member with a login (no new
87
+ accounts, no other tenant's people, no revoked member brought back);
88
+ - a `_platform.*` right in any permission group.
89
+
90
+ A change to the permission groups additionally needs `administration.permissions.manage`,
91
+ a change to `foundation.users` (who sits in which group) `administration.users.manage` —
92
+ the rights the app asks for the same act (`tenant_admin` holds both).
93
+
94
+ Copy those values from `config export` unchanged; a change to them is a platform task.
95
+ Platform-only regardless: `config wipe`, `config prune-offers`, `config apply --scope
96
+ platform`, setup mode (Load N / wipe), `offer hard-delete`.
97
+
98
+ ## Idempotency / gotchas
99
+ - Minting again makes a **second** token; revoke the old one with `tokens list` →
100
+ `tokens revoke <id>`. Without the right, the CLI refuses every call — listing and
101
+ revoking your own tokens then works in the app (Settings → API-Token) only.
102
+ - Taking the right away (group removed or narrowed, tenant access ended, user
103
+ deactivated, module dropped by `config apply` or the deploy, platform right
104
+ dropped) **revokes** the person's tokens in the same change. Giving the
105
+ right back does not revive them — mint a new one. The exchange then answers 401
106
+ „Das API-Token „…“ wurde am <Datum> widerrufen: <Grund>“. A right that lapses without a
107
+ write is still caught: every CLI call asks it and refuses with 403 „Ihr Konto hat
108
+ das Recht „API-Tokens: Verwalten“ nicht mehr …“.
109
+ - A tenant member cannot be made platform admin (`users set-platform-admin`):
110
+ platform rights and tenant access exclude each other — an inactive access row
111
+ counts too.
112
+ - A unit-scoped membership does not count for config: the right must be held
113
+ tenant-wide.
114
+
115
+ ## Related
116
+ - [Add a tenant admin](./add-tenant-admin.md) — the login itself.
117
+ - [Edit a live tenant's offer](../offer/edit-live-tenant-offer.md).
@@ -0,0 +1,76 @@
1
+ # Delete a tenant permission group
2
+
3
+ Remove a permission group that should not exist — typically one created by an
4
+ accidental click in Administration → Berechtigungen, which the admin UI can
5
+ create and rename but **not** delete.
6
+
7
+ ## When to use
8
+
9
+ - A stray group ("Neue Berechtigungsgruppe") with no members.
10
+ - A team that was retired and whose work has been re-pointed elsewhere.
11
+
12
+ Not for: taking someone's access away — that is `users unset-group` (leave the
13
+ group, keep the tenant) or `users remove` (revoke tenant access).
14
+
15
+ ## Prerequisites
16
+
17
+ - `bewerbungsmanagement`-independent: the mutation gates on the tenant's
18
+ **permissions-manage** grant, so a tenant admin or platform admin token.
19
+ - The group must be genuinely unreferenced (see *Guards*).
20
+
21
+ ## Commands
22
+
23
+ ```bash
24
+ # 1. See what the tenant has.
25
+ plexus-cli --env prod users groups --tenant <slug>
26
+
27
+ # 2. Dry-run — prints the member count it would be deleting against.
28
+ plexus-cli --env prod users groups delete neue_berechtigungsgruppe \
29
+ --tenant <slug>
30
+
31
+ # 3. Commit.
32
+ plexus-cli --env prod users groups delete neue_berechtigungsgruppe \
33
+ --tenant <slug> --confirm --allow-prod
34
+ ```
35
+
36
+ ## Verify
37
+
38
+ ```bash
39
+ plexus-cli --env prod users groups --tenant <slug> # key is gone
40
+ ```
41
+
42
+ Config is DB-authoritative, so the group is gone from the tenant's config too. A
43
+ platform operator can confirm it in a `config export` (`foundation.permissionGroups`).
44
+
45
+ ## Guards (the delete REFUSES when…)
46
+
47
+ | Refusal | Meaning | Fix first |
48
+ |---|---|---|
49
+ | `has-members` | Someone is still in the group (the message names them) | `users unset-group` each |
50
+ | `owns-teams` | A running application binds this group as a work owner | Re-assign those applications |
51
+ | `referenced-by-workflow` | A stored graph routes a decision/assign (or a not-yet-migrated legacy team-owner binding) to this key | Re-point the node, re-publish |
52
+ | `structural` | It is `tenant_admin` | — (never deletable) |
53
+ | `default-applicant` | It is the tenant's `defaultApplicantGroupKey` | Point the default at another group |
54
+ | `unknown` | No group with that key in this tenant | Check `users groups` |
55
+
56
+ ## Gotchas
57
+
58
+ - **Hard delete, on purpose.** There is no soft delete and no `--restore`. A
59
+ hidden-but-present group would need an `active` flag every reader honours, and
60
+ a reader that forgets one leaves a ghost — exactly the bug that let a removed
61
+ user keep a `user_tenant_access` row and made `config export` throw for that
62
+ tenant. Re-creating an empty group is one click; a ghost is a day of debugging.
63
+ - **The group's `custom_field_permissions` go with it.** Those grants are the
64
+ group's own field visibility settings and mean nothing without it. Everything
65
+ else refuses rather than cascades.
66
+ - **Key, not label.** `users groups delete` takes the stable `key`
67
+ (`neue_berechtigungsgruppe`), never the display label — renaming a group must
68
+ not change what the command targets.
69
+
70
+ ## Related
71
+
72
+ - [Add a tenant admin](./add-tenant-admin.md)
73
+ - [Update a tenant's config](../config/update-tenant-config.md) — the declarative
74
+ route: drop the group from the exported config and `config apply --confirm
75
+ --allow-destructive` sweeps it as an orphan. Equivalent outcome; use the CLI
76
+ verb for a one-off, the config route when the change belongs in the file.
@@ -0,0 +1,57 @@
1
+ # Grant every tenant's users access to another tenant
2
+
3
+ **When to use:** let **all existing users of every tenant** reach one shared tenant
4
+ — the canonical case is giving every client access to the **Test Tenant** (`test`)
5
+ so they can dogfood the product. One-time + manual: it grants the users that exist
6
+ **now**; new users are **not** auto-enrolled (re-run later to pick up newcomers).
7
+
8
+ > Pair this with the Test-Tenant feedback-privacy rule: the Test Tenant grants no
9
+ > `administration.feedback.viewAll` (part of the `test` tenant's config), so
10
+ > "Alle Rückmeldungen" is unavailable
11
+ > there and each client only sees their own feedback.
12
+
13
+ ## Prerequisites
14
+ - **Env:** target with `--env <local|staging|prod>` (this is a platform operation —
15
+ no `--tenant` needed). `plexus-cli --env <env> tenants` lists the reachable slugs.
16
+ - **Auth:** a platform-admin token with `_platform.users.manage`. Confirm with
17
+ `plexus-cli --env <env> whoami`.
18
+ - **Tooling:** an installed `plexus-cli` (`plexus-cli users grant-all --help`).
19
+
20
+ ## Steps
21
+ Run once per **source** tenant, pointing every one at the target (`test`):
22
+ ```bash
23
+ # Repeat for each non-test tenant slug:
24
+ plexus-cli --env <env> users grant-all --from <sourceSlug> --to test --group tenant_admin
25
+ ```
26
+
27
+ To enumerate the source slugs to loop over:
28
+ ```bash
29
+ plexus-cli --env <env> tenants # list slugs; run grant-all for each but `test`
30
+ ```
31
+
32
+ - `--group tenant_admin` (the default) lets the granted users explore every module in
33
+ the Test Tenant. Pass a different group key for a narrower role.
34
+ - Each user is granted idempotently; a user who already has access is a no-op.
35
+ - Platform operators (tenant-less identities) never appear in a tenant's user set and
36
+ are additionally rejected by the `_platform.* XOR tenant-access` invariant — they
37
+ show up under `skipped` with a reason rather than aborting the run.
38
+
39
+ ## Verify
40
+ ```bash
41
+ plexus-cli --env <env> users show <someEmailFromSource>
42
+ ```
43
+
44
+ Success: the user now lists the `test` tenant with group `tenant_admin, applicant`.
45
+ The command output also prints `Granted N/M users …` plus any `skipped` rows.
46
+
47
+ ## Idempotency / gotchas
48
+ - **Current users only** — there is no standing auto-grant; re-run to enroll users
49
+ added after the last run.
50
+ - Re-running is safe (idempotent per user); it neither rotates passwords nor creates
51
+ logins (contrast `users provision`).
52
+ - Runtime-only grants — a destructive reseed of the source/target tenant drops them;
53
+ re-run this playbook afterwards.
54
+
55
+ ## Related
56
+ - [Add a tenant admin](./add-tenant-admin.md) — single ready-to-log-in account.
57
+ - Command reference: `plexus-cli users grant-all --help`.
@@ -0,0 +1,43 @@
1
+ # Make a platform admin assignable to feedback issues
2
+
3
+ **When to use:** a platform admin should appear in the feedback-board assignee
4
+ picker (and be a valid `feedback assign` target). Being a platform admin is **not**
5
+ enough — assignability is the opt-in `_platform.feedback.assign` permission, granted
6
+ explicitly to the platform's real triage admins only.
7
+
8
+ ## Prerequisites
9
+ - `--env staging|prod` configured with a platform-operator token (the grant is gated
10
+ `_platform.users.manage`).
11
+ - The target already exists as a platform admin (`plexus-cli --env <env> platform users`).
12
+
13
+ ## Steps
14
+ ```bash
15
+ plexus-cli --env <env> users set-platform-permission <email> \
16
+ --permission _platform.feedback.assign --on
17
+ ```
18
+ Example — grant one triage admin on prod:
19
+ ```bash
20
+ plexus-cli --env prod users set-platform-permission --allow-prod ada@example.com \
21
+ --permission _platform.feedback.assign --on
22
+ ```
23
+
24
+ ## Verify
25
+ ```bash
26
+ # The assignee picker lists EXACTLY the assignable admins:
27
+ plexus-cli --env <env> feedback admins
28
+ ```
29
+
30
+ ## Idempotency / gotchas
31
+ - **Opt-in, not part of the full-admin grant.** Making someone a full platform admin
32
+ (`users set-platform-admin … --on`) does **not** grant assignability; this perm is
33
+ excluded from the default set on purpose. Re-affirming full-admin status *preserves*
34
+ an already-granted assign perm (it is never silently stripped).
35
+ - Revoke with `--off`. Removing the last permission from a row deletes the
36
+ `platform_admins` row entirely (the identity stays a normal user).
37
+ - `_platform.* XOR tenant-access`: the grant fails loud if the identity has tenant
38
+ access (platform operators must be tenant-less).
39
+ - Re-running `--on` is a no-op (the perm is added once).
40
+
41
+ ## Related
42
+ - [Add a platform admin](./add-platform-admin.md) · [Add a platform user](./add-platform-user.md)
43
+ - [Create + triage feedback from the CLI](../feedback/create-and-triage-feedback.md)
@@ -0,0 +1,57 @@
1
+ # Set (rotate) a user's password
2
+
3
+ **When to use:** an existing user — tenant user **or** platform admin — needs a new
4
+ login password (reset a lost one, or set a known value). This only changes the
5
+ password; it grants nothing and creates nothing.
6
+
7
+ ## Prerequisites
8
+ - **Env:** target with `--env <local|staging|prod>`. No `--tenant` — the command
9
+ finds the identity by email globally.
10
+ - **Auth:** a token with `_platform.users.manage` (your platform-admin token, no
11
+ Convex admin key). Confirm with `plexus-cli --env <env> whoami`.
12
+ - **Inputs:** the user's email. The identity **must already exist** (provision it
13
+ first with [add-tenant-admin](./add-tenant-admin.md) /
14
+ [add-platform-admin](./add-platform-admin.md)).
15
+ - **Tooling:** an installed `plexus-cli` (`plexus-cli users set-password --help`).
16
+
17
+ ## Steps
18
+ ```bash
19
+ # Set a known password:
20
+ plexus-cli --env <env> users set-password <email> --password 'NewPassw0rd!'
21
+
22
+ # …or let the server generate a strong one (returned once; capture without echoing):
23
+ plexus-cli --env <env> users set-password <email> --output creds.csv --quiet
24
+ ```
25
+
26
+ The server owns hashing + generation and returns the plaintext **once** (only the
27
+ hash is stored). `--output creds.csv` appends the `email,password` row; `--quiet`
28
+ keeps it off stdout.
29
+
30
+ ## Verify
31
+ ```bash
32
+ plexus-cli --env <env> users show <email> # identity unchanged (sanity)
33
+ ```
34
+ Then confirm the new password actually logs in at the env's `/login`.
35
+
36
+ ## Hand the credentials over
37
+
38
+ Same three-line format as every other credential handover — URL, email, password,
39
+ bare, one block per account. See
40
+ [Add a tenant admin](./add-tenant-admin.md) → "Hand the credentials over".
41
+
42
+ ## Idempotency / gotchas
43
+ - **Pure credential write** — it creates no identity, tenant access, person, or
44
+ permission, and changes no groups. Use `users provision` /
45
+ `users provision-platform-admin` to *create* a ready-to-log-in user;
46
+ `set-password` only rotates an **existing** one.
47
+ - **Fails loud, never repairs by creating:** throws if no Plexus identity exists for
48
+ the email, if the email has no live Better Auth account, or if that account
49
+ doesn't match the identity (an orphan → run `users relink-auth` first, then retry).
50
+ - The password is shown **once**; re-run to mint a fresh one if you lose it.
51
+ - Email match is case-insensitive (the backend lowercases it).
52
+
53
+ ## Related
54
+ - [Add a tenant admin](./add-tenant-admin.md) · [Add a platform admin](./add-platform-admin.md)
55
+ — both also accept `--password` at creation time.
56
+ - `users relink-auth <email>` — repair an orphaned identity before setting a password.
57
+ - Command reference: `plexus-cli users set-password --help`.