agentic-dev 0.2.9 → 0.2.11

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 (291) hide show
  1. package/README.md +23 -8
  2. package/bin/agentic-dev.mjs +692 -55
  3. package/lib/scaffold.mjs +109 -6
  4. package/package.json +1 -1
  5. package/client/admin/.dockerignore +0 -3
  6. package/client/admin/.env.example +0 -1
  7. package/client/admin/Dockerfile +0 -16
  8. package/client/admin/Dockerfile.dev +0 -18
  9. package/client/admin/README.md +0 -20
  10. package/client/admin/index.html +0 -12
  11. package/client/admin/package.json +0 -41
  12. package/client/admin/postcss.config.js +0 -6
  13. package/client/admin/scripts/ui-parity-admin-adapter.mjs +0 -65
  14. package/client/admin/src/api/alerts.ts +0 -33
  15. package/client/admin/src/api/client.ts +0 -71
  16. package/client/admin/src/api/orders.ts +0 -33
  17. package/client/admin/src/api/support.ts +0 -11
  18. package/client/admin/src/app/App.tsx +0 -23
  19. package/client/admin/src/auth/AuthProvider.tsx +0 -122
  20. package/client/admin/src/auth/ProtectedRoute.tsx +0 -22
  21. package/client/admin/src/auth/auth-client.ts +0 -38
  22. package/client/admin/src/auth/types.ts +0 -18
  23. package/client/admin/src/components/AdminNotificationsDrawer.tsx +0 -162
  24. package/client/admin/src/components/AdminShell.tsx +0 -76
  25. package/client/admin/src/components/ui/button.tsx +0 -34
  26. package/client/admin/src/components/ui/input.tsx +0 -21
  27. package/client/admin/src/lib/cn.ts +0 -6
  28. package/client/admin/src/lib/specRouteCatalog.json +0 -30
  29. package/client/admin/src/lib/specScreens.json +0 -22
  30. package/client/admin/src/main.tsx +0 -17
  31. package/client/admin/src/pages/AdminDashboardPage.tsx +0 -171
  32. package/client/admin/src/pages/AdminLoginPage.tsx +0 -75
  33. package/client/admin/src/pages/AdminQueuePage.tsx +0 -107
  34. package/client/admin/src/pages/AdminSupportPage.tsx +0 -61
  35. package/client/admin/src/styles/globals.css +0 -17
  36. package/client/admin/src/theme-vars.ts +0 -18
  37. package/client/admin/src/theme.ts +0 -25
  38. package/client/admin/src/vite-env.d.ts +0 -1
  39. package/client/admin/tailwind.config.js +0 -8
  40. package/client/admin/tsconfig.json +0 -25
  41. package/client/admin/vite.config.ts +0 -12
  42. package/client/landing/.dockerignore +0 -3
  43. package/client/landing/.env.example +0 -1
  44. package/client/landing/Dockerfile +0 -16
  45. package/client/landing/Dockerfile.dev +0 -18
  46. package/client/landing/README.md +0 -18
  47. package/client/landing/index.html +0 -12
  48. package/client/landing/package.json +0 -41
  49. package/client/landing/postcss.config.js +0 -6
  50. package/client/landing/scripts/ui-parity-landing-adapter.mjs +0 -65
  51. package/client/landing/src/App.tsx +0 -21
  52. package/client/landing/src/api/catalog.ts +0 -30
  53. package/client/landing/src/api/client.ts +0 -30
  54. package/client/landing/src/auth/AuthProvider.tsx +0 -122
  55. package/client/landing/src/auth/ProtectedRoute.tsx +0 -22
  56. package/client/landing/src/auth/auth-client.ts +0 -38
  57. package/client/landing/src/auth/types.ts +0 -18
  58. package/client/landing/src/components/LandingShell.tsx +0 -34
  59. package/client/landing/src/lib/specRouteCatalog.json +0 -23
  60. package/client/landing/src/lib/specScreens.json +0 -17
  61. package/client/landing/src/main.tsx +0 -17
  62. package/client/landing/src/pages/LandingHomePage.tsx +0 -215
  63. package/client/landing/src/pages/LandingLoginPage.tsx +0 -90
  64. package/client/landing/src/pages/LandingWorkspacePage.tsx +0 -126
  65. package/client/landing/src/styles/globals.css +0 -17
  66. package/client/landing/src/theme-vars.ts +0 -16
  67. package/client/landing/src/theme.ts +0 -21
  68. package/client/landing/src/vite-env.d.ts +0 -1
  69. package/client/landing/tailwind.config.js +0 -8
  70. package/client/landing/tsconfig.json +0 -25
  71. package/client/landing/vite.config.ts +0 -12
  72. package/client/mobile/.dockerignore +0 -2
  73. package/client/mobile/.env.example +0 -1
  74. package/client/mobile/Dockerfile +0 -16
  75. package/client/mobile/Dockerfile.dev +0 -18
  76. package/client/mobile/README.md +0 -19
  77. package/client/mobile/index.html +0 -12
  78. package/client/mobile/package.json +0 -42
  79. package/client/mobile/postcss.config.js +0 -6
  80. package/client/mobile/scripts/ui-parity-mobile-adapter.mjs +0 -67
  81. package/client/mobile/src/App.tsx +0 -1
  82. package/client/mobile/src/api/client.ts +0 -62
  83. package/client/mobile/src/api/fulfillment.ts +0 -55
  84. package/client/mobile/src/api/shipping.ts +0 -56
  85. package/client/mobile/src/app/App.tsx +0 -23
  86. package/client/mobile/src/auth/AuthProvider.tsx +0 -122
  87. package/client/mobile/src/auth/ProtectedRoute.tsx +0 -27
  88. package/client/mobile/src/auth/auth-client.ts +0 -38
  89. package/client/mobile/src/auth/types.ts +0 -18
  90. package/client/mobile/src/components/InShell.tsx +0 -74
  91. package/client/mobile/src/components/ui/button.tsx +0 -35
  92. package/client/mobile/src/components/ui/card.tsx +0 -15
  93. package/client/mobile/src/components/ui/input.tsx +0 -21
  94. package/client/mobile/src/lib/cn.ts +0 -6
  95. package/client/mobile/src/lib/specRouteCatalog.json +0 -26
  96. package/client/mobile/src/lib/specScreens.json +0 -22
  97. package/client/mobile/src/lib/useSpeechRecognitionInput.ts +0 -271
  98. package/client/mobile/src/main.tsx +0 -17
  99. package/client/mobile/src/pages/DashboardPage.tsx +0 -172
  100. package/client/mobile/src/pages/FulfillmentPage.tsx +0 -138
  101. package/client/mobile/src/pages/LoginPage.tsx +0 -74
  102. package/client/mobile/src/pages/ShippingPage.tsx +0 -338
  103. package/client/mobile/src/styles/globals.css +0 -23
  104. package/client/mobile/src/theme-vars.ts +0 -16
  105. package/client/mobile/src/theme.ts +0 -21
  106. package/client/mobile/src/vite-env.d.ts +0 -1
  107. package/client/mobile/tailwind.config.js +0 -8
  108. package/client/mobile/tsconfig.json +0 -25
  109. package/client/mobile/vite.config.ts +0 -12
  110. package/client/web/.dockerignore +0 -3
  111. package/client/web/.env.example +0 -1
  112. package/client/web/Dockerfile +0 -16
  113. package/client/web/Dockerfile.dev +0 -18
  114. package/client/web/README.md +0 -47
  115. package/client/web/index.html +0 -12
  116. package/client/web/package.json +0 -42
  117. package/client/web/postcss.config.js +0 -6
  118. package/client/web/scripts/ui-parity-web-adapter.mjs +0 -66
  119. package/client/web/src/api/client.ts +0 -30
  120. package/client/web/src/api/orders.ts +0 -42
  121. package/client/web/src/app/App.tsx +0 -21
  122. package/client/web/src/auth/AuthProvider.tsx +0 -122
  123. package/client/web/src/auth/ProtectedRoute.tsx +0 -22
  124. package/client/web/src/auth/auth-client.ts +0 -38
  125. package/client/web/src/auth/types.ts +0 -18
  126. package/client/web/src/components/AppShell.tsx +0 -59
  127. package/client/web/src/components/ui/button.tsx +0 -35
  128. package/client/web/src/components/ui/card.tsx +0 -7
  129. package/client/web/src/components/ui/input.tsx +0 -21
  130. package/client/web/src/lib/cn.ts +0 -6
  131. package/client/web/src/lib/specRouteCatalog.json +0 -23
  132. package/client/web/src/lib/specScreens.json +0 -17
  133. package/client/web/src/main.tsx +0 -17
  134. package/client/web/src/pages/DashboardPage.tsx +0 -158
  135. package/client/web/src/pages/LoginPage.tsx +0 -72
  136. package/client/web/src/pages/OrdersPage.tsx +0 -123
  137. package/client/web/src/styles/globals.css +0 -17
  138. package/client/web/src/theme-vars.ts +0 -18
  139. package/client/web/src/theme.ts +0 -25
  140. package/client/web/src/vite-env.d.ts +0 -1
  141. package/client/web/tailwind.config.js +0 -8
  142. package/client/web/tsconfig.json +0 -25
  143. package/client/web/vite.config.ts +0 -12
  144. package/server/.dockerignore +0 -4
  145. package/server/.env.example +0 -19
  146. package/server/Dockerfile +0 -22
  147. package/server/Dockerfile.dev +0 -19
  148. package/server/README.md +0 -33
  149. package/server/__init__.py +0 -0
  150. package/server/api/__init__.py +0 -1
  151. package/server/api/http/__init__.py +0 -4
  152. package/server/api/http/app.py +0 -53
  153. package/server/api/http/router.py +0 -24
  154. package/server/config.py +0 -52
  155. package/server/contexts/__init__.py +0 -12
  156. package/server/contexts/alerts/__init__.py +0 -1
  157. package/server/contexts/alerts/application/__init__.py +0 -13
  158. package/server/contexts/alerts/application/services.py +0 -41
  159. package/server/contexts/alerts/contracts/__init__.py +0 -3
  160. package/server/contexts/alerts/contracts/http/__init__.py +0 -3
  161. package/server/contexts/alerts/contracts/http/router.py +0 -37
  162. package/server/contexts/alerts/domain/__init__.py +0 -15
  163. package/server/contexts/alerts/domain/models.py +0 -29
  164. package/server/contexts/alerts/infrastructure/__init__.py +0 -11
  165. package/server/contexts/alerts/infrastructure/repository.py +0 -41
  166. package/server/contexts/auth/__init__.py +0 -1
  167. package/server/contexts/auth/application/__init__.py +0 -3
  168. package/server/contexts/auth/application/ports.py +0 -10
  169. package/server/contexts/auth/application/services.py +0 -64
  170. package/server/contexts/auth/contracts/__init__.py +0 -4
  171. package/server/contexts/auth/contracts/http/__init__.py +0 -4
  172. package/server/contexts/auth/contracts/http/dependencies.py +0 -37
  173. package/server/contexts/auth/contracts/http/router.py +0 -19
  174. package/server/contexts/auth/domain/__init__.py +0 -3
  175. package/server/contexts/auth/domain/models.py +0 -24
  176. package/server/contexts/auth/infrastructure/__init__.py +0 -4
  177. package/server/contexts/auth/infrastructure/adapters/memory.py +0 -19
  178. package/server/contexts/auth/infrastructure/adapters/mongodb.py +0 -24
  179. package/server/contexts/auth/infrastructure/adapters/sqlalchemy.py +0 -74
  180. package/server/contexts/auth/infrastructure/repository.py +0 -28
  181. package/server/contexts/catalog/__init__.py +0 -1
  182. package/server/contexts/catalog/application/__init__.py +0 -28
  183. package/server/contexts/catalog/application/ports.py +0 -15
  184. package/server/contexts/catalog/application/services.py +0 -154
  185. package/server/contexts/catalog/contracts/__init__.py +0 -3
  186. package/server/contexts/catalog/contracts/http/__init__.py +0 -3
  187. package/server/contexts/catalog/contracts/http/router.py +0 -60
  188. package/server/contexts/catalog/domain/__init__.py +0 -45
  189. package/server/contexts/catalog/domain/models.py +0 -113
  190. package/server/contexts/catalog/infrastructure/__init__.py +0 -4
  191. package/server/contexts/catalog/infrastructure/adapters/memory.py +0 -62
  192. package/server/contexts/catalog/infrastructure/repository.py +0 -8
  193. package/server/contexts/fulfillment/__init__.py +0 -1
  194. package/server/contexts/fulfillment/application/__init__.py +0 -13
  195. package/server/contexts/fulfillment/application/ports.py +0 -20
  196. package/server/contexts/fulfillment/application/services.py +0 -85
  197. package/server/contexts/fulfillment/contracts/__init__.py +0 -3
  198. package/server/contexts/fulfillment/contracts/http/__init__.py +0 -3
  199. package/server/contexts/fulfillment/contracts/http/router.py +0 -40
  200. package/server/contexts/fulfillment/domain/__init__.py +0 -25
  201. package/server/contexts/fulfillment/domain/models.py +0 -73
  202. package/server/contexts/fulfillment/infrastructure/__init__.py +0 -13
  203. package/server/contexts/fulfillment/infrastructure/adapters/memory.py +0 -43
  204. package/server/contexts/fulfillment/infrastructure/repository.py +0 -97
  205. package/server/contexts/health/__init__.py +0 -1
  206. package/server/contexts/health/application/__init__.py +0 -3
  207. package/server/contexts/health/application/services.py +0 -2
  208. package/server/contexts/health/contracts/__init__.py +0 -3
  209. package/server/contexts/health/contracts/http/__init__.py +0 -3
  210. package/server/contexts/health/contracts/http/router.py +0 -10
  211. package/server/contexts/inventory/__init__.py +0 -1
  212. package/server/contexts/inventory/application/__init__.py +0 -28
  213. package/server/contexts/inventory/application/ports.py +0 -11
  214. package/server/contexts/inventory/application/services.py +0 -214
  215. package/server/contexts/inventory/contracts/__init__.py +0 -3
  216. package/server/contexts/inventory/contracts/http/__init__.py +0 -3
  217. package/server/contexts/inventory/contracts/http/router.py +0 -82
  218. package/server/contexts/inventory/domain/__init__.py +0 -33
  219. package/server/contexts/inventory/domain/models.py +0 -93
  220. package/server/contexts/inventory/infrastructure/__init__.py +0 -4
  221. package/server/contexts/inventory/infrastructure/adapters/memory.py +0 -24
  222. package/server/contexts/inventory/infrastructure/repository.py +0 -8
  223. package/server/contexts/orders/__init__.py +0 -1
  224. package/server/contexts/orders/application/__init__.py +0 -19
  225. package/server/contexts/orders/application/services.py +0 -127
  226. package/server/contexts/orders/contracts/__init__.py +0 -3
  227. package/server/contexts/orders/contracts/http/__init__.py +0 -3
  228. package/server/contexts/orders/contracts/http/router.py +0 -82
  229. package/server/contexts/orders/domain/__init__.py +0 -29
  230. package/server/contexts/orders/domain/models.py +0 -95
  231. package/server/contexts/orders/infrastructure/__init__.py +0 -7
  232. package/server/contexts/orders/infrastructure/repository.py +0 -104
  233. package/server/contexts/shipping/__init__.py +0 -1
  234. package/server/contexts/shipping/application/__init__.py +0 -13
  235. package/server/contexts/shipping/application/services.py +0 -92
  236. package/server/contexts/shipping/contracts/__init__.py +0 -3
  237. package/server/contexts/shipping/contracts/http/__init__.py +0 -3
  238. package/server/contexts/shipping/contracts/http/router.py +0 -40
  239. package/server/contexts/shipping/domain/__init__.py +0 -19
  240. package/server/contexts/shipping/domain/models.py +0 -48
  241. package/server/contexts/shipping/infrastructure/__init__.py +0 -9
  242. package/server/contexts/shipping/infrastructure/repository.py +0 -50
  243. package/server/contexts/support/__init__.py +0 -1
  244. package/server/contexts/support/application/__init__.py +0 -13
  245. package/server/contexts/support/application/services.py +0 -29
  246. package/server/contexts/support/contracts/__init__.py +0 -3
  247. package/server/contexts/support/contracts/http/__init__.py +0 -3
  248. package/server/contexts/support/contracts/http/router.py +0 -40
  249. package/server/contexts/support/domain/__init__.py +0 -13
  250. package/server/contexts/support/domain/models.py +0 -27
  251. package/server/contexts/support/infrastructure/__init__.py +0 -11
  252. package/server/contexts/support/infrastructure/repository.py +0 -70
  253. package/server/contexts/user/__init__.py +0 -1
  254. package/server/contexts/user/application/__init__.py +0 -3
  255. package/server/contexts/user/application/ports.py +0 -11
  256. package/server/contexts/user/application/services.py +0 -44
  257. package/server/contexts/user/contracts/__init__.py +0 -3
  258. package/server/contexts/user/contracts/http/__init__.py +0 -3
  259. package/server/contexts/user/contracts/http/router.py +0 -26
  260. package/server/contexts/user/domain/__init__.py +0 -3
  261. package/server/contexts/user/domain/models.py +0 -22
  262. package/server/contexts/user/infrastructure/__init__.py +0 -3
  263. package/server/contexts/user/infrastructure/adapters/memory.py +0 -27
  264. package/server/contexts/user/infrastructure/adapters/mongodb.py +0 -41
  265. package/server/contexts/user/infrastructure/adapters/sqlalchemy.py +0 -94
  266. package/server/contexts/user/infrastructure/factory.py +0 -28
  267. package/server/data/README.md +0 -24
  268. package/server/data/bootstrap/alerts.json +0 -38
  269. package/server/data/bootstrap/auth_accounts.json +0 -18
  270. package/server/data/bootstrap/catalog_products.json +0 -179
  271. package/server/data/bootstrap/fulfillment_events.json +0 -5
  272. package/server/data/bootstrap/fulfillment_notes.json +0 -5
  273. package/server/data/bootstrap/fulfillment_tasks.json +0 -50
  274. package/server/data/bootstrap/inventory_levels.json +0 -80
  275. package/server/data/bootstrap/orders.json +0 -62
  276. package/server/data/bootstrap/shipping_shipments.json +0 -50
  277. package/server/data/bootstrap/support_faqs.json +0 -26
  278. package/server/data/bootstrap/users.json +0 -20
  279. package/server/data/bootstrap_loader.py +0 -15
  280. package/server/docker-entrypoint.sh +0 -56
  281. package/server/main.py +0 -3
  282. package/server/pyproject.toml +0 -36
  283. package/server/shared/__init__.py +0 -1
  284. package/server/shared/application/__init__.py +0 -3
  285. package/server/shared/application/health.py +0 -2
  286. package/server/shared/infrastructure/__init__.py +0 -10
  287. package/server/shared/infrastructure/runtime.py +0 -6
  288. package/server/shared/infrastructure/security.py +0 -33
  289. package/server/tests/e2e/test_domain_feature_flows.py +0 -483
  290. package/server/tests/test_health.py +0 -49
  291. package/server/uv.lock +0 -1169
