@akanjs/cli 3.0.0-beta.9 → 3.0.1

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 (224) hide show
  1. package/.build-stamp +1 -1
  2. package/CodeAgent-zfab7pkn.js +9 -0
  3. package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/CodeTui-0zhnr0pw.js +1457 -0
  6. package/README.ko.md +83 -28
  7. package/README.md +70 -27
  8. package/TunnelShare-cwh9ezsm.js +9 -0
  9. package/{agent.command-0q17pnrs.js → agent.command-aja6z9mn.js} +8 -9
  10. package/akanCode.js +102 -0
  11. package/application.command-049ehgx3.js +246 -0
  12. package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-75n5rpwp.js} +121 -77
  13. package/buildBatch.proc.js +120 -32
  14. package/cloud.command-gw4kqxt8.js +95 -0
  15. package/cloud.script-c723cpcb.js +20 -0
  16. package/code.command-x9t6z5nw.js +154 -0
  17. package/commandManifest.json +1 -1
  18. package/consoleToStderr-h5bryj94.js +7 -0
  19. package/context.command-yfbe1rtd.js +48 -0
  20. package/context.runner-erfe68j5.js +21 -0
  21. package/{dependencyScanner-shs82ynp.js → dependencyScanner-06z2dmrr.js} +2 -2
  22. package/{devTui-m1atgkc9.js → devTui-q7k7bakd.js} +122 -40
  23. package/fileSys-wzzrntkw.js +9 -0
  24. package/guideline.command-kq9gp690.js +42 -0
  25. package/guidelines/agentRule/agentRule.instruction.md +154 -26
  26. package/guidelines/conventions/conventions.instruction.md +138 -48
  27. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  28. package/guidelines/queryRule/queryRule.instruction.md +21 -7
  29. package/guidelines/runtimeRule/runtimeRule.instruction.md +291 -6
  30. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  31. package/guidelines/transportRule/transportRule.instruction.md +10 -8
  32. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +20 -0
  33. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
  34. package/incrementalBuilder.proc.js +564 -109
  35. package/{index-2tv3fdx4.js → index-150s07n8.js} +1230 -1459
  36. package/{index-vyvre9en.js → index-25fvrxmy.js} +6 -2
  37. package/{index-kcxmv48c.js → index-2ahj896a.js} +45 -79
  38. package/index-2wc41k5w.js +49 -0
  39. package/index-3hx1z96c.js +87 -0
  40. package/{index-q0y2jq9j.js → index-52w0fvh8.js} +21 -4
  41. package/{index-04bk599g.js → index-5g4rkrvt.js} +10 -17
  42. package/index-5pvxf7z0.js +53 -0
  43. package/index-5q14pwzd.js +69 -0
  44. package/{index-vxtad5bd.js → index-66yspb67.js} +5 -8
  45. package/index-7md2g9vw.js +6 -0
  46. package/index-7p4c0yer.js +1058 -0
  47. package/{index-d43r08tf.js → index-8b639zes.js} +77 -150
  48. package/{index-ktb5njgy.js → index-8kvy8qb4.js} +49 -99
  49. package/index-94s080qm.js +266 -0
  50. package/index-9dp031by.js +12 -0
  51. package/{index-0g7r8xz3.js → index-a37by9hn.js} +114 -232
  52. package/{index-k2j1hc4r.js → index-b95yhqjr.js} +12 -12
  53. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  54. package/{index-2xp0kfkt.js → index-br8pkrk1.js} +37 -25
  55. package/index-c14nsvnv.js +700 -0
  56. package/index-c6eggbee.js +123 -0
  57. package/index-d2242ksy.js +99 -0
  58. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  59. package/{index-a64esmtb.js → index-fkvb79qe.js} +523 -1022
  60. package/index-h54yj9wr.js +1119 -0
  61. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  62. package/{index-y6n8nmny.js → index-kn5d4jmg.js} +75 -203
  63. package/index-m3xsb1ms.js +4300 -0
  64. package/{index-gyd220p2.js → index-mb59b8x0.js} +554 -577
  65. package/{index-j9yhg404.js → index-mzjb6zp4.js} +4 -7
  66. package/index-p6pbz9n5.js +25 -0
  67. package/{index-sj5vxr8f.js → index-qe71g4ze.js} +983 -898
  68. package/index-rfcz04w9.js +187 -0
  69. package/{index-hwkygn9s.js → index-senscydg.js} +331 -36
  70. package/{index-ffvk10zz.js → index-vs8mefhy.js} +107 -241
  71. package/index-wa5jbxj1.js +760 -0
  72. package/index-y5ga5w9t.js +2729 -0
  73. package/{index-9077wzd2.js → index-y7hx1ygz.js} +43 -26
  74. package/{index-h7yw2z9n.js → index-zzvvc845.js} +8 -14
  75. package/index.js +23 -22
  76. package/{library.command-qzzbj6d8.js → library.command-keqjevpp.js} +4 -5
  77. package/{localRegistry.command-vyrgg4xw.js → localRegistry.command-pydeq5zf.js} +23 -43
  78. package/{module.command-rq5hq3ax.js → module.command-dkrnqx3v.js} +8 -12
  79. package/{package.command-d9hd6v9n.js → package.command-wmc0ys5y.js} +6 -7
  80. package/package.json +15 -7
  81. package/{page.command-126d56te.js → page.command-tf3erhrv.js} +4 -5
  82. package/{primitive.command-taxd1538.js → primitive.command-7hqpegj4.js} +9 -23
  83. package/prompter-76k56b37.js +8 -0
  84. package/{quality.command-6gsna0a3.js → quality.command-8122axq3.js} +205 -377
  85. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  86. package/{repair.command-tq2dgy72.js → repair.command-mcy12h0n.js} +11 -35
  87. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  88. package/{scalar.command-3bcmrrkv.js → scalar.command-vvvbzttc.js} +7 -11
  89. package/skills/akan-code/SKILL.md +130 -0
  90. package/skills/akan-debug/SKILL.md +42 -0
  91. package/skills/akan-deps/SKILL.md +50 -0
  92. package/skills/akan-err/SKILL.md +39 -0
  93. package/skills/akan-module/SKILL.md +45 -0
  94. package/skills/akan-scaffold/SKILL.md +76 -0
  95. package/skills/akan-scalar/SKILL.md +52 -0
  96. package/skills/akan-service/SKILL.md +34 -0
  97. package/skills/akan-store/SKILL.md +67 -0
  98. package/skills/akan-ui/SKILL.md +63 -0
  99. package/skills/akan-validate/SKILL.md +44 -0
  100. package/{subspace.command-eddzqpx3.js → subspace.command-pzvqfy5h.js} +53 -62
  101. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  102. package/templates/app/page/_index.tsx +257 -258
  103. package/templates/app/page/_layout.tsx +5 -1
  104. package/templates/app/page/_overrides.tsx +12 -0
  105. package/templates/app/page/styles.css.template +316 -14
  106. package/templates/app/public/apple-touch-icon.png +0 -0
  107. package/templates/app/public/favicon.ico +0 -0
  108. package/templates/app/public/jelly/cloud.webp +0 -0
  109. package/templates/app/public/jelly/comet.webp +0 -0
  110. package/templates/app/public/jelly/moon.webp +0 -0
  111. package/templates/app/public/jelly/planet.webp +0 -0
  112. package/templates/app/public/jelly/rocket.webp +0 -0
  113. package/templates/app/public/jelly/star.webp +0 -0
  114. package/templates/app/public/jelly/sugar.webp +0 -0
  115. package/templates/app/public/logo.png +0 -0
  116. package/templates/app/ui/Recipe/index.ts +9 -0
  117. package/templates/app/ui/Recipe/jellyButton.ts +63 -0
  118. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  119. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  120. package/templates/appSample/lib/task/Task.Unit.tsx +1 -1
  121. package/templates/appSample/lib/task/Task.Util.tsx +10 -13
  122. package/templates/appSample/lib/task/Task.View.tsx +2 -2
  123. package/templates/appSample/lib/task/Task.Zone.tsx +5 -2
  124. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  125. package/templates/appSample/lib/task/task.signal.spec.ts +1 -15
  126. package/templates/appSample/lib/task/task.signal.test.ts +15 -1
  127. package/templates/appSample/lib/task/task.signal.ts +10 -8
  128. package/templates/appSample/page/task/[taskId]/_index.tsx +6 -6
  129. package/templates/appSample/page/task/[taskId]/edit.tsx +5 -4
  130. package/templates/appSample/page/task/_index.tsx +4 -3
  131. package/templates/appSample/page/task/_layout.tsx +1 -1
  132. package/templates/appSample/page/task/new.tsx +5 -4
  133. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
  134. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
  135. package/templates/appSample/ui/GlobalLoading.tsx +2 -1
  136. package/templates/appSample/ui/QuantityControl.tsx +3 -3
  137. package/templates/client.ts +7 -30
  138. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  139. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  140. package/templates/crudPages/new/page.tsx +2 -1
  141. package/templates/crudPages/page.tsx +2 -1
  142. package/templates/crudSinglePage/page.tsx +2 -1
  143. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  144. package/templates/lib/__lib/lib.document.ts +0 -2
  145. package/templates/lib/sig.ts +8 -30
  146. package/templates/localDev/docker-compose.yaml.template +3 -14
  147. package/templates/module/__model__.signal.ts +12 -4
  148. package/templates/pkgRoot/tsconfig.json.template +2 -7
  149. package/templates/server.ts +1 -3
  150. package/templates/service/__model__.abstract.md.template +8 -0
  151. package/templates/workspaceRoot/.gitignore.template +0 -1
  152. package/templates/workspaceRoot/AGENTS.md.template +6 -0
  153. package/templates/workspaceRoot/package.json.template +1 -3
  154. package/tunnel.command-82zz5xnq.js +129 -0
  155. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  156. package/typecheck.proc.js +1 -1
  157. package/workflow.command-y8x3kgjv.js +79 -0
  158. package/{workspace.command-06wvstgr.js → workspace.command-jvsb7brc.js} +79 -109
  159. package/abstractCompactor-gmkc0z8j.js +0 -102
  160. package/application.command-18y0s485.js +0 -204
  161. package/applicationReleasePackager-4yasxwv9.js +0 -244
  162. package/capacitorApp-36rbr858.js +0 -12
  163. package/cloud.command-av97ndh6.js +0 -94
  164. package/cloud.script-cm11xjdz.js +0 -20
  165. package/context.command-5v37ef3n.js +0 -81
  166. package/devTuiView-0hc2emhe.js +0 -9
  167. package/getDirname-dr3jz1xg.js +0 -7
  168. package/guideline.command-4pz9g1rt.js +0 -360
  169. package/guidelines/agentRule/agentRule.generate.json +0 -31
  170. package/guidelines/componentRule/componentRule.generate.json +0 -31
  171. package/guidelines/conventions/conventions.generate.json +0 -25
  172. package/guidelines/cssRule/cssRule.generate.json +0 -31
  173. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  174. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  175. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  176. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  177. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  178. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  179. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  180. package/guidelines/framework/framework.generate.json +0 -32
  181. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  182. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  183. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  184. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  185. package/guidelines/modelService/modelService.generate.json +0 -31
  186. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  187. package/guidelines/modelStore/modelStore.generate.json +0 -31
  188. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  189. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  190. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  191. package/guidelines/modelView/modelView.generate.json +0 -31
  192. package/guidelines/modelZone/modelZone.generate.json +0 -31
  193. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  194. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  195. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  196. package/guidelines/queryRule/queryRule.generate.json +0 -31
  197. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  198. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  199. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  200. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  201. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  202. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  203. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  204. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  205. package/guidelines/transportRule/transportRule.generate.json +0 -31
  206. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  207. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  208. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  209. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
  210. package/index-47pj3aee.js +0 -76
  211. package/index-5ystnsd5.js +0 -841
  212. package/index-6wwzs1bc.js +0 -7
  213. package/index-a17x49vg.js +0 -229
  214. package/index-m0xccmmm.js +0 -228
  215. package/index-meh558jy.js +0 -65
  216. package/index-rtxxan88.js +0 -471
  217. package/index-te54x9zm.js +0 -338
  218. package/index-w8kmx1b6.js +0 -2176
  219. package/index-wt7qrtd4.js +0 -1516
  220. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  221. package/templates/module/__model__.abstract.md +0 -28
  222. package/templates/service/__model__.abstract.md +0 -28
  223. package/templates/workspaceRoot/patches/react-dom@19.2.7.patch.template +0 -62
  224. package/workflow.command-gtdnzvbz.js +0 -108
