@pikku/skills 0.12.52 → 0.12.55
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-a11y/SKILL.md +22 -15
- package/skills/pikku-addon/SKILL.md +5 -5
- package/skills/pikku-addon/references/addon-package-manifest.md +7 -0
- package/skills/pikku-addon/references/openapi.md +11 -0
- package/skills/pikku-agent/SKILL.md +6 -6
- package/skills/pikku-agent/references/agents.md +8 -1
- package/skills/pikku-agent/references/runner-vercel.md +2 -2
- package/skills/pikku-agent/references/voice.md +7 -1
- package/skills/pikku-architect/SKILL.md +2 -2
- package/skills/pikku-architect/references/plan-defects.md +9 -7
- package/skills/pikku-auth/SKILL.md +15 -36
- package/skills/pikku-auth/references/better-auth.md +106 -133
- package/skills/pikku-auth/references/jose.md +6 -0
- package/skills/pikku-auth/references/machine-auth.md +6 -0
- package/skills/pikku-auth/references/sessions.md +6 -0
- package/skills/pikku-build/SKILL.md +37 -34
- package/skills/pikku-build/references/app.md +113 -99
- package/skills/pikku-build/references/design.md +43 -31
- package/skills/pikku-build/references/feature.md +17 -3
- package/skills/pikku-build/references/mocks.md +29 -0
- package/skills/pikku-build/references/multi-app.md +25 -18
- package/skills/pikku-build/references/native-app.md +9 -0
- package/skills/pikku-build/references/openapi.md +41 -34
- package/skills/pikku-build/references/platform.md +23 -14
- package/skills/pikku-build/references/post-clone.md +1 -1
- package/skills/pikku-build/references/quick.md +76 -39
- package/skills/pikku-build/references/scenarios.md +28 -16
- package/skills/pikku-build/references/ship.md +19 -16
- package/skills/pikku-build/references/theming.md +76 -127
- package/skills/pikku-changes/SKILL.md +7 -10
- package/skills/pikku-concepts/SKILL.md +34 -44
- package/skills/pikku-concepts/references/concept-mapping.md +18 -0
- package/skills/pikku-concepts/references/language.md +6 -6
- package/skills/pikku-convert-screen/SKILL.md +45 -0
- package/skills/pikku-deploy/references/cloudflare.md +8 -0
- package/skills/pikku-deploy/references/lambda.md +8 -0
- package/skills/pikku-deploy/references/nextjs.md +1 -1
- package/skills/pikku-deploy/references/uws.md +1 -1
- package/skills/pikku-deploy/references/ws.md +3 -3
- package/skills/pikku-emails/SKILL.md +3 -9
- package/skills/pikku-guide/SKILL.md +28 -27
- package/skills/pikku-i18n/SKILL.md +7 -7
- package/skills/pikku-i18n/references/enum-labels.md +9 -0
- package/skills/pikku-i18n/references/messages.md +21 -9
- package/skills/pikku-i18n/references/rtl.md +18 -38
- package/skills/pikku-knowledge/SKILL.md +12 -13
- package/skills/pikku-kysely/SKILL.md +3 -21
- package/skills/pikku-list-query/SKILL.md +2 -2
- package/skills/pikku-meta/references/audit.md +10 -1
- package/skills/pikku-meta/references/meta.md +6 -0
- package/skills/pikku-meta/references/versioning.md +10 -0
- package/skills/pikku-middleware/SKILL.md +7 -16
- package/skills/pikku-n8n-import/SKILL.md +9 -1
- package/skills/pikku-n8n-import/references/addon-mapping.md +6 -0
- package/skills/pikku-n8n-import/references/code-translation.md +7 -0
- package/skills/pikku-permissions/SKILL.md +41 -10
- package/skills/pikku-permissions/references/scopes.md +59 -0
- package/skills/pikku-react/SKILL.md +20 -22
- package/skills/pikku-react/references/client.md +2 -70
- package/skills/pikku-react/references/react-query.md +11 -0
- package/skills/pikku-react/references/workflows.md +11 -0
- package/skills/pikku-realtime/SKILL.md +9 -3
- package/skills/pikku-report/SKILL.md +17 -16
- package/skills/pikku-scenario/SKILL.md +72 -81
- 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} +47 -42
- package/skills/pikku-scenario/references/virtual-users.md +114 -0
- package/skills/pikku-seo/SKILL.md +12 -16
- package/skills/pikku-service-backends/SKILL.md +0 -10
- package/skills/pikku-service-backends/references/aws.md +6 -0
- package/skills/pikku-service-backends/references/mongodb.md +7 -0
- package/skills/pikku-service-backends/references/redis.md +6 -0
- package/skills/pikku-services/references/audit-wire-service.md +2 -2
- package/skills/pikku-services/references/audit.md +10 -1
- package/skills/pikku-services/references/config.md +6 -0
- package/skills/pikku-services/references/services.md +9 -2
- package/skills/pikku-software-archaeology/SKILL.md +21 -27
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +16 -16
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
- package/skills/pikku-software-archaeology/references/second-opinion.md +13 -1
- package/skills/pikku-tailwind/SKILL.md +111 -0
- package/skills/pikku-theme/SKILL.md +187 -0
- package/skills/pikku-theme/references/from-a-reference.md +44 -0
- package/skills/pikku-theme/references/presets.md +40 -0
- package/skills/pikku-ui/SKILL.md +41 -0
- package/skills/pikku-wiring/SKILL.md +13 -12
- package/skills/pikku-wiring/references/channel.md +7 -1
- package/skills/pikku-wiring/references/cli.md +7 -1
- package/skills/pikku-wiring/references/gateway-slack.md +6 -0
- package/skills/pikku-wiring/references/http.md +10 -3
- package/skills/pikku-wiring/references/mcp.md +8 -0
- package/skills/pikku-wiring/references/queue.md +6 -0
- package/skills/pikku-wiring/references/realtime.md +34 -4
- package/skills/pikku-wiring/references/rpc.md +6 -0
- package/skills/pikku-wiring/references/scheduler.md +6 -0
- package/skills/pikku-wiring/references/trigger.md +8 -0
- package/skills/pikku-workflow/SKILL.md +9 -7
- package/skills/pikku-admin-to-fabric/SKILL.md +0 -212
- package/skills/pikku-auth/references/permissions.md +0 -261
- package/skills/pikku-blueprint-to-fabric/SKILL.md +0 -377
- package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +0 -367
- package/skills/pikku-fabric/SKILL.md +0 -619
- package/skills/pikku-fabric/references/debugging.md +0 -110
- package/skills/pikku-mantine/SKILL.md +0 -80
- package/skills/pikku-scenario/references/personas.md +0 -117
- package/skills/pikku-wiring/references/realtime-other-routes.md +0 -23
|
@@ -35,5 +35,5 @@ part of cleanup — this step is project hygiene, not a build.
|
|
|
35
35
|
Templates are structure-only starting points. Without this pass, clones carry a
|
|
36
36
|
misleading README, a placeholder package name, and (historically) a gitignored
|
|
37
37
|
lockfile — all of which leak template assumptions into a real project. Running
|
|
38
|
-
it immediately after clone keeps every Pikku project
|
|
38
|
+
it immediately after clone keeps every Pikku project starting
|
|
39
39
|
from a clean, honest baseline.
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
# Build an app on Pikku, fast
|
|
2
2
|
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Agent Operating Procedure
|
|
6
|
+
- 1. One question, then build
|
|
7
|
+
- 2. Virtual users — 60 seconds, not optional
|
|
8
|
+
- 3. Build
|
|
9
|
+
- 4. Look at it — actually
|
|
10
|
+
- 5. One smoke scenario
|
|
11
|
+
- 6. Hand it over honestly
|
|
12
|
+
|
|
3
13
|
You have a scaffolded project with skills installed. Get it to working, seeded,
|
|
4
14
|
signed-in screens in as few steps as possible.
|
|
5
15
|
|
|
6
16
|
**What this mode deliberately skips**, and what that costs:
|
|
7
17
|
|
|
8
|
-
| Skipped
|
|
9
|
-
|
|
10
|
-
| `knowledge/`
|
|
11
|
-
| Changesets and plans | No build order, no per-piece proof. Fine at this size, painful past it.
|
|
12
|
-
| Design direction
|
|
13
|
-
| Refusal scenarios
|
|
18
|
+
| Skipped | Cost |
|
|
19
|
+
| -------------------- | ----------------------------------------------------------------------------- |
|
|
20
|
+
| `knowledge/` | Another agent — or you next week — cannot resume this. Nothing records _why_. |
|
|
21
|
+
| Changesets and plans | No build order, no per-piece proof. Fine at this size, painful past it. |
|
|
22
|
+
| Design direction | It will look like the template. |
|
|
23
|
+
| Refusal scenarios | Access control is asserted, not proven. |
|
|
14
24
|
|
|
15
25
|
**Say this out loud to the user, once, when you finish.** A quick build that gets
|
|
16
26
|
mistaken for a real one is the only way this mode does damage. §6 is the way out.
|
|
@@ -42,12 +52,12 @@ Identifiers are English in every project, whatever the product's market;
|
|
|
42
52
|
`template`, which the Console renders) stays `en` unless the user already told
|
|
43
53
|
you otherwise. If the request says the app's UI is not English, that is the
|
|
44
54
|
message catalogue only: add the locale and set `defaultLocale`, and leave
|
|
45
|
-
`baseLocale` at `en`.
|
|
55
|
+
`baseLocale` at `en`. the app workflow's §1a has the three axes in full; getting
|
|
46
56
|
them confused is how a project ends up unable to add a second language.
|
|
47
57
|
|
|
48
|
-
## 2.
|
|
58
|
+
## 2. Virtual users — 60 seconds, not optional
|
|
49
59
|
|
|
50
|
-
`packages/functions/src/
|
|
60
|
+
`packages/functions/src/virtual-users.ts` ships with a `visitor`. Add one virtual user per
|
|
51
61
|
kind of person, plus **a second one of the primary kind** — that is what makes
|
|
52
62
|
"you see yours, not theirs" observable when you click around.
|
|
53
63
|
|
|
@@ -55,10 +65,14 @@ kind of person, plus **a second one of the primary kind** — that is what makes
|
|
|
55
65
|
rule, and it lives in each function's `permissions`, not in a role:
|
|
56
66
|
|
|
57
67
|
```typescript
|
|
58
|
-
import {
|
|
68
|
+
import { defineVirtualUsers } from '#pikku/scopes/pikku-virtual-users.gen.js'
|
|
59
69
|
|
|
60
|
-
|
|
61
|
-
visitor: {
|
|
70
|
+
defineVirtualUsers({
|
|
71
|
+
visitor: {
|
|
72
|
+
name: 'Visitor',
|
|
73
|
+
jobTitle: 'Synthetic health-check user',
|
|
74
|
+
account: {},
|
|
75
|
+
},
|
|
62
76
|
amina: { name: 'Amina', jobTitle: 'Gardener', account: {} },
|
|
63
77
|
bilal: { name: 'Bilal', jobTitle: 'Gardener', account: {} },
|
|
64
78
|
})
|
|
@@ -68,16 +82,28 @@ definePersonas({
|
|
|
68
82
|
named:
|
|
69
83
|
|
|
70
84
|
```typescript
|
|
71
|
-
import {
|
|
85
|
+
import { defineVirtualUsers } from '#pikku/scopes/pikku-virtual-users.gen.js'
|
|
72
86
|
import { defineSystemRole } from '#pikku/scopes'
|
|
73
87
|
|
|
74
88
|
defineSystemRole({
|
|
75
|
-
owner: {
|
|
76
|
-
|
|
89
|
+
owner: {
|
|
90
|
+
displayName: 'Owner',
|
|
91
|
+
description: 'Sees only their own rows',
|
|
92
|
+
scopes: [],
|
|
93
|
+
},
|
|
94
|
+
tenant: {
|
|
95
|
+
displayName: 'Tenant',
|
|
96
|
+
description: 'Sees only their own tenancy',
|
|
97
|
+
scopes: [],
|
|
98
|
+
},
|
|
77
99
|
})
|
|
78
100
|
|
|
79
|
-
|
|
80
|
-
visitor: {
|
|
101
|
+
defineVirtualUsers({
|
|
102
|
+
visitor: {
|
|
103
|
+
name: 'Visitor',
|
|
104
|
+
jobTitle: 'Synthetic health-check user',
|
|
105
|
+
account: {},
|
|
106
|
+
},
|
|
81
107
|
amina: { name: 'Amina', jobTitle: 'Owner', roles: ['owner'], account: {} },
|
|
82
108
|
bilal: { name: 'Bilal', jobTitle: 'Owner', roles: ['owner'], account: {} },
|
|
83
109
|
chidi: { name: 'Chidi', jobTitle: 'Tenant', roles: ['tenant'], account: {} },
|
|
@@ -87,10 +113,10 @@ definePersonas({
|
|
|
87
113
|
Two owners in both examples, deliberately: one owner cannot demonstrate that
|
|
88
114
|
owners are separated from each other.
|
|
89
115
|
|
|
90
|
-
- **Keep `visitor`.** The shipped scenarios name `
|
|
116
|
+
- **Keep `visitor`.** The shipped scenarios name `virtualUsers.visitor`; removing it
|
|
91
117
|
fails `pikku all` and nothing you write after that registers.
|
|
92
|
-
- **One `
|
|
93
|
-
- **Never write an email address** — each is derived from the
|
|
118
|
+
- **One `defineVirtualUsers` call for the whole project.**
|
|
119
|
+
- **Never write an email address** — each is derived from the virtual user id and
|
|
94
120
|
`scenarios.emailDomain` in `pikku.config.json`.
|
|
95
121
|
- `roles` is typechecked against `defineSystemRole`; an undeclared role is a
|
|
96
122
|
build error.
|
|
@@ -112,7 +138,7 @@ Then, in this order — it is the order codegen depends on:
|
|
|
112
138
|
the file is plain `INSERT`s — no `ON CONFLICT DO NOTHING`. It is local only:
|
|
113
139
|
no deploy applies it, so anything the app cannot run without belongs in a
|
|
114
140
|
migration instead. **Be generous, and
|
|
115
|
-
seed rows for both
|
|
141
|
+
seed rows for both virtual users.** An empty app demos badly, and you cannot see a
|
|
116
142
|
layout break against zero rows.
|
|
117
143
|
3. **Functions** — one `pikkuFunc` per `*.function.ts`, `expose: true`. Pikku
|
|
118
144
|
generates the typed RPC client and React Query hooks; you do NOT write HTTP
|
|
@@ -150,17 +176,15 @@ than they save:
|
|
|
150
176
|
keystroke now and a rewrite later.
|
|
151
177
|
- Never hardcode a host or port — the API base resolves to same-origin `/api`.
|
|
152
178
|
|
|
153
|
-
Before the first run, make sure `.env` holds
|
|
154
|
-
appends missing
|
|
179
|
+
Before the first run, make sure `.env` holds the local secret — `bun run dev`
|
|
180
|
+
appends it if missing, but an older scaffold or a copied `.env` may not have it:
|
|
155
181
|
|
|
156
182
|
```sh
|
|
157
183
|
grep -q '^BETTER_AUTH_SECRET=' .env 2>/dev/null || echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)" >> .env
|
|
158
|
-
grep -q '^SCENARIO_ACTOR_SECRET=' .env 2>/dev/null || echo "SCENARIO_ACTOR_SECRET=$(openssl rand -base64 32)" >> .env
|
|
159
184
|
```
|
|
160
185
|
|
|
161
186
|
Never commit `.env`. Then run it — through `bun run dev`, never `vite` on its
|
|
162
|
-
own, because the dev script is what
|
|
163
|
-
"Sign in as …" switcher; without it the switcher silently renders nothing:
|
|
187
|
+
own, because the dev script is what points the frontend at your API:
|
|
164
188
|
|
|
165
189
|
```sh
|
|
166
190
|
bun run prebuild && bun run dev
|
|
@@ -186,22 +210,35 @@ taller than the viewport. It is the most likely width your demo gets opened at.
|
|
|
186
210
|
If you have five spare minutes, `npx impeccable install` (Node 22.18+) scores
|
|
187
211
|
each screen against interaction heuristics and names what is wrong. Feed it
|
|
188
212
|
screenshots, not source. It will polish the default look; it will not give the
|
|
189
|
-
app a look — that is
|
|
213
|
+
app a look — that is the app workflow's §8a.
|
|
190
214
|
|
|
191
215
|
## 5. One smoke scenario
|
|
192
216
|
|
|
193
|
-
Not the full ladder — one journey, end to end, as a real
|
|
217
|
+
Not the full ladder — one journey, end to end, as a real virtual user, so the app has
|
|
194
218
|
at least one thing that stays true.
|
|
195
219
|
|
|
196
220
|
```typescript
|
|
197
221
|
import { pikkuScenario } from '#pikku/scenarios'
|
|
198
222
|
|
|
199
|
-
export const ownerCreatesAndSeesItScenario = pikkuScenario<
|
|
223
|
+
export const ownerCreatesAndSeesItScenario = pikkuScenario<
|
|
224
|
+
void,
|
|
225
|
+
{ id: string }
|
|
226
|
+
>({
|
|
200
227
|
title: 'An owner creates a thing and sees it',
|
|
201
228
|
tags: ['scenario', 'smoke'],
|
|
202
|
-
func: async (_services, _data, { scenario,
|
|
203
|
-
const row = await scenario.do(
|
|
204
|
-
|
|
229
|
+
func: async (_services, _data, { scenario, virtualUsers }) => {
|
|
230
|
+
const row = await scenario.do(
|
|
231
|
+
'creates',
|
|
232
|
+
'createThing',
|
|
233
|
+
{ name: 'first' },
|
|
234
|
+
{ virtualUser: virtualUsers.amina }
|
|
235
|
+
)
|
|
236
|
+
await scenario.then(
|
|
237
|
+
'sees it listed',
|
|
238
|
+
'thingShowsInList',
|
|
239
|
+
{ id: row.id },
|
|
240
|
+
{ virtualUser: virtualUsers.amina }
|
|
241
|
+
)
|
|
205
242
|
return { id: row.id }
|
|
206
243
|
},
|
|
207
244
|
})
|
|
@@ -211,9 +248,9 @@ export const ownerCreatesAndSeesItScenario = pikkuScenario<void, { id: string }>
|
|
|
211
248
|
`pikkuScenarioStep`.** An RPC name in a `then` will not resolve.
|
|
212
249
|
- **Every scenario must assert.** A ladder with no `then` is a PKU680 critical —
|
|
213
250
|
it fails `pikku all`, stopping codegen rather than a test.
|
|
214
|
-
-
|
|
215
|
-
|
|
216
|
-
a reason that reads like an auth bug.
|
|
251
|
+
- **Run scenarios against a `pikku dev` server.** `pikku dev` creates the virtual
|
|
252
|
+
user signing key; without a running or previously started dev server every
|
|
253
|
+
scenario fails at sign-in, for a reason that reads like an auth bug.
|
|
217
254
|
- **There is no state reset** — scope what you create to unique ids.
|
|
218
255
|
|
|
219
256
|
Keep the three shipped scenarios in `packages/functions/test/scenarios/` green.
|
|
@@ -230,16 +267,16 @@ it is seeded with, and that this is a quick build — no knowledge base, no
|
|
|
230
267
|
changesets, no design pass, access control clicked-through rather than proven.
|
|
231
268
|
|
|
232
269
|
**Upgrading to a real build is additive, not a rewrite.** If they want it, switch
|
|
233
|
-
to
|
|
270
|
+
to the app workflow (the app reference, see SKILL.md) and do this, in order:
|
|
234
271
|
|
|
235
272
|
1. Write `knowledge/` for what already exists — `entities/` for what you built,
|
|
236
273
|
`decisions/` for what you chose silently, `questions/` for what you guessed
|
|
237
274
|
at. Then `pikku knowledge index && pikku knowledge validate`.
|
|
238
275
|
2. Backfill an entity note for each thing the app holds, so `pikku knowledge
|
|
239
|
-
|
|
240
|
-
3. Write the refusal scenarios — the ones proving one
|
|
276
|
+
gaps` has something to measure against.
|
|
277
|
+
3. Write the refusal scenarios — the ones proving one virtual user cannot reach
|
|
241
278
|
another's rows. This is the gap that matters most.
|
|
242
|
-
4. Then pick up
|
|
279
|
+
4. Then pick up the app workflow at its §4 (apps) or §5 (changes) for
|
|
243
280
|
anything new.
|
|
244
281
|
|
|
245
282
|
Nothing built here has to be thrown away to do that — which is the whole reason
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
# Scenarios — writing journeys that stay proven
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- The shape of a scenario
|
|
6
|
+
- Extraction: what survives, and what silently does not
|
|
7
|
+
- What to assert
|
|
8
|
+
- There is no state reset
|
|
9
|
+
- Steps rot as the app grows
|
|
10
|
+
- Browser scenarios
|
|
11
|
+
- Running them
|
|
12
|
+
- Coverage — which functions have actually been run
|
|
13
|
+
|
|
14
|
+
A scenario is a user journey run as one of your virtual users, over the real transport, with that
|
|
15
|
+
virtual user's session. It is the only kind of test worth writing here, because a passing one proves the
|
|
5
16
|
app works the way a signed-in person experiences it.
|
|
6
17
|
|
|
7
18
|
The traps below all cost a real changeset a red run, and most of them are invisible on the run that
|
|
@@ -28,26 +39,27 @@ import { pikkuScenario } from '#pikku/scenarios'
|
|
|
28
39
|
|
|
29
40
|
export const tenantReportsAFaultScenario = pikkuScenario<void, { id: string }>({
|
|
30
41
|
title: 'A tenant reports a fault and the owner sees it',
|
|
31
|
-
description:
|
|
42
|
+
description:
|
|
43
|
+
'The report lands on the owning landlord’s queue, and nobody else’s',
|
|
32
44
|
tags: ['scenario', 'maintenance'],
|
|
33
|
-
func: async (_services, _data, { scenario,
|
|
45
|
+
func: async (_services, _data, { scenario, virtualUsers }) => {
|
|
34
46
|
const report = await scenario.do(
|
|
35
47
|
'reports a broken boiler',
|
|
36
48
|
'createMaintenanceReport',
|
|
37
49
|
{ summary: 'No hot water' },
|
|
38
|
-
{
|
|
50
|
+
{ virtualUser: virtualUsers.chidi }
|
|
39
51
|
)
|
|
40
52
|
await scenario.then(
|
|
41
53
|
'appears on the owner’s queue',
|
|
42
54
|
'reportShowsOnQueue',
|
|
43
55
|
{ id: report.id },
|
|
44
|
-
{
|
|
56
|
+
{ virtualUser: virtualUsers.amina }
|
|
45
57
|
)
|
|
46
58
|
await scenario.then(
|
|
47
59
|
'is invisible to the other owner',
|
|
48
60
|
'reportIsNotVisible',
|
|
49
61
|
{ id: report.id },
|
|
50
|
-
{
|
|
62
|
+
{ virtualUser: virtualUsers.bilal }
|
|
51
63
|
)
|
|
52
64
|
return { id: report.id }
|
|
53
65
|
},
|
|
@@ -59,10 +71,10 @@ export const tenantReportsAFaultScenario = pikkuScenario<void, { id: string }>({
|
|
|
59
71
|
(server-side by default, plus a `browser` one that drives the page). Reaching for an RPC name in a
|
|
60
72
|
`then` will not resolve.
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
for a reason that reads like an auth bug.
|
|
65
|
-
|
|
74
|
+
**Scenarios sign in with the key `pikku dev` created.** Start `pikku dev` once in the project (it writes
|
|
75
|
+
`.pikku-runtime/virtual-user/signing.key`); without that key every scenario fails at sign-in, before its
|
|
76
|
+
first step, for a reason that reads like an auth bug. Against a deployed stage export
|
|
77
|
+
`VIRTUAL_USER_SIGNING_KEY`, which that stage's deployer holds.
|
|
66
78
|
|
|
67
79
|
---
|
|
68
80
|
|
|
@@ -88,7 +100,7 @@ each half of that rule, because the first half does not imply the second.
|
|
|
88
100
|
|
|
89
101
|
**Write each scenario's setup out in full rather than sharing a local helper.** A helper holding
|
|
90
102
|
setup steps does not fail extraction — the steps are recorded and the suite goes green — but the
|
|
91
|
-
extractor cannot bind an `
|
|
103
|
+
extractor cannot bind an `virtualUser` that arrives as a function parameter, so the transcript credits
|
|
92
104
|
every setup step to whoever the last literal binding named. Seven permission scenarios here read
|
|
93
105
|
"henrik sets up her company Salon Nordlicht" in a suite whose whole point was that the company is
|
|
94
106
|
finja's. A scenario body is a recorded document, and the duplication is the price of it saying who
|
|
@@ -98,7 +110,7 @@ did what.
|
|
|
98
110
|
|
|
99
111
|
## What to assert
|
|
100
112
|
|
|
101
|
-
**Write the refusals, and assert WHY.** One
|
|
113
|
+
**Write the refusals, and assert WHY.** One virtual user reaching for another's row has to be rejected,
|
|
102
114
|
and that rejection is a scenario — it is how you prove access control instead of asserting it. But
|
|
103
115
|
only if the step reads the reason: "not ok" is also what a malformed request returns, so a refusal
|
|
104
116
|
step that stops at the status code passes on a call the function never even ran. One here posted
|
|
@@ -139,7 +151,7 @@ second run starts where its first one stopped.
|
|
|
139
151
|
**Run the suite twice and require the second run green.** A suite that only passes on a fresh
|
|
140
152
|
database is a suite that passes once. Two corollaries, both of which cost a changeset a red run:
|
|
141
153
|
|
|
142
|
-
- **Name nothing a setup step might already own.** `setsUpHerCompany` returns the company that
|
|
154
|
+
- **Name nothing a setup step might already own.** `setsUpHerCompany` returns the company that virtual user
|
|
143
155
|
already has rather than renaming it, so a later step passed the literal name it had asked for and
|
|
144
156
|
was told no such company exists. Read the name, slug or id back off the step's output and pass
|
|
145
157
|
THAT.
|
|
@@ -176,7 +188,7 @@ scenarios that had been green for months.
|
|
|
176
188
|
|
|
177
189
|
**A selector on IDENTITY alone rots the same way once rows gain a lifecycle.** One reused the first
|
|
178
190
|
licence assigned to an email regardless of its state, which was correct until a new changeset's
|
|
179
|
-
refusal scenarios left that
|
|
191
|
+
refusal scenarios left that virtual user holding cancelled ones — it then handed back a dead licence, read
|
|
180
192
|
as success, and failed a scenario two changesets older at a step that needed a live one.
|
|
181
193
|
|
|
182
194
|
**A step's input is a recorded contract, and it does not take a version.** Widening one — an extra
|
|
@@ -240,7 +252,7 @@ bunx --bun pikku scenario run local --spawn # server-side, the
|
|
|
240
252
|
bunx --bun pikku scenario run local --spawn --run browser # the same journeys, driven as a human
|
|
241
253
|
```
|
|
242
254
|
|
|
243
|
-
In a multi-app project that one run covers both frontends: each
|
|
255
|
+
In a multi-app project that one run covers both frontends: each virtual user carries
|
|
244
256
|
its own `app` and `@pikku/playwright` resolves the base url from the
|
|
245
257
|
environment's `appUrls` map, so there is no second environment to run.
|
|
246
258
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
# Shipping, and staying
|
|
1
|
+
# Shipping, and staying deploy-ready
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Ship it — open source, no platform
|
|
6
|
+
- Staying deploy-ready
|
|
2
7
|
|
|
3
8
|
Read this when the changes queue is empty and the scenarios are green — it is
|
|
4
9
|
the last phase, and nothing in it is needed before then.
|
|
@@ -81,7 +86,7 @@ Changing the strategy renames units, and a unit name is what a queue consumer, a
|
|
|
81
86
|
scheduled task and a `dependsOn` point at. The manifest rewrites all three, but
|
|
82
87
|
anything holding a unit name outside the manifest does not follow. Units dropped
|
|
83
88
|
from the manifest are not deleted by OSS `deploy()` either (pikkujs/pikku#543) —
|
|
84
|
-
|
|
89
|
+
a hosting platform may sweep them after each deploy, plain pikku leaves the
|
|
85
90
|
old workers in place.
|
|
86
91
|
|
|
87
92
|
`tags` matches the tags a function inherits from its wirings — `wireHTTP({ ...,
|
|
@@ -114,7 +119,7 @@ one hostname, first-party cookies — give its `frontends` entry `"serve": {}`
|
|
|
114
119
|
and a standalone deploy then mount its built `dist`. Pikku never builds it, so
|
|
115
120
|
build the frontend first. Only one entry may set `serve`.
|
|
116
121
|
|
|
117
|
-
To ship an app as a desktop or Android app, read
|
|
122
|
+
To ship an app as a desktop or Android app, read the native-app reference (see SKILL.md).
|
|
118
123
|
|
|
119
124
|
Before shipping, run the full gate:
|
|
120
125
|
|
|
@@ -153,23 +158,22 @@ lint over function return types, catching a `Pii`/`Secret` field that leaks
|
|
|
153
158
|
through an exposed function. Expensive, so run it before a release rather than on
|
|
154
159
|
every save — but run it.
|
|
155
160
|
|
|
156
|
-
## Staying
|
|
161
|
+
## Staying deploy-ready
|
|
157
162
|
|
|
158
163
|
Everything above is open source. This is the contract that keeps
|
|
159
|
-
|
|
164
|
+
the project a one-command import for a hosting platform later, instead of a migration.
|
|
160
165
|
|
|
161
166
|
- **`frontends` in `pikku.config.json` describes reality.** Every app has an
|
|
162
167
|
entry with the right `cwd`, `kind` and `dev` (`command`, `port`); exactly one
|
|
163
|
-
is `primary`; `serves` and `
|
|
164
|
-
|
|
165
|
-
- **`
|
|
166
|
-
have the real id; the CLI writes it
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
frontend. Fabric materialises these as its virtual users; a persona nobody
|
|
168
|
+
is `primary`; `serves` and `virtualUsers` name real virtual users declared in
|
|
169
|
+
`defineVirtualUsers`.
|
|
170
|
+
- **`cloud.projectId` in `pikku.config.json` is optional.** Leave it out unless you
|
|
171
|
+
have the real id; the CLI writes it once the project is linked. Do not invent a value.
|
|
172
|
+
- **One `defineVirtualUsers` call**, every virtual user reachable through exactly one
|
|
173
|
+
frontend. A hosting platform may materialise these as its users; a virtual user nobody
|
|
170
174
|
serves imports as a person with no way in.
|
|
171
175
|
- **`knowledge/` passes `validate`, and `pikku knowledge gaps` lists nothing.** This is
|
|
172
|
-
the part
|
|
176
|
+
the part a hosting platform reads and continues from.
|
|
173
177
|
- **Every plan under `knowledge/plans/` passes `pikku knowledge plan progress`.**
|
|
174
178
|
A merged changeset is a claim; the plan reconciled against the generated meta
|
|
175
179
|
is the check. Anything the first pass still owes is either built now or deferred with
|
|
@@ -187,7 +191,6 @@ Everything above is open source. This is the contract that keeps
|
|
|
187
191
|
the SDK.
|
|
188
192
|
- **`pikku validate` is clean**, and `pikku all` has no critical diagnostics.
|
|
189
193
|
|
|
190
|
-
What you deliberately do NOT do:
|
|
191
|
-
|
|
192
|
-
is needed the day the user wants Fabric to host and build it, and on that day, if
|
|
194
|
+
What you deliberately do NOT do: link a project to a hosting platform. None of it is needed to build, test, critique, or deploy — it
|
|
195
|
+
is needed the day the user wants one to host and build it, and on that day, if
|
|
193
196
|
this section holds, that day is one command long.
|