@pikku/skills 0.12.54 → 0.12.56
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.
- package/README.md +1 -1
- package/dist/skills.gen.js +2 -2
- package/dist/snippets.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-architect/SKILL.md +1 -1
- package/skills/pikku-architect/references/plan-defects.md +7 -7
- package/skills/pikku-auth/references/better-auth.md +92 -96
- package/skills/pikku-build/SKILL.md +9 -9
- package/skills/pikku-build/references/app.md +56 -61
- package/skills/pikku-build/references/design.md +14 -14
- package/skills/pikku-build/references/feature.md +3 -3
- package/skills/pikku-build/references/mocks.md +6 -0
- package/skills/pikku-build/references/multi-app.md +16 -16
- package/skills/pikku-build/references/openapi.md +34 -34
- package/skills/pikku-build/references/platform.md +4 -5
- package/skills/pikku-build/references/post-clone.md +1 -1
- package/skills/pikku-build/references/quick.md +63 -36
- package/skills/pikku-build/references/scenarios.md +17 -16
- package/skills/pikku-build/references/ship.md +14 -16
- package/skills/pikku-build/references/theming.md +2 -2
- package/skills/pikku-changes/SKILL.md +21 -5
- package/skills/pikku-concepts/SKILL.md +26 -27
- package/skills/pikku-concepts/references/language.md +6 -6
- package/skills/pikku-deploy/references/nextjs.md +1 -1
- package/skills/pikku-guide/SKILL.md +18 -17
- package/skills/pikku-i18n/references/messages.md +5 -6
- package/skills/pikku-knowledge/SKILL.md +3 -3
- package/skills/pikku-meta/references/audit.md +1 -1
- package/skills/pikku-permissions/SKILL.md +1 -1
- package/skills/pikku-react/SKILL.md +18 -20
- package/skills/pikku-react/references/client.md +2 -37
- package/skills/pikku-report/SKILL.md +10 -10
- package/skills/pikku-scenario/SKILL.md +63 -66
- package/skills/pikku-scenario/references/browser.md +5 -5
- package/skills/pikku-scenario/references/coverage.md +4 -4
- package/skills/pikku-scenario/references/steps.md +31 -30
- package/skills/pikku-scenario/references/{persona-run.md → virtual-user-run.md} +38 -43
- package/skills/pikku-scenario/references/virtual-users.md +114 -0
- package/skills/pikku-seo/SKILL.md +1 -1
- package/skills/pikku-services/references/audit-wire-service.md +2 -2
- package/skills/pikku-services/references/audit.md +1 -2
- package/skills/pikku-services/references/services.md +1 -1
- package/skills/pikku-software-archaeology/SKILL.md +13 -13
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +9 -9
- package/skills/pikku-theme/SKILL.md +1 -1
- package/skills/pikku-workflow/SKILL.md +1 -1
- package/skills/pikku-admin-to-fabric/SKILL.md +0 -198
- package/skills/pikku-blueprint-to-fabric/SKILL.md +0 -362
- package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +0 -367
- package/skills/pikku-fabric/SKILL.md +0 -331
- package/skills/pikku-fabric/references/database.md +0 -128
- package/skills/pikku-fabric/references/debugging.md +0 -114
- package/skills/pikku-fabric/references/deploy.md +0 -179
- package/skills/pikku-scenario/references/personas.md +0 -123
package/dist/snippets.js
CHANGED
|
@@ -91,7 +91,7 @@ export const collectSnippets = async (projectDir, into = new Map(), origins = ne
|
|
|
91
91
|
/**
|
|
92
92
|
* A fence that names a region instead of carrying code:
|
|
93
93
|
*
|
|
94
|
-
* ```ts snippet:
|
|
94
|
+
* ```ts snippet:defineVirtualUsers
|
|
95
95
|
* ```
|
|
96
96
|
*
|
|
97
97
|
* The language is optional and kept. Marked fences are replaced whole — both
|
package/package.json
CHANGED
|
@@ -285,7 +285,7 @@ one, and is worth opening for any question you cannot answer with a flat yes.
|
|
|
285
285
|
2. **Does pass 1 slice, and does the model fit inside it?** Not "pass 1: the data model, pass 2: the
|
|
286
286
|
API" — and `model` holds only the tables pass 1 or 2 actually migrates, because the model slot has
|
|
287
287
|
no passes and a later table is a PROBLEM from the first day.
|
|
288
|
-
3. **Can each scenario actually be performed?** Name the
|
|
288
|
+
3. **Can each scenario actually be performed?** Name the virtual user; assert what the person got rather
|
|
289
289
|
than that the code ran; write totals as deltas against a database nobody resets; check that every
|
|
290
290
|
input the prose describes is a field somebody planned.
|
|
291
291
|
4. **Does something produce every state and field the plan reads?** For each clause of a description,
|
|
@@ -39,8 +39,8 @@ a second changeset — say so in `covers`.
|
|
|
39
39
|
|
|
40
40
|
## Can each scenario actually be performed?
|
|
41
41
|
|
|
42
|
-
**Ask which
|
|
43
|
-
at all.** The runner drives the app as the
|
|
42
|
+
**Ask which virtual user performs it. If the answer is "nobody", it belongs one level up or to no pass
|
|
43
|
+
at all.** The runner drives the app as the virtual users the project declares; there is no anonymous
|
|
44
44
|
RPC caller, so "a caller with no session is refused" is a sentence a backend or permission
|
|
45
45
|
scenario cannot perform. Signed-out is a BROWSER fact.
|
|
46
46
|
|
|
@@ -80,7 +80,7 @@ decision that nothing records.
|
|
|
80
80
|
in this plan, or one already in the meta. Write "when the distributor is removed its companies
|
|
81
81
|
fall back to the direct catalog" with no function that removes a distributor and `plan set`
|
|
82
82
|
accepts it, `plan progress` passes, and the changeset ships a sentence nothing proves. Read each
|
|
83
|
-
description back asking
|
|
83
|
+
description back asking _which function does this_, and cut the half you cannot name.
|
|
84
84
|
|
|
85
85
|
**Where a scenario calls the same function twice, check it for a per-period guard first.** A
|
|
86
86
|
one-per-day, one-per-order or one-per-person rule makes the second call a refusal, so the journey
|
|
@@ -101,14 +101,14 @@ mark a product's countries, cannot be proven without amending the plan mid-build
|
|
|
101
101
|
**Every state a scenario waits in needs the function that leaves the world like that — checked
|
|
102
102
|
against the code ALREADY built.** Three failure shapes, in rising order of cost:
|
|
103
103
|
|
|
104
|
-
-
|
|
104
|
+
- _Stale_: a staff queue of "paid orders with no invoice yet", where an earlier changeset had
|
|
105
105
|
moved invoicing to checkout. No order a customer could place was ever in that state; three
|
|
106
106
|
scenarios passed once against old rows, then failed.
|
|
107
|
-
-
|
|
107
|
+
- _Unreachable_: staff asked to "capture the payment on an authorised order" when no function in
|
|
108
108
|
the app or its addons could put an order in `authorized` — the addon only holds money when
|
|
109
109
|
checkout was started with a flag the plan's own checkout input did not carry.
|
|
110
|
-
-
|
|
111
|
-
distributor and does not show her the product.
|
|
110
|
+
- _Wrong person_: a distributor salon owner planned to buy from a catalogue that is scoped by
|
|
111
|
+
distributor and does not show her the product. Virtual users are not interchangeable.
|
|
112
112
|
|
|
113
113
|
**A `model` slot saying "this changeset adds no table" has to be true of the DATA the scenarios
|
|
114
114
|
read, not only of the entities they name.** One promised a checkout priced by delivery country — a
|
|
@@ -101,9 +101,9 @@ export const auth = pikkuBetterAuth(async ({ secrets }) => {
|
|
|
101
101
|
|
|
102
102
|
## ⚠️ Stateless session — ALWAYS enable `cookieCache` for deployed apps
|
|
103
103
|
|
|
104
|
-
By default the CLI wires the **stateful** `betterAuthSession` bridge globally — it calls `services.auth()`, so EVERY unit/worker bundles the full better-auth server (~2.5MB each). On per-unit deploy targets (
|
|
104
|
+
By default the CLI wires the **stateful** `betterAuthSession` bridge globally — it calls `services.auth()`, so EVERY unit/worker bundles the full better-auth server (~2.5MB each). On per-unit deploy targets (Pikku Studio Cloud/Cloudflare) that bloats every bundle and the serial upload phase.
|
|
105
105
|
|
|
106
|
-
Enabling `session: { cookieCache: { enabled: true } }` makes the CLI split out a lean `betterAuthStatelessSession` (`src/scaffold/auth-middleware.gen.ts`) that verifies the signed session cookie using only `BETTER_AUTH_SECRET` — no `services.auth()`, no server bundled. Non-auth units drop from ~2.5MB to ~20KB. Only the auth unit carries the server. `pikku
|
|
106
|
+
Enabling `session: { cookieCache: { enabled: true } }` makes the CLI split out a lean `betterAuthStatelessSession` (`src/scaffold/auth-middleware.gen.ts`) that verifies the signed session cookie using only `BETTER_AUTH_SECRET` — no `services.auth()`, no server bundled. Non-auth units drop from ~2.5MB to ~20KB. Only the auth unit carries the server. `pikku validate` warns (`better-auth-stateless-session-disabled`) when it's off.
|
|
107
107
|
|
|
108
108
|
**Tradeoff:** server-side session revocation isn't seen until the cookie cache expires (sign-out is still immediate — it deletes the cookie).
|
|
109
109
|
|
|
@@ -244,13 +244,13 @@ like any other. None is automatic — an app wires the ones it needs.
|
|
|
244
244
|
| Plugin | Plugin `id` | Adds | Use it when |
|
|
245
245
|
| ------------------------ | ------------------ | ----------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
246
246
|
| `pikkuBan()` | `pikku-ban` | `user.banned/banReason/banExpires` | You ban users (the schema + enforcement half of the above) |
|
|
247
|
-
| `
|
|
247
|
+
| `pikkuVirtualUser()` | `virtualUser` | `POST /sign-in/virtual-user`, `user.virtualUser` | Scenarios sign in as a virtual user |
|
|
248
248
|
| `pikkuCredentialOAuth()` | `credential-oauth` | `POST /credential-oauth/link`, `/credential-oauth/callback/:providerId` | An app links OAuth2 **API credentials** for a user |
|
|
249
249
|
| `pikkuDelegatedAuth()` | `delegated-auth` | `POST /sign-in/delegated` | An imported upstream API is the system of record for identity |
|
|
250
250
|
|
|
251
251
|
Every one carries a `pikku` prefix, because a `plugins: [...]` array mixes these
|
|
252
|
-
with better-auth's own and a bare `
|
|
253
|
-
nothing about where it came from. The unprefixed names — `ban`, `
|
|
252
|
+
with better-auth's own and a bare `virtualUser()` next to `organization()` says
|
|
253
|
+
nothing about where it came from. The unprefixed names — `ban`, `virtualUser`,
|
|
254
254
|
`credentialOAuth`, `delegatedAuth` — are still exported as deprecated
|
|
255
255
|
aliases, so existing apps keep working.
|
|
256
256
|
|
|
@@ -342,7 +342,7 @@ an existing user row, so it cannot take over someone else's account.
|
|
|
342
342
|
For an addon generated from an OpenAPI spec, none of this is written by hand:
|
|
343
343
|
`pikku new addon --openapi … --auth-config <file>` generates
|
|
344
344
|
`authenticate<Name>Upstream` in the addon and wires this plugin, the stored
|
|
345
|
-
credential and the
|
|
345
|
+
credential and the virtual user credentials into `src/auth.ts`. The config format is
|
|
346
346
|
in the `pikku-build` skill's `references/openapi.md`. When the upstream later
|
|
347
347
|
refuses the stored token, the addon throws `CredentialRejectedError` (403,
|
|
348
348
|
`reauth: 'sign-in'`): the UI shows the sign-in again.
|
|
@@ -455,154 +455,150 @@ hostname check — because a one-request path to an admin session is exactly the
|
|
|
455
455
|
thing that must not survive a deploy. An app that has not declared the `admin`
|
|
456
456
|
scope still gets a session, with a warning, since a scopeless dev user is useful.
|
|
457
457
|
|
|
458
|
-
###
|
|
458
|
+
### Virtual user sign-in (`virtualUser` plugin)
|
|
459
459
|
|
|
460
460
|
A different thing from dev quick login, and the one to reach for when "sign in as
|
|
461
461
|
someone" means **a particular kind of user** rather than one fixed admin.
|
|
462
462
|
Register it explicitly — it is not automatic:
|
|
463
463
|
|
|
464
464
|
```typescript
|
|
465
|
-
import {
|
|
465
|
+
import {
|
|
466
|
+
VIRTUAL_USER_SIGN_IN_OPT_IN_ENV,
|
|
467
|
+
pikkuVirtualUser,
|
|
468
|
+
} from '@pikku/better-auth'
|
|
466
469
|
|
|
467
470
|
plugins: [
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
allowSignIn: await variables.get(
|
|
471
|
+
pikkuVirtualUser({
|
|
472
|
+
verifyKey: await variables.get('VIRTUAL_USER_VERIFY_KEY'),
|
|
473
|
+
allowSignIn: await variables.get(VIRTUAL_USER_SIGN_IN_OPT_IN_ENV),
|
|
471
474
|
}),
|
|
472
475
|
]
|
|
473
476
|
```
|
|
474
477
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
478
|
+
There is one door, and two ways through it.
|
|
479
|
+
|
|
480
|
+
- **A run signs in from inside the app.** A scheduled virtual user run calls
|
|
481
|
+
`auth.api.signInVirtualUserInternal`, which is `SERVER_ONLY`: it exists on
|
|
482
|
+
`auth.api` and answers 404 through `auth.handler`, so no HTTP caller can reach
|
|
483
|
+
it. The run takes the cookie and then drives the app over HTTP.
|
|
484
|
+
- **An outside caller presents one signed statement.** `pikku dev`, `pikku
|
|
485
|
+
scenario run`, `pikku virtual-user run`, `pikku pages screenshot --as` and the
|
|
486
|
+
Playwright provider `POST ${basePath}/sign-in/virtual-user` `{ statement }` →
|
|
487
|
+
200 + the normal session cookie. The statement is an EdDSA JWT with `sub` (the
|
|
488
|
+
virtual user id), `aud` (the app's origin), a short expiry (180 seconds by
|
|
489
|
+
default, 300 at most) and a one-time `jti`. The plugin verifies it against
|
|
490
|
+
`verifyKey` with a verify-only service; a replayed `jti` is refused. The replay
|
|
491
|
+
record is in memory, so it is per process.
|
|
492
|
+
|
|
493
|
+
**Keys.** `pikku dev` generates a key pair under
|
|
494
|
+
`<runtimeDir>/virtual-user/signing.key` (mode 0600, next to a `.gitignore` of
|
|
495
|
+
`*`) and gives the app the public half, so local development needs no
|
|
496
|
+
configuration. A deployed stage has one key pair: the deployer holds the private
|
|
497
|
+
key (`VIRTUAL_USER_SIGNING_KEY`) and the app reads the public key from
|
|
498
|
+
`VIRTUAL_USER_VERIFY_KEY`. A stage without a verify key refuses statements and
|
|
499
|
+
logs why; it never falls back to anything weaker.
|
|
500
|
+
|
|
501
|
+
**Which command is running decides whether it works.** `pikku dev` sets
|
|
502
|
+
`PIKKU_DEV_VIRTUAL_USER_SIGN_IN`. Everywhere else the endpoint refuses
|
|
503
|
+
(`VirtualUser sign-in is disabled outside \`pikku dev\``) — `pikku serve` clears the
|
|
504
|
+
marker outright. In production neither endpoint is registered at all.
|
|
498
505
|
|
|
499
506
|
A stage that genuinely must run scenarios opts in on purpose, with
|
|
500
|
-
`
|
|
507
|
+
`PIKKU_ALLOW_VIRTUAL_USER_SIGN_IN=passwordless-virtual-user-sign-in`. Any other value is
|
|
501
508
|
ignored and warned about, so the hatch cannot be opened by copying a `true` from
|
|
502
509
|
the line above.
|
|
503
510
|
|
|
504
511
|
**Pass it in on any runtime without a populated `process.env`.** The gate reads
|
|
505
512
|
the environment by default, which is enough for Node but not for a Worker: there
|
|
506
513
|
the opt-in arrives as a binding and reaches user code through the variables
|
|
507
|
-
service
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
what opens the gate is still something the deployment set and an operator can
|
|
512
|
-
read back out of it, never something compiled into the bundle. A value passed
|
|
513
|
-
here is the one consulted, so the environment cannot quietly override what the
|
|
514
|
-
stage was configured with.
|
|
514
|
+
service. `allowSignIn` takes the value the caller already read —
|
|
515
|
+
`await variables.get(VIRTUAL_USER_SIGN_IN_OPT_IN_ENV)` — and is checked against the same
|
|
516
|
+
literal, near-miss warning included. A value passed here is the one consulted, so
|
|
517
|
+
the environment cannot quietly override what the stage was configured with.
|
|
515
518
|
|
|
516
519
|
**Signing in and provisioning are separate powers.** An unknown address becomes
|
|
517
|
-
|
|
518
|
-
in as the
|
|
519
|
-
everything else (`No
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
persona.** Provisioning grants declared roles to actor accounts, so an
|
|
527
|
-
`admin` persona is an actor holding real admin — anyone with the secret _and_ the
|
|
528
|
-
opt-in can take a session as one. Do not treat "actors only" as a licence to open
|
|
529
|
-
the hatch in production.
|
|
520
|
+
a `virtualUser: true` row only under `pikku dev`. With the opt-in set, a stage signs
|
|
521
|
+
in as the virtual users the deployment provisioned when it started and refuses
|
|
522
|
+
everything else (`No virtual user account exists for that address`), so holding the
|
|
523
|
+
signing key on such a stage does not let anyone invent identities.
|
|
524
|
+
|
|
525
|
+
**The signing key is as powerful as the most privileged virtual user.** Provisioning
|
|
526
|
+
grants declared roles to virtual user accounts, so an `admin` virtual user holds
|
|
527
|
+
real admin — anyone with the private key _and_ the opt-in can take a session as one.
|
|
528
|
+
Keep it with the deployer; the app only ever needs the public half.
|
|
530
529
|
|
|
531
530
|
Within that boundary, three properties bound the damage:
|
|
532
531
|
|
|
533
|
-
- **It only ever signs in
|
|
532
|
+
- **It only ever signs in virtual users.** The plugin adds a `user.virtualUser` boolean
|
|
534
533
|
column; an email matching a row without it is refused with `User is not an
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
so a local scenario declaring a new persona needs no seed step. Anywhere else
|
|
534
|
+
virtual user`. So a statement cannot take over a **real user's** account.
|
|
535
|
+
- **Unknown emails are created only under `pikku dev`**, flagged `virtualUser: true`,
|
|
536
|
+
so a local scenario declaring a new virtual user needs no seed step. Anywhere else
|
|
539
537
|
the account has to have been provisioned at boot first.
|
|
540
|
-
- **A
|
|
541
|
-
|
|
542
|
-
paragraph above. The comparison is constant-time and length-hiding, so a wrong
|
|
543
|
-
credential leaks neither the length nor a prefix of the right one.
|
|
538
|
+
- **A statement is bound to one virtual user, one app and a few minutes**, and can
|
|
539
|
+
be used once, so a leaked one is a single short-lived session.
|
|
544
540
|
|
|
545
|
-
This is the endpoint `pikku scenario` signs its
|
|
546
|
-
|
|
547
|
-
id to `/sign-in/
|
|
548
|
-
`
|
|
549
|
-
`pikku-scenario` for the setup
|
|
541
|
+
This is the endpoint `pikku scenario` signs its virtual users in through. The frontend
|
|
542
|
+
does not use it: it posts a virtual user
|
|
543
|
+
id to `/sign-in/switch-virtual-user`, served by
|
|
544
|
+
`pikkuVirtualUser({ virtualUserSignIn: { virtualUsers } })` with no credential — see
|
|
545
|
+
`pikku-scenario` for the setup.
|
|
550
546
|
|
|
551
|
-
### Provisioning
|
|
547
|
+
### Provisioning virtual users
|
|
552
548
|
|
|
553
549
|
Anywhere but `pikku dev`, the accounts have to exist before anyone signs in.
|
|
554
|
-
`
|
|
550
|
+
`provisionVirtualUsers` creates them from the generated virtual users:
|
|
555
551
|
|
|
556
552
|
```ts
|
|
557
|
-
import {
|
|
553
|
+
import { provisionVirtualUsers } from '@pikku/better-auth'
|
|
558
554
|
import {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
} from '#pikku/pikku-
|
|
555
|
+
virtualUserConfigs,
|
|
556
|
+
virtualUserEnvironments,
|
|
557
|
+
} from '#pikku/pikku-virtual-users.gen.js'
|
|
562
558
|
|
|
563
|
-
await
|
|
559
|
+
await provisionVirtualUsers(
|
|
564
560
|
{ auth, scopeService, logger },
|
|
565
|
-
{
|
|
561
|
+
{ virtualUsers: virtualUserConfigs, environments: virtualUserEnvironments }
|
|
566
562
|
)
|
|
567
563
|
```
|
|
568
564
|
|
|
569
565
|
`auth` only needs to resolve `{ $context }`, so the singleton `services.auth`
|
|
570
566
|
works as is. Call it from whatever route resolves the address a caller wants to
|
|
571
567
|
act as: a miss provisions the declaration and looks again. On a stage that
|
|
572
|
-
already holds the
|
|
568
|
+
already holds the virtual user that is one query, and the pass only runs when there
|
|
573
569
|
is genuinely something absent to create.
|
|
574
570
|
|
|
575
571
|
**Do not reach for `pikkuServerLifecycle`'s `afterStart` for this.** That hook is
|
|
576
572
|
invoked by `pikku serve` and `pikku dev` and by nothing else — no deploy runtime
|
|
577
573
|
calls it — so a stage on Workers or a serverless target that provisioned from
|
|
578
|
-
`afterStart` provisioned nothing, and every
|
|
574
|
+
`afterStart` provisioned nothing, and every virtual user signed in holding no roles.
|
|
579
575
|
|
|
580
576
|
Provisioning runs where the database already is, which is the point: the CLI has
|
|
581
577
|
no connection to a deployed environment's database — it resolves one from the
|
|
582
|
-
local project config — so a `pikku
|
|
583
|
-
write them to whatever database the checkout happened to point at. `pikku
|
|
578
|
+
local project config — so a `pikku virtual-user sync staging` that wrote rows would
|
|
579
|
+
write them to whatever database the checkout happened to point at. `pikku virtual-user
|
|
584
580
|
sync <environment>` still exists, and reports who that environment will provision
|
|
585
581
|
and why anyone was skipped, which is what you run _before_ the deploy.
|
|
586
582
|
|
|
587
|
-
It creates missing accounts as `
|
|
583
|
+
It creates missing accounts as `virtualUser: true`, applies the roles each virtual user
|
|
588
584
|
declares, and is additive — it never revokes. `PIKKU_ENV` (or an explicit
|
|
589
585
|
`environment`) selects who is eligible, through the same rule that decides who
|
|
590
|
-
may run there; an address already held by a real, non-
|
|
591
|
-
than being granted the
|
|
586
|
+
may run there; an address already held by a real, non-virtual-user user throws rather
|
|
587
|
+
than being granted the virtual user's roles.
|
|
592
588
|
|
|
593
|
-
**Deleting a
|
|
594
|
-
the account keeps every role it was granted, and the
|
|
595
|
-
on the `
|
|
596
|
-
|
|
589
|
+
**Deleting a virtual user does not delete its account.** Being additive leaves a hole:
|
|
590
|
+
the account keeps every role it was granted, and the virtual user endpoint authenticates
|
|
591
|
+
on the `virtualUser` column alone without consulting the declaration — so an `admin`
|
|
592
|
+
virtual user nobody declares any more is still a live way in wherever that endpoint is
|
|
597
593
|
open. By default provisioning warns about those accounts and changes nothing.
|
|
598
594
|
`orphans: 'ban'` shuts them:
|
|
599
595
|
|
|
600
596
|
```ts
|
|
601
|
-
await
|
|
597
|
+
await provisionVirtualUsers(
|
|
602
598
|
{ auth, scopeService, logger },
|
|
603
599
|
{
|
|
604
|
-
|
|
605
|
-
environments:
|
|
600
|
+
virtualUsers: virtualUserConfigs,
|
|
601
|
+
environments: virtualUserEnvironments,
|
|
606
602
|
orphans: 'ban',
|
|
607
603
|
}
|
|
608
604
|
)
|
|
@@ -611,14 +607,14 @@ await provisionPersonas(
|
|
|
611
607
|
It writes the same `banned` column the console's ban RPC writes (so it needs the
|
|
612
608
|
`pikkuBan()` plugin wired, and says so if it isn't), revokes the account's sessions,
|
|
613
609
|
and leaves the row, its grants and its history intact — provisioning lifts the
|
|
614
|
-
ban again by itself if the
|
|
615
|
-
offered:
|
|
610
|
+
ban again by itself if the virtual user comes back. Deleting is deliberately not
|
|
611
|
+
offered: a virtual user row is referenced by whatever those scenarios did while it
|
|
616
612
|
existed.
|
|
617
613
|
|
|
618
614
|
`report` is the default because a rolling deploy runs the new replica's
|
|
619
615
|
provisioning while the old replica is still serving, so for the length of that
|
|
620
|
-
overlap "no
|
|
621
|
-
A
|
|
616
|
+
overlap "no virtual user claims this" is a statement about the newer declaration only.
|
|
617
|
+
A virtual user pinned to another environment counts as unclaimed here — it has no
|
|
622
618
|
business holding a signable account in an environment its own rule refuses it.
|
|
623
619
|
|
|
624
620
|
---
|
|
@@ -3,7 +3,7 @@ name: pikku-build
|
|
|
3
3
|
description: >-
|
|
4
4
|
Use to build on Pikku — turning a fresh scaffold into a working app (quick spike, real product,
|
|
5
5
|
or a showcase that exercises every surface), adding a feature to an app that already exists, and
|
|
6
|
-
the one-off cleanup right after a template is cloned. Covers the knowledge base,
|
|
6
|
+
the one-off cleanup right after a template is cloned. Covers the knowledge base, virtual users and
|
|
7
7
|
roles, filing the work as changes, the scenario that proves each one, theming, multi-app
|
|
8
8
|
layouts and deploying. TRIGGER when: the user asks for an app to be built on
|
|
9
9
|
Pikku, a freshly scaffolded project needs turning into a product, the user asks to add a feature
|
|
@@ -12,7 +12,7 @@ description: >-
|
|
|
12
12
|
(use pikku-concepts), wants one specific surface explained rather than built (use that surface's
|
|
13
13
|
skill), only needs the technical plan for one claimed changeset (use pikku-architect), or is
|
|
14
14
|
working items off a deployed stage's changes queue (use pikku-changes).
|
|
15
|
-
allowed-tools: Bash(yarn pikku meta *), Bash(yarn pikku all *), Bash(yarn tsc), Bash(git status *), Bash(git diff *), Bash(git switch *), Bash(git checkout *), Bash(git checkout -b *), Bash(git add *), Bash(git commit *), Bash(git rm *), Bash(git mv *), Bash(git log *), Bash(git branch *), Bash(yarn pikku
|
|
15
|
+
allowed-tools: Bash(yarn pikku meta *), Bash(yarn pikku all *), Bash(yarn tsc), Bash(git status *), Bash(git diff *), Bash(git switch *), Bash(git checkout *), Bash(git checkout -b *), Bash(git add *), Bash(git commit *), Bash(git rm *), Bash(git mv *), Bash(git log *), Bash(git branch *), Bash(yarn pikku cloud report *), Bash(npx --no pikku cloud report *)
|
|
16
16
|
argument-hint: '[feature description]'
|
|
17
17
|
installGroups: [core]
|
|
18
18
|
agent:
|
|
@@ -45,7 +45,7 @@ agent:
|
|
|
45
45
|
| A screen needs data no function returns yet | `references/mocks.md` |
|
|
46
46
|
| Adding a second frontend (app §4), at the changeset that needs it | `references/multi-app.md` |
|
|
47
47
|
| Shipping an app as a desktop or Android app | `references/native-app.md` |
|
|
48
|
-
| Deploying, and the
|
|
48
|
+
| Deploying, and the deploy-readiness contract (app §9) | `references/ship.md` |
|
|
49
49
|
| The request is built on an OpenAPI spec (auth mode, sign-in or connect screen) | `references/openapi.md` |
|
|
50
50
|
|
|
51
51
|
**App is the default.** A small or toy-sounding app does not make it Quick;
|
|
@@ -155,11 +155,11 @@ generated functions through `ref()`.
|
|
|
155
155
|
|
|
156
156
|
Whenever pikku or a skill costs you time — a command that failed on a fresh
|
|
157
157
|
tree, a skill that described a flag the CLI does not have, generated code you
|
|
158
|
-
had to fix by hand — file it then
|
|
159
|
-
`pikku-report` skill has the fields. Leave out secrets, tokens and customer data.
|
|
158
|
+
had to fix by hand — file it then, the way the
|
|
159
|
+
`pikku-report` skill describes. That skill has the fields. Leave out secrets, tokens and customer data.
|
|
160
160
|
|
|
161
161
|
Findings are held until hand-over. The last thing in the hand-over, after the
|
|
162
|
-
app runs (and is deployed, if they chose to), is `pikku
|
|
162
|
+
app runs (and is deployed, if they chose to), is the `pikku-report` send step: if it
|
|
163
163
|
lists findings and asks, ask the user — Yes, No, Always or Never — and run it
|
|
164
164
|
again with `--consent <answer>`. If it says reporting is off, do not ask.
|
|
165
165
|
|
|
@@ -171,8 +171,8 @@ build makes or changes something the console can show, give the
|
|
|
171
171
|
`http://localhost:<port>/console/...` link instead of describing it.
|
|
172
172
|
|
|
173
173
|
Until the app is deployed that is the local open-source console, on the port
|
|
174
|
-
`pikku dev` printed. Once it is
|
|
175
|
-
you are talking about instead
|
|
174
|
+
`pikku dev` printed. Once it is deployed, link the hosted console for the stage
|
|
175
|
+
you are talking about instead.
|
|
176
176
|
|
|
177
177
|
| Level | Links | Code in the conversation |
|
|
178
178
|
| ------------------ | --------------------------- | ------------------------ |
|
|
@@ -188,7 +188,7 @@ words and link to where they can see it.
|
|
|
188
188
|
| Shows | Path |
|
|
189
189
|
| --------------------- | -------------------------------------------------------------------------- |
|
|
190
190
|
| Knowledge, plans | `/console/knowledge`, `/console/knowledge?id=<note path>` |
|
|
191
|
-
|
|
|
191
|
+
| Virtual users | `/console/virtual-users`, `/console/virtual-users?virtual user=<id>` |
|
|
192
192
|
| Roles and permissions | `/console/roles`, `/console/scopes` (only with `@pikku/addon-admin` wired) |
|
|
193
193
|
| Scenarios and runs | `/console/scenarios?id=<id>`, `/console/scenarios?view=runs&run=<run id>` |
|
|
194
194
|
| Workflows | `/console/workflow?id=<id>` |
|