@akanjs/cli 3.0.0-alpha.1 → 3.0.0-alpha.100
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/.build-stamp +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/{abstractCompactor-e5yq60qz.js → abstractCompactor-byytxs22.js} +3 -5
- package/{agent.command-yv00p0s0.js → agent.command-v1a4746v.js} +11 -12
- package/{application.command-0qsczf4k.js → application.command-fzdcnzhg.js} +65 -37
- package/{applicationBuildRunner-ct2pxyvw.js → applicationBuildRunner-s4gsk728.js} +28 -24
- package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-28v9vbzk.js} +8 -9
- package/buildBatch.proc.js +12 -13
- package/capacitorApp-8d6d4zkm.js +12 -0
- package/{cloud.command-dxfv18sa.js → cloud.command-wygy2z05.js} +15 -17
- package/commandManifest.json +1 -1
- package/{context.command-8d9e3k6b.js → context.command-4vdt1aqq.js} +19 -22
- package/dependencyScanner-shs82ynp.js +8 -0
- package/devTui-qnf1txdz.js +553 -0
- package/devTuiView-yzct2cq6.js +9 -0
- package/getDirname-dr3jz1xg.js +7 -0
- package/{guideline.command-3jbkxzh6.js → guideline.command-p92dq6ts.js} +16 -17
- package/guidelines/agentRule/agentRule.generate.json +31 -0
- package/guidelines/agentRule/agentRule.instruction.md +533 -0
- package/guidelines/conventions/conventions.generate.json +25 -0
- package/guidelines/conventions/conventions.instruction.md +908 -0
- package/guidelines/cssRule/cssRule.instruction.md +7 -0
- package/guidelines/framework/framework.generate.json +3 -2
- package/guidelines/framework/framework.instruction.md +1 -9
- package/guidelines/mcpRule/mcpRule.generate.json +25 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +217 -0
- package/guidelines/modelStore/modelStore.instruction.md +12 -0
- package/guidelines/modelTemplate/modelTemplate.instruction.md +5 -0
- package/guidelines/queryRule/queryRule.generate.json +31 -0
- package/guidelines/queryRule/queryRule.instruction.md +175 -0
- package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
- package/guidelines/runtimeRule/runtimeRule.instruction.md +220 -0
- package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
- package/guidelines/transportRule/transportRule.generate.json +31 -0
- package/guidelines/transportRule/transportRule.instruction.md +60 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +263 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +402 -0
- package/incrementalBuilder.proc.js +26 -24
- package/{index-mr5s7mqd.js → index-0amdxycf.js} +8 -8
- package/{index-t3723f99.js → index-1yxtbmbj.js} +111 -42
- package/{index-ej426mcr.js → index-29sxqfaw.js} +65 -38
- package/index-3d9y066c.js +76 -0
- package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
- package/index-5svjba73.js +159 -0
- package/index-6wwzs1bc.js +7 -0
- package/{index-k95xkh4p.js → index-7d6vny25.js} +16 -12
- package/{index-ec09pws3.js → index-8p8p0cf8.js} +14 -14
- package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
- package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
- package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
- package/{index-0cj2zxbm.js → index-c69j78kk.js} +12 -11
- package/{index-rzwcpcc3.js → index-fc1bh0a7.js} +4 -4
- package/{index-7c6k4yvg.js → index-gq44bqjt.js} +58 -25
- package/{index-a00jg8x8.js → index-gtmz74tj.js} +79 -55
- package/{index-tdbas9r0.js → index-h7yw2z9n.js} +7 -7
- package/{index-bjpxzr6s.js → index-hwkygn9s.js} +51 -3
- package/{index-bbkek1bp.js → index-hyywke0f.js} +1 -1
- package/{index-46tjzh6s.js → index-kcxmv48c.js} +29 -29
- package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
- package/{index-pyt2b4nw.js → index-p5neav9b.js} +1129 -1356
- package/{index-67546d0j.js → index-q0y2jq9j.js} +14 -2
- package/{index-bekddz9q.js → index-qkk27bk6.js} +32 -32
- package/{index-hgna5rjy.js → index-qsq3q8fy.js} +1034 -257
- package/{index-2q1f5j9k.js → index-srdssqj7.js} +18 -18
- package/{index-rh16j3c7.js → index-w8kmx1b6.js} +23 -13
- package/{index-nm6wghb6.js → index-yks023mb.js} +13 -13
- package/{index-1pvex4az.js → index-yza7zkpt.js} +94 -61
- package/{index-yzmhasdb.js → index-zmjppp25.js} +57 -57
- package/{index-8hsbnyes.js → index-znynzt5w.js} +100 -30
- package/{index-zasydjxd.js → index-zxgr3s8s.js} +31 -30
- package/{index-e16gnn26.js → index-zz5jyd94.js} +1002 -128
- package/index.js +22 -24
- package/{library.command-ebdj1vnm.js → library.command-s4fszngs.js} +11 -9
- package/{localRegistry.command-gb178ne8.js → localRegistry.command-gyw4da9z.js} +20 -22
- package/{module.command-9c1bnsx4.js → module.command-6n7dwvav.js} +13 -15
- package/{package.command-t93p4jkj.js → package.command-gr82ypnr.js} +8 -9
- package/package.json +5 -7
- package/{page.command-k3k0meh2.js → page.command-7gvgb3jb.js} +7 -8
- package/{primitive.command-de6nktdt.js → primitive.command-tk5ckw38.js} +13 -15
- package/{quality.command-z5kth2wa.js → quality.command-38v81baf.js} +229 -138
- package/recipeScanner-fpagtgc1.js +11 -0
- package/{repair.command-ehf2g112.js → repair.command-5xbwvsxp.js} +12 -13
- package/{routeSourceValidator-cncd92fv.js → routeSourceValidator-ze6x894c.js} +2 -40
- package/{scalar.command-7a2jtv33.js → scalar.command-0epwcr5k.js} +11 -13
- package/subspace.command-e2t36xb2.js +755 -0
- package/templates/app/env/env.client.debug.ts.template +1 -5
- package/templates/app/env/env.client.develop.ts.template +1 -5
- package/templates/app/env/env.client.local.ts.template +1 -5
- package/templates/app/env/env.client.main.ts.template +1 -5
- package/templates/app/env/env.client.testing.ts.template +1 -5
- package/templates/app/env/env.client.type.ts +2 -6
- package/templates/app/env/env.server.debug.ts.template +1 -5
- package/templates/app/env/env.server.develop.ts.template +1 -5
- package/templates/app/env/env.server.local.ts.template +1 -5
- package/templates/app/env/env.server.main.ts.template +1 -5
- package/templates/app/main.ts +3 -1
- package/templates/app/page/styles.css.template +3 -3
- package/templates/appSample/lib/task/task.signal.ts +11 -6
- package/templates/appSample/srvkit/AuthGuard.ts +9 -5
- package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
- package/templates/crudPages/[__model__Id]/edit/page.tsx +6 -6
- package/templates/crudPages/[__model__Id]/page.tsx +10 -13
- package/templates/crudPages/new/page.tsx +6 -6
- package/templates/crudPages/page.tsx +9 -9
- package/templates/crudSinglePage/page.tsx +11 -7
- package/templates/env/_env.server.type.ts +7 -5
- package/templates/lib/db.ts +4 -2
- package/templates/lib/dict.ts +1 -1
- package/templates/lib/sig.ts +5 -1
- package/templates/lib/srv.ts +6 -2
- package/templates/lib/useClient.ts +9 -3
- package/templates/module/__Model__.Util.tsx +1 -1
- package/templates/module/__Model__.Zone.tsx +3 -5
- package/templates/module/__model__.dictionary.ts +4 -1
- package/templates/module/__model__.signal.ts +2 -3
- package/templates/module/__model__.store.ts +1 -2
- package/templates/workspaceRoot/.gitignore.template +0 -1
- package/templates/workspaceRoot/.husky/pre-commit.template +16 -0
- package/templates/workspaceRoot/.vscode/settings.json.template +1 -1
- package/templates/workspaceRoot/AGENTS.md.template +4 -948
- package/templates/workspaceRoot/CLAUDE.md.template +19 -0
- package/templates/workspaceRoot/biome.json.template +4 -198
- package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +15 -16
- package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
- package/templates/workspaceRoot/package.json.template +2 -4
- package/typeChecker-3xgrzc2v.js +7 -0
- package/typecheck.proc.js +4 -5
- package/{workflow.command-e0tt0vk2.js → workflow.command-kphbr7eh.js} +21 -23
- package/{workspace.command-fpda0evj.js → workspace.command-j1gatz3d.js} +108 -91
- package/capacitorApp-4r9sm3qg.js +0 -58
- package/dependencyScanner-f6grrep3.js +0 -9
- package/index-mxvakhsm.js +0 -66
- package/index-r24hmh0q.js +0 -4
- package/recipeScanner-tghkzrrt.js +0 -12
- package/templates/libRoot/base/baseLogic.ts +0 -14
- package/templates/libRoot/base/index.ts +0 -8
- package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
- package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -33
- package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
- package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
- package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
- package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
- package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -18
- package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -61
- package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
- package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
- package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -58
- package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
- package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
- package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
- package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
- package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
- package/typeChecker-kravn7ns.js +0 -8
- /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
- /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
## Workspace Layout
|
|
2
|
+
|
|
3
|
+
- `apps/<app>` contains application pages, app UI, app domain modules, env files, and `akan.config.ts`.
|
|
4
|
+
- `libs/<lib>` contains shared domain and utility code reused by apps.
|
|
5
|
+
- `apps/<app>/lib/<model>` holds database-backed domain modules, `lib/_<service>` service modules, and
|
|
6
|
+
`lib/__scalar/<scalar>` reusable value types. Module abstracts sit beside the code as `<name>.abstract.md`.
|
|
7
|
+
- `apps/<app>/page` holds server-side file-routed pages: `<routeName>.tsx` serves `/routeName`, a directory's
|
|
8
|
+
`_index.tsx` serves that directory, `_layout.tsx` nests a layout, and `[modelId]` is a dynamic segment.
|
|
9
|
+
|
|
10
|
+
The file roles inside a module — which file owns persistence, business logic, state, and each UI shape — are in
|
|
11
|
+
the convention set above under **Domain Module Conventions**.
|
|
12
|
+
|
|
13
|
+
## Agent Workflow
|
|
14
|
+
|
|
15
|
+
1. Read the nearby module and convention before creating files. If `*.abstract.md` exists, read it first.
|
|
16
|
+
2. Put new files in the established Akan location instead of adding parallel architecture.
|
|
17
|
+
3. Prefer Akan MCP workflows before direct source edits. Start with `akan mcp --mode plan` for `list_workflows`, `explain_workflow`, and `plan_workflow`.
|
|
18
|
+
4. If `plan_workflow` returns `planPath` or `next.tool=apply_workflow`, call `apply_workflow({ planPath })` before direct source edits.
|
|
19
|
+
5. Use `akan mcp --mode apply` only for allowlisted `apply_workflow`, `run_validation`, and repair tools.
|
|
20
|
+
6. After `apply_workflow`, run `run_validation` with `validationTarget` when present; otherwise use `applyReportPath`.
|
|
21
|
+
7. Direct source edits are denied when an allowlisted Akan workflow or repair tool can perform the change.
|
|
22
|
+
8. If no workflow exists, or apply reports unsupported/no-op/failed diagnostics that require manual action, edit only the owning source files and never patch generated files directly.
|
|
23
|
+
9. Treat `AKAN_PUBLIC_*` env vars as public. Never put secrets in them.
|
|
24
|
+
10. Add or update tests when behavior, contracts, or CLI output changes.
|
|
25
|
+
11. Update `*.abstract.md` when business invariants, workflows, or public behavior change.
|
|
26
|
+
12. Run the smallest relevant verification command after changes. After touching any `.tsx`, that includes
|
|
27
|
+
`akan quality ssr`.
|
|
28
|
+
|
|
29
|
+
The rules for where code goes, the client/server boundary, and SSR discipline are in the convention set above;
|
|
30
|
+
this section covers only the order of operations.
|
|
31
|
+
|
|
32
|
+
## Common Commands
|
|
33
|
+
|
|
34
|
+
Run commands from the workspace root unless a task says otherwise.
|
|
35
|
+
|
|
36
|
+
### Module Addition Workflow
|
|
37
|
+
|
|
38
|
+
When adding a new database-backed domain module (e.g., product, user):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# 1. Scaffold the module with Akan CLI (creates constant, service, signal, store, document files)
|
|
42
|
+
# The target app/lib is a POSITIONAL argument, not a --app flag.
|
|
43
|
+
akan create-module <module-name> <%= appName %>
|
|
44
|
+
|
|
45
|
+
# 2. Start dev server with HMR and type checking at http://localhost:8282
|
|
46
|
+
akan start <%= appName %>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Change Verification Workflow
|
|
50
|
+
|
|
51
|
+
After any code change, run these in order:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# 1. Fast lint check — Akan.js conventions and Biome rules
|
|
55
|
+
akan lint <%= appName %>
|
|
56
|
+
|
|
57
|
+
# 2. Type-only check — catches server/client boundary violations and import errors
|
|
58
|
+
akan typecheck <%= appName %>
|
|
59
|
+
|
|
60
|
+
# 3. Test — Run the test code (lib/*/*.signal.test.ts or others)
|
|
61
|
+
akan test <%= appName %>
|
|
62
|
+
|
|
63
|
+
# 4. SSR balance — only after touching .tsx files. Reports the server render share
|
|
64
|
+
# per app/lib and flags client code that should render on the server.
|
|
65
|
+
akan quality ssr
|
|
66
|
+
|
|
67
|
+
# 5. Full production build — bundles the app, runs all type/lint checks combined
|
|
68
|
+
akan build <%= appName %>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Verify endpoints with signal tests, not raw HTTP.** The canonical way to check a query/mutation/slice
|
|
72
|
+
contract is an in-memory signal test (`<model>.signal.test.ts`), using the test fetch harness
|
|
73
|
+
(`getOrSetupSignalTestFetch`) — it is fast, needs no running server, and exercises `fetch.*`, `view/edit/merge<Model>`,
|
|
74
|
+
and slice `init`/`list`/`insight` directly. Prefer it over `curl`: the dev gateway locale-prefixes routes (`/en/...`),
|
|
75
|
+
so hand-rolled HTTP calls against a raw path can redirect unexpectedly. See `akan test <%= appName %>`.
|
|
76
|
+
|
|
77
|
+
### Other Frequently Used Commands
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
akan create-scalar <scalar-name> <%= appName %> # Add a scalar module (lib/__scalar/<scalar-name>/)
|
|
81
|
+
akan create-service <service-name> <%= appName %> # Add a service module (lib/_<service-name>/)
|
|
82
|
+
akan test <%= appName %> # Run the test code (lib/*/*.signal.test.ts or others)
|
|
83
|
+
akan lint <%= appName %> # Lint only (no typecheck)
|
|
84
|
+
akan quality scan # All code-quality warnings + SSR balance
|
|
85
|
+
akan quality ssr # SSR balance and client-boundary warnings only
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**CLI argument conventions.** Two argument styles, and mixing them up is a common mistake:
|
|
89
|
+
|
|
90
|
+
- Scaffolding and whole-app commands take the target app/lib as a **positional** argument, not a flag:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
akan create-module photo <%= appName %>
|
|
94
|
+
akan create-scalar money <%= appName %>
|
|
95
|
+
akan create-service billing <%= appName %>
|
|
96
|
+
akan sync <%= appName %>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- Only the source-limited field commands use `--app`/`--module` flags:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
akan add-field --app <%= appName %> --module photo --field width --type Int
|
|
103
|
+
akan add-enum-field --app <%= appName %> --module photo --field status --values draft,active
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Passing `--app` to `create-module` is not recognized, and the target app will not resolve.
|
|
107
|
+
|
|
108
|
+
For the default generated app, start with:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
akan start <%= appName %>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### The Essential Loop: Workflow -> Sync -> Check
|
|
115
|
+
|
|
116
|
+
Almost every Akan.js change follows this pattern. **Missing sync or repair is the #1 cause of agent confusion.**
|
|
117
|
+
|
|
118
|
+
> **If the Akan MCP tools are not connected in your agent, skip straight to the CLI-only fallback below.**
|
|
119
|
+
> `akan mcp --mode plan/apply` starts a stdio MCP server that only works when your agent is wired to it as an
|
|
120
|
+
> MCP client. When those `list_workflows` / `plan_workflow` / `apply_workflow` tools are not available, the CLI
|
|
121
|
+
> commands are a fully supported, first-class path — you are not losing any capability by using them.
|
|
122
|
+
|
|
123
|
+
1. **Plan** — Ask the Akan MCP server for the workflow first.
|
|
124
|
+
```
|
|
125
|
+
akan mcp --mode plan
|
|
126
|
+
# use list_workflows, explain_workflow, and plan_workflow
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
2. **Apply the plan** — If `plan_workflow` returns `planPath` or `next.tool=apply_workflow`, call
|
|
130
|
+
`apply_workflow({ planPath })`. Do not copy the workflow plan into direct source edits.
|
|
131
|
+
```
|
|
132
|
+
akan mcp --mode apply
|
|
133
|
+
# use apply_workflow, run_validation, repair_generated, repair_imports, or repair_module_shape
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Direct edits are fallback only: use them after `list_workflows`/`explain_workflow` confirm no matching workflow, or
|
|
137
|
+
after apply reports unsupported/no-op/failed diagnostics that require manual action. Keep fallback edits to owning
|
|
138
|
+
source files such as `task.constant.ts`, `task.dictionary.ts`, `Task.Template.tsx`, or `Task.Unit.tsx`.
|
|
139
|
+
|
|
140
|
+
3. **Validate the apply report** — Use the apply report artifact, not the original raw plan, when it is available.
|
|
141
|
+
```
|
|
142
|
+
# run_validation with validationTarget first; otherwise use applyReportPath
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
4. **Sync or repair** — Regenerate barrel files so Akan discovers your change. This regenerates:
|
|
146
|
+
`cnst.ts`, `db.ts`, `srv.ts`, `sig.ts`, `st.ts`, `dict.ts`, `useClient.ts`, `useServer.ts`,
|
|
147
|
+
`ui/index.ts`, `webkit/index.ts`, `srvkit/index.ts`, `common/index.ts`, and all module `index.ts` files.
|
|
148
|
+
```
|
|
149
|
+
akan sync <%= appName %>
|
|
150
|
+
# or: akan repair generated --app <%= appName %>
|
|
151
|
+
```
|
|
152
|
+
**CRITICAL**: Sync after EVERY file add, delete, or rename. Without sync, other modules cannot
|
|
153
|
+
`import * as cnst from "../cnst"` and find your new model.
|
|
154
|
+
|
|
155
|
+
5. **Check** — Verify your change compiles and lints.
|
|
156
|
+
```
|
|
157
|
+
akan start <%= appName %> # dev server with live feedback (preferred)
|
|
158
|
+
akan lint <%= appName %> # quick lint-only check
|
|
159
|
+
akan doctor --strict # structured workspace diagnostics
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
If `akan sync` gives errors, try:
|
|
163
|
+
- `akan build <%= appName %>` — full rebuild catches type errors sync may miss
|
|
164
|
+
- Re-run `akan create-module <name> <%= appName %>` if the scaffold is corrupted
|
|
165
|
+
|
|
166
|
+
For compound natural-language requests, split the request into workflows and apply each artifact in order. For example,
|
|
167
|
+
"create a project module and add a budget field" should run `create-module` plan/apply first, then `add-field`
|
|
168
|
+
plan/apply, then validation/doctor on the returned `validationTarget`.
|
|
169
|
+
|
|
170
|
+
### CLI-Only Fallback (MCP Not Connected)
|
|
171
|
+
|
|
172
|
+
When the Akan MCP tools are not loaded, run the CLI commands directly. Each MCP tool maps 1:1 to a CLI command,
|
|
173
|
+
and the CLI emits the same structured report via `--format json`:
|
|
174
|
+
|
|
175
|
+
| MCP tool | CLI-only equivalent |
|
|
176
|
+
|----------|---------------------|
|
|
177
|
+
| `list_workflows` | `akan workflow list` |
|
|
178
|
+
| `explain_workflow <name>` | `akan workflow explain <name>` |
|
|
179
|
+
| `plan_workflow <name> ...` | `akan workflow plan <name> ... --format json --out <planPath>` |
|
|
180
|
+
| `apply_workflow { planPath }` | `akan workflow apply <planPath> --format json` (add `--dry-run` to preview) |
|
|
181
|
+
| `run_validation { validationTarget }` | `akan doctor --strict --format json` (or `akan typecheck <%= appName %>`) |
|
|
182
|
+
| `repair_generated` / `repair_imports` / `repair_module_shape` | `akan repair generated\|imports\|module-shape --app <%= appName %> --format json` |
|
|
183
|
+
|
|
184
|
+
The scaffolding primitives (`akan create-module`, `akan create-scalar`, `akan create-service`, `akan add-field`,
|
|
185
|
+
`akan add-enum-field`) are the same primitives the workflows call, so `create-module <name> <%= appName %>` followed
|
|
186
|
+
by `akan sync <%= appName %>` is equivalent to running the `create-module` workflow. Direct source edits remain the
|
|
187
|
+
final fallback when no CLI command covers the change.
|
|
188
|
+
|
|
189
|
+
## Quick Decision Matrix — "Where do I put this code?"
|
|
190
|
+
|
|
191
|
+
| You want to... | Create in... | Run after... |
|
|
192
|
+
|----------------|-------------|--------------|
|
|
193
|
+
| Define a new database-backed noun (e.g., User, Product) | `lib/<model>/` → constant, document, service, signal, store, dictionary, abstract | `akan sync <name>` |
|
|
194
|
+
| Add a pure workflow / integration (e.g., Payment, Email) | `lib/_<service>/` → service, signal, store, dictionary, abstract | `akan sync <name>` |
|
|
195
|
+
| Add a reusable value type (e.g., Address, WorkHistory) | `lib/__scalar/<type>/` → constant, dictionary, abstract | `akan sync <name>` |
|
|
196
|
+
| Create a new URL-visitable page | `page/` → `_index.tsx`, `_layout.tsx`, `[param]/_index.tsx` | Rebuild (akan start auto-detects) |
|
|
197
|
+
| Change the app color theme / design tokens | `apps/<app>/page/styles.css` → override the semantic token values under `:root, [data-theme="dark"]` and `[data-theme="light"]` (`--primary`, `--background`, `--foreground`, …) | akan start hot-reloads |
|
|
198
|
+
| Add a form or reusable UI component | `ui/` → PascalCase `.tsx`, **no** `"use client"` unless it uses a hook, event handler, store, or browser API | `akan sync <name>` |
|
|
199
|
+
| Add a React hook or browser helper | `webkit/` → camelCase `.ts` with `"use client"` | `akan sync <name>` |
|
|
200
|
+
| Add a server-only guard, middleware, or adaptor | `srvkit/` → PascalCase `.ts` | `akan sync <name>` |
|
|
201
|
+
| Add a pure helper (no DOM, no server API) | `common/` → camelCase `.ts` | `akan sync <name>` |
|
|
202
|
+
|
|
203
|
+
## Workflow Recipes
|
|
204
|
+
|
|
205
|
+
Six worked recipes carry the full code for the most frequent Akan changes, together with the reference of what
|
|
206
|
+
`akan sync` generates at each layer. They are **not** inlined here — fetch them when you are about to do one:
|
|
207
|
+
`get_guideline` with `workspaceRecipes`, or `akan guideline show workspaceRecipes`.
|
|
208
|
+
|
|
209
|
+
| Recipe | Covers |
|
|
210
|
+
|---|---|
|
|
211
|
+
| 1. Adding a field to a model | the five `constant.ts` classes, the dictionary entry, the store form, `akan sync` |
|
|
212
|
+
| 2. Injecting a dependency into a service | `service<srv.XService>()`, `plug(Adapter)`, `env(...)`, `use<T>()` |
|
|
213
|
+
| 3. Creating and using a slice | `slice()` guards, the generated `init<Model><Suffix>`, `Load.Units` hydration |
|
|
214
|
+
| 4. Creating a mutation endpoint | the document chain method, the service call, the signal `guards`, the store action |
|
|
215
|
+
| 5. Internal triggers | `internal()` with interval and cron |
|
|
216
|
+
| 6. Creating an insight | the `XInsight` class, the aggregation, the dashboard tile |
|
|
217
|
+
| Data Flow Summary | how a value travels page → store → signal → service → document → DB |
|
|
218
|
+
| Auto-Generated API Reference | what signal, service, store, and document each generate — never hand-write these |
|
|
219
|
+
|
|
220
|
+
The rules those recipes obey are in this file; the recipes only show the code. When you edit a file, read the
|
|
221
|
+
existing content first and change only the relevant sections — never rewrite a whole file.
|
|
222
|
+
|
|
223
|
+
## Modeling & Query Gotchas
|
|
224
|
+
|
|
225
|
+
A short list of things the type system does not always catch. The full rules for text search, `cascade`, and the
|
|
226
|
+
query-level writes are in the convention set above; these are the shapes that build green and fail later.
|
|
227
|
+
|
|
228
|
+
- **Slices return a query, not a list.** A slice `exec` must return `this.<model>Service.query<Filter>(...)`, never
|
|
229
|
+
a `list<Filter>(...)` / `listBy...(...)` array. Returning an array type-checks but fails at runtime with
|
|
230
|
+
`Unknown document field path: 0`. (See Recipe 3.)
|
|
231
|
+
- **Custom endpoint names must not collide with generated CRUD.** `create/update/remove/view/edit/merge<Model>`
|
|
232
|
+
already exist. A collision can build green and fail only at runtime — pick a distinct verb.
|
|
233
|
+
- **Numbers are `Int` or `Float`, never `Number`.** `field(Number)` / `.body("x", Number)` fail to typecheck.
|
|
234
|
+
- **Array fields use `field([T])`** — `tags: field([String])`, `images: field([File])`.
|
|
235
|
+
- **Reading a secret field needs an explicit select.** `field(...).secret()` values are stripped from query results
|
|
236
|
+
by default: `this.userModel.pickById(id, { select: { passwordHash: true } })`.
|
|
237
|
+
- **`cascade` names a direction, and the wrong one is a data loss** — `removeRef` on the relation the owner holds,
|
|
238
|
+
`removeWith` on the child's reference to its owner. A query-level removal fires no hooks and therefore no cascade.
|
|
239
|
+
- **`q.search()` is a filter node, not a slice requirement.** `bySearch: filter().arg("text", String).query((text,
|
|
240
|
+
q) => q.search(text, { prefix: true }))` generates `listBySearch` / `countBySearch` / `queryBySearch` /
|
|
241
|
+
`insightBySearch` for free. Only add a search *slice* when the model's data is safe to enumerate.
|
|
242
|
+
|
|
243
|
+
## Current User, Guards & Auth-Gated Pages
|
|
244
|
+
|
|
245
|
+
Built-in user authentication (session / JWT / password hashing) ships as a separate Akan auth library, not in the
|
|
246
|
+
core framework. The core framework gives you the composition points below; wire the auth library through them.
|
|
247
|
+
|
|
248
|
+
- **A `slice()` takes its guard map as a second argument**, `slice(srv.task, { guards: { root: Admin, get: SignedIn,
|
|
249
|
+
cru: SignedIn } }, (init) => ({...}))`. An `endpoint()` takes no guard argument at all —
|
|
250
|
+
`endpoint(srv.task, ({ mutation }) => ({...}))` — so **every custom `mutation` / `query` / `message` names its own
|
|
251
|
+
`guards: [...]` array**: `mutation(cnst.Task, { guards: [SignedIn] })`. `Public` always allows; other guards
|
|
252
|
+
implement the `Guard` interface in `srvkit/` (server-only).
|
|
253
|
+
- **Read the caller inside a guard** with `context.get<T>("account")`, which works on HTTP and websocket calls
|
|
254
|
+
alike — never branch on `getHttpContext()` / `getWebSocketContext()`. Every guard class also declares
|
|
255
|
+
`static scope: GuardScope`, `"account"` or `"resource"`, with no default.
|
|
256
|
+
- **Read the current user inside a custom endpoint** by injecting an `InternalArg` with `.with(...)`:
|
|
257
|
+
`mutation(cnst.Task, { guards: [SignedIn] }).with(CurrentUserId).exec(async function (currentUserId) { ... })`.
|
|
258
|
+
- **Auto-generated CRUD and `serve()` service methods / lifecycle hooks do not receive session context.** If an
|
|
259
|
+
operation needs the acting user, expose a custom endpoint that takes it via `.with(CurrentUserId)` — never trust a
|
|
260
|
+
client-supplied user id.
|
|
261
|
+
- **SSR auth-gated pages: guard at the layout.** Check the session in the `_layout.tsx` loader and redirect when it is
|
|
262
|
+
absent, so nested pages never render for signed-out users.
|
|
263
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Workspace Recipes",
|
|
3
|
+
"description": "Worked step-by-step recipes for common Akan changes, plus the auto-generated signal/service/store/document API reference",
|
|
4
|
+
"group": "core",
|
|
5
|
+
"codegenPriority": 5,
|
|
6
|
+
"deprecated": false,
|
|
7
|
+
"scans": [
|
|
8
|
+
{
|
|
9
|
+
"type": "example",
|
|
10
|
+
"description": "Module files a recipe walks through",
|
|
11
|
+
"path": "{apps,libs}/*/lib/*/*.{constant,document,service,signal,store}.ts",
|
|
12
|
+
"sample": 5
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"update": {
|
|
16
|
+
"filePath": "./workspaceRecipes.instruction.md",
|
|
17
|
+
"contents": [
|
|
18
|
+
"add a field",
|
|
19
|
+
"inject a dependency",
|
|
20
|
+
"create a slice",
|
|
21
|
+
"create a mutation",
|
|
22
|
+
"internal triggers",
|
|
23
|
+
"insights",
|
|
24
|
+
"auto-generated API reference"
|
|
25
|
+
],
|
|
26
|
+
"rules": [
|
|
27
|
+
"Use current Akan APIs only",
|
|
28
|
+
"Every recipe names the files to edit and the order to edit them in",
|
|
29
|
+
"Keep the <%= appName %> placeholder so the rendered guide names this workspace's app",
|
|
30
|
+
"Never duplicate a rule that workspaceOnboarding already states — link to it instead"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|