@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/esm/index.js CHANGED
@@ -903,10 +903,10 @@ var Executor = class {
903
903
  exec(command, options = {}) {
904
904
  const proc = exec(command, { cwd: this.cwdPath, ...options });
905
905
  proc.stdout?.on("data", (data) => {
906
- Logger.raw(data.toString());
906
+ Logger.raw(chalk.dim(data.toString()));
907
907
  });
908
908
  proc.stderr?.on("data", (data) => {
909
- Logger.raw(chalk.red(data.toString()));
909
+ Logger.raw(chalk.dim(data.toString()));
910
910
  });
911
911
  return new Promise((resolve, reject) => {
912
912
  proc.on("exit", (code, signal) => {
@@ -1436,11 +1436,11 @@ var SysExecutor = class extends Executor {
1436
1436
  return viewComponents;
1437
1437
  }
1438
1438
  async getUnitComponents() {
1439
- const unitComponents = (await fsPromise.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => fs6.existsSync(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`));
1439
+ const unitComponents = (await fsPromise.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => fs6.existsSync(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`));
1440
1440
  return unitComponents;
1441
1441
  }
1442
1442
  async getTemplateComponents() {
1443
- const templateComponents = (await fsPromise.readdir(`${this.cwdPath}/lib`)).filter((name) => name.startsWith("_") && !name.startsWith("__")).filter((name) => fs6.existsSync(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`));
1443
+ const templateComponents = (await fsPromise.readdir(`${this.cwdPath}/lib`)).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => fs6.existsSync(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`));
1444
1444
  return templateComponents;
1445
1445
  }
1446
1446
  async getViewsSourceCode() {
@@ -2028,6 +2028,7 @@ var runCommands = async (...commands) => {
2028
2028
  const errMsg = e instanceof Error ? e.message : typeof e === "string" ? e : JSON.stringify(e);
2029
2029
  Logger.error(`Command Error: ${chalk2.red(errMsg)}`);
2030
2030
  console.error(e);
2031
+ throw e;
2031
2032
  }
2032
2033
  });
2033
2034
  }
@@ -2175,6 +2176,7 @@ var Builder = class {
2175
2176
  return {
2176
2177
  entryPoints: [
2177
2178
  ...bundle ? [`${this.#executor.cwdPath}/index.ts`] : [`${this.#executor.cwdPath}/**/*.ts`, `${this.#executor.cwdPath}/**/*.tsx`],
2179
+ `${this.#executor.cwdPath}/**/*.template`,
2178
2180
  ...additionalEntryPoints
2179
2181
  ],
2180
2182
  bundle,
@@ -2183,7 +2185,8 @@ var Builder = class {
2183
2185
  platform: this.#pkgJson.esbuild?.platform,
2184
2186
  format,
2185
2187
  outdir: `${this.#distExecutor.cwdPath}/${format}`,
2186
- logLevel: "error"
2188
+ logLevel: "error",
2189
+ loader: { ".template": "copy" }
2187
2190
  };
2188
2191
  }
2189
2192
  #getAssetBuildOptions() {
@@ -2193,12 +2196,11 @@ var Builder = class {
2193
2196
  entryPoints: [
2194
2197
  `${this.#executor.cwdPath}/**/*.css`,
2195
2198
  `${this.#executor.cwdPath}/**/*.md`,
2196
- `${this.#executor.cwdPath}/**/*.template`,
2197
2199
  `${this.#executor.cwdPath}/**/*.js`
2198
2200
  ],
2199
2201
  outdir: this.#distExecutor.cwdPath,
2200
2202
  logLevel: "error",
2201
- loader: { ".css": "copy", ".md": "copy", ".template": "copy", ".js": "copy" }
2203
+ loader: { ".css": "copy", ".md": "copy", ".js": "copy" }
2202
2204
  };
2203
2205
  }
2204
2206
  async build(options = {}) {
@@ -2394,525 +2396,1032 @@ import tsconfigPaths from "vite-tsconfig-paths";
2394
2396
 
2395
2397
  // pkgs/@akanjs/cli/src/module/module.prompt.ts
2396
2398
  var frameworkDescription = `
2397
- \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.
2398
- \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.
2399
-
2400
- \uAC00\uC7A5 \uC678\uBD80\uC758 \uAD6C\uC870\uB294
2401
- - app
2399
+ \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.
2400
+
2401
+ \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.
2402
+
2403
+
2404
+
2405
+ \uAC00\uC7A5 \uC678\uBD80\uC758 \uAD6C\uC870\uB294
2406
+
2407
+ - app
2408
+
2402
2409
  - project1
2410
+
2403
2411
  - project2
2412
+
2404
2413
  - project3
2414
+
2405
2415
  - project4
2406
- - lib
2416
+
2417
+ - lib
2418
+
2407
2419
  - core
2420
+
2408
2421
  - external
2422
+
2409
2423
  - game
2424
+
2410
2425
  - mint
2426
+
2411
2427
  - platform
2428
+
2412
2429
  - shared
2430
+
2413
2431
  - social
2432
+
2414
2433
  - util
2415
- app\uC740 \uAC01 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4DC\uB294 \uACF3\uC774\uC57C
2416
- 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.
2417
- \uB2E4\uC74C\uC740 app/project \uB0B4\uBD80\uC758 \uAD6C\uC870\uB97C \uC54C\uB824\uC904\uAC8C.
2418
-
2419
- project
2420
- - app
2434
+
2435
+ app\uC740 \uAC01 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4DC\uB294 \uACF3\uC774\uC57C
2436
+
2437
+ 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.
2438
+
2439
+ \uB2E4\uC74C\uC740 app/project \uB0B4\uBD80\uC758 \uAD6C\uC870\uB97C \uC54C\uB824\uC904\uAC8C.
2440
+
2441
+
2442
+
2443
+ project
2444
+
2445
+ - app
2446
+
2421
2447
  - [lang]
2422
- - (projectName)
2423
- - (user)
2424
- - page.tsx
2425
- - layout.tsx
2426
- - (public)
2427
- - page.tsx
2428
- - layout.tsx
2429
- - (admin)
2430
- - page.tsx
2431
- - layout.tsx
2432
-
2433
- - lib
2448
+
2449
+ - (projectName)
2450
+
2451
+ - (user)
2452
+
2453
+ - page.tsx
2454
+
2455
+ - layout.tsx
2456
+
2457
+ - (public)
2458
+
2459
+ - page.tsx
2460
+
2461
+ - layout.tsx
2462
+
2463
+ - (admin)
2464
+
2465
+ - page.tsx
2466
+
2467
+ - layout.tsx
2468
+
2469
+
2470
+
2471
+ - lib
2472
+
2434
2473
  - dataName1
2474
+
2435
2475
  - dataName2
2476
+
2436
2477
  - dataName3
2478
+
2437
2479
  - dataName4
2480
+
2438
2481
  - dataName5
2482
+
2439
2483
  - dataName6
2484
+
2440
2485
  - dataName7
2441
-
2442
- 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.
2443
- public/page.tsx\uAC00 \uAC00\uC7A5 \uCD5C\uCD08\uB85C \uC811\uADFC\uB418\uB294 Index \uD398\uC774\uC9C0\uAC00 \uB420 \uAC70\uC57C.
2444
- \uC544\uB798\uB294 public/page.tsx\uC758 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2445
- \`\`\`
2446
- import {{ Image, Link }} from "@util/ui";
2447
- import {{ getSelf }} from "@akanjs/client";
2448
-
2449
- export default function Page() {{
2450
- const self = getSelf();
2451
- return (
2452
- <div className="relative w-full h-screen overflow-hidden flex items-center justify-center">
2453
- <Image
2454
- className="absolute left-0 right-0 top-0 bottom-0 w-full h-screen -z-50"
2455
- width={{1920}}
2456
- height={{1080}}
2457
- src="/back.jpg"
2458
- />
2459
- <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">
2460
- <h1 className="text-4xl mt-2"><%= project %></h1>
2461
- <h2 className="text-lg"><%= project %> description</h2>
2462
- <Link className="w-full" href={{self ? "/home" : "/signin"}}>
2463
- <button className="btn w-full btn-primary">Go to dashboard</button>
2464
- </Link>
2465
- </div>
2466
- </div>
2467
- );
2468
- }}
2469
- \`\`\`
2470
-
2471
- 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.
2472
- \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.
2473
-
2474
- \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.
2475
- \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.
2476
-
2477
- \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.
2478
-
2479
- \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.
2480
-
2481
- pencil
2482
- - pencil.constant.ts ( pencil\uC5D0 \uB300\uD55C db schema, query, sort \uAD6C\uBB38\uC744 \uC815\uC758 )
2483
- - 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.)
2484
- - 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. )
2485
- - 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 )
2486
- - 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.)
2487
- - pencil.store.ts (pencil field\uC5D0 \uB300\uD55C \uC0C1\uD0DC\uAD00\uB9AC \uC800\uC7A5\uC18C.)
2488
- - 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. )
2489
- - 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. )
2490
- - 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. )
2491
- - pencil.Util.tsx (Action \uBC84\uD2BC\uC744 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
2492
- - pencil.View.tsx (\uB2E8\uC77C view \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
2493
-
2494
-
2495
- \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.
2496
-
2497
- document, signal, service\uB294 \uBC31\uC5D4\uB4DC\uC640 \uC5F0\uAD00\uB418\uC5B4\uC788\uB294 \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2498
- \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.
2499
- signal - document
2500
- signal - service - document
2501
-
2502
- store\uB294 \uD504\uB860\uD2B8\uC5D4\uB4DC\uC5D0\uC11C \uC0C1\uD0DC\uAD00\uB9AC\uB97C \uD560 \uB54C \uC0AC\uC6A9\uB3FC.
2503
- \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.
2504
-
2505
- \uC774\uB807\uAC8C 11\uAC1C\uC758 \uD30C\uC77C\uB85C \uAD6C\uBD84\uD574\uC11C \uC815\uC758\uAC00 \uB3FC.
2506
- \uC9C0\uAE08\uBD80\uD134 \uD55C \uD30C\uC77C\uB4E4\uB9C8\uB2E4 \uC0C1\uC138\uD55C \uC124\uBA85\uC744 \uD574\uC904\uAC8C.
2507
-
2508
- model.constant.ts
2509
-
2510
- 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.
2511
- \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
2512
- \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.
2513
- \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.
2514
- \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.
2515
-
2516
- \`\`\`
2517
- import { enumOf, Int } from "@akanjs/base";
2518
- import { Field, Filter, Model, sortOf, via } from "@akanjs/constant";
2519
-
2520
- export const \${dict.Model}Statuses = ["active"] as const;
2521
- export type \${dict.Model}Status = (typeof \${dict.Model}Statuses)[number];
2522
-
2523
- //\uB370\uC774\uD130\uB97C \uB9CC\uB4E4 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uACF3
2524
- @Model.Input("\${dict.Model}Input")
2525
- export class \${dict.Model}Input {{
2526
- @Field.Prop(() => String)
2527
- field: string;
2528
-
2529
- @Field.Prop(() => Int, {{ nullable: true }})
2530
- fieldInt: number | null;
2531
-
2532
- @Field.Prop(() => Date, {{default: dayjs()}})
2533
- fieldInt: Dayjs;
2534
- }}
2535
-
2536
- //\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
2537
- @Model.Object("\${dict.Model}Object")
2538
- export class \${dict.Model}Object extends via(\${dict.Model}Input) {
2539
- @Field.Prop(() => String, {{ enum: \${dict.Model}Statuses, default: "active" }})
2540
- status: \${dict.Model}Status;
2541
- }}
2542
-
2543
- //\uB370\uC774\uD130\uB97C \uB9AC\uC2A4\uD2B8\uB85C \uBCF4\uC5EC\uC904 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130\uB9CC \uC81C\uACF5\uD558\uB294 \uACF3
2544
- @Model.Light("Light\${dict.Model}")
2545
- export class Light\${dict.Model} extends via(\${dict.Model}Object, [
2546
- "field",
2547
- "status",
2548
- ] as const) {}
2549
-
2550
- //\uCD5C\uC885 \uB370\uC774\uD130\uC758 Full \uD0C0\uC785\uC774 \uC815\uC758\uB418\uB294 \uACF3
2551
- @Model.Full("\${dict.Model}")
2552
- export class \${dict.Model} extends via(\${dict.Model}Object, Light\${dict.Model}) {}
2553
-
2554
- //\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
2555
- @Model.Insight("\${dict.Model}Insight")
2556
- export class \${dict.Model}Insight {{
2557
- @Field.Prop(() => Int, {{ default: 0, accumulate: {{ $sum: 1 }} }})
2558
- count: number;
2559
- }}
2560
-
2561
- //\uB370\uC774\uD130\uC758 \uD1B5\uACC4\uB97C \uACC4\uC0B0\uD558\uB294 \uACF3
2562
- @Model.Summary("\${dict.Model}Summary")
2563
- export class \${dict.Model}Summary {{
2564
- @Field.Prop(() => Int, {{ min: 0, default: 0, query: {{ status: {{}} }} }})
2565
- total\${dict.Model}: number;
2566
- }}
2567
-
2568
- @Model.Filter("\${dict.Model}Filter")
2569
- export class \${dict.Model}Filter extends sortOf(\${dict.Model}, {}) {}
2570
- \`\`\`
2571
-
2572
-
2573
- model.dictonary.ts
2574
- \`\`\`
2575
- import {
2576
- baseTrans,
2577
- getBaseSignalTrans,
2578
- ModelDictionary,
2579
- SignalDictionary,
2580
- SummaryDictionary,
2581
- } from "@akanjs/dictionary";
2582
-
2583
- import type { \${dict.Model}, \${dict.Model}Filter, \${dict.Model}Insight, \${dict.Model}Summary } from "./\${dict.model}.constant";
2584
- import type { \${dict.Model}Signal } from "./\${dict.model}.signal";
2585
-
2586
- const modelDictionary = {{
2587
- ...baseTrans,
2588
- modelName: ["\${dict.Model}", "\${dict.Model}"],
2589
- modelDesc: [
2590
- "\${dict.Model} description",
2591
- "\${dict.Model} \uC124\uBA85",
2592
- ],
2593
-
2594
- // * ==================== Model ==================== * //
2595
- field: ["Field", "\uD544\uB4DC"],
2596
- "desc-field": ["Field", "\uD544\uB4DC"],
2597
- // * ==================== Model ==================== * //
2598
-
2599
- // * ==================== Insight ==================== * //
2600
- count: ["Count", "\uAC1C\uC218"],
2601
- "desc-count": ["\${dict.Model} count in current query settting", "\uD604\uC7AC \uCFFC\uB9AC \uC124\uC815\uC5D0 \uB9DE\uB294 \${dict.Model} \uC218"],
2602
- // * ==================== Insight ==================== * //
2603
-
2604
- // * ==================== Filter ==================== * //
2605
- // * ==================== Filter ==================== * //
2606
-
2607
- // * ==================== Etc ==================== * //
2608
- "enum-status-active": ["Active", "\uD65C\uC131"],
2609
- "enumdesc-status-active": ["Active status", "\uD65C\uC131 \uC0C1\uD0DC"],
2610
- // * ==================== Etc ==================== * //
2611
- }} satisfies ModelDictionary<\${dict.Model}, \${dict.Model}Insight, typeof \${dict.Model}Sort>;
2612
-
2613
- export const \${dict.Model}SummaryDictionary = {{
2614
- // * ==================== Summary ==================== * //
2615
- total\${dict.Model}: ["Total \${dict.Model}", "\uCD1D \${dict.Model} \uC218"],
2616
- "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"],
2617
- // * ==================== Summary ==================== * //
2618
- }} satisfies SummaryDictionary<\${dict.Model}Summary>;
2619
-
2620
- const signalDictionary = {{
2621
- ...getBaseSignalTrans("\${dict.Model}" as const),
2622
- // * ==================== Endpoint ==================== * //
2623
- "api-\${dict.Model}ListInPublic": ["\${dict.Model} List In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uB9AC\uC2A4\uD2B8"],
2624
- "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"],
2625
- "arg-\${dict.Model}ListInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2626
- "argdesc-\${dict.Model}ListInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2627
- "arg-\${dict.Model}ListInPublic-skip": ["Skip", "\uAC74\uB108\uB6F0\uAE30"],
2628
- "argdesc-\${dict.Model}ListInPublic-skip": ["Number of items to skip", "\uAC74\uB108\uB6F8 \uC544\uC774\uD15C \uC218"],
2629
- "arg-\${dict.Model}ListInPublic-limit": ["Limit", "\uC81C\uD55C"],
2630
- "argdesc-\${dict.Model}ListInPublic-limit": ["Maximum number of items to return", "\uBC18\uD658\uD560 \uCD5C\uB300 \uC544\uC774\uD15C \uC218"],
2631
- "arg-\${dict.Model}ListInPublic-sort": ["Sort", "\uC815\uB82C"],
2632
- "argdesc-\${dict.Model}ListInPublic-sort": ["Sort order of the items", "\uC544\uC774\uD15C\uC758 \uC815\uB82C \uC21C\uC11C"],
2633
-
2634
- "api-\${dict.Model}InsightInPublic": ["\${dict.Model} Insight In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uC778\uC0AC\uC774\uD2B8"],
2635
- "apidesc-\${dict.Model}InsightInPublic": [
2636
- "Get insight data for public \${dict.Model}",
2637
- "\uACF5\uAC1C\uB41C \${dict.Model}\uC5D0 \uB300\uD55C \uC778\uC0AC\uC774\uD2B8 \uB370\uC774\uD130\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4",
2638
- ],
2639
- "arg-\${dict.Model}InsightInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2640
- "argdesc-\${dict.Model}InsightInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2641
- // * ==================== Endpoint ==================== * //
2642
- }} satisfies SignalDictionary<\${dict.Model}Signal, \${dict.Model}>;
2643
- \`\`\`
2644
- export const \${dict.model}Dictionary = {{ ...modelDictionary, ...signalDictionary }};
2645
-
2646
-
2647
-
2648
- model.document.ts
2649
- \`\`\`
2650
- import { beyond, by, Database, into, type SchemaOf } from "@akanjs/document";
2651
-
2652
- import { cnst } from "../cnst";
2653
- @Database.Input(() => cnst.\${dict.Model}Input)
2654
- export class \${dict.Model}Input extends by(cnst.\${dict.Model}Input) {}
2655
-
2656
- @Database.Document(() => cnst.\${dict.Model})
2657
- export class \${dict.Model} extends by(cnst.\${dict.Model}) {}
2658
-
2659
- @Database.Model(() => cnst.\${dict.Model})
2660
- export class \${dict.Model}Model extends into(\${dict.Model}, cnst.\${dict.Model}Cnst) {
2661
- async getSummary(): Promise<cnst.\${dict.Model}Summary> {
2662
- return {
2663
- ...(await this.getDefaultSummary()),
2664
- };
2665
- }
2666
- }
2667
-
2668
- @Database.Middleware(() => cnst.\${dict.Model})
2669
- export class \${dict.Model}Middleware extends beyond(\${dict.Model}Model, \${dict.Model}) {
2670
- onSchema(schema: SchemaOf<\${dict.Model}Model, \${dict.Model}>) {
2671
- // schema.index({ status: 1 })
2672
- }
2673
- }
2674
- \`\`\`
2675
-
2676
-
2677
- model.signal.ts
2678
- \`\`\`
2679
- import { Int } from "@akanjs/base";
2680
- import { SortOf } from "@akanjs/constant";
2681
- import { Arg, DbSignal, Mutation, Query, resolve, Signal } from "@akanjs/signal";
2682
-
2683
- import { cnst, Srvs } from "../cnst";
2684
-
2685
- @Signal(() => cnst.\${dict.Model})
2686
- export class \${dict.Model}Signal extends DbSignal(cnst.\${dict.model}Cnst, Srvs, {
2687
- guards: { get: Query.Public, cru: Mutation.Public },
2688
- }) {
2689
- // * /////////////////////////////////////
2690
- // * Public Slice
2691
- @Query.Public(() => [cnst.\${dict.Model}])
2692
- async \${dict.model}ListInPublic(
2693
- @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null,
2694
- @Arg.Query("skip", () => Int, { nullable: true }) skip: number | null,
2695
- @Arg.Query("limit", () => Int, { nullable: true }) limit: number | null,
2696
- @Arg.Query("sort", () => String, { nullable: true }) sort: SortOf<cnst.\${dict.Model}Filter> | null
2697
- ) {
2698
- const \${dict.models} = await this.\${dict.model}Service.listByStatuses(statuses, { skip, limit, sort });
2699
- return resolve<cnst.\${dict.Model}[]>(\${dict.models});
2700
- }
2701
- @Query.Public(() => cnst.\${dict.Model}Insight)
2702
- async \${dict.model}InsightInPublic(
2703
- @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null
2704
- ) {
2705
- const \${dict.model}Insight = await this.\${dict.model}Service.insightByStatuses(statuses);
2706
- return resolve<cnst.\${dict.Model}Insight>(\${dict.model}Insight);
2707
- }
2708
- // * Public Slice
2709
- // * /////////////////////////////////////
2710
- }
2711
- \`\`\`
2712
-
2713
-
2714
- model.service.ts
2715
- \`\`\`
2716
- import { DbService, Service } from "@akanjs/service";
2717
-
2718
- import { cnst } from "../cnst";
2719
- import * as db from "../db";
2720
-
2721
- @Service("\${dict.Model}Service")
2722
- export class \${dict.Model}Service extends DbService(db.\${dict.Model}Db) {
2723
- async summarize(): Promise<cnst.\${dict.Model}Summary> {
2724
- return {
2725
- ...(await this.\${dict.Model}Model.getSummary()),
2726
- };
2727
- }
2728
- }
2729
- \`\`\`
2730
-
2731
-
2732
- model.store.ts
2733
- \`\`\`
2734
- import { stateOf, Store } from "@akanjs/store";
2735
-
2736
- import { cnst } from "../cnst";
2737
- import { fetch } from "../fetch";
2738
-
2739
- @Store(() => cnst.\${dict.Model})
2740
- export class \${dict.Model}Store extends stateOf(fetch.\${dict.model}Gql, {
2741
- // state
2742
- }) {
2743
- // action
2744
- }
2745
- \`\`\`
2746
-
2747
-
2748
- model.Zone.tsx
2749
- \`\`\`
2750
- "use client";
2751
- import { Data, Load } from "@shared/ui";
2752
- import { ModelsProps } from "@akanjs/client";
2753
- import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
2754
- import { ClientInit, ClientView, DefaultOf } from "@akanjs/signal";
2755
-
2756
- export const Admin = ({ sliceName = "\${dict.model}", init, query }: ModelsProps<cnst.\${dict.Model}>>) => {
2757
- return (
2758
- <Data.ListContainer
2759
- init={init}
2760
- query={query}
2761
- sliceName={sliceName}
2762
- renderItem={\${dict.Model}.Unit.Card}
2763
- renderDashboard={\${dict.Model}.Util.Stat}
2764
- renderInsight={\${dict.Model}.Util.Insight}
2765
- renderTemplate={\${dict.Model}.Template.General}
2766
- renderTitle={(\${dict.model}: DefaultOf<cnst.\${dict.Model}>>) => \`\${dict.Model} - \${\${dict.model}.id ? \${dict.model}.id : "New"}\`}
2767
- renderView={(\${dict.model}: cnst.\${dict.Model}>) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />}
2768
- columns={[
2769
- "id",
2770
- "status",
2771
- "createdAt",
2772
- "updatedAt",
2773
- ]}
2774
- actions={(\${dict.model}: cnst.Light\${dict.Model}, idx) => ["remove", "edit", "view"]}
2775
- />
2776
- );
2777
- };
2778
-
2779
- interface CardProps {
2780
- className?: string;
2781
- init: ClientInit<"\${dict.model}", cnst.Light\${dict.Model}>;
2782
- }
2783
- export const Card = ({ className, init }: CardProps) => {
2784
- return (
2785
- <Load.Units
2786
- className={className}
2787
- init={init}
2788
- renderItem={(\${dict.model}: cnst.Light\${dict.Model}) => (
2789
- <\${dict.Model}.Unit.Card key={\${dict.model}.id} href={\`/\${dict.model}/\${\${dict.model}.id}\`} \${dict.model}={\${dict.model}} />
2790
- )}
2791
- />
2792
- );
2793
- };
2794
-
2795
- interface ViewProps {
2796
- className?: string;
2797
- view: ClientView<"\${dict.model}", cnst.\${dict.Model}>;
2798
- }
2799
- export const View = ({ view }: ViewProps) => {
2800
- return <Load.View view={view} renderView={(\${dict.model}) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />} />;
2801
- };
2802
- \`\`\`
2803
-
2804
- model.Templete.tsx
2805
- \`\`\`
2806
- "use client";
2807
- import { cnst, st, usePage } from "@\${dict.appName}/client";
2808
- import { Field } from "@shared/ui";
2809
- import { Layout } from "@util/ui";
2810
-
2811
- interface \${dict.Model}EditProps {
2812
- \${dict.model}Id?: string | null;
2813
- }
2814
-
2815
- export const General = ({ \${dict.model}Id = undefined }: \${dict.Model}EditProps) => {
2816
- const \${dict.model}Form = st.use.\${dict.model}Form();
2817
- const { l } = usePage();
2818
- return (
2819
- <Layout.Template>
2820
- <Field.Text
2821
- label={l.field("\${dict.model}", "id")}
2822
- desc={l.desc("\${dict.model}", "id")}
2823
- value={\${dict.model}Form.id}
2824
- onChange={st.do.setIdOn\${dict.Model}}
2825
- />
2826
- </Layout.Template>
2827
- );
2828
- };
2829
- \`\`\`
2830
-
2831
-
2832
- model.Unit.tsx
2833
- \`\`\`
2834
- import { ModelProps } from "@akanjs/client";
2835
- import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
2836
- import { Link } from "@util/ui";
2837
-
2838
- export const Card = ({ \${dict.model}, href }: ModelProps<"\${dict.model}", cnst.Light\${dict.Model}>>) => {
2839
- return (
2840
- <Link href={href} className="animate-fadeIn w-full h-36 flex rounded-lg shadow-sm hover:shadow-lg duration-300">
2841
- <div>{\${dict.model}.id}</div>
2842
- </Link>
2843
- );
2844
- };
2845
- \`\`\`
2846
-
2847
-
2848
- model.Util.tsx
2849
- \`\`\`
2850
- "use client";
2851
- import { ModelDashboardProps, ModelInsightProps } from "@akanjs/client";
2852
- import { getQueryMap } from "@akanjs/constant";
2853
- import { cnst } from "@\${dict.appName}/client";
2854
- import { Data } from "@shared/ui";
2855
-
2856
- export const Stat = ({
2857
- className,
2858
- summary,
2859
- sliceName = "\${dict.model}",
2860
- queryMap = getQueryMap(cnst.\${dict.Model}Summary),
2861
- hidePresents,
2862
- }: ModelDashboardProps<cnst.Summary>) => {
2863
- return (
2864
- <Data.Dashboard
2865
- className={className}
2866
- summary={summary}
2867
- sliceName={sliceName}
2868
- queryMap={queryMap}
2869
- columns={["total\${dict.Model}"]}
2870
- hidePresents={hidePresents}
2871
- />
2872
- );
2873
- };
2874
-
2875
- export const Insight = ({
2876
- className,
2877
- insight,
2878
- sliceName = "\${dict.model}",
2879
- }: ModelInsightProps<cnst.\${dict.Model}Insight>) => {
2880
- return (
2881
- <Data.Insight
2882
- className={className}
2883
- insight={insight}
2884
- sliceName={sliceName}
2885
- columns={["count"]}
2886
- />
2887
- );
2888
- };
2889
- \`\`\`
2890
-
2891
-
2892
- model.View.tsx
2893
- \`\`\`
2894
- import { clsx } from "@akanjs/client";
2895
- import { cnst } from "@\${dict.appName}/client";
2896
- import { Image } from "@util/ui";
2897
-
2898
- interface \${dict.Model}ViewProps {
2899
- className?: string;
2900
- \${dict.model}: cnst.\${dict.Model};
2901
- self?: { id?: string } | null;
2902
- }
2903
-
2904
- export const General = ({ className, \${dict.model}, self }: \${dict.Model}ViewProps) => {
2905
- return (
2906
- <div className={clsx(className, "animate-fadeIn w-full")}>
2907
- <div>{\${dict.model}.id}</div>
2908
- </div>
2909
- );
2910
- };
2911
- \`\`\`
2912
- \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.
2913
-
2914
- \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.
2915
- `;
2486
+
2487
+
2488
+
2489
+ 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.
2490
+
2491
+ public/page.tsx\uAC00 \uAC00\uC7A5 \uCD5C\uCD08\uB85C \uC811\uADFC\uB418\uB294 Index \uD398\uC774\uC9C0\uAC00 \uB420 \uAC70\uC57C.
2492
+
2493
+ \uC544\uB798\uB294 public/page.tsx\uC758 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2494
+
2495
+ \`\`\`
2496
+
2497
+ import {{ Image, Link }} from "@util/ui";
2498
+
2499
+ import {{ getSelf }} from "@akanjs/client";
2500
+
2501
+
2502
+
2503
+ export default function Page() {{
2504
+
2505
+ const self = getSelf();
2506
+
2507
+ return (
2508
+
2509
+ <div className="relative w-full h-screen overflow-hidden flex items-center justify-center">
2510
+
2511
+ <Image
2512
+
2513
+ className="absolute left-0 right-0 top-0 bottom-0 w-full h-screen -z-50"
2514
+
2515
+ width={{1920}}
2516
+
2517
+ height={{1080}}
2518
+
2519
+ src="/back.jpg"
2520
+
2521
+ />
2522
+
2523
+ <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">
2524
+
2525
+ <h1 className="text-4xl mt-2"><%= project %></h1>
2526
+
2527
+ <h2 className="text-lg"><%= project %> description</h2>
2528
+
2529
+ <Link className="w-full" href={{self ? "/home" : "/signin"}}>
2530
+
2531
+ <button className="btn w-full btn-primary">Go to dashboard</button>
2532
+
2533
+ </Link>
2534
+
2535
+ </div>
2536
+
2537
+ </div>
2538
+
2539
+ );
2540
+
2541
+ }}
2542
+
2543
+ \`\`\`
2544
+
2545
+
2546
+
2547
+ 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.
2548
+
2549
+ \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.
2550
+
2551
+
2552
+
2553
+ \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.
2554
+
2555
+ \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.
2556
+
2557
+
2558
+
2559
+ \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.
2560
+
2561
+
2562
+
2563
+ \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.
2564
+
2565
+
2566
+
2567
+ pencil
2568
+
2569
+ - pencil.constant.ts ( pencil\uC5D0 \uB300\uD55C db schema, query, sort \uAD6C\uBB38\uC744 \uC815\uC758 )
2570
+
2571
+ - 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.)
2572
+
2573
+ - 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. )
2574
+
2575
+ - 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 )
2576
+
2577
+ - 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.)
2578
+
2579
+ - pencil.store.ts (pencil field\uC5D0 \uB300\uD55C \uC0C1\uD0DC\uAD00\uB9AC \uC800\uC7A5\uC18C.)
2580
+
2581
+ - 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. )
2582
+
2583
+ - 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. )
2584
+
2585
+ - 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. )
2586
+
2587
+ - pencil.Util.tsx (Action \uBC84\uD2BC\uC744 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
2588
+
2589
+ - pencil.View.tsx (\uB2E8\uC77C view \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
2590
+
2591
+
2592
+
2593
+
2594
+ \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.
2595
+
2596
+
2597
+
2598
+ document, signal, service\uB294 \uBC31\uC5D4\uB4DC\uC640 \uC5F0\uAD00\uB418\uC5B4\uC788\uB294 \uC18C\uC2A4\uCF54\uB4DC\uC57C.
2599
+
2600
+ \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.
2601
+
2602
+ signal - document
2603
+
2604
+ signal - service - document
2605
+
2606
+
2607
+
2608
+ store\uB294 \uD504\uB860\uD2B8\uC5D4\uB4DC\uC5D0\uC11C \uC0C1\uD0DC\uAD00\uB9AC\uB97C \uD560 \uB54C \uC0AC\uC6A9\uB3FC.
2609
+
2610
+ \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.
2611
+
2612
+
2613
+
2614
+ \uC774\uB807\uAC8C 11\uAC1C\uC758 \uD30C\uC77C\uB85C \uAD6C\uBD84\uD574\uC11C \uC815\uC758\uAC00 \uB3FC.
2615
+
2616
+ \uC9C0\uAE08\uBD80\uD134 \uD55C \uD30C\uC77C\uB4E4\uB9C8\uB2E4 \uC0C1\uC138\uD55C \uC124\uBA85\uC744 \uD574\uC904\uAC8C.
2617
+
2618
+
2619
+
2620
+ model.constant.ts
2621
+
2622
+
2623
+
2624
+ 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.
2625
+
2626
+ \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
2627
+
2628
+ \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.
2629
+
2630
+ \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.
2631
+
2632
+ \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.
2633
+
2634
+
2635
+
2636
+ \`\`\`
2637
+
2638
+ import { enumOf, Int } from "@akanjs/base";
2639
+
2640
+ import { Field, Filter, Model, sortOf, via } from "@akanjs/constant";
2641
+
2642
+
2643
+
2644
+ export const \${dict.Model}Statuses = ["active"] as const;
2645
+
2646
+ export type \${dict.Model}Status = (typeof \${dict.Model}Statuses)[number];
2647
+
2648
+
2649
+
2650
+ //\uB370\uC774\uD130\uB97C \uB9CC\uB4E4 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uACF3
2651
+
2652
+ @Model.Input("\${dict.Model}Input")
2653
+
2654
+ export class \${dict.Model}Input {{
2655
+
2656
+ @Field.Prop(() => String)
2657
+
2658
+ field: string;
2659
+
2660
+
2661
+
2662
+ @Field.Prop(() => Int, {{ nullable: true }})
2663
+
2664
+ fieldInt: number | null;
2665
+
2666
+
2667
+
2668
+ @Field.Prop(() => Date, {{default: dayjs()}})
2669
+
2670
+ fieldInt: Dayjs;
2671
+
2672
+ }}
2673
+
2674
+
2675
+
2676
+ //\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
2677
+
2678
+ @Model.Object("\${dict.Model}Object")
2679
+
2680
+ export class \${dict.Model}Object extends via(\${dict.Model}Input) {
2681
+
2682
+ @Field.Prop(() => String, {{ enum: \${dict.Model}Statuses, default: "active" }})
2683
+
2684
+ status: \${dict.Model}Status;
2685
+
2686
+ }}
2687
+
2688
+
2689
+
2690
+ //\uB370\uC774\uD130\uB97C \uB9AC\uC2A4\uD2B8\uB85C \uBCF4\uC5EC\uC904 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130\uB9CC \uC81C\uACF5\uD558\uB294 \uACF3
2691
+
2692
+ @Model.Light("Light\${dict.Model}")
2693
+
2694
+ export class Light\${dict.Model} extends via(\${dict.Model}Object, [
2695
+
2696
+ "field",
2697
+
2698
+ "status",
2699
+
2700
+ ] as const) {}
2701
+
2702
+
2703
+
2704
+ //\uCD5C\uC885 \uB370\uC774\uD130\uC758 Full \uD0C0\uC785\uC774 \uC815\uC758\uB418\uB294 \uACF3
2705
+
2706
+ @Model.Full("\${dict.Model}")
2707
+
2708
+ export class \${dict.Model} extends via(\${dict.Model}Object, Light\${dict.Model}) {}
2709
+
2710
+
2711
+
2712
+ //\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
2713
+
2714
+ @Model.Insight("\${dict.Model}Insight")
2715
+
2716
+ export class \${dict.Model}Insight {{
2717
+
2718
+ @Field.Prop(() => Int, {{ default: 0, accumulate: {{ $sum: 1 }} }})
2719
+
2720
+ count: number;
2721
+
2722
+ }}
2723
+
2724
+
2725
+
2726
+ //\uB370\uC774\uD130\uC758 \uD1B5\uACC4\uB97C \uACC4\uC0B0\uD558\uB294 \uACF3
2727
+
2728
+ @Model.Summary("\${dict.Model}Summary")
2729
+
2730
+ export class \${dict.Model}Summary {{
2731
+
2732
+ @Field.Prop(() => Int, {{ min: 0, default: 0, query: {{ status: {{}} }} }})
2733
+
2734
+ total\${dict.Model}: number;
2735
+
2736
+ }}
2737
+
2738
+
2739
+
2740
+ @Model.Filter("\${dict.Model}Filter")
2741
+
2742
+ export class \${dict.Model}Filter extends sortOf(\${dict.Model}, {}) {}
2743
+
2744
+ \`\`\`
2745
+
2746
+
2747
+
2748
+
2749
+ model.dictonary.ts
2750
+
2751
+ \`\`\`
2752
+
2753
+ import {
2754
+
2755
+ baseTrans,
2756
+
2757
+ getBaseSignalTrans,
2758
+
2759
+ ModelDictionary,
2760
+
2761
+ SignalDictionary,
2762
+
2763
+ SummaryDictionary,
2764
+
2765
+ } from "@akanjs/dictionary";
2766
+
2767
+
2768
+
2769
+ import type { \${dict.Model}, \${dict.Model}Filter, \${dict.Model}Insight, \${dict.Model}Summary } from "./\${dict.model}.constant";
2770
+
2771
+ import type { \${dict.Model}Signal } from "./\${dict.model}.signal";
2772
+
2773
+
2774
+
2775
+ const modelDictionary = {{
2776
+
2777
+ ...baseTrans,
2778
+
2779
+ modelName: ["\${dict.Model}", "\${dict.Model}"],
2780
+
2781
+ modelDesc: [
2782
+
2783
+ "\${dict.Model} description",
2784
+
2785
+ "\${dict.Model} \uC124\uBA85",
2786
+
2787
+ ],
2788
+
2789
+
2790
+
2791
+ // * ==================== Model ==================== * //
2792
+
2793
+ field: ["Field", "\uD544\uB4DC"],
2794
+
2795
+ "desc-field": ["Field", "\uD544\uB4DC"],
2796
+
2797
+ // * ==================== Model ==================== * //
2798
+
2799
+
2800
+
2801
+ // * ==================== Insight ==================== * //
2802
+
2803
+ count: ["Count", "\uAC1C\uC218"],
2804
+
2805
+ "desc-count": ["\${dict.Model} count in current query settting", "\uD604\uC7AC \uCFFC\uB9AC \uC124\uC815\uC5D0 \uB9DE\uB294 \${dict.Model} \uC218"],
2806
+
2807
+ // * ==================== Insight ==================== * //
2808
+
2809
+
2810
+
2811
+ // * ==================== Filter ==================== * //
2812
+
2813
+ // * ==================== Filter ==================== * //
2814
+
2815
+
2816
+
2817
+ // * ==================== Etc ==================== * //
2818
+
2819
+ "enum-status-active": ["Active", "\uD65C\uC131"],
2820
+
2821
+ "enumdesc-status-active": ["Active status", "\uD65C\uC131 \uC0C1\uD0DC"],
2822
+
2823
+ // * ==================== Etc ==================== * //
2824
+
2825
+ }} satisfies ModelDictionary<\${dict.Model}, \${dict.Model}Insight, typeof \${dict.Model}Sort>;
2826
+
2827
+
2828
+
2829
+ export const \${dict.Model}SummaryDictionary = {{
2830
+
2831
+ // * ==================== Summary ==================== * //
2832
+
2833
+ total\${dict.Model}: ["Total \${dict.Model}", "\uCD1D \${dict.Model} \uC218"],
2834
+
2835
+ "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"],
2836
+
2837
+ // * ==================== Summary ==================== * //
2838
+
2839
+ }} satisfies SummaryDictionary<\${dict.Model}Summary>;
2840
+
2841
+
2842
+
2843
+ const signalDictionary = {{
2844
+
2845
+ ...getBaseSignalTrans("\${dict.Model}" as const),
2846
+
2847
+ // * ==================== Endpoint ==================== * //
2848
+
2849
+ "api-\${dict.Model}ListInPublic": ["\${dict.Model} List In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uB9AC\uC2A4\uD2B8"],
2850
+
2851
+ "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"],
2852
+
2853
+ "arg-\${dict.Model}ListInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2854
+
2855
+ "argdesc-\${dict.Model}ListInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2856
+
2857
+ "arg-\${dict.Model}ListInPublic-skip": ["Skip", "\uAC74\uB108\uB6F0\uAE30"],
2858
+
2859
+ "argdesc-\${dict.Model}ListInPublic-skip": ["Number of items to skip", "\uAC74\uB108\uB6F8 \uC544\uC774\uD15C \uC218"],
2860
+
2861
+ "arg-\${dict.Model}ListInPublic-limit": ["Limit", "\uC81C\uD55C"],
2862
+
2863
+ "argdesc-\${dict.Model}ListInPublic-limit": ["Maximum number of items to return", "\uBC18\uD658\uD560 \uCD5C\uB300 \uC544\uC774\uD15C \uC218"],
2864
+
2865
+ "arg-\${dict.Model}ListInPublic-sort": ["Sort", "\uC815\uB82C"],
2866
+
2867
+ "argdesc-\${dict.Model}ListInPublic-sort": ["Sort order of the items", "\uC544\uC774\uD15C\uC758 \uC815\uB82C \uC21C\uC11C"],
2868
+
2869
+
2870
+
2871
+ "api-\${dict.Model}InsightInPublic": ["\${dict.Model} Insight In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uC778\uC0AC\uC774\uD2B8"],
2872
+
2873
+ "apidesc-\${dict.Model}InsightInPublic": [
2874
+
2875
+ "Get insight data for public \${dict.Model}",
2876
+
2877
+ "\uACF5\uAC1C\uB41C \${dict.Model}\uC5D0 \uB300\uD55C \uC778\uC0AC\uC774\uD2B8 \uB370\uC774\uD130\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4",
2878
+
2879
+ ],
2880
+
2881
+ "arg-\${dict.Model}InsightInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
2882
+
2883
+ "argdesc-\${dict.Model}InsightInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
2884
+
2885
+ // * ==================== Endpoint ==================== * //
2886
+
2887
+ }} satisfies SignalDictionary<\${dict.Model}Signal, \${dict.Model}>;
2888
+
2889
+ \`\`\`
2890
+
2891
+ export const \${dict.model}Dictionary = {{ ...modelDictionary, ...signalDictionary }};
2892
+
2893
+
2894
+
2895
+
2896
+
2897
+ model.document.ts
2898
+
2899
+ \`\`\`
2900
+
2901
+ import { beyond, by, Database, into, type SchemaOf } from "@akanjs/document";
2902
+
2903
+
2904
+
2905
+ import { cnst } from "../cnst";
2906
+
2907
+ @Database.Input(() => cnst.\${dict.Model}Input)
2908
+
2909
+ export class \${dict.Model}Input extends by(cnst.\${dict.Model}Input) {}
2910
+
2911
+
2912
+
2913
+ @Database.Document(() => cnst.\${dict.Model})
2914
+
2915
+ export class \${dict.Model} extends by(cnst.\${dict.Model}) {}
2916
+
2917
+
2918
+
2919
+ @Database.Model(() => cnst.\${dict.Model})
2920
+
2921
+ export class \${dict.Model}Model extends into(\${dict.Model}, cnst.\${dict.Model}Cnst) {
2922
+
2923
+ async getSummary(): Promise<cnst.\${dict.Model}Summary> {
2924
+
2925
+ return {
2926
+
2927
+ ...(await this.getDefaultSummary()),
2928
+
2929
+ };
2930
+
2931
+ }
2932
+
2933
+ }
2934
+
2935
+
2936
+
2937
+ @Database.Middleware(() => cnst.\${dict.Model})
2938
+
2939
+ export class \${dict.Model}Middleware extends beyond(\${dict.Model}Model, \${dict.Model}) {
2940
+
2941
+ onSchema(schema: SchemaOf<\${dict.Model}Model, \${dict.Model}>) {
2942
+
2943
+ // schema.index({ status: 1 })
2944
+
2945
+ }
2946
+
2947
+ }
2948
+
2949
+ \`\`\`
2950
+
2951
+
2952
+
2953
+
2954
+ model.signal.ts
2955
+
2956
+ \`\`\`
2957
+
2958
+ import { Int } from "@akanjs/base";
2959
+
2960
+ import { SortOf } from "@akanjs/constant";
2961
+
2962
+ import { Arg, DbSignal, Mutation, Query, resolve, Signal } from "@akanjs/signal";
2963
+
2964
+
2965
+
2966
+ import { cnst, Srvs } from "../cnst";
2967
+
2968
+
2969
+
2970
+ @Signal(() => cnst.\${dict.Model})
2971
+
2972
+ export class \${dict.Model}Signal extends DbSignal(cnst.\${dict.model}Cnst, Srvs, {
2973
+
2974
+ guards: { get: Query.Public, cru: Mutation.Public },
2975
+
2976
+ }) {
2977
+
2978
+ // * /////////////////////////////////////
2979
+
2980
+ // * Public Slice
2981
+
2982
+ @Query.Public(() => [cnst.\${dict.Model}])
2983
+
2984
+ async \${dict.model}ListInPublic(
2985
+
2986
+ @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null,
2987
+
2988
+ @Arg.Query("skip", () => Int, { nullable: true }) skip: number | null,
2989
+
2990
+ @Arg.Query("limit", () => Int, { nullable: true }) limit: number | null,
2991
+
2992
+ @Arg.Query("sort", () => String, { nullable: true }) sort: SortOf<cnst.\${dict.Model}Filter> | null
2993
+
2994
+ ) {
2995
+
2996
+ const \${dict.models} = await this.\${dict.model}Service.listByStatuses(statuses, { skip, limit, sort });
2997
+
2998
+ return resolve<cnst.\${dict.Model}[]>(\${dict.models});
2999
+
3000
+ }
3001
+
3002
+ @Query.Public(() => cnst.\${dict.Model}Insight)
3003
+
3004
+ async \${dict.model}InsightInPublic(
3005
+
3006
+ @Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null
3007
+
3008
+ ) {
3009
+
3010
+ const \${dict.model}Insight = await this.\${dict.model}Service.insightByStatuses(statuses);
3011
+
3012
+ return resolve<cnst.\${dict.Model}Insight>(\${dict.model}Insight);
3013
+
3014
+ }
3015
+
3016
+ // * Public Slice
3017
+
3018
+ // * /////////////////////////////////////
3019
+
3020
+ }
3021
+
3022
+ \`\`\`
3023
+
3024
+
3025
+
3026
+
3027
+ model.service.ts
3028
+
3029
+ \`\`\`
3030
+
3031
+ import { DbService, Service } from "@akanjs/service";
3032
+
3033
+
3034
+
3035
+ import { cnst } from "../cnst";
3036
+
3037
+ import * as db from "../db";
3038
+
3039
+
3040
+
3041
+ @Service("\${dict.Model}Service")
3042
+
3043
+ export class \${dict.Model}Service extends DbService(db.\${dict.Model}Db) {
3044
+
3045
+ async summarize(): Promise<cnst.\${dict.Model}Summary> {
3046
+
3047
+ return {
3048
+
3049
+ ...(await this.\${dict.Model}Model.getSummary()),
3050
+
3051
+ };
3052
+
3053
+ }
3054
+
3055
+ }
3056
+
3057
+ \`\`\`
3058
+
3059
+
3060
+
3061
+
3062
+ model.store.ts
3063
+
3064
+ \`\`\`
3065
+
3066
+ import { stateOf, Store } from "@akanjs/store";
3067
+
3068
+
3069
+
3070
+ import { cnst } from "../cnst";
3071
+
3072
+ import { fetch } from "../fetch";
3073
+
3074
+
3075
+
3076
+ @Store(() => cnst.\${dict.Model})
3077
+
3078
+ export class \${dict.Model}Store extends stateOf(fetch.\${dict.model}Gql, {
3079
+
3080
+ // state
3081
+
3082
+ }) {
3083
+
3084
+ // action
3085
+
3086
+ }
3087
+
3088
+ \`\`\`
3089
+
3090
+
3091
+
3092
+
3093
+ model.Zone.tsx
3094
+
3095
+ \`\`\`
3096
+
3097
+ "use client";
3098
+
3099
+ import { Data, Load } from "@shared/ui";
3100
+
3101
+ import { ModelsProps } from "@akanjs/client";
3102
+
3103
+ import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
3104
+
3105
+ import { ClientInit, ClientView, DefaultOf } from "@akanjs/signal";
3106
+
3107
+
3108
+
3109
+ export const Admin = ({ sliceName = "\${dict.model}", init, query }: ModelsProps<cnst.\${dict.Model}>>) => {
3110
+
3111
+ return (
3112
+
3113
+ <Data.ListContainer
3114
+
3115
+ init={init}
3116
+
3117
+ query={query}
3118
+
3119
+ sliceName={sliceName}
3120
+
3121
+ renderItem={\${dict.Model}.Unit.Card}
3122
+
3123
+ renderDashboard={\${dict.Model}.Util.Stat}
3124
+
3125
+ renderInsight={\${dict.Model}.Util.Insight}
3126
+
3127
+ renderTemplate={\${dict.Model}.Template.General}
3128
+
3129
+ renderTitle={(\${dict.model}: DefaultOf<cnst.\${dict.Model}>>) => \`\${dict.Model} - \${\${dict.model}.id ? \${dict.model}.id : "New"}\`}
3130
+
3131
+ renderView={(\${dict.model}: cnst.\${dict.Model}>) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />}
3132
+
3133
+ columns={[
3134
+
3135
+ "id",
3136
+
3137
+ "status",
3138
+
3139
+ "createdAt",
3140
+
3141
+ "updatedAt",
3142
+
3143
+ ]}
3144
+
3145
+ actions={(\${dict.model}: cnst.Light\${dict.Model}, idx) => ["remove", "edit", "view"]}
3146
+
3147
+ />
3148
+
3149
+ );
3150
+
3151
+ };
3152
+
3153
+
3154
+
3155
+ interface CardProps {
3156
+
3157
+ className?: string;
3158
+
3159
+ init: ClientInit<"\${dict.model}", cnst.Light\${dict.Model}>;
3160
+
3161
+ }
3162
+
3163
+ export const Card = ({ className, init }: CardProps) => {
3164
+
3165
+ return (
3166
+
3167
+ <Load.Units
3168
+
3169
+ className={className}
3170
+
3171
+ init={init}
3172
+
3173
+ renderItem={(\${dict.model}: cnst.Light\${dict.Model}) => (
3174
+
3175
+ <\${dict.Model}.Unit.Card key={\${dict.model}.id} href={\`/\${dict.model}/\${\${dict.model}.id}\`} \${dict.model}={\${dict.model}} />
3176
+
3177
+ )}
3178
+
3179
+ />
3180
+
3181
+ );
3182
+
3183
+ };
3184
+
3185
+
3186
+
3187
+ interface ViewProps {
3188
+
3189
+ className?: string;
3190
+
3191
+ view: ClientView<"\${dict.model}", cnst.\${dict.Model}>;
3192
+
3193
+ }
3194
+
3195
+ export const View = ({ view }: ViewProps) => {
3196
+
3197
+ return <Load.View view={view} renderView={(\${dict.model}) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />} />;
3198
+
3199
+ };
3200
+
3201
+ \`\`\`
3202
+
3203
+
3204
+
3205
+ model.Templete.tsx
3206
+
3207
+ \`\`\`
3208
+
3209
+ "use client";
3210
+
3211
+ import { cnst, st, usePage } from "@\${dict.appName}/client";
3212
+
3213
+ import { Field } from "@shared/ui";
3214
+
3215
+ import { Layout } from "@util/ui";
3216
+
3217
+
3218
+
3219
+ interface \${dict.Model}EditProps {
3220
+
3221
+ \${dict.model}Id?: string | null;
3222
+
3223
+ }
3224
+
3225
+
3226
+
3227
+ export const General = ({ \${dict.model}Id = undefined }: \${dict.Model}EditProps) => {
3228
+
3229
+ const \${dict.model}Form = st.use.\${dict.model}Form();
3230
+
3231
+ const { l } = usePage();
3232
+
3233
+ return (
3234
+
3235
+ <Layout.Template>
3236
+
3237
+ <Field.Text
3238
+
3239
+ label={l.field("\${dict.model}", "id")}
3240
+
3241
+ desc={l.desc("\${dict.model}", "id")}
3242
+
3243
+ value={\${dict.model}Form.id}
3244
+
3245
+ onChange={st.do.setIdOn\${dict.Model}}
3246
+
3247
+ />
3248
+
3249
+ </Layout.Template>
3250
+
3251
+ );
3252
+
3253
+ };
3254
+
3255
+ \`\`\`
3256
+
3257
+
3258
+
3259
+
3260
+ model.Unit.tsx
3261
+
3262
+ \`\`\`
3263
+
3264
+ import { ModelProps } from "@akanjs/client";
3265
+
3266
+ import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
3267
+
3268
+ import { Link } from "@util/ui";
3269
+
3270
+
3271
+
3272
+ export const Card = ({ \${dict.model}, href }: ModelProps<"\${dict.model}", cnst.Light\${dict.Model}>>) => {
3273
+
3274
+ return (
3275
+
3276
+ <Link href={href} className="animate-fadeIn w-full h-36 flex rounded-lg shadow-sm hover:shadow-lg duration-300">
3277
+
3278
+ <div>{\${dict.model}.id}</div>
3279
+
3280
+ </Link>
3281
+
3282
+ );
3283
+
3284
+ };
3285
+
3286
+ \`\`\`
3287
+
3288
+
3289
+
3290
+
3291
+ model.Util.tsx
3292
+
3293
+ \`\`\`
3294
+
3295
+ "use client";
3296
+
3297
+ import { ModelDashboardProps, ModelInsightProps } from "@akanjs/client";
3298
+
3299
+ import { getQueryMap } from "@akanjs/constant";
3300
+
3301
+ import { cnst } from "@\${dict.appName}/client";
3302
+
3303
+ import { Data } from "@shared/ui";
3304
+
3305
+
3306
+
3307
+ export const Stat = ({
3308
+
3309
+ className,
3310
+
3311
+ summary,
3312
+
3313
+ sliceName = "\${dict.model}",
3314
+
3315
+ queryMap = getQueryMap(cnst.\${dict.Model}Summary),
3316
+
3317
+ hidePresents,
3318
+
3319
+ }: ModelDashboardProps<cnst.Summary>) => {
3320
+
3321
+ return (
3322
+
3323
+ <Data.Dashboard
3324
+
3325
+ className={className}
3326
+
3327
+ summary={summary}
3328
+
3329
+ sliceName={sliceName}
3330
+
3331
+ queryMap={queryMap}
3332
+
3333
+ columns={["total\${dict.Model}"]}
3334
+
3335
+ hidePresents={hidePresents}
3336
+
3337
+ />
3338
+
3339
+ );
3340
+
3341
+ };
3342
+
3343
+
3344
+
3345
+ export const Insight = ({
3346
+
3347
+ className,
3348
+
3349
+ insight,
3350
+
3351
+ sliceName = "\${dict.model}",
3352
+
3353
+ }: ModelInsightProps<cnst.\${dict.Model}Insight>) => {
3354
+
3355
+ return (
3356
+
3357
+ <Data.Insight
3358
+
3359
+ className={className}
3360
+
3361
+ insight={insight}
3362
+
3363
+ sliceName={sliceName}
3364
+
3365
+ columns={["count"]}
3366
+
3367
+ />
3368
+
3369
+ );
3370
+
3371
+ };
3372
+
3373
+ \`\`\`
3374
+
3375
+
3376
+
3377
+
3378
+ model.View.tsx
3379
+
3380
+ \`\`\`
3381
+
3382
+ import { clsx } from "@akanjs/client";
3383
+
3384
+ import { cnst } from "@\${dict.appName}/client";
3385
+
3386
+ import { Image } from "@util/ui";
3387
+
3388
+
3389
+
3390
+ interface \${dict.Model}ViewProps {
3391
+
3392
+ className?: string;
3393
+
3394
+ \${dict.model}: cnst.\${dict.Model};
3395
+
3396
+ self?: { id?: string } | null;
3397
+
3398
+ }
3399
+
3400
+
3401
+
3402
+ export const General = ({ className, \${dict.model}, self }: \${dict.Model}ViewProps) => {
3403
+
3404
+ return (
3405
+
3406
+ <div className={clsx(className, "animate-fadeIn w-full")}>
3407
+
3408
+ <div>{\${dict.model}.id}</div>
3409
+
3410
+ </div>
3411
+
3412
+ );
3413
+
3414
+ };
3415
+
3416
+ \`\`\`
3417
+
3418
+ \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.
3419
+
3420
+
3421
+
3422
+ \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.
3423
+
3424
+ `;
2916
3425
  var moduleDesription = `
2917
3426
 
2918
3427
  The project follows a modular architecture with clear separation of concerns. Each module in lib/<model>/ represents a domain
@@ -2921,23 +3430,29 @@ entity with a standardized file structure that promotes consistency and maintain
2921
3430
  ## Core Components
2922
3431
 
2923
3432
  ### <Model>.View.tsx
2924
- Presentation-only components that render data without managing state.
2925
- It works as a server component, They accept model data as props and display it according to specific layouts.
2926
- These components focus purely on how data looks to the user.
2927
- only use the full model.
2928
- This component is only viewing the component. So don't use click event or other interaction events.
2929
- If you need interaction, possible to wrapping the component with the <Model>.Zone.tsx component.
2930
- But useable the Link component for navigation.
2931
- 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.
2932
-
3433
+ - Core Purpose: Presentation-only components that render data
3434
+ - Execution Context: Works as a server component
3435
+ - State Management: Does not manage internal state
3436
+ - Data Handling: Accepts model data as props and displays it according to specific layouts
3437
+ - Primary Focus: Focuses purely on how data looks to the user
3438
+ - Model Usage: Only uses the full model
3439
+ - Interaction Restrictions: No click events or other interaction events
3440
+ - Interaction Extension: If interaction is needed, wrap with <Model>.Zone.tsx component
3441
+ - Navigation: Link component can be used for navigation purposes
3442
+ - 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
2933
3443
 
2934
3444
  ### <Model>.Template.tsx
2935
3445
  Reusable layout patterns with integrated state management. It works as a client component, These components provide consistent UI patterns and handle data
2936
3446
  binding, often using store hooks to access application state.
2937
3447
 
2938
3448
  ### <Model>.Unit.tsx
2939
- Small, self-contained UI components representing individual model instances. It works as a server component, They're designed for rendering single items in
2940
- lists or grids, displaying model data in compact formats. only use the light model.
3449
+ - Single Component Export: Each file exports one Card component for displaying model data
3450
+ - Server-Side Rendered: React Server Components without "use client" directive
3451
+ - Type-Safe Props: Uses ModelProps<"modelName", cnst.LightModel> interface
3452
+ - Optional Navigation: useable Link component for navigation in util/ui
3453
+ - Tailwind Styling: Universal use of Tailwind CSS with DaisyUI classes
3454
+ - Model Data Display: Direct access to typed model properties and methods
3455
+
2941
3456
 
2942
3457
  ### <Model>.Zone.tsx
2943
3458
  Top-level container components that orchestrate other components. It works as a client component, They compose views, templates, and units into complete UI
@@ -2981,6 +3496,7 @@ var utilUiDescription = `
2981
3496
  The libs/util/ui directory contains a comprehensive React component library designed for modern web applications.
2982
3497
  This framework provides a complete set of production-ready, reusable UI components with consistent styling, type safety, and advanced functionality.
2983
3498
 
3499
+ [Strict caution]
2984
3500
  - Every component must be used exactly as described in the documentation.
2985
3501
  - Do not add any additional props to the components.
2986
3502
  - Must use the written props exactly.
@@ -2992,7 +3508,7 @@ var utilUiDescription = `
2992
3508
 
2993
3509
  Core Technologies:
2994
3510
  - Built on React 18+ with TypeScript for strict type safety
2995
- - Styled with Tailwind CSS and DaisyUI for consistent design system
3511
+ - Styled based on Tailwind CSS and DaisyUI base for a consistent design system.
2996
3512
  - Implements modern React patterns including hooks, context providers, and portals
2997
3513
  - Full internationalization (i18n) support for multilingual applications
2998
3514
  - Responsive-first design with mobile optimization
@@ -3816,13 +4332,13 @@ var requestView = ({
3816
4332
  1. Akan.js \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uAC1C\uC694
3817
4333
  ${frameworkAbstract}
3818
4334
 
3819
- 2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uAC1C\uC694
4335
+ 2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uC124\uBA85
3820
4336
  ${moduleDesription}
3821
4337
 
3822
- 3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uAC1C\uC694
4338
+ 3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uC124\uBA85
3823
4339
  ${eslintDescription}
3824
4340
 
3825
- 4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uAC1C\uC694
4341
+ 4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uC124\uBA85
3826
4342
  ${utilUiDescription}
3827
4343
 
3828
4344
 
@@ -3843,40 +4359,142 @@ ${properties.map(
3843
4359
  ).join("\n\n")}
3844
4360
 
3845
4361
 
3846
- 7. \uC608\uC2DC \uD30C\uC77C\uB4E4
3847
- ${exampleFiles.map(
4362
+ 7. \uC608\uC2DC \uD30C\uC77C\uB4E4
4363
+ ${exampleFiles.map(
3848
4364
  (example) => `
3849
- Example filename: ${example.filepath}
3850
- \`\`\`
3851
- ${example.content}
3852
- \`\`\`
3853
- `
4365
+ Example filename: ${example.filepath}
4366
+ \`\`\`
4367
+ ${example.content}
4368
+ \`\`\`
4369
+ `
3854
4370
  ).join("\n\n")}
3855
4371
 
3856
4372
 
3857
4373
 
4374
+
4375
+
4376
+
4377
+ \uC5ED\uD560\uBD80\uC5EC
4378
+ - Akan.js \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C \uAE30\uBC18 Typescript \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C
4379
+
4380
+ \uCF54\uB529 \uADDC\uCE59
4381
+ - \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4382
+ - \uC544\uC774\uCF58: react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4383
+ - 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)
4384
+ - \uC870\uAC74\uBD80 \uD074\uB798\uC2A4: clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4385
+ \uCF54\uB4DC \uC2A4\uD0C0\uC77C
4386
+ - \uC0C9\uC0C1: \uD558\uB4DC\uCF54\uB529(bg-red) \uB300\uC2E0 \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary) \uC0AC\uC6A9
4387
+ - \uC870\uAC74\uBD80 \uB80C\uB354\uB9C1: field && <div>... \uB300\uC2E0 field ? <div>... : null \uC0AC\uC6A9
4388
+ - \uBAA8\uB378 \uC811\uADFC: \uAD6C\uC870\uBD84\uD574\uD560\uB2F9 \uB300\uC2E0 ${modelName}.field \uD615\uC2DD\uC73C\uB85C \uC811\uADFC
4389
+ - \uD0C0\uC785 \uC548\uC804: ${modelName}.constant.ts\uC758 \uC2A4\uD0A4\uB9C8 \uCC38\uC870\uD558\uC5EC \uC5D0\uB7EC \uBC29\uC9C0
4390
+ \uD544\uB4DC \uC811\uADFC \uC804: \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8 \uC791\uC131 \uBC0F \uAC80\uD1A0 \uD544\uC218
4391
+
4392
+ \uC5C4\uACA9\uD55C \uC8FC\uC758\uC0AC\uD56D
4393
+ - UI \uD0B7\uC740 \uBB38\uC11C\uC5D0 \uBA85\uC2DC\uB41C \uCEF4\uD3EC\uB10C\uD2B8\uB9CC \uC0AC\uC6A9
4394
+ - \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC804 \uBB38\uC11C \uD655\uC778 \uBC0F props \uC815\uD655\uD788 \uAC80\uC99D
4395
+ - \uBA85\uC2DC\uB41C \uB8F0 \uC678 \uC784\uC758 \uCD94\uC0C1\uD654 \uAE08\uC9C0
4396
+
4397
+ \uC694\uCCAD\uC0AC\uD56D
4398
+ ${ModelName}.View.tsx \uCF54\uB4DC \uC791\uC131
4399
+ \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
4400
+ \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
4401
+ \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.
4402
+
4403
+
3858
4404
  Application name: ${sysName}
3859
4405
  Model name: ${modelName}
4406
+
3860
4407
  Target filename: ${ModelName}.View.tsx
4408
+ \`\`\`
4409
+
4410
+ \`\`\`
3861
4411
 
4412
+
4413
+ `;
4414
+ var requestUnit = ({
4415
+ sysName,
4416
+ modelName,
4417
+ ModelName,
4418
+ constant,
4419
+ properties,
4420
+ exampleFiles
4421
+ }) => `
4422
+
3862
4423
 
3863
- \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.
3864
- \uADF8 \uC911\uC5D0\uC11C\uB3C4 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790.
3865
- \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.
3866
- \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.
3867
- \uADF8\uB9AC\uACE0 optional\uD55C \uD544\uB4DC\uB294 field && <div>... \uAC00 \uC544\uB2CC, field ? <div>... : null \uD615\uD0DC\uB85C \uC791\uC131\uD574\uC918.
3868
- 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.
3869
- \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.
3870
- \uC870\uAC74\uBD80 className\uC774 \uD544\uC694\uD55C \uACBD\uC6B0\uC5D0\uB294 clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC\uB97C \uC0AC\uC6A9\uD574\uC57C\uB3FC.
3871
- \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.
3872
- \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.
3873
- \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...)
3874
- \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.
3875
- \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.
3876
- ${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...)
3877
- \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.
4424
+ 1. Akan.js \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uAC1C\uC694
4425
+ ${frameworkAbstract}
3878
4426
 
3879
- Target filename: ${ModelName}.View.tsx
4427
+ 2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uC124\uBA85
4428
+ ${moduleDesription}
4429
+
4430
+ 3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uC124\uBA85
4431
+ ${eslintDescription}
4432
+
4433
+ 4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uC124\uBA85
4434
+ ${utilUiDescription}
4435
+
4436
+ 5. ${ModelName}.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uC815\uBCF4
4437
+ ${constant}
4438
+
4439
+ 6. ${modelName}\uC5D0\uC11C \uC885\uC18D\uB418\uB294 \uB2E4\uB978 \uBAA8\uB378\uB4E4\uC758 \uD0C0\uC785 \uC815\uC758
4440
+ ${properties.map(
4441
+ (property) => `
4442
+ \`\`\`
4443
+ ${property.key}.constant.ts
4444
+
4445
+
4446
+ ${property.source}
4447
+ \`\`\`
4448
+ `
4449
+ ).join("\n\n")}
4450
+
4451
+
4452
+ 7. \uC608\uC2DC \uD30C\uC77C\uB4E4
4453
+ ${exampleFiles.map(
4454
+ (example) => `
4455
+ Example filename: ${example.filepath}
4456
+ \`\`\`
4457
+ ${example.content}
4458
+ \`\`\`
4459
+ `
4460
+ ).join("\n\n")}
4461
+
4462
+
4463
+
4464
+
4465
+
4466
+
4467
+ \uC5ED\uD560\uBD80\uC5EC
4468
+ - Akan.js \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C \uAE30\uBC18 Typescript \uC2DC\uB2C8\uC5B4 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790.
4469
+
4470
+ \uCF54\uB529 \uADDC\uCE59
4471
+ - \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4472
+ - \uC544\uC774\uCF58: react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4473
+ - 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)
4474
+ - \uC870\uAC74\uBD80 \uD074\uB798\uC2A4: clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
4475
+ \uCF54\uB4DC \uC2A4\uD0C0\uC77C
4476
+ - \uC0C9\uC0C1: \uD558\uB4DC\uCF54\uB529(bg-red) \uB300\uC2E0 \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary) \uC0AC\uC6A9
4477
+ - \uC870\uAC74\uBD80 \uB80C\uB354\uB9C1: field && <div>... \uB300\uC2E0 field ? <div>... : null \uC0AC\uC6A9
4478
+ - \uBAA8\uB378 \uC811\uADFC: \uAD6C\uC870\uBD84\uD574\uD560\uB2F9 \uB300\uC2E0 ${modelName}.field \uD615\uC2DD\uC73C\uB85C \uC811\uADFC
4479
+ - \uD0C0\uC785 \uC548\uC804: ${modelName}.constant.ts\uC758 \uC2A4\uD0A4\uB9C8 \uCC38\uC870\uD558\uC5EC \uC5D0\uB7EC \uBC29\uC9C0
4480
+ \uD544\uB4DC \uC811\uADFC \uC804: \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8 \uC791\uC131 \uBC0F \uAC80\uD1A0 \uD544\uC218
4481
+
4482
+ \uC5C4\uACA9\uD55C \uC8FC\uC758\uC0AC\uD56D
4483
+ - UI \uD0B7\uC740 \uBB38\uC11C\uC5D0 \uBA85\uC2DC\uB41C \uCEF4\uD3EC\uB10C\uD2B8\uB9CC \uC0AC\uC6A9
4484
+ - \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC804 \uBB38\uC11C \uD655\uC778 \uBC0F props \uC815\uD655\uD788 \uAC80\uC99D
4485
+ - \uBA85\uC2DC\uB41C \uB8F0 \uC678 \uC784\uC758 \uCD94\uC0C1\uD654 \uAE08\uC9C0
4486
+
4487
+ \uC694\uCCAD\uC0AC\uD56D
4488
+ - ${ModelName}.Unit.tsx \uCF54\uB4DC \uC791\uC131
4489
+ - \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
4490
+ - \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
4491
+ - \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.
4492
+
4493
+
4494
+ Application name: ${sysName}
4495
+ Model name: ${modelName}
4496
+
4497
+ Target filename: ${ModelName}.Unit.tsx
3880
4498
  \`\`\`
3881
4499
 
3882
4500
  \`\`\`
@@ -5316,7 +5934,6 @@ var ModuleScript = class {
5316
5934
  }
5317
5935
  async createUnit(sys2) {
5318
5936
  const libs = await sys2.getModules();
5319
- const unitExampleFiles = await sys2.getUnitsSourceCode();
5320
5937
  const lib = await select4({
5321
5938
  message: "Select the lib",
5322
5939
  choices: libs
@@ -5330,10 +5947,11 @@ var ModuleScript = class {
5330
5947
  if (!name)
5331
5948
  return;
5332
5949
  const Name = capitalize(name);
5950
+ const unitExampleFiles = (await sys2.getUnitsSourceCode()).filter((f) => !f.filepath.includes(`${name}.Unit.tsx`));
5333
5951
  const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
5334
5952
  const constant = fs12.readFileSync(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`, "utf-8");
