@akanjs/cli 0.0.120 → 0.0.122

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/cjs/index.js +1227 -604
  2. package/{src → cjs/src}/templates/workspaceRoot/package.json.template +1 -1
  3. package/esm/index.js +1227 -604
  4. package/esm/src/templates/app/app/[lang]/(__appName__)/styles.css.template +19 -0
  5. package/esm/src/templates/app/app/index.html.template +13 -0
  6. package/esm/src/templates/app/capacitor.config.ts.template +8 -0
  7. package/esm/src/templates/app/env/env.client.debug.ts.template +7 -0
  8. package/esm/src/templates/app/env/env.client.develop.ts.template +7 -0
  9. package/esm/src/templates/app/env/env.client.local.ts.template +7 -0
  10. package/esm/src/templates/app/env/env.client.main.ts.template +7 -0
  11. package/esm/src/templates/app/env/env.client.testing.ts.template +7 -0
  12. package/esm/src/templates/app/env/env.server.debug.ts.template +15 -0
  13. package/esm/src/templates/app/env/env.server.develop.ts.template +15 -0
  14. package/esm/src/templates/app/env/env.server.local.ts.template +15 -0
  15. package/esm/src/templates/app/env/env.server.main.ts.template +15 -0
  16. package/esm/src/templates/app/env/env.server.testing.ts.template +7 -0
  17. package/esm/src/templates/app/page.test.ts.template +10 -0
  18. package/esm/src/templates/app/playwright.config.ts.template +6 -0
  19. package/esm/src/templates/app/postcss.config.js.template +10 -0
  20. package/esm/src/templates/app/public/manifest.json.template +67 -0
  21. package/esm/src/templates/app/tsconfig.json.template +22 -0
  22. package/esm/src/templates/app/tsconfig.spec.json.template +7 -0
  23. package/esm/src/templates/libRoot/.gitignore.template +15 -0
  24. package/esm/src/templates/libRoot/env/env.server.example.ts.template +7 -0
  25. package/esm/src/templates/libRoot/env/env.server.testing.ts.template +7 -0
  26. package/esm/src/templates/libRoot/package.json.template +4 -0
  27. package/esm/src/templates/libRoot/tsconfig.json.template +13 -0
  28. package/esm/src/templates/libRoot/tsconfig.spec.json.template +7 -0
  29. package/esm/src/templates/localDev/docker-compose.yaml.template +36 -0
  30. package/esm/src/templates/pkgRoot/tsconfig.json.template +15 -0
  31. package/esm/src/templates/workspaceRoot/.env.template +20 -0
  32. package/esm/src/templates/workspaceRoot/.gitignore.template +118 -0
  33. package/esm/src/templates/workspaceRoot/.prettierignore.template +10 -0
  34. package/esm/src/templates/workspaceRoot/.prettierrc.json.template +6 -0
  35. package/esm/src/templates/workspaceRoot/.swcrc.template +9 -0
  36. package/esm/src/templates/workspaceRoot/.vscode/settings.json.template +13 -0
  37. package/esm/src/templates/workspaceRoot/README.md.template +37 -0
  38. package/esm/src/templates/workspaceRoot/eslint.config.ts.template +3 -0
  39. package/esm/src/templates/workspaceRoot/package.json.template +38 -0
  40. package/esm/src/templates/workspaceRoot/tsconfig.json.template +29 -0
  41. package/package.json +2 -1
  42. package/src/module/module.command.d.ts +1 -1
  43. package/src/module/module.prompt.d.ts +19 -4
  44. package/src/workspace/workspace.runner.d.ts +2 -1
  45. /package/{src → cjs/src}/templates/app/app/[lang]/(__appName__)/styles.css.template +0 -0
  46. /package/{src → cjs/src}/templates/app/app/index.html.template +0 -0
  47. /package/{src → cjs/src}/templates/app/capacitor.config.ts.template +0 -0
  48. /package/{src → cjs/src}/templates/app/env/env.client.debug.ts.template +0 -0
  49. /package/{src → cjs/src}/templates/app/env/env.client.develop.ts.template +0 -0
  50. /package/{src → cjs/src}/templates/app/env/env.client.local.ts.template +0 -0
  51. /package/{src → cjs/src}/templates/app/env/env.client.main.ts.template +0 -0
  52. /package/{src → cjs/src}/templates/app/env/env.client.testing.ts.template +0 -0
  53. /package/{src → cjs/src}/templates/app/env/env.server.debug.ts.template +0 -0
  54. /package/{src → cjs/src}/templates/app/env/env.server.develop.ts.template +0 -0
  55. /package/{src → cjs/src}/templates/app/env/env.server.local.ts.template +0 -0
  56. /package/{src → cjs/src}/templates/app/env/env.server.main.ts.template +0 -0
  57. /package/{src → cjs/src}/templates/app/env/env.server.testing.ts.template +0 -0
  58. /package/{src → cjs/src}/templates/app/page.test.ts.template +0 -0
  59. /package/{src → cjs/src}/templates/app/playwright.config.ts.template +0 -0
  60. /package/{src → cjs/src}/templates/app/postcss.config.js.template +0 -0
  61. /package/{src → cjs/src}/templates/app/public/manifest.json.template +0 -0
  62. /package/{src → cjs/src}/templates/app/tsconfig.json.template +0 -0
  63. /package/{src → cjs/src}/templates/app/tsconfig.spec.json.template +0 -0
  64. /package/{src → cjs/src}/templates/libRoot/.gitignore.template +0 -0
  65. /package/{src → cjs/src}/templates/libRoot/env/env.server.example.ts.template +0 -0
  66. /package/{src → cjs/src}/templates/libRoot/env/env.server.testing.ts.template +0 -0
  67. /package/{src → cjs/src}/templates/libRoot/package.json.template +0 -0
  68. /package/{src → cjs/src}/templates/libRoot/tsconfig.json.template +0 -0
  69. /package/{src → cjs/src}/templates/libRoot/tsconfig.spec.json.template +0 -0
  70. /package/{src → cjs/src}/templates/localDev/docker-compose.yaml.template +0 -0
  71. /package/{src → cjs/src}/templates/pkgRoot/tsconfig.json.template +0 -0
  72. /package/{src → cjs/src}/templates/workspaceRoot/.env.template +0 -0
  73. /package/{src → cjs/src}/templates/workspaceRoot/.gitignore.template +0 -0
  74. /package/{src → cjs/src}/templates/workspaceRoot/.prettierignore.template +0 -0
  75. /package/{src → cjs/src}/templates/workspaceRoot/.prettierrc.json.template +0 -0
  76. /package/{src → cjs/src}/templates/workspaceRoot/.swcrc.template +0 -0
  77. /package/{src → cjs/src}/templates/workspaceRoot/.vscode/settings.json.template +0 -0
  78. /package/{src → cjs/src}/templates/workspaceRoot/README.md.template +0 -0
  79. /package/{src → cjs/src}/templates/workspaceRoot/eslint.config.ts.template +0 -0
  80. /package/{src → cjs/src}/templates/workspaceRoot/tsconfig.json.template +0 -0
package/cjs/index.js CHANGED
@@ -916,10 +916,10 @@ var Executor = class {
916
916
  exec(command, options = {}) {
917
917
  const proc = (0, import_child_process.exec)(command, { cwd: this.cwdPath, ...options });
918
918
  proc.stdout?.on("data", (data) => {
919
- Logger.raw(data.toString());
919
+ Logger.raw(import_chalk.default.dim(data.toString()));
920
920
  });
921
921
  proc.stderr?.on("data", (data) => {
922
- Logger.raw(import_chalk.default.red(data.toString()));
922
+ Logger.raw(import_chalk.default.dim(data.toString()));
923
923
  });
924
924
  return new Promise((resolve, reject) => {
925
925
  proc.on("exit", (code, signal) => {
@@ -1449,11 +1449,11 @@ var SysExecutor = class extends Executor {
1449
1449
  return viewComponents;
1450
1450
  }
1451
1451
  async getUnitComponents() {
1452
- const unitComponents = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => import_fs4.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`));
1452
+ const unitComponents = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => import_fs4.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`));
1453
1453
  return unitComponents;
1454
1454
  }
1455
1455
  async getTemplateComponents() {
1456
- const templateComponents = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => import_fs4.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`));
1456
+ const templateComponents = (await import_promises.default.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => import_fs4.default.existsSync(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`));
1457
1457
  return templateComponents;
1458
1458
  }
1459
1459
  async getViewsSourceCode() {
@@ -2041,6 +2041,7 @@ var runCommands = async (...commands) => {
2041
2041
  const errMsg = e instanceof Error ? e.message : typeof e === "string" ? e : JSON.stringify(e);
2042
2042
  Logger.error(`Command Error: ${import_chalk2.default.red(errMsg)}`);
2043
2043
  console.error(e);
2044
+ throw e;
2044
2045
  }
2045
2046
  });
2046
2047
  }
@@ -2188,6 +2189,7 @@ var Builder = class {
2188
2189
  return {
2189
2190
  entryPoints: [
2190
2191
  ...bundle ? [`${this.#executor.cwdPath}/index.ts`] : [`${this.#executor.cwdPath}/**/*.ts`, `${this.#executor.cwdPath}/**/*.tsx`],
2192
+ `${this.#executor.cwdPath}/**/*.template`,
2191
2193
  ...additionalEntryPoints
2192
2194
  ],
2193
2195
  bundle,
@@ -2196,7 +2198,8 @@ var Builder = class {
2196
2198
  platform: this.#pkgJson.esbuild?.platform,
2197
2199
  format,
2198
2200
  outdir: `${this.#distExecutor.cwdPath}/${format}`,
2199
- logLevel: "error"
2201
+ logLevel: "error",
2202
+ loader: { ".template": "copy" }
2200
2203
  };
2201
2204
  }
2202
2205
  #getAssetBuildOptions() {
@@ -2206,12 +2209,11 @@ var Builder = class {
2206
2209
  entryPoints: [
2207
2210
  `${this.#executor.cwdPath}/**/*.css`,
2208
2211
  `${this.#executor.cwdPath}/**/*.md`,
2209
- `${this.#executor.cwdPath}/**/*.template`,
2210
2212
  `${this.#executor.cwdPath}/**/*.js`
2211
2213
  ],
2212
2214
  outdir: this.#distExecutor.cwdPath,
2213
2215
  logLevel: "error",
2214
- loader: { ".css": "copy", ".md": "copy", ".template": "copy", ".js": "copy" }
2216
+ loader: { ".css": "copy", ".md": "copy", ".js": "copy" }
2215
2217
  };
2216
2218
  }