@@ -3,38 +3,18 @@ import type { AppInfo, LibInfo } from "akanjs";
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
4
  return {
5
5
  filename: "task.abstract.md",
6
- content: `# Task Abstract
7
-
8
- ## Akan.js Module Pattern
9
-
10
- Task is a **database-backed domain module** — the standard Akan.js pattern for persisted entities.
11
- This module demonstrates the full Akan.js module lifecycle:
12
- constant -> document -> service -> signal -> store -> UI.
13
-
14
- Every database module in Akan.js follows this layered architecture:
15
- - task.constant.ts — data shape (enum, Input, Object, Light, Full layers via via())
16
- - task.document.ts — DB queries, filters, sorts, indexes, Document chain methods
17
- - task.dictionary.ts — i18n labels, error messages, UI translations
18
- - task.service.ts — business logic orchestration bound to DB via serve(db.task, ...)
19
- - task.signal.ts — API surface (query, mutation, pubsub endpoints bound via endpoint(srv.task, ...))
20
- - task.store.ts — client state management bound to signal via store(sig.task, ...)
21
- - Task.*.tsx — UI components (Zone -> Load -> Unit / View / Template / Util)
22
-
23
- ## Convention: lib/<module>/ directory naming
24
-
25
- - Database modules live under lib/<module>/ (no underscore prefix)
26
- - Files follow <module>.<layer>.ts naming — e.g., task.constant.ts, task.service.ts
27
- - UI files use PascalCase with explicit suffix: Task.Zone.tsx, Task.Unit.tsx, Task.View.tsx
28
-
29
- ## Convention: scan-registered barrels
30
-
31
- akan sync auto-discovers each file and registers it in the corresponding barrel:
32
- cnst.ts, db.ts, dict.ts, srv.ts, sig.ts, st.ts
33
-
34
- ## Related Modules
35
-
36
- - lib/__scalar/workHistory/ — standard scalar modules with double-underscore prefix (reusable field sets)
37
- - lib/_noti/ — pure service module (compare structure differences: no constant/document, serve without DB binding)
6
+ content: `# task Abstract
7
+ A task is one unit of work that moves from todo through in progress to completed, and keeps a record of each move.
8
+
9
+ ## Rules
10
+ - A task only moves forward: \`start()\` needs \`todo\` and \`complete()\` needs \`inProgress\`; any other state throws.
11
+ - Every move appends one \`workHistory\` entry, and creation writes the first (\`created\`), so the history is never
12
+ empty and its last entry always matches \`status\`.
13
+ - Anyone may read a task; creating, changing, starting and completing one needs a signed-in caller. There is no
14
+ generated admin API (\`root: None\`).
15
+ - Removal is soft: a removed task keeps its row with \`removedAt\` set.
16
+
17
+ todo -> inProgress -> completed
38
18
  `,
39
19
  };