5335
5953
  const session = new AiSession();
5336
- const promptRst = requestView({
5954
+ const promptRst = requestUnit({
5337
5955
  sysName: sys2.name,
5338
5956
  modelName: name,
5339
5957
  ModelName: Name,
@@ -5342,8 +5960,8 @@ var ModuleScript = class {
5342
5960
  exampleFiles: randomPicks(unitExampleFiles, Math.min(10, unitExampleFiles.length))
5343
5961
  });
5344
5962
  const content = await session.editTypescript(promptRst);
5345
- fs12.writeFileSync(`${sys2.cwdPath}/prompt.txt`, promptRst);
5346
- fs12.writeFileSync(`${sys2.cwdPath}/result.txt`, content);
5963
+ fs12.writeFileSync(`${sys2.cwdPath}/promptUnit.txt`, promptRst);
5964
+ fs12.writeFileSync(`${sys2.cwdPath}/resultUnit.txt`, content);
5347
5965
  }
5348
5966
  async createView(sys2) {
5349
5967
  const libs = await sys2.getModules();
@@ -5359,7 +5977,7 @@ var ModuleScript = class {
5359
5977
  const name = lib.split("/").pop();
5360
5978
  if (!name)
5361
5979
  return;
5362
- const viewExampleFiles = (await sys2.getViewsSourceCode()).filter((f) => f.filepath.includes(`${name}.View.tsx`));
5980
+ const viewExampleFiles = (await sys2.getViewsSourceCode()).filter((f) => !f.filepath.includes(`${name}.View.tsx`));
5363
5981
  const Name = capitalize(name);
5364
5982
  const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
5365
5983
  const constant = fs12.readFileSync(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`, "utf-8");
@@ -5398,7 +6016,8 @@ var ModuleCommand = class {
5398
6016
  async createView(sys2, workspace) {
5399
6017
  await this.moduleScript.createView(sys2);
5400
6018
  }
5401
- async createUnit(name, workspace) {
6019
+ async createUnit(sys2, workspace) {
6020
+ await this.moduleScript.createUnit(sys2);
5402
6021
  }
5403
6022
  };
5404
6023
  __decorateClass([
@@ -5441,7 +6060,7 @@ __decorateClass([
5441
6060
  ], ModuleCommand.prototype, "createView", 1);
5442
6061
  __decorateClass([
5443
6062
  Target.Public(),
5444
- __decorateParam(0, Option("name", { desc: "name of unit module" })),
6063
+ __decorateParam(0, Sys()),
5445
6064
  __decorateParam(1, Workspace())
5446
6065
  ], ModuleCommand.prototype, "createUnit", 1);
5447
6066
  ModuleCommand = __decorateClass([
@@ -5521,60 +6140,12 @@ PageCommand = __decorateClass([
5521
6140
  Commands()
5522
6141
  ], PageCommand);
5523
6142
 
5524
- // pkgs/@akanjs/cli/src/workspace/workspace.script.ts
5525
- import latestVersion2 from "latest-version";
5526
- import path6 from "path";
5527
-
5528
6143
  // pkgs/@akanjs/cli/src/workspace/workspace.runner.ts
5529
6144
  import { v5 as uuid } from "uuid";
6145
+ import { capitalize as capitalize2 } from "lodash";
6146
+ import latestVersion2 from "latest-version";
6147
+ import path6 from "path";
5530
6148
  var WorkspaceRunner = class {
5531
- async createWorkspace(repoName, appName, dirname = ".") {
5532
- }
5533
- async generateMongo(workspace) {
5534
- const namespace = "00000000-0000-0000-0000-000000000000";
5535
- const appNames = await workspace.getApps();
5536
- const apps = appNames.map((appName) => AppExecutor.from(workspace, appName));
5537
- const appDatas = apps.reduce(
5538
- (acc, app) => [
5539
- ...acc,
5540
- ...["debug", "develop", "main"].map((env) => ({
5541
- appName: app.name,
5542
- env,
5543
- secret: getCredentials(app, env)
5544
- }))
5545
- ],
5546
- []
5547
- );
5548
- const mongoConnectionList = {
5549
- type: "Compass Connections",
5550
- version: { $numberInt: "1" },
5551
- connections: appDatas.map(({ appName, env, secret }) => ({
5552
- id: uuid(`${appName}-${env}`, namespace),
5553
- favorite: {
5554
- name: `${appName}-${env}`,
5555
- color: "color9"
5556
- },
5557
- savedConnectionType: "favorite",
5558
- connectionOptions: {
5559
- connectionString: `mongodb://${secret.mongo.account.user.username}:${secret.mongo.account.user.password}@mongo-0.mongo-svc.${appName}-${env}/?directConnection=true&authSource=${appName}-${env}`,
5560
- sshTunnel: {
5561
- host: `${appName}-${env}.akamir.com`,
5562
- port: "32767",
5563
- username: "root",
5564
- password: "akamir"
5565
- }
5566
- }
5567
- }))
5568
- };
5569
- workspace.writeJson(`infra/master/mongo-connections.json`, mongoConnectionList);
5570
- }
5571
- };
5572
-
5573
- // pkgs/@akanjs/cli/src/workspace/workspace.script.ts
5574
- var WorkspaceScript = class {
5575
- #runner = new WorkspaceRunner();
5576
- applicationScript = new ApplicationScript();
5577
- libraryScript = new LibraryScript();
5578
6149
  async createWorkspace(repoName, appName, dirname = ".") {
5579
6150
  const cwdPath = process.cwd();
5580
6151
  const workspaceRoot = path6.join(cwdPath, dirname, repoName);
@@ -5584,9 +6155,9 @@ var WorkspaceScript = class {
5584
6155
  template: "workspaceRoot",
5585
6156
  dict: {
5586
6157
  repoName,
5587
- RepoName: capitalize(repoName),
6158
+ RepoName: capitalize2(repoName),
5588
6159
  appName,
5589
- AppName: capitalize(appName),
6160
+ AppName: capitalize2(appName),
5590
6161
  serveDomain: "localhost"
5591
6162
  }
5592
6163
  });
@@ -5626,9 +6197,60 @@ var WorkspaceScript = class {
5626
6197
  await workspace.spawn("pnpm", ["install", "--reporter=silent"]);
5627
6198
  workspace.log("Initializing git repository and commit...");
5628
6199
  await workspace.commit("Initial commit", { init: true });
6200
+ return workspace;
6201
+ }
6202
+ async generateMongo(workspace) {
6203
+ const namespace = "00000000-0000-0000-0000-000000000000";
6204
+ const appNames = await workspace.getApps();
6205
+ const apps = appNames.map((appName) => AppExecutor.from(workspace, appName));
6206
+ const appDatas = apps.reduce(
6207
+ (acc, app) => [
6208
+ ...acc,
6209
+ ...["debug", "develop", "main"].map((env) => ({
6210
+ appName: app.name,
6211
+ env,
6212
+ secret: getCredentials(app, env)
6213
+ }))
6214
+ ],
6215
+ []
6216
+ );
6217
+ const mongoConnectionList = {
6218
+ type: "Compass Connections",
6219
+ version: { $numberInt: "1" },
6220
+ connections: appDatas.map(({ appName, env, secret }) => ({
6221
+ id: uuid(`${appName}-${env}`, namespace),
6222
+ favorite: {
6223
+ name: `${appName}-${env}`,
6224
+ color: "color9"
6225
+ },
6226
+ savedConnectionType: "favorite",
6227
+ connectionOptions: {
6228
+ connectionString: `mongodb://${secret.mongo.account.user.username}:${secret.mongo.account.user.password}@mongo-0.mongo-svc.${appName}-${env}/?directConnection=true&authSource=${appName}-${env}`,
6229
+ sshTunnel: {
6230
+ host: `${appName}-${env}.akamir.com`,
6231
+ port: "32767",
6232
+ username: "root",
6233
+ password: "akamir"
6234
+ }
6235
+ }
6236
+ }))
6237
+ };
6238
+ workspace.writeJson(`infra/master/mongo-connections.json`, mongoConnectionList);
6239
+ }
6240
+ };
6241
+
6242
+ // pkgs/@akanjs/cli/src/workspace/workspace.script.ts
6243
+ var WorkspaceScript = class {
6244
+ #runner = new WorkspaceRunner();
6245
+ applicationScript = new ApplicationScript();
6246
+ libraryScript = new LibraryScript();
6247
+ async createWorkspace(repoName, appName, dirname = ".") {
6248
+ const workspace = await this.#runner.createWorkspace(repoName, appName, dirname);
5629
6249
  await this.libraryScript.installLibrary(workspace, "util");
5630
6250
  await this.libraryScript.installLibrary(workspace, "shared");
5631
6251
  await this.applicationScript.createApplication(appName, workspace);
6252
+ workspace.log(`Workspace created in ${workspace.workspaceRoot}`);
6253
+ Logger.rawLog(`Run \`cd ${repoName} && akan start ${appName}\` to start the development server.`);
5632
6254
  }
5633
6255
  async generateMongo(workspace) {
5634
6256
  await this.#runner.generateMongo(workspace);
@@ -5678,4 +6300,5 @@ void runCommands(
5678
6300
  //! 2. csr폴더를 현 위치로 복사 후 압축 후 삭제
5679
6301
  //! execSync를 가져오기 싫으니 일단 2번 방법으로 해보자
5680
6302
  //! add path in tsconfig.json
6303
+ //! 파일을 {name}.Unit.tsx에 저장.
5681
6304
  //! 파일을 {name}.View.tsx에 저장.