create-einja-app 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/README.md +307 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +1041 -0
  4. package/dist/cli.js.map +1 -0
  5. package/package.json +62 -0
  6. package/templates/turborepo-pandacss/.biomeignore +15 -0
  7. package/templates/turborepo-pandacss/.claude/hooks/einja/biome-format.sh +49 -0
  8. package/templates/turborepo-pandacss/.claude/hooks/einja/design-doc-check.sh +61 -0
  9. package/templates/turborepo-pandacss/.claude/hooks/einja/detect-secrets.sh +62 -0
  10. package/templates/turborepo-pandacss/.claude/hooks/einja/large-file-warning.sh +42 -0
  11. package/templates/turborepo-pandacss/.claude/hooks/einja/playwright-resize.sh +36 -0
  12. package/templates/turborepo-pandacss/.claude/hooks/einja/typecheck.sh +37 -0
  13. package/templates/turborepo-pandacss/.claude/hooks/einja/unset-volta-recursion.sh +32 -0
  14. package/templates/turborepo-pandacss/.claude/hooks/einja/validate-git-commit.sh +239 -0
  15. package/templates/turborepo-pandacss/.claude/hooks/einja/warn-index-ts.sh +34 -0
  16. package/templates/turborepo-pandacss/.claude/hooks/einja/warn-relative-import.sh +48 -0
  17. package/templates/turborepo-pandacss/.claude/settings.json +174 -0
  18. package/templates/turborepo-pandacss/.claude/skills/create-einja-app-release/SKILL.md +186 -0
  19. package/templates/turborepo-pandacss/.claude/skills/dev-cli-release/SKILL.md +173 -0
  20. package/templates/turborepo-pandacss/.cursor/commands/spec-create.md +227 -0
  21. package/templates/turborepo-pandacss/.cursor/commands/start-dev.md +98 -0
  22. package/templates/turborepo-pandacss/.cursor/commands/task-exec.md +287 -0
  23. package/templates/turborepo-pandacss/.cursor/commands/task-vibe-kanban-loop.md +532 -0
  24. package/templates/turborepo-pandacss/.cursor/commands/update-docs-by-task-specs.md +448 -0
  25. package/templates/turborepo-pandacss/.cursor/mcp.json +45 -0
  26. package/templates/turborepo-pandacss/.cursor/rules/api-rules.mdc +171 -0
  27. package/templates/turborepo-pandacss/.cursor/rules/api-test-rules.mdc +181 -0
  28. package/templates/turborepo-pandacss/.cursor/rules/base-code.mdc +70 -0
  29. package/templates/turborepo-pandacss/.cursor/rules/base-commit-rules.mdc +174 -0
  30. package/templates/turborepo-pandacss/.cursor/rules/base-design.mdc +12 -0
  31. package/templates/turborepo-pandacss/.cursor/rules/base-rules.mdc +231 -0
  32. package/templates/turborepo-pandacss/.cursor/rules/error-handling-rules.mdc +188 -0
  33. package/templates/turborepo-pandacss/.cursor/rules/refactor-rules.mdc +93 -0
  34. package/templates/turborepo-pandacss/.dockerignore +126 -0
  35. package/templates/turborepo-pandacss/.einja-sync.json +35 -0
  36. package/templates/turborepo-pandacss/.env.ci +25 -0
  37. package/templates/turborepo-pandacss/.env.example +35 -0
  38. package/templates/turborepo-pandacss/.env.personal.example +27 -0
  39. package/templates/turborepo-pandacss/.envrc +4 -0
  40. package/templates/turborepo-pandacss/.gitattributes +5 -0
  41. package/templates/turborepo-pandacss/.husky/pre-commit +1 -0
  42. package/templates/turborepo-pandacss/.lintstagedrc.js +24 -0
  43. package/templates/turborepo-pandacss/.mcp.json +45 -0
  44. package/templates/turborepo-pandacss/.node-version +1 -0
  45. package/templates/turborepo-pandacss/.templateignore +60 -0
  46. package/templates/turborepo-pandacss/.vscode/extensions.json +3 -0
  47. package/templates/turborepo-pandacss/CLAUDE.md +415 -0
  48. package/templates/turborepo-pandacss/README.md +322 -0
  49. package/templates/turborepo-pandacss/apps/web/middleware.ts +28 -0
  50. package/templates/turborepo-pandacss/apps/web/next.config.ts +10 -0
  51. package/templates/turborepo-pandacss/apps/web/package.json +80 -0
  52. package/templates/turborepo-pandacss/apps/web/panda.config.ts +114 -0
  53. package/templates/turborepo-pandacss/apps/web/postcss.config.cjs +6 -0
  54. package/templates/turborepo-pandacss/apps/web/public/file.svg +1 -0
  55. package/templates/turborepo-pandacss/apps/web/public/globe.svg +1 -0
  56. package/templates/turborepo-pandacss/apps/web/public/next.svg +1 -0
  57. package/templates/turborepo-pandacss/apps/web/public/vercel.svg +1 -0
  58. package/templates/turborepo-pandacss/apps/web/public/window.svg +1 -0
  59. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/dashboard/page.tsx +79 -0
  60. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/data/_components/UserTable.tsx +203 -0
  61. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/data/page.tsx +57 -0
  62. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/layout-client.tsx +31 -0
  63. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/layout.tsx +17 -0
  64. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/profile/page.tsx +59 -0
  65. package/templates/turborepo-pandacss/apps/web/src/app/api/auth/[...nextauth]/route.ts +3 -0
  66. package/templates/turborepo-pandacss/apps/web/src/app/api/auth/signup/route.ts +70 -0
  67. package/templates/turborepo-pandacss/apps/web/src/app/error.tsx +106 -0
  68. package/templates/turborepo-pandacss/apps/web/src/app/favicon.ico +0 -0
  69. package/templates/turborepo-pandacss/apps/web/src/app/global-error.tsx +110 -0
  70. package/templates/turborepo-pandacss/apps/web/src/app/globals.css +121 -0
  71. package/templates/turborepo-pandacss/apps/web/src/app/layout.tsx +28 -0
  72. package/templates/turborepo-pandacss/apps/web/src/app/not-found.tsx +54 -0
  73. package/templates/turborepo-pandacss/apps/web/src/app/page.module.css +165 -0
  74. package/templates/turborepo-pandacss/apps/web/src/app/page.test.tsx +52 -0
  75. package/templates/turborepo-pandacss/apps/web/src/app/page.tsx +284 -0
  76. package/templates/turborepo-pandacss/apps/web/src/app/signin/page.tsx +296 -0
  77. package/templates/turborepo-pandacss/apps/web/src/app/signup/page.tsx +395 -0
  78. package/templates/turborepo-pandacss/apps/web/src/application/use-cases/UserUseCases.test.ts +229 -0
  79. package/templates/turborepo-pandacss/apps/web/src/application/use-cases/UserUseCases.ts +115 -0
  80. package/templates/turborepo-pandacss/apps/web/src/components/auth/login-button.tsx +35 -0
  81. package/templates/turborepo-pandacss/apps/web/src/components/auth/logout-button.tsx +24 -0
  82. package/templates/turborepo-pandacss/apps/web/src/components/auth/user-avatar.test.tsx +68 -0
  83. package/templates/turborepo-pandacss/apps/web/src/components/auth/user-avatar.tsx +43 -0
  84. package/templates/turborepo-pandacss/apps/web/src/components/dashboard/dashboard-stats.tsx +128 -0
  85. package/templates/turborepo-pandacss/apps/web/src/components/providers/query-provider.tsx +30 -0
  86. package/templates/turborepo-pandacss/apps/web/src/components/providers/session-provider.tsx +12 -0
  87. package/templates/turborepo-pandacss/apps/web/src/components/shared/Sidebar.tsx +175 -0
  88. package/templates/turborepo-pandacss/apps/web/src/components/shared/header.tsx +166 -0
  89. package/templates/turborepo-pandacss/apps/web/src/components/ui/accordion.tsx +64 -0
  90. package/templates/turborepo-pandacss/apps/web/src/components/ui/alert-dialog.tsx +135 -0
  91. package/templates/turborepo-pandacss/apps/web/src/components/ui/alert.tsx +60 -0
  92. package/templates/turborepo-pandacss/apps/web/src/components/ui/aspect-ratio.tsx +9 -0
  93. package/templates/turborepo-pandacss/apps/web/src/components/ui/avatar.tsx +41 -0
  94. package/templates/turborepo-pandacss/apps/web/src/components/ui/badge.tsx +39 -0
  95. package/templates/turborepo-pandacss/apps/web/src/components/ui/breadcrumb.tsx +101 -0
  96. package/templates/turborepo-pandacss/apps/web/src/components/ui/button.tsx +56 -0
  97. package/templates/turborepo-pandacss/apps/web/src/components/ui/card.tsx +75 -0
  98. package/templates/turborepo-pandacss/apps/web/src/components/ui/checkbox.tsx +29 -0
  99. package/templates/turborepo-pandacss/apps/web/src/components/ui/data-table.tsx +189 -0
  100. package/templates/turborepo-pandacss/apps/web/src/components/ui/dialog-hook.tsx +210 -0
  101. package/templates/turborepo-pandacss/apps/web/src/components/ui/dialog.tsx +129 -0
  102. package/templates/turborepo-pandacss/apps/web/src/components/ui/drawer.tsx +124 -0
  103. package/templates/turborepo-pandacss/apps/web/src/components/ui/dropdown-menu.tsx +228 -0
  104. package/templates/turborepo-pandacss/apps/web/src/components/ui/form.tsx +152 -0
  105. package/templates/turborepo-pandacss/apps/web/src/components/ui/hover-card.tsx +38 -0
  106. package/templates/turborepo-pandacss/apps/web/src/components/ui/input.tsx +21 -0
  107. package/templates/turborepo-pandacss/apps/web/src/components/ui/label.tsx +21 -0
  108. package/templates/turborepo-pandacss/apps/web/src/components/ui/pagination.tsx +105 -0
  109. package/templates/turborepo-pandacss/apps/web/src/components/ui/popover.tsx +42 -0
  110. package/templates/turborepo-pandacss/apps/web/src/components/ui/progress.tsx +28 -0
  111. package/templates/turborepo-pandacss/apps/web/src/components/ui/select.tsx +170 -0
  112. package/templates/turborepo-pandacss/apps/web/src/components/ui/separator.tsx +28 -0
  113. package/templates/turborepo-pandacss/apps/web/src/components/ui/skeleton.tsx +13 -0
  114. package/templates/turborepo-pandacss/apps/web/src/components/ui/sonner.tsx +25 -0
  115. package/templates/turborepo-pandacss/apps/web/src/components/ui/table.tsx +92 -0
  116. package/templates/turborepo-pandacss/apps/web/src/components/ui/tabs.tsx +54 -0
  117. package/templates/turborepo-pandacss/apps/web/src/components/ui/textarea.tsx +18 -0
  118. package/templates/turborepo-pandacss/apps/web/src/components/ui/tooltip.tsx +57 -0
  119. package/templates/turborepo-pandacss/apps/web/src/components/ui/typography.tsx +158 -0
  120. package/templates/turborepo-pandacss/apps/web/src/lib/auth/guard.ts +36 -0
  121. package/templates/turborepo-pandacss/apps/web/src/lib/auth/index.ts +22 -0
  122. package/templates/turborepo-pandacss/apps/web/src/lib/prisma.ts +3 -0
  123. package/templates/turborepo-pandacss/apps/web/src/lib/utils.ts +6 -0
  124. package/templates/turborepo-pandacss/apps/web/test/globals.d.ts +1 -0
  125. package/templates/turborepo-pandacss/apps/web/test/matchers.d.ts +1 -0
  126. package/templates/turborepo-pandacss/apps/web/test/setup.ts +22 -0
  127. package/templates/turborepo-pandacss/apps/web/tsconfig.json +37 -0
  128. package/templates/turborepo-pandacss/apps/web/vitest.config.ts +20 -0
  129. package/templates/turborepo-pandacss/apps/web/vitest.d.ts +2 -0
  130. package/templates/turborepo-pandacss/biome.json +60 -0
  131. package/templates/turborepo-pandacss/components.json +21 -0
  132. package/templates/turborepo-pandacss/docker-compose.yml +27 -0
  133. package/templates/turborepo-pandacss/middleware.ts +32 -0
  134. package/templates/turborepo-pandacss/next.config.ts +10 -0
  135. package/templates/turborepo-pandacss/package-lock.json +9346 -0
  136. package/templates/turborepo-pandacss/package.json +64 -0
  137. package/templates/turborepo-pandacss/packages/config/package.json +41 -0
  138. package/templates/turborepo-pandacss/packages/config/panda.config.ts +114 -0
  139. package/templates/turborepo-pandacss/packages/config/src/index.ts +24 -0
  140. package/templates/turborepo-pandacss/packages/config/src/worktree-config-loader.ts +129 -0
  141. package/templates/turborepo-pandacss/packages/config/src/worktree-config.ts +75 -0
  142. package/templates/turborepo-pandacss/packages/config/tsconfig.build.json +19 -0
  143. package/templates/turborepo-pandacss/packages/config/tsconfig.json +24 -0
  144. package/templates/turborepo-pandacss/packages/config/typescript/base.json +19 -0
  145. package/templates/turborepo-pandacss/packages/front-core/package.json +24 -0
  146. package/templates/turborepo-pandacss/packages/front-core/src/auth/config.ts +84 -0
  147. package/templates/turborepo-pandacss/packages/front-core/src/auth/index.ts +5 -0
  148. package/templates/turborepo-pandacss/packages/front-core/src/auth/types/next-auth.d.ts +20 -0
  149. package/templates/turborepo-pandacss/packages/front-core/src/auth/utils.ts +29 -0
  150. package/templates/turborepo-pandacss/packages/front-core/src/context/index.ts +2 -0
  151. package/templates/turborepo-pandacss/packages/front-core/src/hooks/index.ts +2 -0
  152. package/templates/turborepo-pandacss/packages/front-core/src/index.ts +4 -0
  153. package/templates/turborepo-pandacss/packages/front-core/src/utils/index.ts +2 -0
  154. package/templates/turborepo-pandacss/packages/front-core/tsconfig.json +14 -0
  155. package/templates/turborepo-pandacss/packages/server-core/package.json +32 -0
  156. package/templates/turborepo-pandacss/packages/server-core/prisma/schema.prisma +102 -0
  157. package/templates/turborepo-pandacss/packages/server-core/prisma/seed.ts +67 -0
  158. package/templates/turborepo-pandacss/packages/server-core/prisma.config.ts +8 -0
  159. package/templates/turborepo-pandacss/packages/server-core/src/__generated__/fabbrica/index.d.ts +270 -0
  160. package/templates/turborepo-pandacss/packages/server-core/src/__generated__/fabbrica/index.js +484 -0
  161. package/templates/turborepo-pandacss/packages/server-core/src/core/result.test.ts +78 -0
  162. package/templates/turborepo-pandacss/packages/server-core/src/core/result.ts +53 -0
  163. package/templates/turborepo-pandacss/packages/server-core/src/domain/.gitkeep +0 -0
  164. package/templates/turborepo-pandacss/packages/server-core/src/domain/entities/User.test.ts +232 -0
  165. package/templates/turborepo-pandacss/packages/server-core/src/domain/entities/User.ts +105 -0
  166. package/templates/turborepo-pandacss/packages/server-core/src/domain/repository-interfaces/IUserRepository.ts +101 -0
  167. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/client.ts +15 -0
  168. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/mappers/UserMapper.test.ts +278 -0
  169. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/mappers/UserMapper.ts +103 -0
  170. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/repositories/UserRepository.test.ts +317 -0
  171. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/repositories/UserRepository.ts +169 -0
  172. package/templates/turborepo-pandacss/packages/server-core/src/testing/factories/index.ts +22 -0
  173. package/templates/turborepo-pandacss/packages/server-core/src/testing/factories/user.factory.ts +123 -0
  174. package/templates/turborepo-pandacss/packages/server-core/src/testing/fixtures/users.ts +92 -0
  175. package/templates/turborepo-pandacss/packages/server-core/src/testing/helpers/date.ts +49 -0
  176. package/templates/turborepo-pandacss/packages/server-core/src/testing/helpers/password.ts +50 -0
  177. package/templates/turborepo-pandacss/packages/server-core/src/testing/index.ts +26 -0
  178. package/templates/turborepo-pandacss/packages/server-core/tsconfig.json +14 -0
  179. package/templates/turborepo-pandacss/packages/server-core/vitest.config.ts +15 -0
  180. package/templates/turborepo-pandacss/packages/ui/package.json +37 -0
  181. package/templates/turborepo-pandacss/packages/ui/src/accordion.tsx +66 -0
  182. package/templates/turborepo-pandacss/packages/ui/src/alert-dialog.tsx +157 -0
  183. package/templates/turborepo-pandacss/packages/ui/src/alert.tsx +66 -0
  184. package/templates/turborepo-pandacss/packages/ui/src/aspect-ratio.tsx +11 -0
  185. package/templates/turborepo-pandacss/packages/ui/src/avatar.tsx +53 -0
  186. package/templates/turborepo-pandacss/packages/ui/src/badge.tsx +46 -0
  187. package/templates/turborepo-pandacss/packages/ui/src/breadcrumb.tsx +108 -0
  188. package/templates/turborepo-pandacss/packages/ui/src/button.tsx +59 -0
  189. package/templates/turborepo-pandacss/packages/ui/src/card.tsx +92 -0
  190. package/templates/turborepo-pandacss/packages/ui/src/checkbox.tsx +32 -0
  191. package/templates/turborepo-pandacss/packages/ui/src/data-table.tsx +216 -0
  192. package/templates/turborepo-pandacss/packages/ui/src/dialog-hook.tsx +226 -0
  193. package/templates/turborepo-pandacss/packages/ui/src/dialog.tsx +143 -0
  194. package/templates/turborepo-pandacss/packages/ui/src/drawer.tsx +135 -0
  195. package/templates/turborepo-pandacss/packages/ui/src/dropdown-menu.tsx +257 -0
  196. package/templates/turborepo-pandacss/packages/ui/src/form.tsx +168 -0
  197. package/templates/turborepo-pandacss/packages/ui/src/hover-card.tsx +44 -0
  198. package/templates/turborepo-pandacss/packages/ui/src/input.tsx +21 -0
  199. package/templates/turborepo-pandacss/packages/ui/src/label.tsx +24 -0
  200. package/templates/turborepo-pandacss/packages/ui/src/lib/utils.ts +6 -0
  201. package/templates/turborepo-pandacss/packages/ui/src/pagination.tsx +126 -0
  202. package/templates/turborepo-pandacss/packages/ui/src/popover.tsx +48 -0
  203. package/templates/turborepo-pandacss/packages/ui/src/progress.tsx +31 -0
  204. package/templates/turborepo-pandacss/packages/ui/src/select.tsx +185 -0
  205. package/templates/turborepo-pandacss/packages/ui/src/separator.tsx +28 -0
  206. package/templates/turborepo-pandacss/packages/ui/src/skeleton.tsx +13 -0
  207. package/templates/turborepo-pandacss/packages/ui/src/sonner.tsx +25 -0
  208. package/templates/turborepo-pandacss/packages/ui/src/table.tsx +116 -0
  209. package/templates/turborepo-pandacss/packages/ui/src/tabs.tsx +66 -0
  210. package/templates/turborepo-pandacss/packages/ui/src/textarea.tsx +18 -0
  211. package/templates/turborepo-pandacss/packages/ui/src/tooltip.tsx +61 -0
  212. package/templates/turborepo-pandacss/packages/ui/src/typography.tsx +187 -0
  213. package/templates/turborepo-pandacss/packages/ui/tsconfig.json +20 -0
  214. package/templates/turborepo-pandacss/panda.config.ts +114 -0
  215. package/templates/turborepo-pandacss/pnpm-lock.yaml +9032 -0
  216. package/templates/turborepo-pandacss/pnpm-workspace.yaml +11 -0
  217. package/templates/turborepo-pandacss/postcss.config.cjs +6 -0
  218. package/templates/turborepo-pandacss/prisma/schema.prisma +82 -0
  219. package/templates/turborepo-pandacss/public/file.svg +1 -0
  220. package/templates/turborepo-pandacss/public/globe.svg +1 -0
  221. package/templates/turborepo-pandacss/public/next.svg +1 -0
  222. package/templates/turborepo-pandacss/public/vercel.svg +1 -0
  223. package/templates/turborepo-pandacss/public/window.svg +1 -0
  224. package/templates/turborepo-pandacss/scripts/cli-template-update.ts +387 -0
  225. package/templates/turborepo-pandacss/scripts/env-show.ts +129 -0
  226. package/templates/turborepo-pandacss/scripts/env.ts +555 -0
  227. package/templates/turborepo-pandacss/scripts/init.sh +92 -0
  228. package/templates/turborepo-pandacss/scripts/setup-dev.ts +640 -0
  229. package/templates/turborepo-pandacss/scripts/template-update.ts +277 -0
  230. package/templates/turborepo-pandacss/scripts/worktree/dev.ts +872 -0
  231. package/templates/turborepo-pandacss/test/globals.d.ts +1 -0
  232. package/templates/turborepo-pandacss/test/setup.ts +22 -0
  233. package/templates/turborepo-pandacss/tsconfig.json +46 -0
  234. package/templates/turborepo-pandacss/turbo.json +57 -0
  235. package/templates/turborepo-pandacss/vitest.config.ts +20 -0