2217
2219
  async build(options = {}) {
@@ -2407,525 +2409,1032 @@ var import_vite_tsconfig_paths = __toESM(require("vite-tsconfig-paths"));
2407
2409
 
2408
2410
  // pkgs/@akanjs/cli/src/module/module.prompt.ts
2409
2411
  var frameworkDescription = `
2410
- \uB098\uB294 \uC880 \uB354 \uD6A8\uC728\uC801\uC73C\uB85C \uCF54\uB529\uC744 \uD558\uAE30 \uC704\uD574\uC11C \uC790\uCCB4 \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uC81C\uC791\uD588\uC5B4.
2411
- \uADF8\uB798\uC11C \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC744 \uD574\uC904\uD14C\uB2C8\uAE4C \uC798 \uC774\uD574\uD558\uB3C4\uB85D \uD574. \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uB294 next.js 13\uACFC nest.js, capacitor.js, nx, mongoDB \uAE30\uBC18\uC758 \uD504\uB860\uD2B8\uC5D4\uB4DC, \uC571, \uBC31\uC5D4\uB4DC \uD1B5\uD569 \uD504\uB808\uC784\uC6CC\uD06C\uC57C. \uADF8\uB798\uC11C \uBC31\uC5D4\uB4DC, \uD504\uB860\uD2B8\uC5D4\uB4DC, DB Schema\uC5D0 \uB300\uD55C \uCF54\uB4DC\uAC00 \uBAA8\uB450 \uD55C \uD3F4\uB354 \uC548\uC5D0 \uC788\uC5B4. \uADF8\uB798\uC11C \uC790\uBC14\uC2A4\uD06C\uB9BD\uD2B8, \uD0C0\uC785\uC2A4\uD06C\uB9BD\uD2B8, \uADF8\uB9AC\uACE0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC774\uD574\uB9CC \uC788\uB2E4\uBA74 \uAD6C\uBD84\uC9D3\uC9C0 \uC54A\uACE0 \uC0AC\uC6A9\uD560 \uC218 \uC788\uB2E4\uB294 \uC7A5\uC810\uC774 \uC788\uC5B4.
2412
-
2413
- \uAC00\uC7A5 \uC678\uBD80\uC758 \uAD6C\uC870\uB294
2414
- - app
2412
+ \uB098\uB294 \uC880 \uB354 \uD6A8\uC728\uC801\uC73C\uB85C \uCF54\uB529\uC744 \uD558\uAE30 \uC704\uD574\uC11C \uC790\uCCB4 \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uC81C\uC791\uD588\uC5B4.
2413
+
2414
+ \uADF8\uB798\uC11C \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC744 \uD574\uC904\uD14C\uB2C8\uAE4C \uC798 \uC774\uD574\uD558\uB3C4\uB85D \uD574. \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uB294 next.js 13\uACFC nest.js, capacitor.js, nx, mongoDB \uAE30\uBC18\uC758 \uD504\uB860\uD2B8\uC5D4\uB4DC, \uC571, \uBC31\uC5D4\uB4DC \uD1B5\uD569 \uD504\uB808\uC784\uC6CC\uD06C\uC57C. \uADF8\uB798\uC11C \uBC31\uC5D4\uB4DC, \uD504\uB860\uD2B8\uC5D4\uB4DC, DB Schema\uC5D0 \uB300\uD55C \uCF54\uB4DC\uAC00 \uBAA8\uB450 \uD55C \uD3F4\uB354 \uC548\uC5D0 \uC788\uC5B4. \uADF8\uB798\uC11C \uC790\uBC14\uC2A4\uD06C\uB9BD\uD2B8, \uD0C0\uC785\uC2A4\uD06C\uB9BD\uD2B8, \uADF8\uB9AC\uACE0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC774\uD574\uB9CC \uC788\uB2E4\uBA74 \uAD6C\uBD84\uC9D3\uC9C0 \uC54A\uACE0 \uC0AC\uC6A9\uD560 \uC218 \uC788\uB2E4\uB294 \uC7A5\uC810\uC774 \uC788\uC5B4.
2415
+
2416
+
2417
+
2418
+ \uAC00\uC7A5 \uC678\uBD80\uC758 \uAD6C\uC870\uB294
2419
+
2420
+ - app
2421
+
2415
2422
  - project1
2423
+
2416
2424
  - project2
2425
+
2417
2426
  - project3
2427
+
2418
2428
  - project4
2419
- - lib
2429
+
2430
+ - lib
2431
+
2420
2432
  - core
2433
+
2421
2434
  - external
2435
+
2422
2436
  - game
2437
+
2423
2438
  - mint
2439
+
2424
2440
  - platform
2441
+
2425
2442
  - shared
2443
+
2426
2444
  - social
2445
+
2427
2446
  - util
2428
- app\uC740 \uAC01 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4DC\uB294 \uACF3\uC774\uC57C
2429
- lib \uD558\uC704 \uD3F4\uB354\uB4E4\uC740 \uC5EC\uB7EC \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uACF5\uC6A9\uC73C\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uACA0\uB2E4 \uB77C\uACE0 \uD310\uB2E8\uD574\uC11C \uBD84\uB9AC\uD574\uB193\uC740 \uACF3\uC774\uC57C.
2430
- \uB2E4\uC74C\uC740 app/project \uB0B4\uBD80\uC758 \uAD6C\uC870\uB97C \uC54C\uB824\uC904\uAC8C.
2431
-
2432
- project
2433
- - app
2447
+
2448
+ app\uC740 \uAC01 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4DC\uB294 \uACF3\uC774\uC57C
2449
+
2450
+ lib \uD558\uC704 \uD3F4\uB354\uB4E4\uC740 \uC5EC\uB7EC \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uACF5\uC6A9\uC73C\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uACA0\uB2E4 \uB77C\uACE0 \uD310\uB2E8\uD574\uC11C \uBD84\uB9AC\uD574\uB193\uC740 \uACF3\uC774\uC57C.
2451
+
2452
+ \uB2E4\uC74C\uC740 app/project \uB0B4\uBD80\uC758 \uAD6C\uC870\uB97C \uC54C\uB824\uC904\uAC8C.
2453
+
2454
+
2455
+
2456
+ project
2457
+
2458
+ - app
2459
+
2434
2460
  - [lang]
2435
- - (projectName)
2436
- - (user)
2437
- - page.tsx
2438
- - layout.tsx
2439
- - (public)
2440
- - page.tsx
2441
- - layout.tsx
2442
- - (admin)
2443
- - page.tsx
2444
- - layout.tsx
2445
-
2446
- - lib
2461
+
2462
+ - (projectName)
2463
+
2464
+ - (user)
2465
+
2466
+ - page.tsx
2467
+
2468
+ - layout.tsx
2469
+
2470
+ - (public)
2471
+
2472
+ - page.tsx
2473
+
2474
+ - layout.tsx
2475
+
2476
+ - (admin)
2477
+
2478
+ - page.tsx
2479
+
2480
+ - layout.tsx
2481
+
2482
+
2483
+
2484
+ - lib
2485
+
2447
2486
  - dataName1
2487
+
2448
2488
  - dataName2
2489
+
2449
2490
  - dataName3
2491
+
2450
2492
  - dataName4
2493
+
2451
2494
  - dataName5
2495
+
2452
2496
  - dataName6
2497
+
2453
2498
  - dataName7
2454
-
2455
- app\uC740 \uC9C1\uC811\uC801\uC73C\uB85C \uC720\uC800\uAC00 \uBCF4\uB294 \uD398\uC774\uC9C0\uB97C \uC9DC\uB294 \uACF3\uC774\uC57C. \uD3F4\uB354 \uAD6C\uC870\uB294 next 13\uC758 app directory\uB97C \uB530\uB974\uACE0 \uC788\uC5B4.
2456
- public/page.tsx\uAC00 \uAC00\uC7A5 \uCD5C\uCD08\uB85C \uC811\uADFC\uB418\uB294 Index \uD398\uC774\uC9C0\uAC00 \uB420 \uAC70\uC57C.
2457
- \uC544\uB798\uB294 public/page.tsx\uC758 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2458
- \`\`\`
2459
- import {{ Image, Link }} from "@util/ui";
2460
- import {{ getSelf }} from "@akanjs/client";
2461
-
2462
- export default function Page() {{
2463
- const self = getSelf();
2464
- return (
2465
- <div className="relative w-full h-screen overflow-hidden flex items-center justify-center">
2466
- <Image
2467
- className="absolute left-0 right-0 top-0 bottom-0 w-full h-screen -z-50"
2468
- width={{1920}}
2469
- height={{1080}}
2470
- src="/back.jpg"
2471
- />
2472
- <div className="max-w-md bg-base-100/50 shadow-lg rounded-xl backdrop-blur-xs w-full py-8 px-16 flex flex-col items-center justify-center gap-3">
2473
- <h1 className="text-4xl mt-2"><%= project %></h1>
2474
- <h2 className="text-lg"><%= project %> description</h2>
2475
- <Link className="w-full" href={{self ? "/home" : "/signin"}}>
2476
- <button className="btn w-full btn-primary">Go to dashboard</button>
2477
- </Link>
2478
- </div>
2479
- </div>
2480
- );
2481
- }}
2482
- \`\`\`
2483
-
2484
- lib\uC740 \uC11C\uBE44\uC2A4\uB97C \uB9CC\uB4E4\uB2E4\uBCF4\uBA74 \uD544\uC694\uD55C \uB370\uC774\uD130\uB97C \uC815\uC758\uD558\uB294 \uACF3\uC774\uC57C.
2485
- \uB530\uB77C\uC11C dataName\uC740 DB\uC774\uB984. \uC989 \uB370\uC774\uD130\uBA85\uC744 \uB530\uB77C. \uB2E4\uB9CC \uD3F4\uB354 \uB0B4\uBD80\uC5D0\uB294 backend, frontend\uC5D0\uC11C \uD1B5\uD569\uC73C\uB85C \uC4F0\uB294 \uC18C\uC2A4\uCF54\uB4DC\uB4E4\uC774 \uC788\uC5B4.
2486
-
2487
- \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC758 \uD575\uC2EC\uC740 \uC815\uC758\uD55C \uBA54\uD0C0\uB370\uC774\uD130\uB4E4\uC744 \uC774\uC6A9\uD574\uC11C \uAC01 \uB370\uC774\uD130\uAC04\uC758 \uC5F0\uAD00\uC810\uC774\uB098, \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uBCF4\uACE0 \uBBF8\uB9AC \uC815\uB9AC\uB41C \uACB0\uACFC\uB97C \uB9CC\uB4E4\uC5B4\uC8FC\uACE0 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4E0\uB2E4\uBA74 \uAC70\uC758 \uBAA8\uB450 \uD544\uC694\uD55C \uC791\uC5C5\uB4E4\uC744 \uBBF8\uB9AC \uC815\uB9AC\uD574\uB1A8\uC5B4. \uC608\uB97C \uB4E4\uC5B4 \uB370\uC774\uD130 \uD0C0\uC785\uC5D0 \uC774\uBBF8\uC9C0 \uD30C\uC77C\uC774 \uC788\uB2E4\uACE0 \uD55C\uB2E4\uBA74 \uBC31\uC5D4\uB4DC\uB97C \uD1B5\uD574 \uADF8 \uC774\uBBF8\uC9C0\uB97C \uC11C\uBC84\uC758 \uC2A4\uD1A0\uB9AC\uC9C0\uC5D0 \uC800\uC7A5\uD558\uACE0 \uADF8 \uC800\uC7A5\uB41C \uD30C\uC77C\uC744 \uD2B9\uC815 db\uC5D0 id\uB97C \uCD94\uAC00\uD574\uC8FC\uB294 \uD568\uC218\uB4E4 \uAC19\uC740 \uAC83\uB4E4\uC740 \uC5B4\uB290 \uD504\uB85C\uC81D\uD2B8\uB358 \uAC04\uC5D0 \uBAA8\uB450 \uC0AC\uC6A9\uB418\uB294 \uBC29\uC2DD\uC774\uB77C\uACE0 \uD310\uB2E8\uD588\uC5B4. \uD558\uC9C0\uB9CC \uC6B0\uB9AC\uB294 \uD504\uB85C\uC81D\uD2B8\uB97C \uC791\uC5C5\uD560 \uB54C\uB9C8\uB2E4 \uC774 \uBD88\uD544\uC694\uD55C \uC791\uC5C5\uB4E4\uC744 \uD56D\uC0C1 \uB9CC\uB4E4\uACE0 \uD14C\uC2A4\uD2B8\uB97C \uD558\uB294 \uBD88\uD544\uC694\uD55C \uC77C\uB4E4\uC744 \uD558\uACE0\uC788\uC9C0. \uADF8\uB798\uC11C \uC6B0\uB9AC\uB294 \uAC01 \uD504\uB85C\uC81D\uD2B8\uAC00 \uB9CC\uB4E4 \uB54C\uB9C8\uB2E4 \uD544\uC218\uB85C \uC788\uC5B4\uC57C\uD560 \uC774\uBBF8\uC9C0 \uC5C5\uB85C\uB4DC \uD504\uB85C\uC138\uC2A4\uB97C \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uD1B5\uD574 \uBBF8\uB9AC \uC815\uC758\uB41C \uC0C1\uD0DC\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC5B4.
2488
- \uACB0\uACFC\uC801\uC73C\uB85C \uC6B0\uB9B0 \uD544\uC694\uD558\uC9C0\uB9CC \uB9E4\uBC88 \uC791\uC5C5\uD558\uAE30\uC5D4 \uC190\uC774 \uB9CE\uC774\uAC00\uB294 \uC791\uC5C5\uB4E4\uC744 \uBBF8\uB9AC \uC815\uC758\uD574\uB1A8\uC5B4.
2489
-
2490
- \uB610\uD55C \uC6B0\uB9B0 CLI\uB97C \uD1B5\uD574\uC11C \uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354 \uD15C\uD50C\uB9BF\uC744 \uB9CC\uB4E4\uC5B4\uC8FC\uAC70\uB098, \uD2B9\uC815 \uBAA8\uB378\uC758 \uD544\uB4DC\uB4E4\uC744 \uB9CC\uB4E4 \uC218 \uC788\uB3C4\uB85D \uD574\uB1A8\uC5B4. Model\uC774\uB77C\uB294 \uBCC0\uC218\uC758 \uACB0\uACFC\uAC12\uC744 \uBC1B\uACE0 \uC800 \uD15C\uD50C\uB9BF\uC5D0 \uB9DE\uAC8C\uB054 \uC774\uB984\uC744 \uB123\uC5B4\uC8FC\uB294 \uAC70\uC9C0. \uB9CC\uC57D \uB0B4\uAC00 phone\uC774\uB77C\uB294 \uBCC0\uC218\uB97C \uB123\uC5C8\uB2E4\uBA74 \uC800 \uBAA8\uB378\uC5D0 Phone\uACFC \uAC19\uC740 \uACB0\uACFC\uAC12\uC73C\uB85C \uAC12\uC774 \uB4E4\uC5B4\uAC00\uAC8C \uB428\uC73C\uB85C\uC11C \uD15C\uD50C\uB9BF\uC774 \uC0DD\uC131\uB3FC. \uC774\uB294 \uC6B0\uB9AC\uAC00 \uC774\uBBF8 \uB9CC\uB4E4\uC5B4\uB193\uC740 \uCEE4\uB9E8\uB4DC\uAC00 \uC788\uC5B4.
2491
-
2492
- \uC608\uB97C \uB4E4\uC5B4 \uC5F0\uD544\uC774\uB77C\uB294 \uBAA8\uB378\uC744 \uCEE4\uB9E8\uB4DC\uB97C \uD1B5\uD574 \uC0DD\uC131\uD558\uBA74 \uC544\uB798\uC640 \uAC19\uC740 \uD30C\uC77C\uB4E4\uC774 \uC0DD\uC131\uB3FC.
2493
-
2494
- pencil
2495
- - pencil.constant.ts ( pencil\uC5D0 \uB300\uD55C db schema, query, sort \uAD6C\uBB38\uC744 \uC815\uC758 )
2496
- - pencil.document.ts ( model\uC5D0\uC11C \uC790\uC8FC \uC0AC\uC6A9\uD558\uB294 method, static function, middleware\uB85C \uAC04\uB2E8\uD55C db \uAD00\uB9AC \uD568\uC218\uB4F1\uC744 \uAD00\uB9AC\uD568.)
2497
- - pencil.dictionary.ts (\uB2E4\uAD6D\uC5B4\uB97C \uC704\uD574\uC11C schema field, enum, service name\uC758 \uB2E4\uAD6D\uC5B4 \uC815\uBCF4 \uB4F1\uC744 \uBAA8\uB450 \uAD00\uB9AC. )
2498
- - pencil.signal.ts (frontend\uC758 fetch\uB97C \uC5F4\uC5B4\uC8FC\uB294 \uC77C\uC885\uC758 \uCC3D\uAD6C, \uAD8C\uD55C\uAD00\uB9AC\uB4F1\uC744 \uD568 nestjs\uC758 resolver\uC640 \uC720\uC0AC )
2499
- - pencil.service.ts (\uC2E4\uC9C8\uC801\uC778 \uC11C\uBE44\uC2A4 \uCF54\uB4DC\uB97C \uC791\uC131\uD558\uB294 \uACF3. \uAC01\uC885 \uBE44\uC988\uB2C8\uC2A4 \uB85C\uC9C1\uC744 \uCC98\uB9AC\uD568.)
2500
- - pencil.store.ts (pencil field\uC5D0 \uB300\uD55C \uC0C1\uD0DC\uAD00\uB9AC \uC800\uC7A5\uC18C.)
2501
- - pencil.Zone.tsx (\uC544\uB798 Templete, Unit, Util, View, Util\uB4F1\uC744 \uC870\uD569\uD574\uC11C \uB2E4\uC74C \uB808\uBCA8 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC791\uC131\uD558\uB294 \uACF3 client component\uB85C \uC815\uC758\uB428. )
2502
- - pencil.Templete.tsx (\uC8FC\uB85C edit\uC5D0 \uC5F0\uAD00\uB41C \uCEF4\uD3EC\uB10C\uD2B8 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
2503
- - pencil.Unit.tsx (list \uCC98\uB7FC \uBCF5\uC218\uAC1C\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
2504
- - pencil.Util.tsx (Action \uBC84\uD2BC\uC744 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
2505
- - pencil.View.tsx (\uB2E8\uC77C view \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
2506
-
2507
-
2508
- \uC5EC\uAE30\uC11C constant\uC5D0 \uC815\uC758 \uB418\uC5B4\uC788\uB294 schema\uB97C \uAE30\uBCF8\uC73C\uB85C \uD574\uC11C \uAC01 document, dictionary, signal, service, store\uB97C \uC0DD\uC131\uD574.
2509
-
2510
- document, signal, service\uB294 \uBC31\uC5D4\uB4DC\uC640 \uC5F0\uAD00\uB418\uC5B4\uC788\uB294 \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2511
- \uC11C\uB85C\uAC04\uC758 \uAD00\uACC4\uB294 \uC8FC\uB85C signal\uC5D0\uC11C \uAC00\uC7A5 \uBA3C\uC800 \uC694\uCCAD\uC744 \uBC1B\uACE0 \uC774\uD6C4 \uB85C\uC9C1\uC758 \uBCF5\uC7A1\uB3C4\uC5D0 \uB530\uB77C\uC11C service\uB85C \uCC98\uB9AC\uD560 \uC9C0, docuemnt\uB85C \uCC98\uB9AC\uD560 \uC9C0\uB97C \uACB0\uC815\uD574.
2512
- signal - document
2513
- signal - service - document
2514
-
2515
- store\uB294 \uD504\uB860\uD2B8\uC5D4\uB4DC\uC5D0\uC11C \uC0C1\uD0DC\uAD00\uB9AC\uB97C \uD560 \uB54C \uC0AC\uC6A9\uB3FC.
2516
- \uC6B0\uB9AC\uB294 signal\uC758 \uCF54\uB4DC\uB85C \uB098\uC628 \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uC774\uC6A9\uD574\uC11C store\uC5D0\uC11C \uD754\uD788 \uC0AC\uC6A9\uB420\uB9CC\uD55C \uD568\uC218\uB4E4\uC744 \uBBF8\uB9AC \uC815\uC758\uD558\uAC8C\uB054 \uB9CC\uB4E4\uC5C8\uC5B4.
2517
-
2518
- \uC774\uB807\uAC8C 11\uAC1C\uC758 \uD30C\uC77C\uB85C \uAD6C\uBD84\uD574\uC11C \uC815\uC758\uAC00 \uB3FC.
2519
- \uC9C0\uAE08\uBD80\uD134 \uD55C \uD30C\uC77C\uB4E4\uB9C8\uB2E4 \uC0C1\uC138\uD55C \uC124\uBA85\uC744 \uD574\uC904\uAC8C.
2520
-
2521
- model.constant.ts
2522
-
2523
- constant\uB294 \uAE30\uBCF8 \uC2A4\uD0A4\uB9C8\uAC00 \uAD6C\uC131\uB418\uB294 \uACF3\uC774\uC57C. \uADF8\uB798\uC11C \uC774 \uACF3\uC5D0\uC11C DB \uC2A4\uD0A4\uB9C8, \uCFFC\uB9AC, \uC815\uB82C \uAD6C\uBB38\uC744 \uC815\uC758\uD574.
2524
- \uC8FC\uC758\uD574\uC57C\uD560 \uAC74 decorator\uC5D0\uC11C \uC815\uC758\uD558\uB294 \uD0C0\uC785\uACFC \uC544\uB798\uC5D0 \uC815\uC758\uD558\uB294 \uD0C0\uC785\uC774 \uC57D\uAC04 \uB2E4\uB97C \uC218 \uC788\uC5B4
2525
- \uC608\uB97C \uB4E4\uC5B4 decorator\uC5D0\uC11C\uB294 Int\uB85C \uC815\uC758\uD558\uACE0 constant\uC5D0\uC11C\uB294 number\uB85C \uC815\uC758\uD574\uC57C\uD574.
2526
- \uCD94\uAC00\uB85C createdAt\uACFC updatedAt, status\uB294 \uAE30\uBCF8\uC801\uC73C\uB85C \uC0DD\uC131\uB418\uB294 \uD544\uB4DC\uC774\uB2C8\uAE4C \uB530\uB85C \uC815\uC758\uD558\uC9C0 \uC54A\uC544\uB3C4 \uB3FC.
2527
- \uC774\uB294 decorator\uC5D0\uC11C\uB294 GraphQL\uC5D0\uC11C \uC0AC\uC6A9\uD560 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uACE0 constant\uC5D0\uC11C\uB294 \uC2E4\uC81C \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uAC70\uC9C0.
2528
-
2529
- \`\`\`
2530
- import { enumOf, Int } from "@akanjs/base";
2531
- import { Field, Filter, Model, sortOf, via } from "@akanjs/constant";
2532
-
2533
- export const \${dict.Model}Statuses = ["active"] as const;
2534
- export type \${dict.Model}Status = (typeof \${dict.Model}Statuses)[number];
2535
-
2536
- //\uB370\uC774\uD130\uB97C \uB9CC\uB4E4 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uACF3
2537
- @Model.Input("\${dict.Model}Input")
2538
- export class \${dict.Model}Input {{
2539
- @Field.Prop(() => String)
2540
- field: string;
2541
-
2542
- @Field.Prop(() => Int, {{ nullable: true }})
2543
- fieldInt: number | null;
2544
-
2545
- @Field.Prop(() => Date, {{default: dayjs()}})
2546
- fieldInt: Dayjs;
2547
- }}
2548
-
2549
- //\uB370\uC774\uD130\uAC00 \uB9CC\uB4E4\uC5B4\uC9C4 \uC774\uD6C4 \uC0DD\uC131\uB418\uAC70\uB098 \uC800\uC7A5\uC73C\uB85C \uCD94\uAC00\uD560 \uC218 \uC788\uB294 \uACF3
2550
- @Model.Object("\${dict.Model}Object")
2551
- export class \${dict.Model}Object extends via(\${dict.Model}Input) {
2552
- @Field.Prop(() => String, {{ enum: \${dict.Model}Statuses, default: "active" }})
2553
- status: \${dict.Model}Status;
2554
- }}
2555
-
2556
- //\uB370\uC774\uD130\uB97C \uB9AC\uC2A4\uD2B8\uB85C \uBCF4\uC5EC\uC904 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130\uB9CC \uC81C\uACF5\uD558\uB294 \uACF3
2557
- @Model.Light("Light\${dict.Model}")
2558
- export class Light\${dict.Model} extends via(\${dict.Model}Object, [
2559
- "field",
2560
- "status",
2561
- ] as const) {}
2562
-
2563
- //\uCD5C\uC885 \uB370\uC774\uD130\uC758 Full \uD0C0\uC785\uC774 \uC815\uC758\uB418\uB294 \uACF3
2564
- @Model.Full("\${dict.Model}")
2565
- export class \${dict.Model} extends via(\${dict.Model}Object, Light\${dict.Model}) {}
2566
-
2567
- //\uB370\uC774\uD130\uC758 \uC778\uC0AC\uC774\uD2B8\uB97C \uCE21\uC815\uD558\uAE30 \uC704\uD574\uC11C \uD544\uC694\uD55C \uB370\uC774\uD130\uB97C \uC815\uC758\uD558\uB294 \uACF3
2568
- @Model.Insight("\${dict.Model}Insight")
2569
- export class \${dict.Model}Insight {{
2570
- @Field.Prop(() => Int, {{ default: 0, accumulate: {{ $sum: 1 }} }})
2571
- count: number;
2572
- }}
2573
-
2574
- //\uB370\uC774\uD130\uC758 \uD1B5\uACC4\uB97C \uACC4\uC0B0\uD558\uB294 \uACF3
2575
- @Model.Summary("\${dict.Model}Summary")
2576
- export class \${dict.Model}Summary {{
2577
- @Field.Prop(() => Int, {{ min: 0, default: 0, query: {{ status: {{}} }} }})
2578
- total\${dict.Model}: number;
2579
- }}
2580
-
2581
- @Model.Filter("\${dict.Model}Filter")
2582
- export class \${dict.Model}Filter extends sortOf(\${dict.Model}, {}) {}
2583
- \`\`\`
2584
-
2585
-
2586
- model.dictonary.ts
2587
- \`\`\`
2588
- import {
2589
- baseTrans,
2590
- getBaseSignalTrans,
2591
- ModelDictionary,
2592
- SignalDictionary,
2593
- SummaryDictionary,
2594
- } from "@akanjs/dictionary";
2595
-
2596
- import type { \${dict.Model}, \${dict.Model}Filter, \${dict.Model}Insight, \${dict.Model}Summary } from "./\${dict.model}.constant";
2597
- import type { \${dict.Model}Signal } from "./\${dict.model}.signal";
2598
-
2599
- const modelDictionary = {{
2600
- ...baseTrans,
2601
- modelName: ["\${dict.Model}", "\${dict.Model}"],
2602
- modelDesc: [
2603
- "\${dict.Model} description",
2604
- "\${dict.Model} \uC124\uBA85",
2605
- ],
2606
-
2607
- // * ==================== Model ==================== * //
2608
- field: ["Field", "\uD544\uB4DC"],
2609
- "desc-field": ["Field", "\uD544\uB4DC"],
2610
- // * ==================== Model ==================== * //
2611
-
2612
- // * ==================== Insight ==================== * //
2613
- count: ["Count", "\uAC1C\uC218"],
2614
- "desc-count": ["\${dict.Model} count in current query settting", "\uD604\uC7AC \uCFFC\uB9AC \uC124\uC815\uC5D0 \uB9DE\uB294 \${dict.Model} \uC218"],
2615
- // * ==================== Insight ==================== * //
2616
-
2617
- // * ==================== Filter ==================== * //
2618
- // * ==================== Filter ==================== * //
2619
-
2620
- // * ==================== Etc ==================== * //
2621
- "enum-status-active": ["Active", "\uD65C\uC131"],
2622
- "enumdesc-status-active": ["Active status", "\uD65C\uC131 \uC0C1\uD0DC"],
2623
- // * ==================== Etc ==================== * //
2624
- }} satisfies ModelDictionary<\${dict.Model}, \${dict.Model}Insight, typeof \${dict.Model}Sort>;
2625
-
2626
- export const \${dict.Model}SummaryDictionary = {{
2627
- // * ==================== Summary ==================== * //
2628
- total\${dict.Model}: ["Total \${dict.Model}", "\uCD1D \${dict.Model} \uC218"],
2629
- "desc-total\${dict.Model}": ["Total \${dict.Model} count in the database", "\uB370\uC774\uD130\uBCA0\uC774\uC2A4\uC5D0 \uC800\uC7A5\uB41C \uCD1D \${dict.Model} \uC218"],
2630
- // * ==================== Summary ==================== * //
2631
- }} satisfies SummaryDictionary<\${dict.Model}Summary>;
2632
-
2633
- const signalDictionary = {{
2634
- ...getBaseSignalTrans("\${dict.Model}" as const),
2635
- // * ==================== Endpoint ==================== * //
2636
- "api-\${dict.Model}ListInPublic": ["\${dict.Model} List In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uB9AC\uC2A4\uD2B8"],
2637
- "apidesc-\${dict.Model}ListInPublic": ["Get a list of public \${dict.Model}", "\uACF5\uAC1C\uB41C \${dict.Model}\uC758 \uB9AC\uC2A4\uD2B8\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4"],
2638
- "arg-\${dict.Model}ListInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2639
- "argdesc-\${dict.Model}ListInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2640
- "arg-\${dict.Model}ListInPublic-skip": ["Skip", "\uAC74\uB108\uB6F0\uAE30"],
2641
- "argdesc-\${dict.Model}ListInPublic-skip": ["Number of items to skip", "\uAC74\uB108\uB6F8 \uC544\uC774\uD15C \uC218"],
2642
- "arg-\${dict.Model}ListInPublic-limit": ["Limit", "\uC81C\uD55C"],
2643
- "argdesc-\${dict.Model}ListInPublic-limit": ["Maximum number of items to return", "\uBC18\uD658\uD560 \uCD5C\uB300 \uC544\uC774\uD15C \uC218"],
2644
- "arg-\${dict.Model}ListInPublic-sort": ["Sort", "\uC815\uB82C"],
2645
- "argdesc-\${dict.Model}ListInPublic-sort": ["Sort order of the items", "\uC544\uC774\uD15C\uC758 \uC815\uB82C \uC21C\uC11C"],
2646
-
2647
- "api-\${dict.Model}InsightInPublic": ["\${dict.Model} Insight In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uC778\uC0AC\uC774\uD2B8"],
2648
- "apidesc-\${dict.Model}InsightInPublic": [
2649
- "Get insight data for public \${dict.Model}",
2650
- "\uACF5\uAC1C\uB41C \${dict.Model}\uC5D0 \uB300\uD55C \uC778\uC0AC\uC774\uD2B8 \uB370\uC774\uD130\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4",
2651
- ],
2652
- "arg-\${dict.Model}InsightInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2653
- "argdesc-\${dict.Model}InsightInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2654
- // * ==================== Endpoint ==================== * //
2655
- }} satisfies SignalDictionary<\${dict.Model}Signal, \${dict.Model}>;
2656
- \`\`\`
2657
- export const \${dict.model}Dictionary = {{ ...modelDictionary, ...signalDictionary }};
2658
-
2659
-
2660
-
2661
- model.document.ts
2662
- \`\`\`
2663
- import { beyond, by, Database, into, type SchemaOf } from "@akanjs/document";
2664
-
2665
- import { cnst } from "../cnst";
2666
- @Database.Input(() => cnst.\${dict.Model}Input)
2667
- export class \${dict.Model}Input extends by(cnst.\${dict.Model}Input) {}
2668
-
2669
- @Database.Document(() => cnst.\${dict.Model})
2670
- export class \${dict.Model} extends by(cnst.\${dict.Model}) {}
2671
-
2672
- @Database.Model(() => cnst.\${dict.Model})
2673
- export class \${dict.Model}Model extends into(\${dict.Model}, cnst.\${dict.Model}Cnst) {
2674
- async getSummary(): Promise<cnst.\${dict.Model}Summary> {
2675
- return {
2676
- ...(await this.getDefaultSummary()),
2677
- };
2678
- }
2679
- }
2680
-
2681
- @Database.Middleware(() => cnst.\${dict.Model})
2682
- export class \${dict.Model}Middleware extends beyond(\${dict.Model}Model, \${dict.Model}) {
2683
- onSchema(schema: SchemaOf<\${dict.Model}Model, \${dict.Model}>) {
2684
- // schema.index({ status: 1 })
2685
- }
2686
- }
2687
- \`\`\`
2688
-
2689
-
2690
- model.signal.ts
2691
- \`\`\`
2692
- import { Int } from "@akanjs/base";
2693
- import { SortOf } from "@akanjs/constant";
2694
- import { Arg, DbSignal, Mutation, Query, resolve, Signal } from "@akanjs/signal";
2695
-
2696
- import { cnst, Srvs } from "../cnst";
2697
-
2698
- @Signal(() => cnst.\${dict.Model})
2699
- export class \${dict.Model}Signal extends DbSignal(cnst.\${dict.model}Cnst, Srvs, {
2700
- guards: { get: Query.Public, cru: Mutation.Public },
2701
- }) {
2702
- // * /////////////////////////////////////
2703
- // * Public Slice
2704
- @Query.Public(() => [cnst.\${dict.Model}])
2705
- async \${dict.model}ListInPublic(
2706
- @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null,
2707
- @Arg.Query("skip", () => Int, { nullable: true }) skip: number | null,
2708
- @Arg.Query("limit", () => Int, { nullable: true }) limit: number | null,
2709
- @Arg.Query("sort", () => String, { nullable: true }) sort: SortOf<cnst.\${dict.Model}Filter> | null
2710
- ) {
2711
- const \${dict.models} = await this.\${dict.model}Service.listByStatuses(statuses, { skip, limit, sort });
2712
- return resolve<cnst.\${dict.Model}[]>(\${dict.models});
2713
- }
2714
- @Query.Public(() => cnst.\${dict.Model}Insight)
2715
- async \${dict.model}InsightInPublic(
2716
- @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null
2717
- ) {
2718
- const \${dict.model}Insight = await this.\${dict.model}Service.insightByStatuses(statuses);
2719
- return resolve<cnst.\${dict.Model}Insight>(\${dict.model}Insight);
2720
- }
2721
- // * Public Slice
2722
- // * /////////////////////////////////////
2723
- }
2724
- \`\`\`
2725
-
2726
-
2727
- model.service.ts
2728
- \`\`\`
2729
- import { DbService, Service } from "@akanjs/service";
2730
-
2731
- import { cnst } from "../cnst";
2732
- import * as db from "../db";
2733
-
2734
- @Service("\${dict.Model}Service")
2735
- export class \${dict.Model}Service extends DbService(db.\${dict.Model}Db) {
2736
- async summarize(): Promise<cnst.\${dict.Model}Summary> {
2737
- return {
2738
- ...(await this.\${dict.Model}Model.getSummary()),
2739
- };
2740
- }
2741
- }
2742
- \`\`\`
2743
-
2744
-
2745
- model.store.ts
2746
- \`\`\`
2747
- import { stateOf, Store } from "@akanjs/store";
2748
-
2749
- import { cnst } from "../cnst";
2750
- import { fetch } from "../fetch";
2751
-
2752
- @Store(() => cnst.\${dict.Model})
2753
- export class \${dict.Model}Store extends stateOf(fetch.\${dict.model}Gql, {
2754
- // state
2755
- }) {
2756
- // action
2757
- }
2758
- \`\`\`
2759
-
2760
-
2761
- model.Zone.tsx
2762
- \`\`\`
2763
- "use client";
2764
- import { Data, Load } from "@shared/ui";
2765
- import { ModelsProps } from "@akanjs/client";
2766
- import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
2767
- import { ClientInit, ClientView, DefaultOf } from "@akanjs/signal";
2768
-
2769
- export const Admin = ({ sliceName = "\${dict.model}", init, query }: ModelsProps<cnst.\${dict.Model}>>) => {
2770
- return (
2771
- <Data.ListContainer
2772
- init={init}
2773
- query={query}
2774
- sliceName={sliceName}
2775
- renderItem={\${dict.Model}.Unit.Card}
2776
- renderDashboard={\${dict.Model}.Util.Stat}
2777
- renderInsight={\${dict.Model}.Util.Insight}
2778
- renderTemplate={\${dict.Model}.Template.General}
2779
- renderTitle={(\${dict.model}: DefaultOf<cnst.\${dict.Model}>>) => \`\${dict.Model} - \${\${dict.model}.id ? \${dict.model}.id : "New"}\`}
2780
- renderView={(\${dict.model}: cnst.\${dict.Model}>) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />}
2781
- columns={[
2782
- "id",
2783
- "status",
2784
- "createdAt",
2785
- "updatedAt",
2786
- ]}
2787
- actions={(\${dict.model}: cnst.Light\${dict.Model}, idx) => ["remove", "edit", "view"]}
2788
- />
2789
- );
2790
- };
2791
-
2792
- interface CardProps {
2793
- className?: string;
2794
- init: ClientInit<"\${dict.model}", cnst.Light\${dict.Model}>;
2795
- }
2796
- export const Card = ({ className, init }: CardProps) => {
2797
- return (
2798
- <Load.Units
2799
- className={className}
2800
- init={init}
2801
- renderItem={(\${dict.model}: cnst.Light\${dict.Model}) => (
2802
- <\${dict.Model}.Unit.Card key={\${dict.model}.id} href={\`/\${dict.model}/\${\${dict.model}.id}\`} \${dict.model}={\${dict.model}} />
2803
- )}
2804
- />
2805
- );
2806
- };
2807
-
2808
- interface ViewProps {
2809
- className?: string;
2810
- view: ClientView<"\${dict.model}", cnst.\${dict.Model}>;
2811
- }
2812
- export const View = ({ view }: ViewProps) => {
2813
- return <Load.View view={view} renderView={(\${dict.model}) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />} />;
2814
- };
2815
- \`\`\`
2816
-
2817
- model.Templete.tsx
2818
- \`\`\`
2819
- "use client";
2820
- import { cnst, st, usePage } from "@\${dict.appName}/client";
2821
- import { Field } from "@shared/ui";
2822
- import { Layout } from "@util/ui";
2823
-
2824
- interface \${dict.Model}EditProps {
2825
- \${dict.model}Id?: string | null;
2826
- }
2827
-
2828
- export const General = ({ \${dict.model}Id = undefined }: \${dict.Model}EditProps) => {
2829
- const \${dict.model}Form = st.use.\${dict.model}Form();
2830
- const { l } = usePage();
2831
- return (
2832
- <Layout.Template>
2833
- <Field.Text
2834
- label={l.field("\${dict.model}", "id")}
2835
- desc={l.desc("\${dict.model}", "id")}
2836
- value={\${dict.model}Form.id}
2837
- onChange={st.do.setIdOn\${dict.Model}}
2838
- />
2839
- </Layout.Template>
2840
- );
2841
- };
2842
- \`\`\`
2843
-
2844
-
2845
- model.Unit.tsx
2846
- \`\`\`
2847
- import { ModelProps } from "@akanjs/client";
2848
- import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
2849
- import { Link } from "@util/ui";
2850
-
2851
- export const Card = ({ \${dict.model}, href }: ModelProps<"\${dict.model}", cnst.Light\${dict.Model}>>) => {
2852
- return (
2853
- <Link href={href} className="animate-fadeIn w-full h-36 flex rounded-lg shadow-sm hover:shadow-lg duration-300">
2854
- <div>{\${dict.model}.id}</div>
2855
- </Link>
2856
- );
2857
- };
2858
- \`\`\`
2859
-
2860
-
2861
- model.Util.tsx
2862
- \`\`\`
2863
- "use client";
2864
- import { ModelDashboardProps, ModelInsightProps } from "@akanjs/client";
2865
- import { getQueryMap } from "@akanjs/constant";
2866
- import { cnst } from "@\${dict.appName}/client";
2867
- import { Data } from "@shared/ui";
2868
-
2869
- export const Stat = ({
2870
- className,
2871
- summary,
2872
- sliceName = "\${dict.model}",
2873
- queryMap = getQueryMap(cnst.\${dict.Model}Summary),
2874
- hidePresents,
2875
- }: ModelDashboardProps<cnst.Summary>) => {
2876
- return (
2877
- <Data.Dashboard
2878
- className={className}
2879
- summary={summary}
2880
- sliceName={sliceName}
2881
- queryMap={queryMap}
2882
- columns={["total\${dict.Model}"]}
2883
- hidePresents={hidePresents}
2884
- />
2885
- );
2886
- };
2887
-
2888
- export const Insight = ({
2889
- className,
2890
- insight,
2891
- sliceName = "\${dict.model}",
2892
- }: ModelInsightProps<cnst.\${dict.Model}Insight>) => {
2893
- return (
2894
- <Data.Insight
2895
- className={className}
2896
- insight={insight}
2897
- sliceName={sliceName}
2898
- columns={["count"]}
2899
- />
2900
- );
2901
- };
2902
- \`\`\`
2903
-
2904
-
2905
- model.View.tsx
2906
- \`\`\`
2907
- import { clsx } from "@akanjs/client";
2908
- import { cnst } from "@\${dict.appName}/client";
2909
- import { Image } from "@util/ui";
2910
-
2911
- interface \${dict.Model}ViewProps {
2912
- className?: string;
2913
- \${dict.model}: cnst.\${dict.Model};
2914
- self?: { id?: string } | null;
2915
- }
2916
-
2917
- export const General = ({ className, \${dict.model}, self }: \${dict.Model}ViewProps) => {
2918
- return (
2919
- <div className={clsx(className, "animate-fadeIn w-full")}>
2920
- <div>{\${dict.model}.id}</div>
2921
- </div>
2922
- );
2923
- };
2924
- \`\`\`
2925
- \uC774\uB7F0\uC2DD\uC73C\uB85C \uC6B0\uB9AC\uAC00 \uC9C1\uC811 \uB9CC\uB4E0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uAE30\uBC18\uD574\uC11C db\uC640 \uC11C\uBE44\uC2A4 \uC2A4\uD1A0\uC5B4\uAE4C\uC9C0 \uBAA8\uB450 \uC5F0\uB3D9\uD574\uC11C \uD558\uB098\uC758 \uBAA8\uB378\uC5D0 \uB9DE\uAC8C\uB054 \uBAA8\uB4C8\uC744 \uD55C \uD3F4\uB354\uC5D0\uC11C \uC791\uC5C5\uD560 \uC218 \uC788\uAC8C\uB054 \uAD6C\uC870\uB97C \uB9CC\uB4E4\uC5C8\uC5B4.
2926
-
2927
- \uC77C\uB2E8 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC740 \uC774 \uC815\uB3C4\uB85C \uD558\uACE0 \uC774 \uC815\uBCF4\uB4E4\uC744 \uAE30\uBC18\uC73C\uB85C \uB0B4\uAC00 \uC6D0\uD558\uB294 \uC694\uAD6C\uB97C \uB4E4\uC5B4\uC918.
2928
- `;
2499
+
2500
+
2501
+
2502
+ app\uC740 \uC9C1\uC811\uC801\uC73C\uB85C \uC720\uC800\uAC00 \uBCF4\uB294 \uD398\uC774\uC9C0\uB97C \uC9DC\uB294 \uACF3\uC774\uC57C. \uD3F4\uB354 \uAD6C\uC870\uB294 next 13\uC758 app directory\uB97C \uB530\uB974\uACE0 \uC788\uC5B4.
2503
+
2504
+ public/page.tsx\uAC00 \uAC00\uC7A5 \uCD5C\uCD08\uB85C \uC811\uADFC\uB418\uB294 Index \uD398\uC774\uC9C0\uAC00 \uB420 \uAC70\uC57C.
2505
+
2506
+ \uC544\uB798\uB294 public/page.tsx\uC758 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2507
+
2508
+ \`\`\`
2509
+
2510
+ import {{ Image, Link }} from "@util/ui";
2511
+
2512
+ import {{ getSelf }} from "@akanjs/client";
2513
+
2514
+
2515
+
2516
+ export default function Page() {{
2517
+
2518
+ const self = getSelf();
2519
+
2520
+ return (
2521
+
2522
+ <div className="relative w-full h-screen overflow-hidden flex items-center justify-center">
2523
+
2524
+ <Image
2525
+
2526
+ className="absolute left-0 right-0 top-0 bottom-0 w-full h-screen -z-50"
2527
+
2528
+ width={{1920}}
2529
+
2530
+ height={{1080}}
2531
+
2532
+ src="/back.jpg"
2533
+
2534
+ />
2535
+
2536
+ <div className="max-w-md bg-base-100/50 shadow-lg rounded-xl backdrop-blur-xs w-full py-8 px-16 flex flex-col items-center justify-center gap-3">
2537
+
2538
+ <h1 className="text-4xl mt-2"><%= project %></h1>
2539
+
2540
+ <h2 className="text-lg"><%= project %> description</h2>
2541
+
2542
+ <Link className="w-full" href={{self ? "/home" : "/signin"}}>
2543
+
2544
+ <button className="btn w-full btn-primary">Go to dashboard</button>
2545
+
2546
+ </Link>
2547
+
2548
+ </div>
2549
+
2550
+ </div>
2551
+
2552
+ );
2553
+
2554
+ }}
2555
+
2556
+ \`\`\`
2557
+
2558
+
2559
+
2560
+ lib\uC740 \uC11C\uBE44\uC2A4\uB97C \uB9CC\uB4E4\uB2E4\uBCF4\uBA74 \uD544\uC694\uD55C \uB370\uC774\uD130\uB97C \uC815\uC758\uD558\uB294 \uACF3\uC774\uC57C.
2561
+
2562
+ \uB530\uB77C\uC11C dataName\uC740 DB\uC774\uB984. \uC989 \uB370\uC774\uD130\uBA85\uC744 \uB530\uB77C. \uB2E4\uB9CC \uD3F4\uB354 \uB0B4\uBD80\uC5D0\uB294 backend, frontend\uC5D0\uC11C \uD1B5\uD569\uC73C\uB85C \uC4F0\uB294 \uC18C\uC2A4\uCF54\uB4DC\uB4E4\uC774 \uC788\uC5B4.
2563
+
2564
+
2565
+
2566
+ \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC758 \uD575\uC2EC\uC740 \uC815\uC758\uD55C \uBA54\uD0C0\uB370\uC774\uD130\uB4E4\uC744 \uC774\uC6A9\uD574\uC11C \uAC01 \uB370\uC774\uD130\uAC04\uC758 \uC5F0\uAD00\uC810\uC774\uB098, \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uBCF4\uACE0 \uBBF8\uB9AC \uC815\uB9AC\uB41C \uACB0\uACFC\uB97C \uB9CC\uB4E4\uC5B4\uC8FC\uACE0 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4E0\uB2E4\uBA74 \uAC70\uC758 \uBAA8\uB450 \uD544\uC694\uD55C \uC791\uC5C5\uB4E4\uC744 \uBBF8\uB9AC \uC815\uB9AC\uD574\uB1A8\uC5B4. \uC608\uB97C \uB4E4\uC5B4 \uB370\uC774\uD130 \uD0C0\uC785\uC5D0 \uC774\uBBF8\uC9C0 \uD30C\uC77C\uC774 \uC788\uB2E4\uACE0 \uD55C\uB2E4\uBA74 \uBC31\uC5D4\uB4DC\uB97C \uD1B5\uD574 \uADF8 \uC774\uBBF8\uC9C0\uB97C \uC11C\uBC84\uC758 \uC2A4\uD1A0\uB9AC\uC9C0\uC5D0 \uC800\uC7A5\uD558\uACE0 \uADF8 \uC800\uC7A5\uB41C \uD30C\uC77C\uC744 \uD2B9\uC815 db\uC5D0 id\uB97C \uCD94\uAC00\uD574\uC8FC\uB294 \uD568\uC218\uB4E4 \uAC19\uC740 \uAC83\uB4E4\uC740 \uC5B4\uB290 \uD504\uB85C\uC81D\uD2B8\uB358 \uAC04\uC5D0 \uBAA8\uB450 \uC0AC\uC6A9\uB418\uB294 \uBC29\uC2DD\uC774\uB77C\uACE0 \uD310\uB2E8\uD588\uC5B4. \uD558\uC9C0\uB9CC \uC6B0\uB9AC\uB294 \uD504\uB85C\uC81D\uD2B8\uB97C \uC791\uC5C5\uD560 \uB54C\uB9C8\uB2E4 \uC774 \uBD88\uD544\uC694\uD55C \uC791\uC5C5\uB4E4\uC744 \uD56D\uC0C1 \uB9CC\uB4E4\uACE0 \uD14C\uC2A4\uD2B8\uB97C \uD558\uB294 \uBD88\uD544\uC694\uD55C \uC77C\uB4E4\uC744 \uD558\uACE0\uC788\uC9C0. \uADF8\uB798\uC11C \uC6B0\uB9AC\uB294 \uAC01 \uD504\uB85C\uC81D\uD2B8\uAC00 \uB9CC\uB4E4 \uB54C\uB9C8\uB2E4 \uD544\uC218\uB85C \uC788\uC5B4\uC57C\uD560 \uC774\uBBF8\uC9C0 \uC5C5\uB85C\uB4DC \uD504\uB85C\uC138\uC2A4\uB97C \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uD1B5\uD574 \uBBF8\uB9AC \uC815\uC758\uB41C \uC0C1\uD0DC\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC5B4.
2567
+
2568
+ \uACB0\uACFC\uC801\uC73C\uB85C \uC6B0\uB9B0 \uD544\uC694\uD558\uC9C0\uB9CC \uB9E4\uBC88 \uC791\uC5C5\uD558\uAE30\uC5D4 \uC190\uC774 \uB9CE\uC774\uAC00\uB294 \uC791\uC5C5\uB4E4\uC744 \uBBF8\uB9AC \uC815\uC758\uD574\uB1A8\uC5B4.
2569
+
2570
+
2571
+
2572
+ \uB610\uD55C \uC6B0\uB9B0 CLI\uB97C \uD1B5\uD574\uC11C \uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354 \uD15C\uD50C\uB9BF\uC744 \uB9CC\uB4E4\uC5B4\uC8FC\uAC70\uB098, \uD2B9\uC815 \uBAA8\uB378\uC758 \uD544\uB4DC\uB4E4\uC744 \uB9CC\uB4E4 \uC218 \uC788\uB3C4\uB85D \uD574\uB1A8\uC5B4. Model\uC774\uB77C\uB294 \uBCC0\uC218\uC758 \uACB0\uACFC\uAC12\uC744 \uBC1B\uACE0 \uC800 \uD15C\uD50C\uB9BF\uC5D0 \uB9DE\uAC8C\uB054 \uC774\uB984\uC744 \uB123\uC5B4\uC8FC\uB294 \uAC70\uC9C0. \uB9CC\uC57D \uB0B4\uAC00 phone\uC774\uB77C\uB294 \uBCC0\uC218\uB97C \uB123\uC5C8\uB2E4\uBA74 \uC800 \uBAA8\uB378\uC5D0 Phone\uACFC \uAC19\uC740 \uACB0\uACFC\uAC12\uC73C\uB85C \uAC12\uC774 \uB4E4\uC5B4\uAC00\uAC8C \uB428\uC73C\uB85C\uC11C \uD15C\uD50C\uB9BF\uC774 \uC0DD\uC131\uB3FC. \uC774\uB294 \uC6B0\uB9AC\uAC00 \uC774\uBBF8 \uB9CC\uB4E4\uC5B4\uB193\uC740 \uCEE4\uB9E8\uB4DC\uAC00 \uC788\uC5B4.
2573
+
2574
+
2575
+
2576
+ \uC608\uB97C \uB4E4\uC5B4 \uC5F0\uD544\uC774\uB77C\uB294 \uBAA8\uB378\uC744 \uCEE4\uB9E8\uB4DC\uB97C \uD1B5\uD574 \uC0DD\uC131\uD558\uBA74 \uC544\uB798\uC640 \uAC19\uC740 \uD30C\uC77C\uB4E4\uC774 \uC0DD\uC131\uB3FC.
2577
+
2578
+
2579
+
2580
+ pencil
2581
+
2582
+ - pencil.constant.ts ( pencil\uC5D0 \uB300\uD55C db schema, query, sort \uAD6C\uBB38\uC744 \uC815\uC758 )
2583
+
2584
+ - pencil.document.ts ( model\uC5D0\uC11C \uC790\uC8FC \uC0AC\uC6A9\uD558\uB294 method, static function, middleware\uB85C \uAC04\uB2E8\uD55C db \uAD00\uB9AC \uD568\uC218\uB4F1\uC744 \uAD00\uB9AC\uD568.)
2585
+
2586
+ - pencil.dictionary.ts (\uB2E4\uAD6D\uC5B4\uB97C \uC704\uD574\uC11C schema field, enum, service name\uC758 \uB2E4\uAD6D\uC5B4 \uC815\uBCF4 \uB4F1\uC744 \uBAA8\uB450 \uAD00\uB9AC. )
2587
+
2588
+ - pencil.signal.ts (frontend\uC758 fetch\uB97C \uC5F4\uC5B4\uC8FC\uB294 \uC77C\uC885\uC758 \uCC3D\uAD6C, \uAD8C\uD55C\uAD00\uB9AC\uB4F1\uC744 \uD568 nestjs\uC758 resolver\uC640 \uC720\uC0AC )
2589
+
2590
+ - pencil.service.ts (\uC2E4\uC9C8\uC801\uC778 \uC11C\uBE44\uC2A4 \uCF54\uB4DC\uB97C \uC791\uC131\uD558\uB294 \uACF3. \uAC01\uC885 \uBE44\uC988\uB2C8\uC2A4 \uB85C\uC9C1\uC744 \uCC98\uB9AC\uD568.)
2591
+
2592
+ - pencil.store.ts (pencil field\uC5D0 \uB300\uD55C \uC0C1\uD0DC\uAD00\uB9AC \uC800\uC7A5\uC18C.)
2593
+
2594
+ - pencil.Zone.tsx (\uC544\uB798 Templete, Unit, Util, View, Util\uB4F1\uC744 \uC870\uD569\uD574\uC11C \uB2E4\uC74C \uB808\uBCA8 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC791\uC131\uD558\uB294 \uACF3 client component\uB85C \uC815\uC758\uB428. )
2595
+
2596
+ - pencil.Templete.tsx (\uC8FC\uB85C edit\uC5D0 \uC5F0\uAD00\uB41C \uCEF4\uD3EC\uB10C\uD2B8 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
2597
+
2598
+ - pencil.Unit.tsx (list \uCC98\uB7FC \uBCF5\uC218\uAC1C\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
2599
+
2600
+ - pencil.Util.tsx (Action \uBC84\uD2BC\uC744 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
2601
+
2602
+ - pencil.View.tsx (\uB2E8\uC77C view \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
2603
+
2604
+
2605
+
2606
+
2607
+ \uC5EC\uAE30\uC11C constant\uC5D0 \uC815\uC758 \uB418\uC5B4\uC788\uB294 schema\uB97C \uAE30\uBCF8\uC73C\uB85C \uD574\uC11C \uAC01 document, dictionary, signal, service, store\uB97C \uC0DD\uC131\uD574.
2608
+
2609
+
2610
+
2611
+ document, signal, service\uB294 \uBC31\uC5D4\uB4DC\uC640 \uC5F0\uAD00\uB418\uC5B4\uC788\uB294 \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2612
+
2613
+ \uC11C\uB85C\uAC04\uC758 \uAD00\uACC4\uB294 \uC8FC\uB85C signal\uC5D0\uC11C \uAC00\uC7A5 \uBA3C\uC800 \uC694\uCCAD\uC744 \uBC1B\uACE0 \uC774\uD6C4 \uB85C\uC9C1\uC758 \uBCF5\uC7A1\uB3C4\uC5D0 \uB530\uB77C\uC11C service\uB85C \uCC98\uB9AC\uD560 \uC9C0, docuemnt\uB85C \uCC98\uB9AC\uD560 \uC9C0\uB97C \uACB0\uC815\uD574.
2614
+
2615
+ signal - document
2616
+
2617
+ signal - service - document
2618
+
2619
+
2620
+
2621
+ store\uB294 \uD504\uB860\uD2B8\uC5D4\uB4DC\uC5D0\uC11C \uC0C1\uD0DC\uAD00\uB9AC\uB97C \uD560 \uB54C \uC0AC\uC6A9\uB3FC.
2622
+
2623
+ \uC6B0\uB9AC\uB294 signal\uC758 \uCF54\uB4DC\uB85C \uB098\uC628 \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uC774\uC6A9\uD574\uC11C store\uC5D0\uC11C \uD754\uD788 \uC0AC\uC6A9\uB420\uB9CC\uD55C \uD568\uC218\uB4E4\uC744 \uBBF8\uB9AC \uC815\uC758\uD558\uAC8C\uB054 \uB9CC\uB4E4\uC5C8\uC5B4.
2624
+
2625
+
2626
+
2627
+ \uC774\uB807\uAC8C 11\uAC1C\uC758 \uD30C\uC77C\uB85C \uAD6C\uBD84\uD574\uC11C \uC815\uC758\uAC00 \uB3FC.
2628
+
2629
+ \uC9C0\uAE08\uBD80\uD134 \uD55C \uD30C\uC77C\uB4E4\uB9C8\uB2E4 \uC0C1\uC138\uD55C \uC124\uBA85\uC744 \uD574\uC904\uAC8C.
2630
+
2631
+
2632
+
2633
+ model.constant.ts
2634
+
2635
+
2636
+
2637
+ constant\uB294 \uAE30\uBCF8 \uC2A4\uD0A4\uB9C8\uAC00 \uAD6C\uC131\uB418\uB294 \uACF3\uC774\uC57C. \uADF8\uB798\uC11C \uC774 \uACF3\uC5D0\uC11C DB \uC2A4\uD0A4\uB9C8, \uCFFC\uB9AC, \uC815\uB82C \uAD6C\uBB38\uC744 \uC815\uC758\uD574.
2638
+
2639
+ \uC8FC\uC758\uD574\uC57C\uD560 \uAC74 decorator\uC5D0\uC11C \uC815\uC758\uD558\uB294 \uD0C0\uC785\uACFC \uC544\uB798\uC5D0 \uC815\uC758\uD558\uB294 \uD0C0\uC785\uC774 \uC57D\uAC04 \uB2E4\uB97C \uC218 \uC788\uC5B4
2640
+
2641
+ \uC608\uB97C \uB4E4\uC5B4 decorator\uC5D0\uC11C\uB294 Int\uB85C \uC815\uC758\uD558\uACE0 constant\uC5D0\uC11C\uB294 number\uB85C \uC815\uC758\uD574\uC57C\uD574.
2642
+
2643
+ \uCD94\uAC00\uB85C createdAt\uACFC updatedAt, status\uB294 \uAE30\uBCF8\uC801\uC73C\uB85C \uC0DD\uC131\uB418\uB294 \uD544\uB4DC\uC774\uB2C8\uAE4C \uB530\uB85C \uC815\uC758\uD558\uC9C0 \uC54A\uC544\uB3C4 \uB3FC.
2644
+
2645
+ \uC774\uB294 decorator\uC5D0\uC11C\uB294 GraphQL\uC5D0\uC11C \uC0AC\uC6A9\uD560 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uACE0 constant\uC5D0\uC11C\uB294 \uC2E4\uC81C \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uAC70\uC9C0.
2646
+
2647
+
2648
+
2649
+ \`\`\`
2650
+
2651
+ import { enumOf, Int } from "@akanjs/base";
2652
+
2653
+ import { Field, Filter, Model, sortOf, via } from "@akanjs/constant";
2654
+
2655
+
2656
+
2657
+ export const \${dict.Model}Statuses = ["active"] as const;
2658
+
2659
+ export type \${dict.Model}Status = (typeof \${dict.Model}Statuses)[number];
2660
+
2661
+
2662
+
2663
+ //\uB370\uC774\uD130\uB97C \uB9CC\uB4E4 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uACF3
2664
+
2665
+ @Model.Input("\${dict.Model}Input")
2666
+
2667
+ export class \${dict.Model}Input {{
2668
+
2669
+ @Field.Prop(() => String)
2670
+
2671
+ field: string;
2672
+
2673
+
2674
+
2675
+ @Field.Prop(() => Int, {{ nullable: true }})
2676
+
2677
+ fieldInt: number | null;
2678
+
2679
+
2680
+
2681
+ @Field.Prop(() => Date, {{default: dayjs()}})
2682
+
2683
+ fieldInt: Dayjs;
2684
+
2685
+ }}
2686
+
2687
+
2688
+
2689
+ //\uB370\uC774\uD130\uAC00 \uB9CC\uB4E4\uC5B4\uC9C4 \uC774\uD6C4 \uC0DD\uC131\uB418\uAC70\uB098 \uC800\uC7A5\uC73C\uB85C \uCD94\uAC00\uD560 \uC218 \uC788\uB294 \uACF3
2690
+
2691
+ @Model.Object("\${dict.Model}Object")
2692
+
2693
+ export class \${dict.Model}Object extends via(\${dict.Model}Input) {
2694
+
2695
+ @Field.Prop(() => String, {{ enum: \${dict.Model}Statuses, default: "active" }})
2696
+
2697
+ status: \${dict.Model}Status;
2698
+
2699
+ }}
2700
+
2701
+
2702
+
2703
+ //\uB370\uC774\uD130\uB97C \uB9AC\uC2A4\uD2B8\uB85C \uBCF4\uC5EC\uC904 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130\uB9CC \uC81C\uACF5\uD558\uB294 \uACF3
2704
+
2705
+ @Model.Light("Light\${dict.Model}")
2706
+
2707
+ export class Light\${dict.Model} extends via(\${dict.Model}Object, [
2708
+
2709
+ "field",
2710
+
2711
+ "status",
2712
+
2713
+ ] as const) {}
2714
+
2715
+
2716
+
2717
+ //\uCD5C\uC885 \uB370\uC774\uD130\uC758 Full \uD0C0\uC785\uC774 \uC815\uC758\uB418\uB294 \uACF3
2718
+
2719
+ @Model.Full("\${dict.Model}")
2720
+
2721
+ export class \${dict.Model} extends via(\${dict.Model}Object, Light\${dict.Model}) {}
2722
+
2723
+
2724
+
2725
+ //\uB370\uC774\uD130\uC758 \uC778\uC0AC\uC774\uD2B8\uB97C \uCE21\uC815\uD558\uAE30 \uC704\uD574\uC11C \uD544\uC694\uD55C \uB370\uC774\uD130\uB97C \uC815\uC758\uD558\uB294 \uACF3
2726
+
2727
+ @Model.Insight("\${dict.Model}Insight")
2728
+
2729
+ export class \${dict.Model}Insight {{
2730
+
2731
+ @Field.Prop(() => Int, {{ default: 0, accumulate: {{ $sum: 1 }} }})
2732
+
2733
+ count: number;
2734
+
2735
+ }}
2736
+
2737
+
2738
+
2739
+ //\uB370\uC774\uD130\uC758 \uD1B5\uACC4\uB97C \uACC4\uC0B0\uD558\uB294 \uACF3
2740
+
2741
+ @Model.Summary("\${dict.Model}Summary")
2742
+
2743
+ export class \${dict.Model}Summary {{
2744
+
2745
+ @Field.Prop(() => Int, {{ min: 0, default: 0, query: {{ status: {{}} }} }})
2746
+
2747
+ total\${dict.Model}: number;
2748
+
2749
+ }}
2750
+
2751
+
2752
+
2753
+ @Model.Filter("\${dict.Model}Filter")
2754
+
2755
+ export class \${dict.Model}Filter extends sortOf(\${dict.Model}, {}) {}
2756
+
2757
+ \`\`\`
2758
+
2759
+
2760
+
2761
+
2762
+ model.dictonary.ts
2763
+
2764
+ \`\`\`
2765
+
2766
+ import {
2767
+
2768
+ baseTrans,
2769
+
2770
+ getBaseSignalTrans,
2771
+
2772
+ ModelDictionary,
2773
+
2774
+ SignalDictionary,
2775
+
2776
+ SummaryDictionary,
2777
+
2778
+ } from "@akanjs/dictionary";
2779
+
2780
+
2781
+
2782
+ import type { \${dict.Model}, \${dict.Model}Filter, \${dict.Model}Insight, \${dict.Model}Summary } from "./\${dict.model}.constant";
2783
+
2784
+ import type { \${dict.Model}Signal } from "./\${dict.model}.signal";
2785
+
2786
+
2787
+
2788
+ const modelDictionary = {{
2789
+
2790
+ ...baseTrans,
2791
+
2792
+ modelName: ["\${dict.Model}", "\${dict.Model}"],
2793
+
2794
+ modelDesc: [
2795
+
2796
+ "\${dict.Model} description",
2797
+
2798
+ "\${dict.Model} \uC124\uBA85",
2799
+
2800
+ ],
2801
+
2802
+
2803
+
2804
+ // * ==================== Model ==================== * //
2805
+
2806
+ field: ["Field", "\uD544\uB4DC"],
2807
+
2808
+ "desc-field": ["Field", "\uD544\uB4DC"],
2809
+
2810
+ // * ==================== Model ==================== * //
2811
+
2812
+
2813
+
2814
+ // * ==================== Insight ==================== * //
2815
+
2816
+ count: ["Count", "\uAC1C\uC218"],
2817
+
2818
+ "desc-count": ["\${dict.Model} count in current query settting", "\uD604\uC7AC \uCFFC\uB9AC \uC124\uC815\uC5D0 \uB9DE\uB294 \${dict.Model} \uC218"],
2819
+
2820
+ // * ==================== Insight ==================== * //
2821
+
2822
+
2823
+
2824
+ // * ==================== Filter ==================== * //
2825
+
2826
+ // * ==================== Filter ==================== * //
2827
+
2828
+
2829
+
2830
+ // * ==================== Etc ==================== * //
2831
+
2832
+ "enum-status-active": ["Active", "\uD65C\uC131"],
2833
+
2834
+ "enumdesc-status-active": ["Active status", "\uD65C\uC131 \uC0C1\uD0DC"],
2835
+
2836
+ // * ==================== Etc ==================== * //
2837
+
2838
+ }} satisfies ModelDictionary<\${dict.Model}, \${dict.Model}Insight, typeof \${dict.Model}Sort>;
2839
+
2840
+
2841
+
2842
+ export const \${dict.Model}SummaryDictionary = {{
2843
+
2844
+ // * ==================== Summary ==================== * //
2845
+
2846
+ total\${dict.Model}: ["Total \${dict.Model}", "\uCD1D \${dict.Model} \uC218"],
2847
+
2848
+ "desc-total\${dict.Model}": ["Total \${dict.Model} count in the database", "\uB370\uC774\uD130\uBCA0\uC774\uC2A4\uC5D0 \uC800\uC7A5\uB41C \uCD1D \${dict.Model} \uC218"],
2849
+
2850
+ // * ==================== Summary ==================== * //
2851
+
2852
+ }} satisfies SummaryDictionary<\${dict.Model}Summary>;
2853
+
2854
+
2855
+
2856
+ const signalDictionary = {{
2857
+
2858
+ ...getBaseSignalTrans("\${dict.Model}" as const),
2859
+
2860
+ // * ==================== Endpoint ==================== * //
2861
+
2862
+ "api-\${dict.Model}ListInPublic": ["\${dict.Model} List In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uB9AC\uC2A4\uD2B8"],
2863
+
2864
+ "apidesc-\${dict.Model}ListInPublic": ["Get a list of public \${dict.Model}", "\uACF5\uAC1C\uB41C \${dict.Model}\uC758 \uB9AC\uC2A4\uD2B8\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4"],
2865
+
2866
+ "arg-\${dict.Model}ListInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2867
+
2868
+ "argdesc-\${dict.Model}ListInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2869
+
2870
+ "arg-\${dict.Model}ListInPublic-skip": ["Skip", "\uAC74\uB108\uB6F0\uAE30"],
2871
+
2872
+ "argdesc-\${dict.Model}ListInPublic-skip": ["Number of items to skip", "\uAC74\uB108\uB6F8 \uC544\uC774\uD15C \uC218"],
2873
+
2874
+ "arg-\${dict.Model}ListInPublic-limit": ["Limit", "\uC81C\uD55C"],
2875
+
2876
+ "argdesc-\${dict.Model}ListInPublic-limit": ["Maximum number of items to return", "\uBC18\uD658\uD560 \uCD5C\uB300 \uC544\uC774\uD15C \uC218"],
2877
+
2878
+ "arg-\${dict.Model}ListInPublic-sort": ["Sort", "\uC815\uB82C"],
2879
+
2880
+ "argdesc-\${dict.Model}ListInPublic-sort": ["Sort order of the items", "\uC544\uC774\uD15C\uC758 \uC815\uB82C \uC21C\uC11C"],
2881
+
2882
+
2883
+
2884
+ "api-\${dict.Model}InsightInPublic": ["\${dict.Model} Insight In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uC778\uC0AC\uC774\uD2B8"],
2885
+
2886
+ "apidesc-\${dict.Model}InsightInPublic": [
2887
+
2888
+ "Get insight data for public \${dict.Model}",
2889
+
2890
+ "\uACF5\uAC1C\uB41C \${dict.Model}\uC5D0 \uB300\uD55C \uC778\uC0AC\uC774\uD2B8 \uB370\uC774\uD130\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4",
2891
+
2892
+ ],
2893
+
2894
+ "arg-\${dict.Model}InsightInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2895
+
2896
+ "argdesc-\${dict.Model}InsightInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2897
+
2898
+ // * ==================== Endpoint ==================== * //
2899
+
2900
+ }} satisfies SignalDictionary<\${dict.Model}Signal, \${dict.Model}>;
2901
+
2902
+ \`\`\`
2903
+
2904
+ export const \${dict.model}Dictionary = {{ ...modelDictionary, ...signalDictionary }};
2905
+
2906
+
2907
+
2908
+
2909
+
2910
+ model.document.ts
2911
+
2912
+ \`\`\`
2913
+
2914
+ import { beyond, by, Database, into, type SchemaOf } from "@akanjs/document";
2915
+
2916
+
2917
+
2918
+ import { cnst } from "../cnst";
2919
+
2920
+ @Database.Input(() => cnst.\${dict.Model}Input)
2921
+
2922
+ export class \${dict.Model}Input extends by(cnst.\${dict.Model}Input) {}
2923
+
2924
+
2925
+
2926
+ @Database.Document(() => cnst.\${dict.Model})
2927
+
2928
+ export class \${dict.Model} extends by(cnst.\${dict.Model}) {}
2929
+
2930
+
2931
+
2932
+ @Database.Model(() => cnst.\${dict.Model})
2933
+
2934
+ export class \${dict.Model}Model extends into(\${dict.Model}, cnst.\${dict.Model}Cnst) {
2935
+
2936
+ async getSummary(): Promise<cnst.\${dict.Model}Summary> {
2937
+
2938
+ return {
2939
+
2940
+ ...(await this.getDefaultSummary()),
2941
+
2942
+ };
2943
+
2944
+ }
2945
+
2946
+ }
2947
+
2948
+
2949
+
2950
+ @Database.Middleware(() => cnst.\${dict.Model})
2951
+
2952
+ export class \${dict.Model}Middleware extends beyond(\${dict.Model}Model, \${dict.Model}) {
2953
+
2954
+ onSchema(schema: SchemaOf<\${dict.Model}Model, \${dict.Model}>) {
2955
+
2956
+ // schema.index({ status: 1 })
2957
+
2958
+ }
2959
+
2960
+ }
2961
+
2962
+ \`\`\`
2963
+
2964
+
2965
+
2966
+
2967
+ model.signal.ts
2968
+
2969
+ \`\`\`
2970
+
2971
+ import { Int } from "@akanjs/base";
2972
+
2973
+ import { SortOf } from "@akanjs/constant";
2974
+
2975
+ import { Arg, DbSignal, Mutation, Query, resolve, Signal } from "@akanjs/signal";
2976
+
2977
+
2978
+
2979
+ import { cnst, Srvs } from "../cnst";
2980
+
2981
+
2982
+
2983
+ @Signal(() => cnst.\${dict.Model})
2984
+
2985
+ export class \${dict.Model}Signal extends DbSignal(cnst.\${dict.model}Cnst, Srvs, {
2986
+
2987
+ guards: { get: Query.Public, cru: Mutation.Public },
2988
+
2989
+ }) {
2990
+
2991
+ // * /////////////////////////////////////
2992
+
2993
+ // * Public Slice
2994
+
2995
+ @Query.Public(() => [cnst.\${dict.Model}])
2996
+
2997
+ async \${dict.model}ListInPublic(
2998
+
2999
+ @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null,
3000
+
3001
+ @Arg.Query("skip", () => Int, { nullable: true }) skip: number | null,
3002
+
3003
+ @Arg.Query("limit", () => Int, { nullable: true }) limit: number | null,
3004
+
3005
+ @Arg.Query("sort", () => String, { nullable: true }) sort: SortOf<cnst.\${dict.Model}Filter> | null
3006
+
3007
+ ) {
3008
+
3009
+ const \${dict.models} = await this.\${dict.model}Service.listByStatuses(statuses, { skip, limit, sort });
3010
+
3011
+ return resolve<cnst.\${dict.Model}[]>(\${dict.models});
3012
+
3013
+ }
3014
+
3015
+ @Query.Public(() => cnst.\${dict.Model}Insight)
3016
+
3017
+ async \${dict.model}InsightInPublic(
3018
+
3019
+ @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null
3020
+
3021
+ ) {
3022
+
3023
+ const \${dict.model}Insight = await this.\${dict.model}Service.insightByStatuses(statuses);
3024
+
3025
+ return resolve<cnst.\${dict.Model}Insight>(\${dict.model}Insight);
3026
+
3027
+ }
3028
+
3029
+ // * Public Slice
3030
+
3031
+ // * /////////////////////////////////////
3032
+
3033
+ }
3034
+
3035
+ \`\`\`
3036
+
3037
+
3038
+
3039
+
3040
+ model.service.ts
3041
+
3042
+ \`\`\`
3043
+
3044
+ import { DbService, Service } from "@akanjs/service";
3045
+
3046
+
3047
+
3048
+ import { cnst } from "../cnst";
3049
+
3050
+ import * as db from "../db";
3051
+
3052
+
3053
+
3054
+ @Service("\${dict.Model}Service")
3055
+
3056
+ export class \${dict.Model}Service extends DbService(db.\${dict.Model}Db) {
3057
+
3058
+ async summarize(): Promise<cnst.\${dict.Model}Summary> {
3059
+
3060
+ return {
3061
+
3062
+ ...(await this.\${dict.Model}Model.getSummary()),
3063
+
3064
+ };
3065
+
3066
+ }
3067
+
3068
+ }
3069
+
3070
+ \`\`\`
3071
+
3072
+
3073
+
3074
+
3075
+ model.store.ts
3076
+
3077
+ \`\`\`
3078
+
3079
+ import { stateOf, Store } from "@akanjs/store";
3080
+
3081
+
3082
+
3083
+ import { cnst } from "../cnst";
3084
+
3085
+ import { fetch } from "../fetch";
3086
+
3087
+
3088
+
3089
+ @Store(() => cnst.\${dict.Model})
3090
+
3091
+ export class \${dict.Model}Store extends stateOf(fetch.\${dict.model}Gql, {
3092
+
3093
+ // state
3094
+
3095
+ }) {
3096
+
3097
+ // action
3098
+
3099
+ }
3100
+
3101
+ \`\`\`
3102
+
3103
+
3104
+
3105
+
3106
+ model.Zone.tsx
3107
+
3108
+ \`\`\`
3109
+
3110
+ "use client";
3111
+
3112
+ import { Data, Load } from "@shared/ui";
3113
+
3114
+ import { ModelsProps } from "@akanjs/client";
3115
+
3116
+ import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
3117
+
3118
+ import { ClientInit, ClientView, DefaultOf } from "@akanjs/signal";
3119
+
3120
+
3121
+
3122
+ export const Admin = ({ sliceName = "\${dict.model}", init, query }: ModelsProps<cnst.\${dict.Model}>>) => {
3123
+
3124
+ return (
3125
+
3126
+ <Data.ListContainer
3127
+
3128
+ init={init}
3129
+
3130
+ query={query}
3131
+
3132
+ sliceName={sliceName}
3133
+
3134
+ renderItem={\${dict.Model}.Unit.Card}
3135
+
3136
+ renderDashboard={\${dict.Model}.Util.Stat}
3137
+
3138
+ renderInsight={\${dict.Model}.Util.Insight}
3139
+
3140
+ renderTemplate={\${dict.Model}.Template.General}
3141
+
3142
+ renderTitle={(\${dict.model}: DefaultOf<cnst.\${dict.Model}>>) => \`\${dict.Model} - \${\${dict.model}.id ? \${dict.model}.id : "New"}\`}
3143
+
3144
+ renderView={(\${dict.model}: cnst.\${dict.Model}>) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />}
3145
+
3146
+ columns={[
3147
+
3148
+ "id",
3149
+
3150
+ "status",
3151
+
3152
+ "createdAt",
3153
+
3154
+ "updatedAt",
3155
+
3156
+ ]}
3157
+
3158
+ actions={(\${dict.model}: cnst.Light\${dict.Model}, idx) => ["remove", "edit", "view"]}
3159
+
3160
+ />
3161
+
3162
+ );
3163
+
3164
+ };
3165
+
3166
+
3167
+
3168
+ interface CardProps {
3169
+
3170
+ className?: string;
3171
+
3172
+ init: ClientInit<"\${dict.model}", cnst.Light\${dict.Model}>;
3173
+
3174
+ }
3175
+
3176
+ export const Card = ({ className, init }: CardProps) => {
3177
+
3178
+ return (
3179
+
3180
+ <Load.Units
3181
+
3182
+ className={className}
3183
+
3184
+ init={init}
3185
+
3186
+ renderItem={(\${dict.model}: cnst.Light\${dict.Model}) => (
3187
+
3188
+ <\${dict.Model}.Unit.Card key={\${dict.model}.id} href={\`/\${dict.model}/\${\${dict.model}.id}\`} \${dict.model}={\${dict.model}} />
3189
+
3190
+ )}
3191
+
3192
+ />
3193
+
3194
+ );
3195
+
3196
+ };
3197
+
3198
+
3199
+
3200
+ interface ViewProps {
3201
+
3202
+ className?: string;
3203
+
3204
+ view: ClientView<"\${dict.model}", cnst.\${dict.Model}>;
3205
+
3206
+ }
3207
+
3208
+ export const View = ({ view }: ViewProps) => {
3209
+
3210
+ return <Load.View view={view} renderView={(\${dict.model}) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />} />;
3211
+
3212
+ };
3213
+
3214
+ \`\`\`
3215
+
3216
+
3217
+
3218
+ model.Templete.tsx
3219
+
3220
+ \`\`\`
3221
+
3222
+ "use client";
3223
+
3224
+ import { cnst, st, usePage } from "@\${dict.appName}/client";
3225
+
3226
+ import { Field } from "@shared/ui";
3227
+
3228
+ import { Layout } from "@util/ui";
3229
+
3230
+
3231
+
3232
+ interface \${dict.Model}EditProps {
3233
+
3234
+ \${dict.model}Id?: string | null;
3235
+
3236
+ }
3237
+
3238
+
3239
+
3240
+ export const General = ({ \${dict.model}Id = undefined }: \${dict.Model}EditProps) => {
3241
+
3242
+ const \${dict.model}Form = st.use.\${dict.model}Form();
3243
+
3244
+ const { l } = usePage();
3245
+
3246
+ return (
3247
+
3248
+ <Layout.Template>
3249
+
3250
+ <Field.Text
3251
+
3252
+ label={l.field("\${dict.model}", "id")}
3253
+
3254
+ desc={l.desc("\${dict.model}", "id")}
3255
+
3256
+ value={\${dict.model}Form.id}
3257
+
3258
+ onChange={st.do.setIdOn\${dict.Model}}
3259
+
3260
+ />
3261
+
3262
+ </Layout.Template>
3263
+
3264
+ );
3265
+
3266
+ };
3267
+
3268
+ \`\`\`
3269
+
3270
+
3271
+
3272
+
3273
+ model.Unit.tsx
3274
+
3275
+ \`\`\`
3276
+
3277
+ import { ModelProps } from "@akanjs/client";
3278
+
3279
+ import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
3280
+
3281
+ import { Link } from "@util/ui";
3282
+
3283
+
3284
+
3285
+ export const Card = ({ \${dict.model}, href }: ModelProps<"\${dict.model}", cnst.Light\${dict.Model}>>) => {
3286
+
3287
+ return (
3288
+
3289
+ <Link href={href} className="animate-fadeIn w-full h-36 flex rounded-lg shadow-sm hover:shadow-lg duration-300">
3290
+
3291
+ <div>{\${dict.model}.id}</div>
3292
+
3293
+ </Link>
3294
+
3295
+ );
3296
+
3297
+ };
3298
+
3299
+ \`\`\`
3300
+
3301
+
3302
+
3303
+
3304
+ model.Util.tsx
3305
+
3306
+ \`\`\`
3307
+
3308
+ "use client";
3309
+
3310
+ import { ModelDashboardProps, ModelInsightProps } from "@akanjs/client";
3311
+
3312
+ import { getQueryMap } from "@akanjs/constant";
3313
+
3314
+ import { cnst } from "@\${dict.appName}/client";
3315
+
3316
+ import { Data } from "@shared/ui";
3317
+
3318
+
3319
+
3320
+ export const Stat = ({
3321
+
3322
+ className,
3323
+
3324
+ summary,
3325
+
3326
+ sliceName = "\${dict.model}",
3327
+
3328
+ queryMap = getQueryMap(cnst.\${dict.Model}Summary),
3329
+
3330
+ hidePresents,
3331
+
3332
+ }: ModelDashboardProps<cnst.Summary>) => {
3333
+
3334
+ return (
3335
+
3336
+ <Data.Dashboard
3337
+
3338
+ className={className}
3339
+
3340
+ summary={summary}
3341
+
3342
+ sliceName={sliceName}
3343
+
3344
+ queryMap={queryMap}
3345
+
3346
+ columns={["total\${dict.Model}"]}
3347
+
3348
+ hidePresents={hidePresents}
3349
+
3350
+ />
3351
+
3352
+ );
3353
+
3354
+ };
3355
+
3356
+
3357
+
3358
+ export const Insight = ({
3359
+
3360
+ className,
3361
+
3362
+ insight,
3363
+
3364
+ sliceName = "\${dict.model}",
3365
+
3366
+ }: ModelInsightProps<cnst.\${dict.Model}Insight>) => {
3367
+
3368
+ return (
3369
+
3370
+ <Data.Insight
3371
+
3372
+ className={className}
3373
+
3374
+ insight={insight}
3375
+
3376
+ sliceName={sliceName}
3377
+
3378
+ columns={["count"]}
3379
+
3380
+ />
3381
+
3382
+ );
3383
+
3384
+ };
3385
+
3386
+ \`\`\`
3387
+
3388
+
3389
+
3390
+
3391
+ model.View.tsx
3392
+
3393
+ \`\`\`
3394
+
3395
+ import { clsx } from "@akanjs/client";
3396
+
3397
+ import { cnst } from "@\${dict.appName}/client";
3398
+
3399
+ import { Image } from "@util/ui";
3400
+
3401
+
3402
+
3403
+ interface \${dict.Model}ViewProps {
3404
+
3405
+ className?: string;
3406
+
3407
+ \${dict.model}: cnst.\${dict.Model};
3408
+
3409
+ self?: { id?: string } | null;
3410
+
3411
+ }
3412
+
3413
+
3414
+
3415
+ export const General = ({ className, \${dict.model}, self }: \${dict.Model}ViewProps) => {
3416
+
3417
+ return (
3418
+
3419
+ <div className={clsx(className, "animate-fadeIn w-full")}>
3420
+
3421
+ <div>{\${dict.model}.id}</div>
3422
+
3423
+ </div>
3424
+
3425
+ );
3426
+
3427
+ };
3428
+
3429
+ \`\`\`
3430
+
3431
+ \uC774\uB7F0\uC2DD\uC73C\uB85C \uC6B0\uB9AC\uAC00 \uC9C1\uC811 \uB9CC\uB4E0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uAE30\uBC18\uD574\uC11C db\uC640 \uC11C\uBE44\uC2A4 \uC2A4\uD1A0\uC5B4\uAE4C\uC9C0 \uBAA8\uB450 \uC5F0\uB3D9\uD574\uC11C \uD558\uB098\uC758 \uBAA8\uB378\uC5D0 \uB9DE\uAC8C\uB054 \uBAA8\uB4C8\uC744 \uD55C \uD3F4\uB354\uC5D0\uC11C \uC791\uC5C5\uD560 \uC218 \uC788\uAC8C\uB054 \uAD6C\uC870\uB97C \uB9CC\uB4E4\uC5C8\uC5B4.
3432
+
3433
+
3434
+
3435
+ \uC77C\uB2E8 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC740 \uC774 \uC815\uB3C4\uB85C \uD558\uACE0 \uC774 \uC815\uBCF4\uB4E4\uC744 \uAE30\uBC18\uC73C\uB85C \uB0B4\uAC00 \uC6D0\uD558\uB294 \uC694\uAD6C\uB97C \uB4E4\uC5B4\uC918.
3436
+
3437
+ `;
2929
3438
  var moduleDesription = `
2930
3439
 
2931
3440
  The project follows a modular architecture with clear separation of concerns. Each module in lib/<model>/ represents a domain
@@ -2934,23 +3443,29 @@ entity with a standardized file structure that promotes consistency and maintain
2934
3443
  ## Core Components
2935
3444
 
2936
3445
  ### <Model>.View.tsx
2937
- Presentation-only components that render data without managing state.
2938
- It works as a server component, They accept model data as props and display it according to specific layouts.
2939
- These components focus purely on how data looks to the user.
2940
- only use the full model.
2941
- This component is only viewing the component. So don't use click event or other interaction events.
2942
- If you need interaction, possible to wrapping the component with the <Model>.Zone.tsx component.
2943
- But useable the Link component for navigation.
2944
- Components created in Model.View.tsx should primarily be made to show the entire detailed data of the model rather than showing only partial data of the model.
2945
-
3446
+ - Core Purpose: Presentation-only components that render data
3447
+ - Execution Context: Works as a server component
3448
+ - State Management: Does not manage internal state
3449
+ - Data Handling: Accepts model data as props and displays it according to specific layouts
3450
+ - Primary Focus: Focuses purely on how data looks to the user
3451
+ - Model Usage: Only uses the full model
3452
+ - Interaction Restrictions: No click events or other interaction events
3453
+ - Interaction Extension: If interaction is needed, wrap with <Model>.Zone.tsx component
3454
+ - Navigation: Link component can be used for navigation purposes
3455
+ - Full Model Rendering: Implements complete rendering of the entire model data structure, ensuring all properties and relationships within the model are displayed rather than selecting only partial attributes
2946
3456
 
2947
3457
  ### <Model>.Template.tsx
2948
3458
  Reusable layout patterns with integrated state management. It works as a client component, These components provide consistent UI patterns and handle data
2949
3459
  binding, often using store hooks to access application state.
2950
3460
 
2951
3461
  ### <Model>.Unit.tsx
2952
- Small, self-contained UI components representing individual model instances. It works as a server component, They're designed for rendering single items in
2953
- lists or grids, displaying model data in compact formats. only use the light model.
3462
+ - Single Component Export: Each file exports one Card component for displaying model data
3463
+ - Server-Side Rendered: React Server Components without "use client" directive
3464
+ - Type-Safe Props: Uses ModelProps<"modelName", cnst.LightModel> interface
3465
+ - Optional Navigation: useable Link component for navigation in util/ui
3466
+ - Tailwind Styling: Universal use of Tailwind CSS with DaisyUI classes
3467
+ - Model Data Display: Direct access to typed model properties and methods
3468
+
2954
3469
 
2955
3470
  ### <Model>.Zone.tsx
2956
3471
  Top-level container components that orchestrate other components. It works as a client component, They compose views, templates, and units into complete UI
@@ -2994,6 +3509,7 @@ var utilUiDescription = `
2994
3509
  The libs/util/ui directory contains a comprehensive React component library designed for modern web applications.
2995
3510
  This framework provides a complete set of production-ready, reusable UI components with consistent styling, type safety, and advanced functionality.
2996
3511
 
3512
+ [Strict caution]
2997
3513
  - Every component must be used exactly as described in the documentation.
2998
3514
  - Do not add any additional props to the components.
2999
3515
  - Must use the written props exactly.
@@ -3005,7 +3521,7 @@ var utilUiDescription = `
3005
3521
 
3006
3522
  Core Technologies:
3007
3523
  - Built on React 18+ with TypeScript for strict type safety
3008
- - Styled with Tailwind CSS and DaisyUI for consistent design system
3524
+ - Styled based on Tailwind CSS and DaisyUI base for a consistent design system.
3009
3525
  - Implements modern React patterns including hooks, context providers, and portals
3010
3526
  - Full internationalization (i18n) support for multilingual applications
3011
3527
  - Responsive-first design with mobile optimization
@@ -3829,13 +4345,13 @@ var requestView = ({
3829
4345
  1. Akan.js \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uAC1C\uC694
3830
4346
  ${frameworkAbstract}
3831
4347
 
3832
- 2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uAC1C\uC694
4348
+ 2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uC124\uBA85
3833
4349
  ${moduleDesription}
3834
4350
 
3835
- 3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uAC1C\uC694
4351
+ 3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uC124\uBA85
3836
4352
  ${eslintDescription}
3837
4353
 
3838
- 4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uAC1C\uC694
4354
+ 4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uC124\uBA85
3839
4355
  ${utilUiDescription}
3840
4356
 
3841
4357
 
@@ -3856,40 +4372,142 @@ ${properties.map(
3856
4372
  ).join("\n\n")}
3857
4373
 
3858
4374
 
3859
- 7. \uC608\uC2DC \uD30C\uC77C\uB4E4
3860
- ${exampleFiles.map(
4375
+ 7. \uC608\uC2DC \uD30C\uC77C\uB4E4
4376
+ ${exampleFiles.map(
3861
4377
  (example) => `
3862
- Example filename: ${example.filepath}
3863
- \`\`\`
3864
- ${example.content}
3865
- \`\`\`
3866
- `
4378
+ Example filename: ${example.filepath}
4379
+ \`\`\`
4380
+ ${example.content}
4381
+ \`\`\`
4382
+ `
3867
4383
  ).join("\n\n")}