40
20
  }
@@ -1,8 +1,7 @@
1
1
  import type { AppInfo, LibInfo } from "akanjs";
2
2
 
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
- return `import { expect } from "bun:test";
5
- import type { DocumentModel } from "akanjs/constant";
4
+ return `import type { DocumentModel } from "akanjs/constant";
6
5
  import { getOrSetupSignalTestFetch, sampleOf } from "akanjs/test";
7
6
 
8
7
  import * as cnst from "../cnst";
@@ -27,13 +26,6 @@ export const createTask = async (overrides: Partial<DocumentModel<cnst.TaskInput
27
26
 
28
27
  const task = await fetch.createTask(taskInput);
29
28
 
30
- expect(task).toMatchObject({
31
- title: taskInput.title,
32
- content: taskInput.content,
33
- status: "todo",
34
- });
35
- expect(task.workHistory.map((entry) => entry.action)).toEqual(["created"]);
36
-
37
29
  return {
38
30
  task,
39
31
  fetch,
@@ -45,9 +37,6 @@ export const getStartedTask = async (overrides: Partial<DocumentModel<cnst.TaskI
45
37
  const agent = await createTask(overrides);
46
38
  const task = await agent.fetch.startTask(agent.task.id);
47
39
 
48
- expect(task.status).toBe("inProgress");
49
- expect(task.workHistory.map((entry) => entry.action)).toEqual(["created", "started"]);
50
-
51
40
  return {
52
41
  ...agent,
53
42
  task,
@@ -58,9 +47,6 @@ export const getCompletedTask = async (overrides: Partial<DocumentModel<cnst.Tas
58
47
  const agent = await getStartedTask(overrides);
59
48
  const task = await agent.fetch.completeTask(agent.task.id);
60
49
 
61
- expect(task.status).toBe("completed");
62
- expect(task.workHistory.map((entry) => entry.action)).toEqual(["created", "started", "completed"]);
63
-
64
50
  return {
65
51
  ...agent,
66
52
  task,
@@ -6,9 +6,23 @@ import { configureSignalTest } from "akanjs/test";
6
6
 
7
7
  import * as taskSpec from "./task.signal.spec";
8
8
 
9
- configureSignalTest({ databaseMode: "memory" });
9
+ configureSignalTest({ storage: "memory" });
10
10
 
11
11
  describe("Task signal smoke", () => {
12
+ test("creates a task in todo", async () => {
13
+ const { task, taskInput } = await taskSpec.createTask({ title: "Signal smoke task" });
14
+
15
+ expect(task).toMatchObject({ title: taskInput.title, content: taskInput.content, status: "todo" });
16
+ expect(task.workHistory.map((entry) => entry.action)).toEqual(["created"]);
17
+ });
18
+
19
+ test("starts a task", async () => {
20
+ const { task } = await taskSpec.getStartedTask({ title: "Signal smoke task" });
21
+
22
+ expect(task.status).toBe("inProgress");
23
+ expect(task.workHistory.map((entry) => entry.action)).toEqual(["created", "started"]);
24
+ });
25
+
12
26
  test("exposes custom task mutations over fetch", async () => {
13
27
  const { task } = await taskSpec.getCompletedTask({ title: "Signal smoke task" });
14
28
 
@@ -1,8 +1,7 @@
1
1
  import type { AppInfo, LibInfo } from "akanjs";
2
2
 
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
- return `import { SignedIn } from "@apps/${dict.appName}/srvkit";
5
- import { endpoint, internal, None, Public, slice } from "akanjs/signal";
4
+ return `import { endpoint, internal, None, Public, slice } from "akanjs/signal";
6
5
 
7
6
  import * as cnst from "../cnst";
8
7
  import * as srv from "../srv";
@@ -23,23 +22,26 @@ import * as srv from "../srv";
23
22
  export class TaskInternal extends internal(srv.task, ({ interval }) => ({})) {}
24
23
 
25
24
  // Guards, per key: root = the generated admin API (runs any filter with caller-supplied args), get = reads,
26
- // cru = create/update/remove. root and cru are never Public; None here means "nobody until you name a guard".
27
- export class TaskSlice extends slice(srv.task, { guards: { root: None, get: Public, cru: SignedIn } }, (init) => ({
28
- inPublic: init().exec(function () {
25
+ // cru = create/update/remove. None here means "nobody until you name a guard".
26
+ // The sample lets guests write so it works before the app has sign-in. Once it does, swap Public for SignedIn
27
+ // (srvkit/guards.ts) on cru and on the mutations below — a real app never leaves writes Public.
28
+ export class TaskSlice extends slice(srv.task, { guards: { root: None, get: Public, cru: Public } }, (init) => ({
29
+ inPublic: init({ guards: [Public] }).exec(function () {
29
30
  return this.taskService.queryAny();
30
31
  }),
31
32
  })) {}
32
33
 
33
34
  // Every custom endpoint names its own guards array — the slice's map above only covers generated CRUD.
34
- // It is also the MCP decision: an endpoint declaring no guard is not published to agents at all.
35
+ // It is also the MCP decision: an endpoint declaring no guard, or a mutation guarded only by Public, is not
36
+ // published to agents at all.
35
37
  export class TaskEndpoint extends endpoint(srv.task, ({ mutation }) => ({
36
- startTask: mutation(cnst.Task, { guards: [SignedIn] })
38
+ startTask: mutation(cnst.Task, { guards: [Public] })
37
39
  .param("taskId", String)
38
40
  .exec(async function (taskId) {
39
41
  return await this.taskService.startTask(taskId);
40
42
  }),
41
43
 
42
- completeTask: mutation(cnst.Task, { guards: [SignedIn] })
44
+ completeTask: mutation(cnst.Task, { guards: [Public] })
43
45
  .param("taskId", String)
44
46
  .exec(async function (taskId) {
45
47
  return await this.taskService.completeTask(taskId);
@@ -3,11 +3,11 @@ import type { AppInfo, LibInfo } from "akanjs";
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
4
  return {
5
5
  filename: "_index.tsx",
6
- content: `import { fetch, usePage } from "@apps/${dict.appName}/client";
7
- import { Task } from "@apps/${dict.appName}/lib/task";
6
+ content: `import { fetch, Task, usePage } from "@apps/${dict.appName}/client";
7
+ import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
8
8
  import { ID } from "akanjs/base";
9
9
  import { page } from "akanjs/client";
10
- import { Link, buttonRecipe } from "akanjs/ui";
10
+ import { Link } from "akanjs/ui";
11
11
 
12
12
  export default page()
13
13
  .param("taskId", ID)
@@ -17,10 +17,10 @@ export default page()
17
17
  return (
18
18
  <main className="mx-auto max-w-4xl px-6 py-8">
19
19
  <div className="mb-6 flex items-center justify-between">
20
- <a href="/task" className={buttonRecipe({ variant: "ghost", size: "sm" })}>
20
+ <Link href="/task" className={jellyButtonRecipe({ variant: "ghost", size: "sm" })}>
21
21
  {l("task.taskBackToTasks")}
22
- </a>
23
- <Link href={\`/task/\${taskId}/edit\`} className={buttonRecipe({ variant: "primary", size: "sm" })}>
22
+ </Link>
23
+ <Link href={\`/task/\${taskId}/edit\`} className={jellyButtonRecipe({ variant: "primary", size: "sm" })}>
24
24
  {l("task.taskEdit")}
25
25
  </Link>
26
26
  </div>
@@ -4,9 +4,10 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
4
4
  return {
5
5
  filename: "edit.tsx",
6
6
  content: `import { fetch, Task } from "@apps/${dict.appName}/client";
7
+ import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
7
8
  import { ID } from "akanjs/base";
8
9
  import { page } from "akanjs/client";
9
- import { Load, Link, buttonRecipe } from "akanjs/ui";
10
+ import { Link, Load } from "akanjs/ui";
10
11
 
11
12
  export default page()
12
13
  .param("taskId", ID)
@@ -16,15 +17,15 @@ export default page()
16
17
  return (
17
18
  <main className="mx-auto max-w-2xl px-6 py-8">
18
19
  <div className="mb-6">
19
- <Link href={\`/task/\${taskId}\`} className={buttonRecipe({ variant: "ghost", size: "sm" })}>
20
+ <Link href={\`/task/\${taskId}\`} className={jellyButtonRecipe({ variant: "ghost", size: "sm" })}>
20
21
  ← Back to Task
21
22
  </Link>
22
23
  </div>
23
24
  <div className="mb-6">
24
- <h1 className="font-extrabold text-3xl text-foreground">Edit Task</h1>
25
+ <h1 className="font-black text-4xl text-foreground">Edit Task</h1>
25
26
  <p className="mt-1 text-foreground/60 text-sm">Update the task details</p>
26
27
  </div>
27
- <div className="rounded-xl border border-foreground/10 bg-background p-6 shadow-sm">
28
+ <div className="jelly-glass rounded-box p-6">
28
29
  <Load.Edit slice={fetch.slice.taskInPublic} edit={taskEdit} type="form" onSubmit={\`/task/\${taskId}\`}>
29
30
  <Task.Template.General />
30
31
  </Load.Edit>
@@ -4,8 +4,9 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
4
4
  return {
5
5
  filename: "_index.tsx",
6
6
  content: `import { fetch, Task, usePage } from "@apps/${dict.appName}/client";
7
+ import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
7
8
  import { page } from "akanjs/client";
8
- import { Link, buttonRecipe } from "akanjs/ui";
9
+ import { Link } from "akanjs/ui";
9
10
 
10
11
  export default page().render(async () => {
11
12
  const { l } = usePage();
@@ -14,10 +15,10 @@ export default page().render(async () => {
14
15
  <main className="mx-auto max-w-4xl px-6 py-8">
15
16
  <div className="mb-6 flex items-center justify-between">
16
17
  <div>
17
- <h1 className="font-extrabold text-3xl text-foreground">{l("task.modelName")}</h1>
18
+ <h1 className="font-black text-4xl text-foreground">{l("task.modelName")}</h1>
18
19
  <p className="mt-1 text-foreground/60 text-sm">{l("task.modelDesc")}</p>
19
20
  </div>
20
- <Link href="/task/new" className={buttonRecipe({ variant: "primary", size: "sm" })}>
21
+ <Link href="/task/new" className={jellyButtonRecipe({ variant: "primary", size: "sm" })}>
21
22
  {l("task.taskNew")}
22
23
  </Link>
23
24
  </div>
@@ -6,7 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
6
6
  content: `import { layout } from "akanjs/client";
7
7
 
8
8
  export default layout().render(({ children }) => {
9
- return <div className="min-h-screen bg-muted">{children}</div>;
9
+ return <div className="min-h-screen">{children}</div>;
10
10
  });
11
11
  `,
12
12
  };
@@ -4,8 +4,9 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
4
4
  return {
5
5
  filename: "new.tsx",
6
6
  content: `import { type cnst, fetch, Task } from "@apps/${dict.appName}/client";
7
+ import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
7
8
  import { page } from "akanjs/client";
8
- import { Load, Link, buttonRecipe } from "akanjs/ui";
9
+ import { Link, Load } from "akanjs/ui";
9
10
 
10
11
  export default page().render(() => {
11
12
  const taskForm: Partial<cnst.Task> = { status: "todo" };
@@ -13,15 +14,15 @@ export default page().render(() => {
13
14
  return (
14
15
  <main className="mx-auto max-w-2xl px-6 py-8">
15
16
  <div className="mb-6">
16
- <Link href="/task" className={buttonRecipe({ variant: "ghost", size: "sm" })}>
17
+ <Link href="/task" className={jellyButtonRecipe({ variant: "ghost", size: "sm" })}>
17
18
  ← Tasks
18
19
  </Link>
19
20
  </div>
20
21
  <div className="mb-6">
21
- <h1 className="font-extrabold text-3xl text-foreground">New Task</h1>
22
+ <h1 className="font-black text-4xl text-foreground">New Task</h1>
22
23
  <p className="mt-1 text-foreground/60 text-sm">Create a new task with title and description</p>
23
24
  </div>
24
- <div className="rounded-xl border border-foreground/10 bg-background p-6 shadow-sm">
25
+ <div className="jelly-glass rounded-box p-6">
25
26
  <Load.Edit slice={fetch.slice.taskInPublic} edit={taskForm} type="form" onCancel="back" onSubmit="/task">
26
27
  <Task.Template.General />
27
28
  </Load.Edit>
@@ -2,14 +2,14 @@ import type { AppInfo, LibInfo } from "akanjs";
2
2
 
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
4
  return {
5
- filename: "AuthGuard.ts",
5
+ filename: "guards.ts",
6
6
  content: `import type { Guard, GuardScope, SignalContext } from "akanjs/signal";
7
7
 
8
- // ===== AuthGuard.ts =====
8
+ // ===== guards.ts =====
9
9
  // Convention: srvkit/ folder — server-only helpers, cannot import from client code.
10
10
  // Implements the Guard interface from akanjs/signal.
11
11
  // Guards are applied at endpoint/slice declaration: { guards: { root: SignedIn } }.
12
- // Naming: PascalCase .ts, static name property matches the guard identifier.
12
+ // Naming: camelCase file, PascalCase classes; each static name matches its guard identifier.
13
13
  // Scanned by akan sync into srvkit/index.ts barrel automatically.
14
14
 
15
15
  export class SignedIn implements Guard {
@@ -21,7 +21,10 @@ export class SignedIn implements Guard {
21
21
 
22
22
  canPass(context: SignalContext): boolean {
23
23
  // Reads the account the middleware resolved, so the same guard answers over HTTP, a websocket and MCP alike.
24
- return !!context.get<{ id?: string }>("account");
24
+ // A guest still has an account — libs/shared resolves one to \`{ appName, environment }\` — so only an
25
+ // identity on it proves a sign-in: your own middleware's \`id\`, or libs/shared's \`self\` (user) / \`me\` (admin).
26
+ const account = context.get<{ id?: string; self?: { id?: string }; me?: { id?: string } }>("account");
27
+ return !!(account?.id ?? account?.self?.id ?? account?.me?.id);
25
28
  }
26
29
  }
27
30
 
@@ -2,22 +2,24 @@ import type { AppInfo, LibInfo } from "akanjs";
2
2
 
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
4
  return {
5
- filename: "SessionInternalArg.ts",
5
+ filename: "internalArgs.ts",
6
6
  content: `import type { InternalArg, SignalContext } from "akanjs/signal";
7
7
 
8
- // ===== SessionInternalArg.ts =====
8
+ // ===== internalArgs.ts =====
9
9
  // Convention: srvkit/ folder — server-only helpers.
10
10
  // Implements the InternalArg interface from akanjs/signal.
11
11
  // InternalArg is an auto-injected argument for resolveField/endpoint .with() chains.
12
12
  // Appended to a query/mutation via: .with(CurrentUserId, { nullable: true }).exec(...)
13
- // Naming: PascalCase .ts, class name = arg identifier.
13
+ // Naming: camelCase file, PascalCase classes; each class name is its arg identifier.
14
14
  // Scanned by akan sync into srvkit/index.ts barrel automatically.
15
15
 
16
16
  export class CurrentUserId implements InternalArg<string | null> {
17
17
  getArg(context: SignalContext): string | null {
18
18
  // \`context.get\` reads what the account middleware resolved, on every transport. Branching on
19
19
  // \`getHttpContext()\` would return null for the same caller arriving over a websocket or MCP.
20
- return context.get<{ id?: string }>("account")?.id ?? null;
20
+ // An app's own middleware may put the id on the account itself; libs/shared puts it on \`self\` or \`me\`.
21
+ const account = context.get<{ id?: string; self?: { id?: string }; me?: { id?: string } }>("account");
22
+ return account?.id ?? account?.self?.id ?? account?.me?.id ?? null;
21
23
  }
22
24
  }
23
25
 
@@ -6,6 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
6
6
  content: `"use client";
7
7
 
8
8
  import { cn } from "akanjs/client";
9
+ import { Image } from "akanjs/ui";
9
10
 
10
11
  // ===== GlobalLoading.tsx =====
11
12
  // Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
@@ -20,7 +21,7 @@ interface GlobalLoadingProps {
20
21
  export const GlobalLoading = ({ className, message = "Loading..." }: GlobalLoadingProps) => {
21
22
  return (
22
23
  <div className={cn("flex flex-col items-center justify-center gap-4 py-32", className)}>
23
- <span className="inline-block size-8 animate-spin rounded-full border-2 border-primary border-t-transparent" />
24
+ <Image alt="" className="size-12 animate-bounce" height={96} src="/jelly/star.webp" width={96} />
24
25
  <span className="text-foreground/60 text-sm">{message}</span>
25
26
  </div>
26
27
  );
@@ -6,7 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
6
6
  content: `"use client";
7
7
 
8
8
  import { cn } from "akanjs/client";
9
- import { buttonRecipe } from "akanjs/ui";
9
+ import { jellyButtonRecipe } from "./Recipe";
10
10
 
11
11
  // ===== QuantityControl.tsx =====
12
12
  // Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
@@ -31,7 +31,7 @@ export const QuantityControl = ({
31
31
  return (
32
32
  <div className={cn("inline-flex items-center gap-1", className)}>
33
33
  <button
34
- className={buttonRecipe({ variant: "outline", size: "icon" }, "size-6 rounded-full")}
34
+ className={jellyButtonRecipe({ variant: "default", size: "icon" }, "size-7")}
35
35
  disabled={value <= min}
36
36
  onClick={() => onChange(Math.max(min, value - 1))}
37
37
  >
@@ -39,7 +39,7 @@ export const QuantityControl = ({
39
39
  </button>
40
40
  <span className="w-8 text-center font-medium tabular-nums">{value}</span>
41
41
  <button
42
- className={buttonRecipe({ variant: "outline", size: "icon" }, "size-6 rounded-full")}
42
+ className={jellyButtonRecipe({ variant: "default", size: "icon" }, "size-7")}
43
43
  disabled={value >= max}
44
44
  onClick={() => onChange(Math.min(max, value + 1))}
45
45
  >
@@ -4,36 +4,13 @@ const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
4
4
 
5
5
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
6
6
  if (!scanInfo) return null;
7
- const databaseModules = [...scanInfo.database.entries()]
8
- .filter(
9
- ([_, fileTypes]) =>
10
- fileTypes.has("template") ||
11
- fileTypes.has("unit") ||
12
- fileTypes.has("util") ||
13
- fileTypes.has("view") ||
14
- fileTypes.has("zone"),
15
- )
16
- .map(([key]) => key);
17
- const scalarModules = [...scanInfo.scalar.entries()]
18
- .filter(
19
- ([_, fileTypes]) =>
20
- fileTypes.has("template") ||
21
- fileTypes.has("unit") ||
22
- fileTypes.has("util") ||
23
- fileTypes.has("view") ||
24
- fileTypes.has("zone"),
25
- )
26
- .map(([key]) => key);
27
- const serviceModules = [...scanInfo.service.entries()]
28
- .filter(
29
- ([_, fileTypes]) =>
30
- fileTypes.has("template") ||
31
- fileTypes.has("unit") ||
32
- fileTypes.has("util") ||
33
- fileTypes.has("view") ||
34
- fileTypes.has("zone"),
35
- )
36
- .map(([key]) => key);
7
+ const uiModules = (modules: Map<string, Set<string>>) =>
8
+ [...modules.entries()]
9
+ .filter(([_, fileTypes]) => ["template", "unit", "util", "view", "zone"].some((type) => fileTypes.has(type)))
10
+ .map(([key]) => key);
11
+ const databaseModules = uiModules(scanInfo.database);
12
+ const scalarModules = uiModules(scanInfo.scalar);
13
+ const serviceModules = uiModules(scanInfo.service);
37
14
  return `
38
15
  export * as cnst from "./lib/cnst";
39
16
  export { msg, Err, usePage, fetch, sig } from "./lib/useClient";
@@ -4,12 +4,13 @@ interface Dict {
4
4
  Model: string;
5
5
  model: string;
6
6
  appName: string;
7
+ clientPath: string;
7
8
  }
8
9
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
9
10
  return {
10
11
  filename: "_index.tsx",
11
12
  content: `
12
- import { ${dict.Model}, fetch, usePage } from "@apps/${dict.appName}/client";
13
+ import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
13
14
  import { ID } from "akanjs/base";
14
15
  import { page } from "akanjs/client";
15
16
  import { Load } from "akanjs/ui";
@@ -4,12 +4,13 @@ interface Dict {
4
4
  Model: string;
5
5
  model: string;
6
6
  appName: string;
7
+ clientPath: string;
7
8
  }
8
9
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
9
10
  return {
10
11
  filename: "_index.tsx",
11
12
  content: `
12
- import { ${dict.Model}, fetch, usePage } from "@apps/${dict.appName}/client";
13
+ import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
13
14
  import { ID } from "akanjs/base";
14
15
  import { page } from "akanjs/client";
15
16
  import { buttonRecipe, Link } from "akanjs/ui";
@@ -4,12 +4,13 @@ interface Dict {
4
4
  Model: string;
5
5
  model: string;
6
6
  appName: string;
7
+ clientPath: string;
7
8
  }
8
9
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
9
10
  return {
10
11
  filename: "_index.tsx",
11
12
  content: `
12
- import { type cnst, fetch, usePage, ${dict.Model} } from "@apps/${dict.appName}/client";
13
+ import { type cnst, fetch, usePage, ${dict.Model} } from "${dict.clientPath}";
13
14
  import { page } from "akanjs/client";
14
15
  import { Load } from "akanjs/ui";
15
16
 
@@ -4,12 +4,13 @@ interface Dict {
4
4
  Model: string;
5
5
  model: string;
6
6
  appName: string;
7
+ clientPath: string;
7
8
  }
8
9
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
9
10
  return {
10
11
  filename: "_index.tsx",
11
12
  content: `
12
- import { ${dict.Model}, fetch, usePage } from "@apps/${dict.appName}/client";
13
+ import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
13
14
  import { page } from "akanjs/client";
14
15
  import { buttonRecipe, Link } from "akanjs/ui";
15
16
 
@@ -4,12 +4,13 @@ interface Dict {
4
4
  Model: string;
5
5
  model: string;
6
6
  appName: string;
7
+ clientPath: string;
7
8
  }
8
9
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
9
10
  return {
10
11
  filename: "_index.tsx",
11
12
  content: `
12
- import { ${dict.Model}, fetch, usePage } from "@apps/${dict.appName}/client";
13
+ import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
13
14
  import { page } from "akanjs/client";
14
15
  import { buttonRecipe, Model } from "akanjs/ui";
15
16
 
@@ -1,7 +1,5 @@
1
1
  import type { AppInfo, LibInfo } from "akanjs";
2
2
 
3
- const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
4
-
5
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
6
4
  if (!scanInfo) return null;
7
5
  const libs = scanInfo.getLibs();
@@ -1,7 +1,5 @@
1
1
  import type { AppInfo, LibInfo } from "akanjs";
2
2
 
3
- const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
4
-
5
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
6
4
  if (!scanInfo) return null;
7
5
  const libs = scanInfo.getLibs();
@@ -13,6 +13,8 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [
13
13
  const libs = scanInfo.getLibs();
14
14
 
15
15
  const signalNames = [...(libs.length === 0 ? ["base"] : libs), ...databaseModules, ...serviceModules];
16
+ const serverSignalClass = (module: string) =>
17
+ `export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`;
16
18
 
17
19
  return `
18
20
  import { FetchClient, type FetchClientType } from "akanjs/fetch";
@@ -20,38 +22,14 @@ import { SignalRegistry, serverSignal${libs.length === 0 ? ", fetch as base" : "
20
22
  import { Err } from "./dict";
21
23
  ${libs.map((lib) => `import { fetch as ${lib} } from "@libs/${lib}/lib/sig";`).join("\n")}
22
24
 
23
- ${[...scanInfo.database.entries()]
24
- .filter(([_, files]) => files.has("signal"))
25
- .map(([module]) => `import * as ${module}Sig from "./${module}/${module}.signal";`)
26
- .join("\n")}
27
- ${[...scanInfo.service.entries()]
28
- .filter(([_, files]) => files.has("signal"))
29
- .map(([module]) => `import * as ${module}Sig from "./_${module}/${module}.signal";`)
30
- .join("\n")}
25
+ ${databaseModules.map((module) => `import * as ${module}Sig from "./${module}/${module}.signal";`).join("\n")}
26
+ ${serviceModules.map((module) => `import * as ${module}Sig from "./_${module}/${module}.signal";`).join("\n")}
31
27
 
32
- ${[...scanInfo.database.entries()]
33
- .filter(([_, files]) => files.has("signal"))
34
- .map(([module]) => `export * from "./${module}/${module}.signal";`)
35
- .join("\n")}
36
- ${[...scanInfo.service.entries()]
37
- .filter(([_, files]) => files.has("signal"))
38
- .map(([module]) => `export * from "./_${module}/${module}.signal";`)
39
- .join("\n")}
28
+ ${databaseModules.map((module) => `export * from "./${module}/${module}.signal";`).join("\n")}
29
+ ${serviceModules.map((module) => `export * from "./_${module}/${module}.signal";`).join("\n")}
40
30
 
41
- ${[...scanInfo.database.entries()]
42
- .filter(([_, files]) => files.has("signal"))
43
- .map(
44
- ([module]) =>
45
- `export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`,
46
- )
47
- .join("\n")}
48
- ${[...scanInfo.service.entries()]
49
- .filter(([_, files]) => files.has("signal"))
50
- .map(
51
- ([module]) =>
52
- `export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`,
53
- )
54
- .join("\n")}
31
+ ${databaseModules.map(serverSignalClass).join("\n")}
32
+ ${serviceModules.map(serverSignalClass).join("\n")}
55
33
 
56
34
  ${databaseModules.map((module) => `export const ${module} = SignalRegistry.registerDatabase("${module}" as const, ${module}Sig.${capitalize(module)}Internal, ${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Slice, ${capitalize(module)});`).join("\n")}
57
35
  ${serviceModules.map((module) => `export const ${module} = SignalRegistry.registerService("${module}" as const, ${module}Sig.${capitalize(module)}Internal, ${module}Sig.${capitalize(module)}Endpoint, ${capitalize(module)});`).join("\n")}
@@ -1,29 +1,18 @@
1
- version: "3.8"
2
1
  networks:
3
2
  <%= repoName %>-network:
4
3
  driver: bridge
5
4
  services:
6
5
  redis:
7
6
  container_name: <%= repoName %>-redis
8
- image: redis
7
+ image: redis:8
9
8
  restart: unless-stopped
10
9
  ports:
11
10
  - 6379:6379
12
11
  networks:
13
12
  - <%= repoName %>-network
14
- libsql:
15
- container_name: <%= repoName %>-libsql
16
- image: ghcr.io/tursodatabase/libsql-server:latest
17
- restart: unless-stopped
18
- ports:
19
- - 8080:8080
20
- volumes:
21
- - ./libsql:/var/lib/sqld
22
- networks:
23
- - <%= repoName %>-network
24
13
  postgres:
25
14
  container_name: <%= repoName %>-postgres
26
- image: postgres:17
15
+ image: postgres:18
27
16
  restart: unless-stopped
28
17
  ports:
29
18
  - 5432:5432
@@ -32,6 +21,6 @@ services:
32
21
  - POSTGRES_USER=akan
33
22
  - POSTGRES_PASSWORD=akan
34
23
  volumes:
35
- - ./postgres:/var/lib/postgresql/data
24
+ - ./postgres:/var/lib/postgresql
36
25
  networks:
37
26
  - <%= repoName %>-network