@@ -0,0 +1,203 @@
1
+ "use client";
2
+
3
+ import type { UserListItem } from "@/application/use-cases/UserUseCases";
4
+ import { Badge } from "@/components/ui/badge";
5
+ import { Button } from "@/components/ui/button";
6
+ import { DataTable } from "@/components/ui/data-table";
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuItem,
11
+ DropdownMenuTrigger,
12
+ } from "@/components/ui/dropdown-menu";
13
+ import type { ColumnDef } from "@tanstack/react-table";
14
+ import { ArrowUpDown, Edit, Eye, MoreHorizontal, Trash2 } from "lucide-react";
15
+
16
+ /**
17
+ * ステータスバッジを表示
18
+ */
19
+ function getStatusBadge(status: UserListItem["status"]) {
20
+ switch (status) {
21
+ case "active":
22
+ return <Badge variant="default">アクティブ</Badge>;
23
+ case "inactive":
24
+ return <Badge variant="secondary">非アクティブ</Badge>;
25
+ case "pending":
26
+ return <Badge variant="outline">保留中</Badge>;
27
+ default:
28
+ return <Badge variant="outline">{status}</Badge>;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * ロールバッジを表示
34
+ */
35
+ function getRoleBadge(role: UserListItem["role"]) {
36
+ switch (role) {
37
+ case "admin":
38
+ return <Badge variant="destructive">管理者</Badge>;
39
+ case "moderator":
40
+ return <Badge variant="default">モデレーター</Badge>;
41
+ case "user":
42
+ return <Badge variant="secondary">ユーザー</Badge>;
43
+ default:
44
+ return <Badge variant="outline">{role}</Badge>;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * 日付をフォーマット
50
+ */
51
+ function formatDate(dateString: string | null): string {
52
+ if (!dateString) return "-";
53
+ const date = new Date(dateString);
54
+ return date.toLocaleDateString("ja-JP");
55
+ }
56
+
57
+ /**
58
+ * テーブルの列定義
59
+ */
60
+ const columns: ColumnDef<UserListItem>[] = [
61
+ {
62
+ accessorKey: "name",
63
+ header: ({ column }) => {
64
+ return (
65
+ <Button
66
+ variant="ghost"
67
+ onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
68
+ >
69
+ 名前
70
+ <ArrowUpDown className="ml-2 h-4 w-4" />
71
+ </Button>
72
+ );
73
+ },
74
+ cell: ({ row }) => {
75
+ const name = row.getValue("name") as string;
76
+ return <div className="font-medium">{name || "-"}</div>;
77
+ },
78
+ },
79
+ {
80
+ accessorKey: "email",
81
+ header: ({ column }) => {
82
+ return (
83
+ <Button
84
+ variant="ghost"
85
+ onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
86
+ >
87
+ メールアドレス
88
+ <ArrowUpDown className="ml-2 h-4 w-4" />
89
+ </Button>
90
+ );
91
+ },
92
+ cell: ({ row }) => {
93
+ return <div className="text-muted-foreground">{row.getValue("email")}</div>;
94
+ },
95
+ },
96
+ {
97
+ accessorKey: "status",
98
+ header: "ステータス",
99
+ cell: ({ row }) => {
100
+ const status = row.getValue("status") as UserListItem["status"];
101
+ return getStatusBadge(status);
102
+ },
103
+ },
104
+ {
105
+ accessorKey: "role",
106
+ header: "ロール",
107
+ cell: ({ row }) => {
108
+ const role = row.getValue("role") as UserListItem["role"];
109
+ return getRoleBadge(role);
110
+ },
111
+ },
112
+ {
113
+ accessorKey: "createdAt",
114
+ header: ({ column }) => {
115
+ return (
116
+ <Button
117
+ variant="ghost"
118
+ onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
119
+ >
120
+ 作成日
121
+ <ArrowUpDown className="ml-2 h-4 w-4" />
122
+ </Button>
123
+ );
124
+ },
125
+ cell: ({ row }) => {
126
+ return <div>{formatDate(row.getValue("createdAt"))}</div>;
127
+ },
128
+ },
129
+ {
130
+ accessorKey: "lastLogin",
131
+ header: ({ column }) => {
132
+ return (
133
+ <Button
134
+ variant="ghost"
135
+ onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
136
+ >
137
+ 最終ログイン
138
+ <ArrowUpDown className="ml-2 h-4 w-4" />
139
+ </Button>
140
+ );
141
+ },
142
+ cell: ({ row }) => {
143
+ return <div>{formatDate(row.getValue("lastLogin"))}</div>;
144
+ },
145
+ },
146
+ {
147
+ id: "actions",
148
+ header: "操作",
149
+ enableHiding: false,
150
+ cell: ({ row }) => {
151
+ const user = row.original;
152
+
153
+ return (
154
+ <DropdownMenu>
155
+ <DropdownMenuTrigger asChild>
156
+ <Button variant="ghost" className="h-8 w-8 p-0">
157
+ <span className="sr-only">メニューを開く</span>
158
+ <MoreHorizontal className="h-4 w-4" />
159
+ </Button>
160
+ </DropdownMenuTrigger>
161
+ <DropdownMenuContent align="end">
162
+ <DropdownMenuItem onClick={() => console.log("詳細表示:", user.id)}>
163
+ <Eye className="mr-2 h-4 w-4" />
164
+ 詳細表示
165
+ </DropdownMenuItem>
166
+ <DropdownMenuItem onClick={() => console.log("編集:", user.id)}>
167
+ <Edit className="mr-2 h-4 w-4" />
168
+ 編集
169
+ </DropdownMenuItem>
170
+ <DropdownMenuItem
171
+ onClick={() => console.log("削除:", user.id)}
172
+ className="text-destructive"
173
+ >
174
+ <Trash2 className="mr-2 h-4 w-4" />
175
+ 削除
176
+ </DropdownMenuItem>
177
+ </DropdownMenuContent>
178
+ </DropdownMenu>
179
+ );
180
+ },
181
+ },
182
+ ];
183
+
184
+ interface UserTableProps {
185
+ users: readonly UserListItem[];
186
+ }
187
+
188
+ /**
189
+ * ユーザーテーブルコンポーネント
190
+ */
191
+ export function UserTable({ users }: UserTableProps) {
192
+ return (
193
+ <DataTable
194
+ columns={columns}
195
+ data={users as UserListItem[]}
196
+ searchKey="name"
197
+ searchPlaceholder="ユーザー名で検索..."
198
+ enableColumnVisibility={true}
199
+ enablePagination={true}
200
+ pageSize={10}
201
+ />
202
+ );
203
+ }
@@ -0,0 +1,57 @@
1
+ import { userUseCases } from "@/application/use-cases/UserUseCases";
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
3
+ import { UserTable } from "./_components/UserTable";
4
+
5
+ export default async function DataPage() {
6
+ const result = await userUseCases.list({}, { page: 1, limit: 100 });
7
+
8
+ if (!result.isSuccess) {
9
+ return (
10
+ <div className="container mx-auto p-6">
11
+ <div className="space-y-6">
12
+ <div>
13
+ <h1 className="text-3xl font-bold tracking-tight">データ管理</h1>
14
+ <p className="text-muted-foreground">
15
+ ユーザーデータの管理と操作を行うことができます。
16
+ </p>
17
+ </div>
18
+
19
+ <Card>
20
+ <CardHeader>
21
+ <CardTitle>エラー</CardTitle>
22
+ <CardDescription>データの取得中にエラーが発生しました。</CardDescription>
23
+ </CardHeader>
24
+ <CardContent>
25
+ <p className="text-destructive">{result.error.message}</p>
26
+ </CardContent>
27
+ </Card>
28
+ </div>
29
+ </div>
30
+ );
31
+ }
32
+
33
+ const { items: users } = result.value;
34
+
35
+ return (
36
+ <div className="container mx-auto p-6">
37
+ <div className="space-y-6">
38
+ <div>
39
+ <h1 className="text-3xl font-bold tracking-tight">データ管理</h1>
40
+ <p className="text-muted-foreground">ユーザーデータの管理と操作を行うことができます。</p>
41
+ </div>
42
+
43
+ <Card>
44
+ <CardHeader>
45
+ <CardTitle>ユーザー一覧</CardTitle>
46
+ <CardDescription>
47
+ システムに登録されているユーザーの一覧です。検索、フィルタリング、ソートが可能です。
48
+ </CardDescription>
49
+ </CardHeader>
50
+ <CardContent>
51
+ <UserTable users={users} />
52
+ </CardContent>
53
+ </Card>
54
+ </div>
55
+ </div>
56
+ );
57
+ }
@@ -0,0 +1,31 @@
1
+ "use client";
2
+
3
+ import { Sidebar } from "@/components/shared/Sidebar";
4
+ import { Header } from "@/components/shared/header";
5
+ import { useState } from "react";
6
+
7
+ interface AuthenticatedLayoutClientProps {
8
+ children: React.ReactNode;
9
+ user:
10
+ | {
11
+ id?: string;
12
+ name?: string | null;
13
+ email?: string | null;
14
+ image?: string | null;
15
+ }
16
+ | undefined;
17
+ }
18
+
19
+ export function AuthenticatedLayoutClient({ children, user }: AuthenticatedLayoutClientProps) {
20
+ const [isMobileOpen, setIsMobileOpen] = useState(false);
21
+
22
+ return (
23
+ <div className="flex h-screen bg-background">
24
+ <Sidebar isMobileOpen={isMobileOpen} setIsMobileOpen={setIsMobileOpen} />
25
+ <div className="flex-1 flex flex-col overflow-hidden">
26
+ <Header user={user} onMobileMenuToggle={() => setIsMobileOpen(!isMobileOpen)} />
27
+ <main className="flex-1 overflow-auto p-6">{children}</main>
28
+ </div>
29
+ </div>
30
+ );
31
+ }
@@ -0,0 +1,17 @@
1
+ import { auth } from "@/lib/auth";
2
+ import { redirect } from "next/navigation";
3
+ import { AuthenticatedLayoutClient } from "./layout-client";
4
+
5
+ interface AuthenticatedLayoutProps {
6
+ children: React.ReactNode;
7
+ }
8
+
9
+ export default async function AuthenticatedLayout({ children }: AuthenticatedLayoutProps) {
10
+ const session = await auth();
11
+
12
+ if (!session) {
13
+ redirect("/signin");
14
+ }
15
+
16
+ return <AuthenticatedLayoutClient user={session.user}>{children}</AuthenticatedLayoutClient>;
17
+ }
@@ -0,0 +1,59 @@
1
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
2
+ import { auth } from "@/lib/auth";
3
+
4
+ export default async function ProfilePage() {
5
+ const session = await auth();
6
+
7
+ if (!session?.user) {
8
+ return <div>ユーザー情報が見つかりません</div>;
9
+ }
10
+
11
+ const { user } = session;
12
+
13
+ return (
14
+ <div className="space-y-6">
15
+ <div>
16
+ <h1 className="text-3xl font-bold">プロフィール</h1>
17
+ <p className="text-muted-foreground">あなたのアカウント情報を確認できます。</p>
18
+ </div>
19
+
20
+ <Card>
21
+ <CardHeader>
22
+ <CardTitle>ユーザー情報</CardTitle>
23
+ <CardDescription>現在のアカウント情報です。</CardDescription>
24
+ </CardHeader>
25
+ <CardContent className="space-y-4">
26
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
27
+ <div>
28
+ <span className="text-sm font-medium text-muted-foreground">名前</span>
29
+ <p className="text-sm">{user.name || "未設定"}</p>
30
+ </div>
31
+
32
+ <div>
33
+ <span className="text-sm font-medium text-muted-foreground">メールアドレス</span>
34
+ <p className="text-sm">{user.email || "未設定"}</p>
35
+ </div>
36
+
37
+ <div>
38
+ <span className="text-sm font-medium text-muted-foreground">ユーザーID</span>
39
+ <p className="text-sm font-mono">{user.id || "未設定"}</p>
40
+ </div>
41
+
42
+ {user.image && (
43
+ <div>
44
+ <span className="text-sm font-medium text-muted-foreground">プロフィール画像</span>
45
+ <div className="mt-2">
46
+ <img
47
+ src={user.image}
48
+ alt={user.name || "Profile"}
49
+ className="w-16 h-16 rounded-full object-cover"
50
+ />
51
+ </div>
52
+ </div>
53
+ )}
54
+ </div>
55
+ </CardContent>
56
+ </Card>
57
+ </div>
58
+ );
59
+ }
@@ -0,0 +1,3 @@
1
+ import { handlers } from "@/lib/auth";
2
+
3
+ export const { GET, POST } = handlers;
@@ -0,0 +1,70 @@
1
+ import { prisma } from "{{packageName}}/server-core/infrastructure/database/client";
2
+ import bcrypt from "bcryptjs";
3
+ import { type NextRequest, NextResponse } from "next/server";
4
+ import { z } from "zod";
5
+
6
+ const signupSchema = z.object({
7
+ name: z.string().min(1, "名前は必須です"),
8
+ email: z.string().email("有効なメールアドレスを入力してください"),
9
+ password: z.string().min(8, "パスワードは8文字以上で入力してください"),
10
+ });
11
+
12
+ export async function POST(request: NextRequest) {
13
+ try {
14
+ const body = await request.json();
15
+
16
+ // バリデーション
17
+ const { name, email, password } = signupSchema.parse(body);
18
+
19
+ // 既存ユーザーのチェック
20
+ const existingUser = await prisma.user.findUnique({
21
+ where: { email },
22
+ });
23
+
24
+ if (existingUser) {
25
+ return NextResponse.json(
26
+ { error: "このメールアドレスは既に使用されています" },
27
+ { status: 400 }
28
+ );
29
+ }
30
+
31
+ // パスワードをハッシュ化
32
+ const hashedPassword = await bcrypt.hash(password, 12);
33
+
34
+ // ユーザーを作成
35
+ const user = await prisma.user.create({
36
+ data: {
37
+ name,
38
+ email,
39
+ password: hashedPassword,
40
+ },
41
+ select: {
42
+ id: true,
43
+ name: true,
44
+ email: true,
45
+ createdAt: true,
46
+ },
47
+ });
48
+
49
+ return NextResponse.json(
50
+ {
51
+ message: "アカウントが正常に作成されました",
52
+ user,
53
+ },
54
+ { status: 201 }
55
+ );
56
+ } catch (error) {
57
+ console.error("Signup error:", error);
58
+
59
+ if (error instanceof z.ZodError) {
60
+ return NextResponse.json({ error: error.errors[0].message }, { status: 400 });
61
+ }
62
+
63
+ return NextResponse.json(
64
+ {
65
+ error: "アカウント作成中にエラーが発生しました",
66
+ },
67
+ { status: 500 }
68
+ );
69
+ }
70
+ }
@@ -0,0 +1,106 @@
1
+ "use client";
2
+
3
+ import { css } from "@/styled-system/css";
4
+ import { flex } from "@/styled-system/patterns";
5
+
6
+ type ErrorPageProps = {
7
+ error: Error & { digest?: string };
8
+ reset: () => void;
9
+ };
10
+
11
+ export default function ErrorPage({ error, reset }: ErrorPageProps) {
12
+ const handleHomeClick = () => {
13
+ window.location.href = "/";
14
+ };
15
+
16
+ return (
17
+ <div
18
+ className={css({
19
+ minH: "100vh",
20
+ display: "flex",
21
+ flexDir: "column",
22
+ alignItems: "center",
23
+ justifyContent: "center",
24
+ p: "4",
25
+ bg: "white",
26
+ })}
27
+ >
28
+ <div
29
+ className={css({
30
+ textAlign: "center",
31
+ })}
32
+ >
33
+ <h1 className={css({ mb: "4" })}>エラーが発生しました</h1>
34
+ <p
35
+ className={css({
36
+ color: "gray.600",
37
+ mb: "8",
38
+ fontSize: "lg",
39
+ })}
40
+ >
41
+ 申し訳ありません。予期せぬエラーが発生しました。
42
+ </p>
43
+ <div className={flex({ gap: "4", justify: "center" })}>
44
+ <button
45
+ type="button"
46
+ onClick={reset}
47
+ className={css({
48
+ display: "inline-flex",
49
+ alignItems: "center",
50
+ justifyContent: "center",
51
+ px: "6",
52
+ py: "3",
53
+ bg: "blue.500",
54
+ color: "white",
55
+ fontWeight: "semibold",
56
+ rounded: "md",
57
+ _hover: { bg: "blue.600" },
58
+ _active: { bg: "blue.700" },
59
+ transition: "all 0.2s",
60
+ })}
61
+ >
62
+ もう一度試す
63
+ </button>
64
+ <button
65
+ type="button"
66
+ onClick={handleHomeClick}
67
+ className={css({
68
+ display: "inline-flex",
69
+ alignItems: "center",
70
+ justifyContent: "center",
71
+ px: "6",
72
+ py: "3",
73
+ border: "1px solid",
74
+ borderColor: "blue.500",
75
+ color: "blue.500",
76
+ fontWeight: "semibold",
77
+ rounded: "md",
78
+ _hover: { bg: "blue.50" },
79
+ _active: { bg: "blue.100" },
80
+ transition: "all 0.2s",
81
+ })}
82
+ >
83
+ トップページへ戻る
84
+ </button>
85
+ </div>
86
+ {process.env.NODE_ENV === "development" && (
87
+ <pre
88
+ className={css({
89
+ mt: "8",
90
+ p: "4",
91
+ bg: "gray.100",
92
+ rounded: "md",
93
+ textAlign: "left",
94
+ overflow: "auto",
95
+ maxW: "full",
96
+ fontFamily: "mono",
97
+ fontSize: "sm",
98
+ })}
99
+ >
100
+ {error.message}
101
+ </pre>
102
+ )}
103
+ </div>
104
+ </div>
105
+ );
106
+ }
@@ -0,0 +1,110 @@
1
+ "use client";
2
+
3
+ import { css } from "@/styled-system/css";
4
+ import { flex } from "@/styled-system/patterns";
5
+
6
+ type GlobalErrorPageProps = {
7
+ error: Error & { digest?: string };
8
+ reset: () => void;
9
+ };
10
+
11
+ export default function GlobalError({ error, reset }: GlobalErrorPageProps) {
12
+ const handleHomeClick = () => {
13
+ window.location.href = "/";
14
+ };
15
+
16
+ return (
17
+ <html lang="ja">
18
+ <body>
19
+ <div
20
+ className={css({
21
+ minH: "100vh",
22
+ display: "flex",
23
+ flexDir: "column",
24
+ alignItems: "center",
25
+ justifyContent: "center",
26
+ p: "4",
27
+ bg: "gray.50",
28
+ })}
29
+ >
30
+ <div
31
+ className={css({
32
+ textAlign: "center",
33
+ })}
34
+ >
35
+ <h1 className={css({ mb: "4" })}>システムエラー</h1>
36
+ <p
37
+ className={css({
38
+ color: "gray.600",
39
+ mb: "8",
40
+ fontSize: "lg",
41
+ })}
42
+ >
43
+ 申し訳ありません。システムエラーが発生しました。
44
+ </p>
45
+ <div className={flex({ gap: "4", justify: "center" })}>
46
+ <button
47
+ type="button"
48
+ onClick={reset}
49
+ className={css({
50
+ display: "inline-flex",
51
+ alignItems: "center",
52
+ justifyContent: "center",
53
+ px: "6",
54
+ py: "3",
55
+ bg: "blue.500",
56
+ color: "white",
57
+ fontWeight: "semibold",
58
+ rounded: "md",
59
+ _hover: { bg: "blue.600" },
60
+ _active: { bg: "blue.700" },
61
+ transition: "all 0.2s",
62
+ })}
63
+ >
64
+ もう一度試す
65
+ </button>
66
+ <button
67
+ type="button"
68
+ onClick={handleHomeClick}
69
+ className={css({
70
+ display: "inline-flex",
71
+ alignItems: "center",
72
+ justifyContent: "center",
73
+ px: "6",
74
+ py: "3",
75
+ border: "1px solid",
76
+ borderColor: "blue.500",
77
+ color: "blue.500",
78
+ fontWeight: "semibold",
79
+ rounded: "md",
80
+ _hover: { bg: "blue.50" },
81
+ _active: { bg: "blue.100" },
82
+ transition: "all 0.2s",
83
+ })}
84
+ >
85
+ トップページへ戻る
86
+ </button>
87
+ </div>
88
+ {process.env.NODE_ENV === "development" && (
89
+ <pre
90
+ className={css({
91
+ mt: "8",
92
+ p: "4",
93
+ bg: "gray.100",
94
+ rounded: "md",
95
+ textAlign: "left",
96
+ overflow: "auto",
97
+ maxW: "full",
98
+ fontFamily: "mono",
99
+ fontSize: "sm",
100
+ })}
101
+ >
102
+ {error.message}
103
+ </pre>
104
+ )}
105
+ </div>
106
+ </div>
107
+ </body>
108
+ </html>
109
+ );
110
+ }