3868
4384
 
3869
4385
 
3870
4386
 
4387
+
4388
+
4389
+
4390
+ \uC5ED\uD560\uBD80\uC5EC
4391
+ - Akan.js \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C \uAE30\uBC18 Typescript \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C
4392
+
4393
+ \uCF54\uB529 \uADDC\uCE59
4394
+ - \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4395
+ - \uC544\uC774\uCF58: react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4396
+ - CSS: DaisyUI (btn, input, badge \uAC19\uC740 \uAE30\uBCF8 \uC694\uC18C\uB9CC \uC0AC\uC6A9 \uAC00\uB2A5, card/hero \uAC19\uC740 \uBCF5\uC7A1\uD55C \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uBD88\uAC00)
4397
+ - \uC870\uAC74\uBD80 \uD074\uB798\uC2A4: clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4398
+ \uCF54\uB4DC \uC2A4\uD0C0\uC77C
4399
+ - \uC0C9\uC0C1: \uD558\uB4DC\uCF54\uB529(bg-red) \uB300\uC2E0 \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary) \uC0AC\uC6A9
4400
+ - \uC870\uAC74\uBD80 \uB80C\uB354\uB9C1: field && <div>... \uB300\uC2E0 field ? <div>... : null \uC0AC\uC6A9
4401
+ - \uBAA8\uB378 \uC811\uADFC: \uAD6C\uC870\uBD84\uD574\uD560\uB2F9 \uB300\uC2E0 ${modelName}.field \uD615\uC2DD\uC73C\uB85C \uC811\uADFC
4402
+ - \uD0C0\uC785 \uC548\uC804: ${modelName}.constant.ts\uC758 \uC2A4\uD0A4\uB9C8 \uCC38\uC870\uD558\uC5EC \uC5D0\uB7EC \uBC29\uC9C0
4403
+ \uD544\uB4DC \uC811\uADFC \uC804: \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8 \uC791\uC131 \uBC0F \uAC80\uD1A0 \uD544\uC218
4404
+
4405
+ \uC5C4\uACA9\uD55C \uC8FC\uC758\uC0AC\uD56D
4406
+ - UI \uD0B7\uC740 \uBB38\uC11C\uC5D0 \uBA85\uC2DC\uB41C \uCEF4\uD3EC\uB10C\uD2B8\uB9CC \uC0AC\uC6A9
4407
+ - \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC804 \uBB38\uC11C \uD655\uC778 \uBC0F props \uC815\uD655\uD788 \uAC80\uC99D
4408
+ - \uBA85\uC2DC\uB41C \uB8F0 \uC678 \uC784\uC758 \uCD94\uC0C1\uD654 \uAE08\uC9C0
4409
+
4410
+ \uC694\uCCAD\uC0AC\uD56D
4411
+ ${ModelName}.View.tsx \uCF54\uB4DC \uC791\uC131
4412
+ \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984\uC740 \uBAA8\uB378 \uC774\uB984\uC740 \uC81C\uC678\uD55C \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uB514\uC790\uC778\uC5D0 \uCD08\uC810\uC744 \uB450\uACE0 \uC791\uC131
4413
+ \uC77C\uBC18\uC801\uC73C\uB85C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C General \uCEF4\uD3EC\uB10C\uD2B8 1\uAC1C\uB97C \uC81C\uC678\uD55C \uB514\uC790\uC778 \uCEF4\uD3EC\uB10C\uD2B8 4\uAC1C \uAC1C\uBC1C
4414
+ \uCD94\uC0C1\uD654 \uD574\uC57C\uD558\uB294 \uACBD\uC6B0\uAC00 \uC788\uC744 \uACBD\uC6B0\uC5D4 \uBB38\uC11C\uB97C \uB2E4\uC2DC \uCC38\uACE0\uD558\uACE0 \uC124\uBA85\uB41C \uB0B4\uC5D0\uC11C \uD574\uACB0\uD574\uC57C\uD568.
4415
+
4416
+
3871
4417
  Application name: ${sysName}