@@ -1,72 +0,0 @@
1
- import { useState } from "react";
2
- import { Navigate, useLocation } from "react-router-dom";
3
-
4
- import { useAuth } from "@/auth/AuthProvider";
5
- import { Button } from "@/components/ui/button";
6
- import { Card } from "@/components/ui/card";
7
- import { Input } from "@/components/ui/input";
8
- import { appTheme } from "@/theme";
9
- import { appThemeVars } from "@/theme-vars";
10
-
11
- export function LoginPage() {
12
- const { authenticating, login, user } = useAuth();
13
- const location = useLocation();
14
- const [email, setEmail] = useState("admin@example.com");
15
- const [password, setPassword] = useState("");
16
- const [error, setError] = useState<string | null>(null);
17
-
18
- if (user) {
19
- const destination = (location.state as { from?: { pathname?: string } } | null)?.from?.pathname ?? "/";
20
- return <Navigate to={destination} replace />;
21
- }
22
-
23
- async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
24
- event.preventDefault();
25
- setError(null);
26
-
27
- try {
28
- await login({ email, password });
29
- } catch (submitError) {
30
- setError(submitError instanceof Error ? submitError.message : "로그인에 실패했습니다.");
31
- }
32
- }
33
-
34
- return (
35
- <div className="min-h-screen bg-[var(--app-shell-bg)] px-6 py-12 text-[#22314d]" style={appThemeVars(appTheme)}>
36
- <div className="mx-auto grid max-w-6xl gap-10 lg:grid-cols-[1.1fr_420px] lg:items-center">
37
- <div>
38
- <p className="inline-flex rounded-full bg-white px-4 py-2 text-sm font-semibold text-[#223a82] shadow-sm">Customer workspace</p>
39
- <h1 className="mt-6 text-5xl font-black tracking-[-0.04em] text-[#16253f]">실제 API에 연결된 로그인 흐름</h1>
40
- <p className="mt-5 max-w-xl text-lg leading-8 text-[#5f6e86]">
41
- `VITE_API_BASE_URL/auth/login`으로 인증하고, 저장된 토큰으로 `auth/me`를 다시 호출해 앱 셸을 엽니다.
42
- </p>
43
- </div>
44
-
45
- <Card className="border-[var(--app-border)] bg-white p-7 shadow-[0_24px_60px_rgba(31,58,138,0.1)]">
46
- <form className="space-y-5" onSubmit={handleSubmit}>
47
- <div>
48
- <p className="text-2xl font-bold text-[#16253f]">Sign in</p>
49
- <p className="mt-2 text-sm text-[#6b7890]">예시 계정 값이 기본으로 채워져 있습니다.</p>
50
- </div>
51
-
52
- <label className="block space-y-2">
53
- <span className="text-sm font-semibold text-[#314157]">Email</span>
54
- <Input type="email" value={email} onChange={(event) => setEmail(event.target.value)} required />
55
- </label>
56
-
57
- <label className="block space-y-2">
58
- <span className="text-sm font-semibold text-[#314157]">Password</span>
59
- <Input type="password" value={password} onChange={(event) => setPassword(event.target.value)} required />
60
- </label>
61
-
62
- {error ? <p className="text-sm font-medium text-[#c53030]">{error}</p> : null}
63
-
64
- <Button className="w-full" size="lg" type="submit" disabled={authenticating}>
65
- {authenticating ? "Signing in..." : "Continue to app"}
66
- </Button>
67
- </form>
68
- </Card>
69
- </div>
70
- </div>
71
- );
72
- }
@@ -1,123 +0,0 @@
1
- import { useEffect, useState } from "react";
2
- import { Search } from "lucide-react";
3
-
4
- import { useAuth } from "@/auth/AuthProvider";
5
- import { fetchOrders, type OrderSummary } from "@/api/orders";
6
- import { Button } from "@/components/ui/button";
7
- import { Card } from "@/components/ui/card";
8
- import { Input } from "@/components/ui/input";
9
-
10
- export function OrdersPage() {
11
- const { token } = useAuth();
12
- const [orders, setOrders] = useState<OrderSummary[]>([]);
13
- const [query, setQuery] = useState("");
14
- const [loading, setLoading] = useState(true);
15
- const [error, setError] = useState<string | null>(null);
16
-
17
- useEffect(() => {
18
- if (!token?.access_token) {
19
- return;
20
- }
21
-
22
- let cancelled = false;
23
-
24
- setLoading(true);
25
- setError(null);
26
-
27
- fetchOrders(token.access_token)
28
- .then((response) => {
29
- if (!cancelled) {
30
- setOrders(response);
31
- }
32
- })
33
- .catch((nextError: Error) => {
34
- if (!cancelled) {
35
- setError(nextError.message);
36
- setOrders([]);
37
- }
38
- })
39
- .finally(() => {
40
- if (!cancelled) {
41
- setLoading(false);
42
- }
43
- });
44
-
45
- return () => {
46
- cancelled = true;
47
- };
48
- }, [token?.access_token]);
49
-
50
- const normalizedQuery = query.trim().toLowerCase();
51
- const filteredOrders = orders.filter((order) =>
52
- [order.id, order.product_name, order.customer_name, order.status].some((field) =>
53
- field.toLowerCase().includes(normalizedQuery),
54
- ),
55
- );
56
-
57
- return (
58
- <div className="space-y-6">
59
- <Card className="p-[var(--app-card-padding)]">
60
- <div className="flex flex-wrap items-center gap-3">
61
- <div className="relative min-w-[280px] flex-1">
62
- <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[#8d97a8]" />
63
- <Input className="pl-9" placeholder="Search orders" value={query} onChange={(event) => setQuery(event.target.value)} />
64
- </div>
65
- <Button variant="outline" onClick={() => setQuery("")}>
66
- Reset
67
- </Button>
68
- <Button>New order</Button>
69
- </div>
70
- <p className="mt-4 text-sm text-[var(--app-muted)]">
71
- {loading ? "Loading order list..." : `Showing ${filteredOrders.length} of ${orders.length} orders`}
72
- </p>
73
- </Card>
74
-
75
- <Card className="overflow-hidden">
76
- <table className="w-full border-collapse text-sm">
77
- <thead className="bg-[#f8fafe] text-left text-[#516174]">
78
- <tr>
79
- {["Order", "Product", "Customer", "Status"].map((cell) => (
80
- <th key={cell} className="border-y border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] font-semibold">
81
- {cell}
82
- </th>
83
- ))}
84
- </tr>
85
- </thead>
86
- <tbody>
87
- {loading ? (
88
- <tr>
89
- <td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-muted)]" colSpan={4}>
90
- Loading orders...
91
- </td>
92
- </tr>
93
- ) : null}
94
- {error ? (
95
- <tr>
96
- <td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-danger)]" colSpan={4}>
97
- {error}
98
- </td>
99
- </tr>
100
- ) : null}
101
- {!loading && !error && !filteredOrders.length ? (
102
- <tr>
103
- <td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-muted)]" colSpan={4}>
104
- No orders matched the current search.
105
- </td>
106
- </tr>
107
- ) : null}
108
- {filteredOrders.map((order) => (
109
- <tr key={order.id}>
110
- <td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-accent)]">{order.id}</td>
111
- <td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)]">{order.product_name}</td>
112
- <td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)]">{order.customer_name}</td>
113
- <td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)]">
114
- <span className={order.status === "At risk" ? "text-[var(--app-danger)]" : "text-[#314157]"}>{order.status}</span>
115
- </td>
116
- </tr>
117
- ))}
118
- </tbody>
119
- </table>
120
- </Card>
121
- </div>
122
- );
123
- }
@@ -1,17 +0,0 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
4
-
5
- :root {
6
- color-scheme: light;
7
- font-family: "SUIT", "Pretendard", "Noto Sans KR", sans-serif;
8
- }
9
-
10
- body {
11
- margin: 0;
12
- background: var(--app-shell-bg, #f5f7fb);
13
- }
14
-
15
- * {
16
- box-sizing: border-box;
17
- }
@@ -1,18 +0,0 @@
1
- import type { CSSProperties } from "react";
2
-
3
- import type { AppTheme } from "./theme";
4
-
5
- export function appThemeVars(theme: AppTheme): CSSProperties {
6
- return {
7
- "--app-shell-bg": theme.shellBg,
8
- "--app-card-radius": theme.cardRadius,
9
- "--app-card-padding": theme.cardPadding,
10
- "--app-border": theme.border,
11
- "--app-accent": theme.accent,
12
- "--app-danger": theme.danger,
13
- "--app-muted": theme.muted,
14
- "--app-table-cell-py": theme.tableCellPy,
15
- "--app-table-cell-px": theme.tableCellPx,
16
- "--app-panel-width": theme.panelWidth,
17
- } as CSSProperties;
18
- }
@@ -1,25 +0,0 @@
1
- export type AppTheme = {
2
- shellBg: string;
3
- cardRadius: string;
4
- cardPadding: string;
5
- border: string;
6
- accent: string;
7
- danger: string;
8
- muted: string;
9
- tableCellPy: string;
10
- tableCellPx: string;
11
- panelWidth: string;
12
- };
13
-
14
- export const appTheme: AppTheme = {
15
- shellBg: "#f5f7fb",
16
- cardRadius: "18px",
17
- cardPadding: "20px",
18
- border: "#e8edf5",
19
- accent: "#496fe8",
20
- danger: "#d95d4a",
21
- muted: "#708097",
22
- tableCellPy: "14px",
23
- tableCellPx: "16px",
24
- panelWidth: "340px",
25
- };
@@ -1 +0,0 @@
1
- /// <reference types="vite/client" />
@@ -1,8 +0,0 @@
1
- /** @type {import('tailwindcss').Config} */
2
- export default {
3
- content: ["./index.html", "./src/**/*.{ts,tsx}"],
4
- theme: {
5
- extend: {},
6
- },
7
- plugins: [],
8
- };
@@ -1,25 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "useDefineForClassFields": true,
5
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
- "allowJs": false,
7
- "skipLibCheck": true,
8
- "esModuleInterop": true,
9
- "allowSyntheticDefaultImports": true,
10
- "strict": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "module": "ESNext",
13
- "moduleResolution": "Node",
14
- "resolveJsonModule": true,
15
- "isolatedModules": true,
16
- "noEmit": true,
17
- "jsx": "react-jsx",
18
- "baseUrl": ".",
19
- "paths": {
20
- "@/*": ["src/*"]
21
- }
22
- },
23
- "include": ["src"],
24
- "references": []
25
- }
@@ -1,12 +0,0 @@
1
- import { defineConfig } from "vite";
2
- import react from "@vitejs/plugin-react";
3
- import { fileURLToPath, URL } from "node:url";
4
-
5
- export default defineConfig({
6
- plugins: [react()],
7
- resolve: {
8
- alias: {
9
- "@": fileURLToPath(new URL("./src", import.meta.url)),
10
- },
11
- },
12
- });
@@ -1,4 +0,0 @@
1
- .venv
2
- __pycache__
3
- .pytest_cache
4
- .env
@@ -1,19 +0,0 @@
1
- APP_NAME=Template Server
2
- ENVIRONMENT=development
3
- API_PREFIX=/api/v1
4
- CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001,http://localhost:3002,http://127.0.0.1:3002,http://localhost:4000,http://127.0.0.1:4000
5
- DATABASE_BACKEND=postgres
6
- POSTGRES_URL=postgresql+psycopg://template:template@postgres:5432/template
7
- MYSQL_URL=mysql+pymysql://template:template@mysql:3306/template
8
- MARIADB_URL=mysql+pymysql://template:template@mariadb:3306/template
9
- MONGODB_URL=mongodb://mongo:27017
10
- MONGODB_DATABASE=template
11
- JWT_SECRET=change-me
12
- JWT_ALGORITHM=HS256
13
- ACCESS_TOKEN_TTL_MINUTES=120
14
- BOOTSTRAP_ADMIN_EMAIL=admin@example.com
15
- BOOTSTRAP_ADMIN_PASSWORD=<CHANGE_ME>
16
- BOOTSTRAP_ADMIN_NAME=Template Admin
17
- BOOTSTRAP_OPERATOR_EMAIL=operator@example.com
18
- BOOTSTRAP_OPERATOR_PASSWORD=<CHANGE_ME>
19
- BOOTSTRAP_OPERATOR_NAME=Template Operator
package/server/Dockerfile DELETED
@@ -1,22 +0,0 @@
1
- FROM python:3.12-slim
2
-
3
- ENV PYTHONDONTWRITEBYTECODE=1 \
4
- PYTHONUNBUFFERED=1
5
-
6
- WORKDIR /app
7
-
8
- COPY pyproject.toml README.md ./
9
- COPY api ./api
10
- COPY contexts ./contexts
11
- COPY shared ./shared
12
- COPY data ./data
13
- COPY config.py ./config.py
14
- COPY main.py ./main.py
15
- COPY tests ./tests
16
- COPY .env.example ./.env.example
17
-
18
- RUN pip install --no-cache-dir -e ".[dev]"
19
-
20
- EXPOSE 8000
21
-
22
- CMD ["uvicorn", "api.http.app:app", "--host", "0.0.0.0", "--port", "8000"]
@@ -1,19 +0,0 @@
1
- FROM python:3.12-slim
2
-
3
- ENV PYTHONDONTWRITEBYTECODE=1 \
4
- PYTHONUNBUFFERED=1 \
5
- PIP_DISABLE_PIP_VERSION_CHECK=1
6
-
7
- WORKDIR /app
8
-
9
- COPY server /app/server
10
-
11
- RUN python -m pip install --no-cache-dir --upgrade pip && \
12
- python -m pip install --no-cache-dir -e "/app/server[dev]" && \
13
- chmod +x /app/server/docker-entrypoint.sh
14
-
15
- WORKDIR /app/server
16
-
17
- EXPOSE 8000
18
-
19
- CMD ["bash", "/app/server/docker-entrypoint.sh"]
package/server/README.md DELETED
@@ -1,33 +0,0 @@
1
- # server
2
-
3
- hexagonal/DDD 구조를 따르는 HTTP 서버 보일러플레이트다.
4
-
5
- 포함 패턴:
6
-
7
- - `api/http`, `contexts`, `data`, `tests` root layout
8
- - `contexts/*/(application|domain|infrastructure|contracts)` 중심 DDD 분리
9
- - `contexts/auth`, `contexts/user`, `contexts/shipping`, `contexts/alerts` 예시 도메인과 실제 호출 가능한 sample logic
10
- - HTTP 계약은 `contexts/*/contracts/http`에 둔다
11
- - `shared/(application|infrastructure)` 공통 레이어
12
- - `memory`, `postgres`, `mysql`, `mariadb`, `mongodb` adapter 선택 가능
13
- - `api/http/app.py` FastAPI app entrypoint
14
- - `config.py` settings cache
15
- - `api/http/router.py` 중심의 HTTP router aggregation
16
- - `/health`와 `/api/v1/*` 기본 계약
17
- - `.env.example`와 pytest 기본 테스트
18
-
19
- 시작:
20
-
21
- ```bash
22
- uv sync --extra dev
23
- uv run uvicorn api.http.app:app --reload
24
- ```
25
-
26
- 기본 인증 예시:
27
-
28
- - `POST /api/v1/auth/login`
29
- - `GET /api/v1/auth/me`
30
- - `GET /api/v1/users`
31
- - `GET /api/v1/users/{user_id}`
32
- - `GET /api/v1/shipping/overview`
33
- - `GET /api/v1/alerts`
File without changes
@@ -1 +0,0 @@
1
- __all__ = ["http"]
@@ -1,4 +0,0 @@
1
- from .app import app
2
- from .router import api_router
3
-
4
- __all__ = ["app", "api_router"]
@@ -1,53 +0,0 @@
1
- from collections.abc import AsyncIterator
2
- from contextlib import asynccontextmanager
3
-
4
- from fastapi import FastAPI
5
- from fastapi.middleware.cors import CORSMiddleware
6
-
7
- from api.http.router import api_router
8
- from config import get_settings
9
- from contexts.alerts.application import prepare_alert_store
10
- from contexts.auth.application import prepare_auth_store
11
- from contexts.catalog.application import prepare_catalog_store
12
- from contexts.fulfillment.application import prepare_fulfillment_store
13
- from contexts.inventory.application import prepare_inventory_store
14
- from contexts.orders.application import prepare_order_store
15
- from contexts.shipping.application import prepare_shipping_store
16
- from contexts.support.application import prepare_support_store
17
- from contexts.user.application import prepare_user_store
18
- from shared.application import health_response
19
-
20
- settings = get_settings()
21
-
22
-
23
- @asynccontextmanager
24
- async def lifespan(_: FastAPI) -> AsyncIterator[None]:
25
- prepare_alert_store()
26
- prepare_auth_store()
27
- prepare_catalog_store()
28
- prepare_fulfillment_store()
29
- prepare_inventory_store()
30
- prepare_order_store()
31
- prepare_shipping_store()
32
- prepare_support_store()
33
- prepare_user_store()
34
- yield
35
-
36
-
37
- app = FastAPI(title=settings.app_name, version="0.1.0", lifespan=lifespan)
38
-
39
- app.add_middleware(
40
- CORSMiddleware,
41
- allow_origins=settings.cors_origins,
42
- allow_credentials=True,
43
- allow_methods=["*"],
44
- allow_headers=["*"],
45
- )
46
-
47
-
48
- @app.get("/health")
49
- def health() -> dict[str, str]:
50
- return health_response()
51
-
52
-
53
- app.include_router(api_router, prefix=settings.api_prefix)
@@ -1,24 +0,0 @@
1
- from fastapi import APIRouter
2
-
3
- from contexts.alerts.contracts.http.router import router as alerts_router
4
- from contexts.auth.contracts.http.router import router as auth_router
5
- from contexts.catalog.contracts.http.router import router as catalog_router
6
- from contexts.fulfillment.contracts.http.router import router as fulfillment_router
7
- from contexts.health.contracts.http.router import router as health_router
8
- from contexts.inventory.contracts.http.router import router as inventory_router
9
- from contexts.orders.contracts.http.router import router as orders_router
10
- from contexts.shipping.contracts.http.router import router as shipping_router
11
- from contexts.support.contracts.http.router import router as support_router
12
- from contexts.user.contracts.http.router import router as user_router
13
-
14
- api_router = APIRouter()
15
- api_router.include_router(alerts_router)
16
- api_router.include_router(auth_router)
17
- api_router.include_router(catalog_router)
18
- api_router.include_router(fulfillment_router)
19
- api_router.include_router(health_router)
20
- api_router.include_router(inventory_router)
21
- api_router.include_router(orders_router)
22
- api_router.include_router(shipping_router)
23
- api_router.include_router(support_router)
24
- api_router.include_router(user_router)
package/server/config.py DELETED
@@ -1,52 +0,0 @@
1
- from functools import lru_cache
2
- from typing import Literal
3
-
4
- from pydantic import Field, field_validator
5
- from pydantic_settings import BaseSettings, SettingsConfigDict
6
-
7
-
8
- class Settings(BaseSettings):
9
- model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
10
-
11
- app_name: str = "Template Server"
12
- environment: str = "development"
13
- api_prefix: str = "/api/v1"
14
- database_backend: Literal["memory", "postgres", "mysql", "mariadb", "mongodb"] = "memory"
15
- postgres_url: str = "postgresql+psycopg://template:template@postgres:5432/template"
16
- mysql_url: str = "mysql+pymysql://template:template@mysql:3306/template"
17
- mariadb_url: str = "mysql+pymysql://template:template@mariadb:3306/template"
18
- mongodb_url: str = "mongodb://mongo:27017"
19
- mongodb_database: str = "template"
20
- jwt_secret: str = "change-me"
21
- jwt_algorithm: str = "HS256"
22
- access_token_ttl_minutes: int = 120
23
- bootstrap_admin_email: str = "admin@example.com"
24
- bootstrap_admin_password: str = "<CHANGE_ME>"
25
- bootstrap_admin_name: str = "Template Admin"
26
- bootstrap_operator_email: str = "operator@example.com"
27
- bootstrap_operator_password: str = "<CHANGE_ME>"
28
- bootstrap_operator_name: str = "Template Operator"
29
- cors_origins: list[str] = Field(
30
- default_factory=lambda: [
31
- "http://localhost:3000",
32
- "http://127.0.0.1:3000",
33
- "http://localhost:3001",
34
- "http://127.0.0.1:3001",
35
- "http://localhost:3002",
36
- "http://127.0.0.1:3002",
37
- "http://localhost:4000",
38
- "http://127.0.0.1:4000",
39
- ]
40
- )
41
-
42
- @field_validator("cors_origins", mode="before")
43
- @classmethod
44
- def parse_cors_origins(cls, value: str | list[str]) -> list[str]:
45
- if isinstance(value, str):
46
- return [item.strip() for item in value.split(",") if item.strip()]
47
- return value
48
-
49
-
50
- @lru_cache
51
- def get_settings() -> Settings:
52
- return Settings()
@@ -1,12 +0,0 @@
1
- __all__ = [
2
- "alerts",
3
- "auth",
4
- "catalog",
5
- "fulfillment",
6
- "health",
7
- "inventory",
8
- "orders",
9
- "shipping",
10
- "support",
11
- "user",
12
- ]
@@ -1 +0,0 @@
1
- __all__ = ["application", "contracts", "domain", "infrastructure"]
@@ -1,13 +0,0 @@
1
- from .services import (
2
- get_alerts,
3
- mark_alert_read,
4
- mark_all_alerts_read,
5
- prepare_alert_store,
6
- )
7
-
8
- __all__ = [
9
- "get_alerts",
10
- "mark_alert_read",
11
- "mark_all_alerts_read",
12
- "prepare_alert_store",
13
- ]
@@ -1,41 +0,0 @@
1
- from contexts.alerts.domain import (
2
- AlertItem,
3
- AlertReadResult,
4
- AlertsPayload,
5
- AlertsReadAllResult,
6
- )
7
- from contexts.alerts.infrastructure import (
8
- list_seed_alerts,
9
- mark_all_seed_alerts_read,
10
- mark_seed_alert_read,
11
- )
12
-
13
-
14
- def _to_alert_item(record: AlertItem) -> AlertItem:
15
- return AlertItem(**record.model_dump())
16
-
17
-
18
- def get_alerts() -> AlertsPayload:
19
- records = list_seed_alerts()
20
- return AlertsPayload(
21
- unread_count=sum(1 for record in records if not record.read),
22
- items=[_to_alert_item(record) for record in records],
23
- )
24
-
25
-
26
- def mark_alert_read(alert_id: str) -> AlertReadResult:
27
- record = mark_seed_alert_read(alert_id)
28
- return AlertReadResult(**record.model_dump())
29
-
30
-
31
- def mark_all_alerts_read() -> AlertsReadAllResult:
32
- updated_count = mark_all_seed_alerts_read()
33
- unread_count = sum(1 for record in list_seed_alerts() if not record.read)
34
- return AlertsReadAllResult(
35
- updated_count=updated_count,
36
- unread_count=unread_count,
37
- )
38
-
39
-
40
- def prepare_alert_store() -> None:
41
- list_seed_alerts()
@@ -1,3 +0,0 @@
1
- from .http.router import router
2
-
3
- __all__ = ["router"]
@@ -1,3 +0,0 @@
1
- from .router import router
2
-
3
- __all__ = ["router"]