3872
4418
  Model name: ${modelName}
4419
+
3873
4420
  Target filename: ${ModelName}.View.tsx
4421
+ \`\`\`
4422
+
4423
+ \`\`\`
3874
4424
 
4425
+
4426
+ `;
4427
+ var requestUnit = ({
4428
+ sysName,
4429
+ modelName,
4430
+ ModelName,
4431
+ constant,
4432
+ properties,
4433
+ exampleFiles
4434
+ }) => `
4435
+
3875
4436
 
3876
- \uB108\uB294 Akan.js\uB77C\uB294 \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C\uB85C Typescript \uAE30\uBC18 \uD504\uB85C\uADF8\uB7A8\uC744 \uC791\uC131\uD558\uB294 \uC2DC\uB2C8\uC5B4 \uAC1C\uBC1C\uC790\uC57C.
3877
- \uADF8 \uC911\uC5D0\uC11C\uB3C4 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790.
3878
- \uB9CC\uC57D\uC5D0 \uC544\uC774\uCF58 \uC0AC\uC6A9\uC774 \uD544\uC694\uD558\uBA74 react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC\uC5D0\uC11C \uC801\uD569\uD55C \uC544\uC774\uCF58\uC744 \uCC3E\uC544\uC11C \uC0AC\uC6A9\uD574\uC918.
3879
- \uB610, \uC0C9\uC0C1\uC744 \uC0AC\uC6A9\uD558\uB824\uACE0 \uD558\uBA74 \uD558\uB4DC\uCF54\uB529\uB41C \uC0C9\uC0C1(bg-red)\uC774 \uC544\uB2CC \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary)\uC744 \uC0AC\uC6A9\uD574\uC11C \uC791\uC131\uD574\uC918.
3880
- \uADF8\uB9AC\uACE0 optional\uD55C \uD544\uB4DC\uB294 field && <div>... \uAC00 \uC544\uB2CC, field ? <div>... : null \uD615\uD0DC\uB85C \uC791\uC131\uD574\uC918.
3881
- css\uB77C\uC774\uBE0C\uB7EC\uB9AC\uB294 DaisyUI\uB97C \uAE30\uBC18\uC73C\uB85C \uC791\uC131\uD574\uC8FC\uB294\uB370, btn, input, badge\uC640 \uAC19\uC740 \uB2E8\uC21C\uD55C \uAE30\uBCF8 css\uB294 \uC0AC\uC6A9\uD574\uB3C4 \uAD1C\uCC2E\uC544. \uADF8\uB7F0\uB370 card, hero\uAC19\uC774 \uBCF5\uC7A1\uD55C \uCEF4\uD3EC\uB10C\uD2B8\uB294 \uC0AC\uC6A9\uD558\uBA74 \uC548\uB3FC.
3882
- \uBAA8\uB378\uC5D0 \uB300\uD574\uC11C object destructuring\uC740 \uD558\uC9C0\uB9D0\uACE0 ${modelName}.field \uD615\uD0DC\uB85C \uC811\uADFC\uD558\uACE0, \uD0C0\uC785\uC5D0 \uC5D0\uB7EC\uB294 \uC808\uB300\uB85C \uBC1C\uC0DD\uD558\uC9C0 \uC54A\uB3C4\uB85D ${modelName}.constant.ts\uC5D0 \uC791\uC131\uB418\uC788\uB294 \uC2A4\uD0A4\uB9C8\uB97C \uBCF4\uACE0 \uC791\uC131\uD574.
3883
- \uC870\uAC74\uBD80 className\uC774 \uD544\uC694\uD55C \uACBD\uC6B0\uC5D0\uB294 clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC\uB97C \uC0AC\uC6A9\uD574\uC57C\uB3FC.
3884
- \uBAA8\uB4E0 \uBAA8\uB378 \uD544\uB4DC\uC5D0 \uC811\uADFC\uD558\uAE30 \uC804\uC5D0, \uAC01 \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8\uB97C \uC791\uC131\uD558\uACE0 \uAC80\uD1A0\uD574. \uD2B9\uD788 \uC911\uCCA9\uB41C \uAC1D\uCCB4( ex) XXX.XXX.XXX )\uC5D0 \uC811\uADFC\uD560 \uB54C\uB294 \uB354\uC6B1 \uC8FC\uC758\uD574.
3885
- \uB610\uD55C ${modelName}\uACFC \uC885\uC18D\uC131\uC774 \uC788\uB294 \uB2E4\uB978 \uBAA8\uB378\uB4E4\uC758 \uD0C0\uC785\uB4E4\uB3C4 \uBAA8\uB450 \uC704\uBC30\uD558\uC9C0\uB9D0\uACE0 \uC798 \uD30C\uC545\uD558\uACE0 \uC791\uC131\uD574.
3886
- \uC704\uC5D0\uC11C \uC124\uBA85\uD55C \uBAA8\uB4E0 \uB8F0\uACFC \uC124\uBA85, \uD0C0\uC785\uC744 \uC808\uB300\uB85C \uC704\uBC30\uD558\uC9C0\uB9D0\uACE0 \uC798 \uD30C\uC545\uD558\uACE0 \uC791\uC131\uD574.(\uAC01 \uB370\uC774\uD130\uC758 \uD0C0\uC785, \uCEF4\uD3EC\uB10C\uD2B8\uC758 props\uB4F1...)
3887
- \uC124\uBA85\uD55C \uB0B4\uC6A9 \uC774\uC678\uC5D0 \uB0B4\uC6A9\uC73C\uB85C \uB2C8\uAC00 \uCD94\uC0C1\uD574\uC11C \uC4F0\uC9C0\uB9D0\uACE0 \uC704\uC5D0 \uBA85\uC2DC\uB418\uC788\uB294 \uB8F0 \uC548\uC5D0\uC11C\uB9CC \uC791\uC131\uD574. \uC788\uC9C0\uB3C4 \uC54A\uC740 \uAC83\uB4E4 \uB9CC\uB4E4\uC5B4\uC11C \uCD94\uC0C1\uD654 \uC2DC\uCF1C\uC11C \uC790\uAFB8 \uC4F0\uB294 \uC77C\uC740 \uC808\uB300\uB85C \uD558\uC9C0\uB9C8.
3888
- \uD2B9\uD788\uB098 \uBC29\uAE08 \uB9D0\uD55C \uC774 \uC704 \uB450 \uBB38\uC7A5\uC740 \uC808\uB300\uC801\uC73C\uB85C \uC9C0\uCF1C\uC57C \uD560 \uB8F0\uC774\uC57C \uC791\uC131\uD560 \uB54C \uD56D\uC0C1 \uC9C0\uD0A4\uACE0 \uB530\uB77C.
3889
- ${ModelName}.View.tsx \uCF54\uB4DC\uB97C \uC791\uC131\uD574\uC918. \uC77C\uBC18\uC801\uC73C\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uB294 \uB514\uC790\uC778\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uB97C 4\uAC1C \uC815\uB3C4 \uB9CC\uB4E4\uC5B4\uC918. (ex card, table...)
3890
- \uC608\uC2DC \uB4E4\uC5B4\uC92C\uB2E4\uACE0 \uC608\uC2DC\uB9CC \uB9CC\uB4E4\uC9C0 \uB9D0\uACE0 \uB2C8 \uC0DD\uAC01\uC5D0 \uC77C\uBC18\uC801\uC73C\uB85C \uC0AC\uC6A9\uD55C\uB2E4 \uD558\uB294 \uCEF4\uD3EC\uB10C\uD2B8\uB85C \uC0DD\uAC01\uD574\uC11C \uB9CC\uB4E4\uC5B4.
4437
+ 1. Akan.js \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uAC1C\uC694
4438
+ ${frameworkAbstract}
3891
4439
 
3892
- Target filename: ${ModelName}.View.tsx
4440
+ 2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uC124\uBA85
4441
+ ${moduleDesription}
4442
+
4443
+ 3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uC124\uBA85
4444
+ ${eslintDescription}
4445
+
4446
+ 4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uC124\uBA85
4447
+ ${utilUiDescription}
4448
+
4449
+ 5. ${ModelName}.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uC815\uBCF4
4450
+ ${constant}
4451
+
4452
+ 6. ${modelName}\uC5D0\uC11C \uC885\uC18D\uB418\uB294 \uB2E4\uB978 \uBAA8\uB378\uB4E4\uC758 \uD0C0\uC785 \uC815\uC758
4453
+ ${properties.map(
4454
+ (property) => `
4455
+ \`\`\`
4456
+ ${property.key}.constant.ts
4457
+
4458
+
4459
+ ${property.source}
4460
+ \`\`\`
4461
+ `
4462
+ ).join("\n\n")}
4463
+
4464
+
4465
+ 7. \uC608\uC2DC \uD30C\uC77C\uB4E4
4466
+ ${exampleFiles.map(
4467
+ (example) => `
4468
+ Example filename: ${example.filepath}
4469
+ \`\`\`
4470
+ ${example.content}
4471
+ \`\`\`
4472
+ `
4473
+ ).join("\n\n")}
4474
+
4475
+
4476
+
4477
+
4478
+
4479
+
4480
+ \uC5ED\uD560\uBD80\uC5EC
4481
+ - Akan.js \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C \uAE30\uBC18 Typescript \uC2DC\uB2C8\uC5B4 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790.
4482
+
4483
+ \uCF54\uB529 \uADDC\uCE59
4484
+ - \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4485
+ - \uC544\uC774\uCF58: react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4486
+ - CSS: DaisyUI (btn, input, badge \uAC19\uC740 \uAE30\uBCF8 \uC694\uC18C\uB9CC \uC0AC\uC6A9 \uAC00\uB2A5, card/hero \uAC19\uC740 \uBCF5\uC7A1\uD55C \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uBD88\uAC00)
4487
+ - \uC870\uAC74\uBD80 \uD074\uB798\uC2A4: clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4488
+ \uCF54\uB4DC \uC2A4\uD0C0\uC77C
4489
+ - \uC0C9\uC0C1: \uD558\uB4DC\uCF54\uB529(bg-red) \uB300\uC2E0 \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary) \uC0AC\uC6A9
4490
+ - \uC870\uAC74\uBD80 \uB80C\uB354\uB9C1: field && <div>... \uB300\uC2E0 field ? <div>... : null \uC0AC\uC6A9
4491
+ - \uBAA8\uB378 \uC811\uADFC: \uAD6C\uC870\uBD84\uD574\uD560\uB2F9 \uB300\uC2E0 ${modelName}.field \uD615\uC2DD\uC73C\uB85C \uC811\uADFC
4492
+ - \uD0C0\uC785 \uC548\uC804: ${modelName}.constant.ts\uC758 \uC2A4\uD0A4\uB9C8 \uCC38\uC870\uD558\uC5EC \uC5D0\uB7EC \uBC29\uC9C0
4493
+ \uD544\uB4DC \uC811\uADFC \uC804: \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8 \uC791\uC131 \uBC0F \uAC80\uD1A0 \uD544\uC218
4494
+
4495
+ \uC5C4\uACA9\uD55C \uC8FC\uC758\uC0AC\uD56D
4496
+ - UI \uD0B7\uC740 \uBB38\uC11C\uC5D0 \uBA85\uC2DC\uB41C \uCEF4\uD3EC\uB10C\uD2B8\uB9CC \uC0AC\uC6A9
4497
+ - \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC804 \uBB38\uC11C \uD655\uC778 \uBC0F props \uC815\uD655\uD788 \uAC80\uC99D
4498
+ - \uBA85\uC2DC\uB41C \uB8F0 \uC678 \uC784\uC758 \uCD94\uC0C1\uD654 \uAE08\uC9C0
4499
+
4500
+ \uC694\uCCAD\uC0AC\uD56D
4501
+ - ${ModelName}.Unit.tsx \uCF54\uB4DC \uC791\uC131
4502
+ - \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984\uC5D0 ModelName\uC740 \uC0DD\uB7B5\uD558\uBA70, \uC608\uC2DC\uD30C\uC77C\uB4E4\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCC38\uACE0\uD558\uC5EC \uC791\uBA85
4503
+ - \uC608\uC2DC\uD30C\uC77C \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uAE30\uBC18\uD558\uC5EC \uC77C\uBC18\uC801\uC73C\uB85C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3EC\uB10C\uD2B8 1\uAC1C\uC640 \uB514\uC790\uC778\uC801 \uC694\uC18C\uAC00 \uD3EC\uD568\uB41C \uCEF4\uD3EC\uB10C\uD2B8 3\uAC1C \uAC1C\uBC1C
4504
+ - \uCD94\uC0C1\uD654 \uD574\uC57C\uD558\uB294 \uACBD\uC6B0\uAC00 \uC788\uC744 \uACBD\uC6B0\uC5D4 \uBB38\uC11C\uB97C \uB2E4\uC2DC \uCC38\uACE0\uD558\uACE0 \uC124\uBA85\uB41C \uB0B4\uC5D0\uC11C \uD574\uACB0\uD574\uC57C\uD568.
4505
+
4506
+
4507
+ Application name: ${sysName}
4508
+ Model name: ${modelName}
4509
+
4510
+ Target filename: ${ModelName}.Unit.tsx
3893
4511
  \`\`\`
3894
4512
 
3895
4513
  \`\`\`
@@ -5329,7 +5947,6 @@ var ModuleScript = class {
5329
5947
  }
5330
5948
  async createUnit(sys2) {
5331
5949
  const libs = await sys2.getModules();
5332
- const unitExampleFiles = await sys2.getUnitsSourceCode();
5333
5950
  const lib = await (0, import_prompts8.select)({
5334
5951
  message: "Select the lib",
5335
5952
  choices: libs
@@ -5343,10 +5960,11 @@ var ModuleScript = class {
5343
5960
  if (!name)
5344
5961
  return;
5345
5962
  const Name = capitalize(name);
5963
+ const unitExampleFiles = (await sys2.getUnitsSourceCode()).filter((f) => !f.filepath.includes(`${name}.Unit.tsx`));
5346
5964
  const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
5347
5965
  const constant = import_fs10.default.readFileSync(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`, "utf-8");
5348
5966
  const session = new AiSession();
5349
- const promptRst = requestView({
5967
+ const promptRst = requestUnit({
5350
5968
  sysName: sys2.name,
5351
5969
  modelName: name,
5352
5970
  ModelName: Name,
@@ -5355,8 +5973,8 @@ var ModuleScript = class {
5355
5973
  exampleFiles: randomPicks(unitExampleFiles, Math.min(10, unitExampleFiles.length))
5356
5974
  });
5357
5975
  const content = await session.editTypescript(promptRst);
5358
- import_fs10.default.writeFileSync(`${sys2.cwdPath}/prompt.txt`, promptRst);
5359
- import_fs10.default.writeFileSync(`${sys2.cwdPath}/result.txt`, content);
5976
+ import_fs10.default.writeFileSync(`${sys2.cwdPath}/promptUnit.txt`, promptRst);
5977
+ import_fs10.default.writeFileSync(`${sys2.cwdPath}/resultUnit.txt`, content);
5360
5978
  }
5361
5979
  async createView(sys2) {
5362
5980
  const libs = await sys2.getModules();
@@ -5372,7 +5990,7 @@ var ModuleScript = class {
5372
5990
  const name = lib.split("/").pop();
5373
5991
  if (!name)
5374
5992
  return;
5375
- const viewExampleFiles = (await sys2.getViewsSourceCode()).filter((f) => f.filepath.includes(`${name}.View.tsx`));
5993
+ const viewExampleFiles = (await sys2.getViewsSourceCode()).filter((f) => !f.filepath.includes(`${name}.View.tsx`));
5376
5994
  const Name = capitalize(name);
5377
5995
  const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
5378
5996
  const constant = import_fs10.default.readFileSync(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`, "utf-8");
@@ -5411,7 +6029,8 @@ var ModuleCommand = class {
5411
6029
  async createView(sys2, workspace) {
5412
6030
  await this.moduleScript.createView(sys2);
5413
6031
  }
5414
- async createUnit(name, workspace) {
6032
+ async createUnit(sys2, workspace) {
6033
+ await this.moduleScript.createUnit(sys2);
5415
6034
  }
5416
6035
  };
5417
6036
  __decorateClass([
@@ -5454,7 +6073,7 @@ __decorateClass([
5454
6073
  ], ModuleCommand.prototype, "createView", 1);
5455
6074
  __decorateClass([
5456
6075
  Target.Public(),
5457
- __decorateParam(0, Option("name", { desc: "name of unit module" })),
6076
+ __decorateParam(0, Sys()),
5458
6077
  __decorateParam(1, Workspace())
5459
6078
  ], ModuleCommand.prototype, "createUnit", 1);
5460
6079
  ModuleCommand = __decorateClass([
@@ -5534,60 +6153,12 @@ PageCommand = __decorateClass([
5534
6153
  Commands()
5535
6154
  ], PageCommand);
5536
6155
 
5537
- // pkgs/@akanjs/cli/src/workspace/workspace.script.ts
5538
- var import_latest_version2 = __toESM(require("latest-version"));
5539
- var import_path5 = __toESM(require("path"));
5540
-
5541
6156
  // pkgs/@akanjs/cli/src/workspace/workspace.runner.ts
5542
6157
  var import_uuid2 = require("uuid");
6158
+ var import_lodash = require("lodash");
6159
+ var import_latest_version2 = __toESM(require("latest-version"));
6160
+ var import_path5 = __toESM(require("path"));
5543
6161
  var WorkspaceRunner = class {
5544
- async createWorkspace(repoName, appName, dirname = ".") {
5545
- }
5546
- async generateMongo(workspace) {
5547
- const namespace = "00000000-0000-0000-0000-000000000000";
5548
- const appNames = await workspace.getApps();
5549
- const apps = appNames.map((appName) => AppExecutor.from(workspace, appName));
5550
- const appDatas = apps.reduce(
5551
- (acc, app) => [
5552
- ...acc,
5553
- ...["debug", "develop", "main"].map((env) => ({
5554
- appName: app.name,
5555
- env,
5556
- secret: getCredentials(app, env)
5557
- }))
5558
- ],
5559
- []
5560
- );
5561
- const mongoConnectionList = {
5562
- type: "Compass Connections",
5563
- version: { $numberInt: "1" },
5564
- connections: appDatas.map(({ appName, env, secret }) => ({
5565
- id: (0, import_uuid2.v5)(`${appName}-${env}`, namespace),
5566
- favorite: {
5567
- name: `${appName}-${env}`,
5568
- color: "color9"
5569
- },
5570
- savedConnectionType: "favorite",
5571
- connectionOptions: {
5572
- connectionString: `mongodb://${secret.mongo.account.user.username}:${secret.mongo.account.user.password}@mongo-0.mongo-svc.${appName}-${env}/?directConnection=true&authSource=${appName}-${env}`,
5573
- sshTunnel: {
5574
- host: `${appName}-${env}.akamir.com`,
5575
- port: "32767",
5576
- username: "root",
5577
- password: "akamir"
5578
- }
5579
- }
5580
- }))
5581
- };
5582
- workspace.writeJson(`infra/master/mongo-connections.json`, mongoConnectionList);
5583
- }
5584
- };
5585
-
5586
- // pkgs/@akanjs/cli/src/workspace/workspace.script.ts
5587
- var WorkspaceScript = class {
5588
- #runner = new WorkspaceRunner();
5589
- applicationScript = new ApplicationScript();
5590
- libraryScript = new LibraryScript();
5591
6162
  async createWorkspace(repoName, appName, dirname = ".") {
5592
6163
  const cwdPath = process.cwd();
5593
6164
  const workspaceRoot = import_path5.default.join(cwdPath, dirname, repoName);
@@ -5597,9 +6168,9 @@ var WorkspaceScript = class {
5597
6168
  template: "workspaceRoot",
5598
6169
  dict: {
5599
6170
  repoName,
5600
- RepoName: capitalize(repoName),
6171
+ RepoName: (0, import_lodash.capitalize)(repoName),
5601
6172
  appName,
5602
- AppName: capitalize(appName),
6173
+ AppName: (0, import_lodash.capitalize)(appName),
5603
6174
  serveDomain: "localhost"
5604
6175
  }
5605
6176
  });
@@ -5639,9 +6210,60 @@ var WorkspaceScript = class {
5639
6210
  await workspace.spawn("pnpm", ["install", "--reporter=silent"]);
5640
6211
  workspace.log("Initializing git repository and commit...");
5641
6212
  await workspace.commit("Initial commit", { init: true });
6213
+ return workspace;
6214
+ }
6215
+ async generateMongo(workspace) {
6216
+ const namespace = "00000000-0000-0000-0000-000000000000";
6217
+ const appNames = await workspace.getApps();
6218
+ const apps = appNames.map((appName) => AppExecutor.from(workspace, appName));
6219
+ const appDatas = apps.reduce(
6220
+ (acc, app) => [
6221
+ ...acc,
6222
+ ...["debug", "develop", "main"].map((env) => ({
6223
+ appName: app.name,
6224
+ env,
6225
+ secret: getCredentials(app, env)
6226
+ }))
6227
+ ],
6228
+ []
6229
+ );
6230
+ const mongoConnectionList = {
6231
+ type: "Compass Connections",
6232
+ version: { $numberInt: "1" },
6233
+ connections: appDatas.map(({ appName, env, secret }) => ({
6234
+ id: (0, import_uuid2.v5)(`${appName}-${env}`, namespace),
6235
+ favorite: {
6236
+ name: `${appName}-${env}`,
6237
+ color: "color9"
6238
+ },
6239
+ savedConnectionType: "favorite",
6240
+ connectionOptions: {
6241
+ connectionString: `mongodb://${secret.mongo.account.user.username}:${secret.mongo.account.user.password}@mongo-0.mongo-svc.${appName}-${env}/?directConnection=true&authSource=${appName}-${env}`,
6242
+ sshTunnel: {
6243
+ host: `${appName}-${env}.akamir.com`,
6244
+ port: "32767",
6245
+ username: "root",
6246
+ password: "akamir"
6247
+ }
6248
+ }
6249
+ }))
6250
+ };
6251
+ workspace.writeJson(`infra/master/mongo-connections.json`, mongoConnectionList);
6252
+ }
6253
+ };
6254
+
6255
+ // pkgs/@akanjs/cli/src/workspace/workspace.script.ts
6256
+ var WorkspaceScript = class {
6257
+ #runner = new WorkspaceRunner();
6258
+ applicationScript = new ApplicationScript();
6259
+ libraryScript = new LibraryScript();
6260
+ async createWorkspace(repoName, appName, dirname = ".") {
6261
+ const workspace = await this.#runner.createWorkspace(repoName, appName, dirname);
5642
6262
  await this.libraryScript.installLibrary(workspace, "util");
5643
6263
  await this.libraryScript.installLibrary(workspace, "shared");
5644
6264
  await this.applicationScript.createApplication(appName, workspace);
6265
+ workspace.log(`Workspace created in ${workspace.workspaceRoot}`);
6266
+ Logger.rawLog(`Run \`cd ${repoName} && akan start ${appName}\` to start the development server.`);
5645
6267
  }
5646
6268
  async generateMongo(workspace) {
5647
6269
  await this.#runner.generateMongo(workspace);
@@ -5691,4 +6313,5 @@ void runCommands(
5691
6313
  //! 2. csr폴더를 현 위치로 복사 후 압축 후 삭제
5692
6314
  //! execSync를 가져오기 싫으니 일단 2번 방법으로 해보자
5693
6315
  //! add path in tsconfig.json
6316
+ //! 파일을 {name}.Unit.tsx에 저장.
5694
6317
  //! 파일을 {name}.View.tsx에 저장.