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,122 +0,0 @@
1
- import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
2
-
3
- import { getMe, login as loginRequest } from "@/auth/auth-client";
4
- import type { AuthToken, AuthUser, LoginCommand } from "@/auth/types";
5
-
6
- const STORAGE_KEY = "mobile.auth.token";
7
-
8
- interface AuthContextValue {
9
- user: AuthUser | null;
10
- token: AuthToken | null;
11
- initializing: boolean;
12
- authenticating: boolean;
13
- login: (command: LoginCommand) => Promise<void>;
14
- logout: () => void;
15
- }
16
-
17
- const AuthContext = createContext<AuthContextValue | undefined>(undefined);
18
-
19
- function readStoredToken(): AuthToken | null {
20
- const raw = window.localStorage.getItem(STORAGE_KEY);
21
- if (!raw) {
22
- return null;
23
- }
24
-
25
- try {
26
- return JSON.parse(raw) as AuthToken;
27
- } catch {
28
- window.localStorage.removeItem(STORAGE_KEY);
29
- return null;
30
- }
31
- }
32
-
33
- function storeToken(token: AuthToken | null) {
34
- if (token) {
35
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(token));
36
- return;
37
- }
38
-
39
- window.localStorage.removeItem(STORAGE_KEY);
40
- }
41
-
42
- export function AuthProvider({ children }: { children: ReactNode }) {
43
- const [token, setToken] = useState<AuthToken | null>(() => readStoredToken());
44
- const [user, setUser] = useState<AuthUser | null>(null);
45
- const [initializing, setInitializing] = useState(true);
46
- const [authenticating, setAuthenticating] = useState(false);
47
-
48
- useEffect(() => {
49
- let cancelled = false;
50
-
51
- async function bootstrap() {
52
- if (!token) {
53
- setUser(null);
54
- setInitializing(false);
55
- return;
56
- }
57
-
58
- try {
59
- const currentUser = await getMe(token.access_token);
60
- if (!cancelled) {
61
- setUser(currentUser);
62
- }
63
- } catch {
64
- if (!cancelled) {
65
- setToken(null);
66
- setUser(null);
67
- storeToken(null);
68
- }
69
- } finally {
70
- if (!cancelled) {
71
- setInitializing(false);
72
- }
73
- }
74
- }
75
-
76
- void bootstrap();
77
-
78
- return () => {
79
- cancelled = true;
80
- };
81
- }, [token]);
82
-
83
- const value = useMemo<AuthContextValue>(
84
- () => ({
85
- user,
86
- token,
87
- initializing,
88
- authenticating,
89
- async login(command) {
90
- setAuthenticating(true);
91
- try {
92
- const nextToken = await loginRequest(command);
93
- storeToken(nextToken);
94
- setToken(nextToken);
95
- const currentUser = await getMe(nextToken.access_token);
96
- setUser(currentUser);
97
- } finally {
98
- setAuthenticating(false);
99
- setInitializing(false);
100
- }
101
- },
102
- logout() {
103
- storeToken(null);
104
- setToken(null);
105
- setUser(null);
106
- setInitializing(false);
107
- },
108
- }),
109
- [authenticating, initializing, token, user],
110
- );
111
-
112
- return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
113
- }
114
-
115
- export function useAuth() {
116
- const context = useContext(AuthContext);
117
- if (!context) {
118
- throw new Error("useAuth must be used within an AuthProvider");
119
- }
120
-
121
- return context;
122
- }
@@ -1,27 +0,0 @@
1
- import { Navigate, Outlet, useLocation } from "react-router-dom";
2
-
3
- import { useAuth } from "@/auth/AuthProvider";
4
- import { inTheme } from "@/theme";
5
- import { inThemeVars } from "@/theme-vars";
6
-
7
- export function ProtectedRoute() {
8
- const { initializing, user } = useAuth();
9
- const location = useLocation();
10
-
11
- if (initializing) {
12
- return (
13
- <div
14
- className="flex min-h-screen items-center justify-center bg-[var(--in-shell-bg)] text-sm font-medium text-[var(--in-muted)]"
15
- style={inThemeVars(inTheme)}
16
- >
17
- 세션을 확인하는 중입니다.
18
- </div>
19
- );
20
- }
21
-
22
- if (!user) {
23
- return <Navigate to="/login" replace state={{ from: location }} />;
24
- }
25
-
26
- return <Outlet />;
27
- }
@@ -1,38 +0,0 @@
1
- import type { AuthToken, AuthUser, LoginCommand } from "@/auth/types";
2
-
3
- const API_BASE_URL = (import.meta.env.VITE_API_BASE_URL as string | undefined)?.replace(/\/$/, "") ?? "";
4
-
5
- async function readJson<T>(response: Response): Promise<T> {
6
- if (!response.ok) {
7
- let message = "Request failed";
8
- try {
9
- const data = (await response.json()) as { detail?: string };
10
- if (typeof data.detail === "string" && data.detail.length > 0) {
11
- message = data.detail;
12
- }
13
- } catch {
14
- message = response.statusText || message;
15
- }
16
- throw new Error(message);
17
- }
18
-
19
- return (await response.json()) as T;
20
- }
21
-
22
- export async function login(command: LoginCommand): Promise<AuthToken> {
23
- const response = await fetch(`${API_BASE_URL}/auth/login`, {
24
- method: "POST",
25
- headers: { "Content-Type": "application/json" },
26
- body: JSON.stringify(command),
27
- });
28
-
29
- return readJson<AuthToken>(response);
30
- }
31
-
32
- export async function getMe(accessToken: string): Promise<AuthUser> {
33
- const response = await fetch(`${API_BASE_URL}/auth/me`, {
34
- headers: { Authorization: `Bearer ${accessToken}` },
35
- });
36
-
37
- return readJson<AuthUser>(response);
38
- }
@@ -1,18 +0,0 @@
1
- export interface AuthToken {
2
- access_token: string;
3
- token_type: string;
4
- user_id: string;
5
- }
6
-
7
- export interface AuthUser {
8
- id: string;
9
- name: string;
10
- email: string;
11
- role: string;
12
- status: string;
13
- }
14
-
15
- export interface LoginCommand {
16
- email: string;
17
- password: string;
18
- }
@@ -1,74 +0,0 @@
1
- import { Globe2, Languages, Sparkles, Truck } from "lucide-react";
2
- import { NavLink, Outlet } from "react-router-dom";
3
-
4
- import { useAuth } from "@/auth/AuthProvider";
5
- import { Button } from "@/components/ui/button";
6
- import { inTheme } from "@/theme";
7
- import { inThemeVars } from "@/theme-vars";
8
-
9
- const navItems = [
10
- { to: "/", label: "Overview", icon: Globe2 },
11
- { to: "/fulfillment", label: "Fulfillment", icon: Languages },
12
- { to: "/shipping", label: "Shipping", icon: Truck },
13
- ];
14
-
15
- export function InShell() {
16
- const { logout, user } = useAuth();
17
-
18
- return (
19
- <div
20
- className="min-h-screen bg-[var(--in-shell-bg)] text-[var(--in-text)]"
21
- style={inThemeVars(inTheme)}
22
- >
23
- <header className="border-b border-[var(--in-border)] bg-[var(--in-panel-bg)]">
24
- <div className="mx-auto flex max-w-7xl flex-wrap items-center gap-4 px-6 py-5">
25
- <div>
26
- <div className="text-xs font-black uppercase tracking-[0.24em] text-[var(--in-accent)]">IN</div>
27
- <div className="mt-1 text-xl font-black tracking-[-0.04em]">Operations Relay Workspace</div>
28
- </div>
29
-
30
- <nav className="flex items-center gap-2 md:ml-8">
31
- {navItems.map((item) => {
32
- const Icon = item.icon;
33
- return (
34
- <NavLink
35
- key={item.to}
36
- to={item.to}
37
- end={item.to === "/"}
38
- className={({ isActive }) =>
39
- [
40
- "inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm font-semibold transition-colors",
41
- isActive
42
- ? "bg-[var(--in-accent-soft)] text-[var(--in-accent)]"
43
- : "text-[var(--in-muted)] hover:bg-white",
44
- ].join(" ")
45
- }
46
- >
47
- <Icon className="h-4 w-4" />
48
- {item.label}
49
- </NavLink>
50
- );
51
- })}
52
- </nav>
53
-
54
- <div className="ml-auto flex flex-wrap items-center gap-3">
55
- <div className="inline-flex items-center gap-2 rounded-full bg-[var(--in-accent-soft)] px-3 py-2 text-sm font-semibold text-[var(--in-accent)]">
56
- <Sparkles className="h-4 w-4" />
57
- Multilingual relay active
58
- </div>
59
- <div className="rounded-full border border-[var(--in-border)] bg-white px-4 py-2 text-sm font-semibold text-[var(--in-text)]">
60
- {user?.name ?? user?.email}
61
- </div>
62
- <Button variant="outline" onClick={logout}>
63
- Log out
64
- </Button>
65
- </div>
66
- </div>
67
- </header>
68
-
69
- <main className="mx-auto max-w-7xl px-6 py-8">
70
- <Outlet />
71
- </main>
72
- </div>
73
- );
74
- }
@@ -1,35 +0,0 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
-
4
- import { cn } from "@/lib/cn";
5
-
6
- const buttonVariants = cva(
7
- "inline-flex items-center justify-center rounded-full text-sm font-semibold transition-colors disabled:pointer-events-none disabled:opacity-50",
8
- {
9
- variants: {
10
- variant: {
11
- default: "bg-[var(--in-accent)] text-white hover:opacity-90",
12
- secondary: "bg-[var(--in-accent-soft)] text-[var(--in-accent)] hover:opacity-90",
13
- outline: "border border-[var(--in-border)] bg-white text-[var(--in-text)] hover:bg-[var(--in-accent-soft)]",
14
- },
15
- size: {
16
- default: "h-10 px-4 py-2",
17
- sm: "h-9 px-3",
18
- lg: "h-11 px-5",
19
- },
20
- },
21
- defaultVariants: {
22
- variant: "default",
23
- size: "default",
24
- },
25
- },
26
- );
27
-
28
- export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}
29
-
30
- const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, ...props }, ref) => {
31
- return <button ref={ref} className={cn(buttonVariants({ variant, size }), className)} {...props} />;
32
- });
33
- Button.displayName = "Button";
34
-
35
- export { Button, buttonVariants };
@@ -1,15 +0,0 @@
1
- import type { HTMLAttributes } from "react";
2
-
3
- import { cn } from "@/lib/cn";
4
-
5
- export function Card({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
6
- return (
7
- <div
8
- className={cn(
9
- "rounded-[var(--in-card-radius)] border border-[var(--in-border)] bg-[var(--in-panel-bg)]",
10
- className,
11
- )}
12
- {...props}
13
- />
14
- );
15
- }
@@ -1,21 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "@/lib/cn";
4
-
5
- export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
6
-
7
- const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, ...props }, ref) => {
8
- return (
9
- <input
10
- ref={ref}
11
- className={cn(
12
- "flex h-11 w-full rounded-2xl border border-[var(--in-border)] bg-white px-4 py-2 text-sm text-[var(--in-text)] outline-none placeholder:text-[var(--in-muted)] focus:border-[var(--in-accent)] focus:ring-2 focus:ring-[#d6eee7]",
13
- className,
14
- )}
15
- {...props}
16
- />
17
- );
18
- });
19
- Input.displayName = "Input";
20
-
21
- export { Input };
@@ -1,6 +0,0 @@
1
- import { clsx, type ClassValue } from "clsx";
2
- import { twMerge } from "tailwind-merge";
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
6
- }
@@ -1,26 +0,0 @@
1
- [
2
- {
3
- "id": "TIN_001",
4
- "route": "/login",
5
- "binding": "direct",
6
- "notes": ["Authentication entry route for the mobile workspace."]
7
- },
8
- {
9
- "id": "TIN_002",
10
- "route": "/",
11
- "binding": "protected",
12
- "notes": ["Overview route for fulfillment and shipping relay status."]
13
- },
14
- {
15
- "id": "TIN_003",
16
- "route": "/fulfillment",
17
- "binding": "protected",
18
- "notes": ["Fulfillment board route backed by the fulfillment domain."]
19
- },
20
- {
21
- "id": "TIN_004",
22
- "route": "/shipping",
23
- "binding": "protected",
24
- "notes": ["Shipping operations route backed by the shipping domain."]
25
- }
26
- ]
@@ -1,22 +0,0 @@
1
- [
2
- {
3
- "id": "TIN_001",
4
- "title": "Login",
5
- "tags": ["auth", "entry"]
6
- },
7
- {
8
- "id": "TIN_002",
9
- "title": "Overview",
10
- "tags": ["dashboard", "protected"]
11
- },
12
- {
13
- "id": "TIN_003",
14
- "title": "Fulfillment",
15
- "tags": ["fulfillment", "protected"]
16
- },
17
- {
18
- "id": "TIN_004",
19
- "title": "Shipping",
20
- "tags": ["shipping", "protected"]
21
- }
22
- ]
@@ -1,271 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from "react";
2
-
3
- interface BrowserSpeechRecognitionAlternative {
4
- transcript: string;
5
- }
6
-
7
- interface BrowserSpeechRecognitionResult {
8
- isFinal: boolean;
9
- length: number;
10
- [index: number]: BrowserSpeechRecognitionAlternative;
11
- }
12
-
13
- interface BrowserSpeechRecognitionResultList {
14
- length: number;
15
- [index: number]: BrowserSpeechRecognitionResult;
16
- }
17
-
18
- interface BrowserSpeechRecognitionEvent extends Event {
19
- resultIndex: number;
20
- results: BrowserSpeechRecognitionResultList;
21
- }
22
-
23
- interface BrowserSpeechRecognitionErrorEvent extends Event {
24
- error: string;
25
- }
26
-
27
- interface BrowserSpeechRecognition extends EventTarget {
28
- continuous: boolean;
29
- interimResults: boolean;
30
- lang: string;
31
- maxAlternatives: number;
32
- onend: ((event: Event) => void) | null;
33
- onerror: ((event: BrowserSpeechRecognitionErrorEvent) => void) | null;
34
- onresult: ((event: BrowserSpeechRecognitionEvent) => void) | null;
35
- onstart: ((event: Event) => void) | null;
36
- abort: () => void;
37
- start: () => void;
38
- stop: () => void;
39
- }
40
-
41
- interface BrowserSpeechRecognitionConstructor {
42
- new (): BrowserSpeechRecognition;
43
- }
44
-
45
- declare global {
46
- interface Window {
47
- SpeechRecognition?: BrowserSpeechRecognitionConstructor;
48
- webkitSpeechRecognition?: BrowserSpeechRecognitionConstructor;
49
- }
50
- }
51
-
52
- export interface SpeechRecognitionMessages {
53
- applied: string;
54
- errors: Partial<Record<string, string>>;
55
- listening: string;
56
- startFailed: string;
57
- unsupported: string;
58
- }
59
-
60
- export interface UseSpeechRecognitionInputOptions {
61
- lang?: string;
62
- mergeTranscript?: (baseValue: string, transcript: string) => string;
63
- messages?: Partial<SpeechRecognitionMessages>;
64
- onValueChange: (nextValue: string) => void;
65
- value: string;
66
- }
67
-
68
- export interface UseSpeechRecognitionInputResult {
69
- abortListening: () => void;
70
- clearStatus: () => void;
71
- error: string | null;
72
- feedback: string | null;
73
- isListening: boolean;
74
- isSupported: boolean;
75
- startListening: () => void;
76
- stopListening: () => void;
77
- toggleListening: () => void;
78
- }
79
-
80
- const defaultSpeechRecognitionErrorMessages: Record<string, string> = {
81
- "audio-capture": "사용 가능한 마이크를 찾지 못했어요. 기기 연결 상태를 확인해주세요.",
82
- "network": "음성 인식 연결이 불안정해요. 네트워크 상태를 확인한 뒤 다시 시도해주세요.",
83
- "no-speech": "음성이 들리지 않았어요. 조금 더 가까이에서 다시 말씀해주세요.",
84
- "not-allowed": "마이크 권한이 필요해요. 브라우저 설정에서 마이크 접근을 허용해주세요.",
85
- "service-not-allowed": "마이크 권한이 필요해요. 브라우저 설정에서 마이크 접근을 허용해주세요.",
86
- };
87
-
88
- const defaultSpeechRecognitionMessages: SpeechRecognitionMessages = {
89
- applied: "음성 입력이 반영됐어요. 필요하면 바로 수정할 수 있어요.",
90
- errors: defaultSpeechRecognitionErrorMessages,
91
- listening: "듣는 중이에요. 말씀을 마치면 자동으로 입력돼요.",
92
- startFailed: "음성 입력을 시작하지 못했어요. 잠시 후 다시 시도해주세요.",
93
- unsupported: "현재 브라우저에서는 음성 입력을 지원하지 않아요. 외부 브라우저에서 다시 시도해주세요.",
94
- };
95
-
96
- function getSpeechRecognitionConstructor(): BrowserSpeechRecognitionConstructor | null {
97
- if (typeof window === "undefined") {
98
- return null;
99
- }
100
-
101
- return window.SpeechRecognition ?? window.webkitSpeechRecognition ?? null;
102
- }
103
-
104
- function resolveSpeechRecognitionMessages(messages?: Partial<SpeechRecognitionMessages>): SpeechRecognitionMessages {
105
- return {
106
- ...defaultSpeechRecognitionMessages,
107
- ...messages,
108
- errors: {
109
- ...defaultSpeechRecognitionErrorMessages,
110
- ...(messages?.errors ?? {}),
111
- },
112
- };
113
- }
114
-
115
- export function mergeSpeechRecognitionText(baseValue: string, transcript: string) {
116
- const trimmedBaseValue = baseValue.trim();
117
- const trimmedTranscript = transcript.trim();
118
-
119
- if (!trimmedBaseValue) {
120
- return trimmedTranscript;
121
- }
122
-
123
- if (!trimmedTranscript) {
124
- return trimmedBaseValue;
125
- }
126
-
127
- return `${trimmedBaseValue} ${trimmedTranscript}`;
128
- }
129
-
130
- export function getSpeechRecognitionErrorMessage(error: string, messages?: Partial<Record<string, string>>) {
131
- if (error === "aborted") {
132
- return null;
133
- }
134
-
135
- return messages?.[error] ?? defaultSpeechRecognitionErrorMessages[error] ?? defaultSpeechRecognitionMessages.startFailed;
136
- }
137
-
138
- export function useSpeechRecognitionInput({
139
- lang,
140
- mergeTranscript = mergeSpeechRecognitionText,
141
- messages,
142
- onValueChange,
143
- value,
144
- }: UseSpeechRecognitionInputOptions): UseSpeechRecognitionInputResult {
145
- const recognitionRef = useRef<BrowserSpeechRecognition | null>(null);
146
- const baseValueRef = useRef(value);
147
- const valueRef = useRef(value);
148
- const onValueChangeRef = useRef(onValueChange);
149
- const [isListening, setIsListening] = useState(false);
150
- const [feedback, setFeedback] = useState<string | null>(null);
151
- const [error, setError] = useState<string | null>(null);
152
- const isSupported = Boolean(getSpeechRecognitionConstructor());
153
- const resolvedMessages = resolveSpeechRecognitionMessages(messages);
154
-
155
- useEffect(() => {
156
- valueRef.current = value;
157
- onValueChangeRef.current = onValueChange;
158
- }, [onValueChange, value]);
159
-
160
- const clearStatus = useCallback(() => {
161
- setError(null);
162
- setFeedback(null);
163
- }, []);
164
-
165
- const abortListening = useCallback(() => {
166
- recognitionRef.current?.abort();
167
- recognitionRef.current = null;
168
- setIsListening(false);
169
- setFeedback(null);
170
- }, []);
171
-
172
- const stopListening = useCallback(() => {
173
- recognitionRef.current?.stop();
174
- setFeedback(null);
175
- }, []);
176
-
177
- const startListening = useCallback(() => {
178
- if (recognitionRef.current) {
179
- recognitionRef.current.abort();
180
- recognitionRef.current = null;
181
- }
182
-
183
- const SpeechRecognition = getSpeechRecognitionConstructor();
184
-
185
- if (!SpeechRecognition) {
186
- setError(resolvedMessages.unsupported);
187
- setFeedback(null);
188
- setIsListening(false);
189
- return;
190
- }
191
-
192
- const recognition = new SpeechRecognition();
193
- recognition.lang = lang ?? (typeof navigator !== "undefined" && navigator.language ? navigator.language : "ko-KR");
194
- recognition.continuous = false;
195
- recognition.interimResults = true;
196
- recognition.maxAlternatives = 1;
197
- baseValueRef.current = valueRef.current;
198
-
199
- recognition.onstart = () => {
200
- setIsListening(true);
201
- setError(null);
202
- setFeedback(resolvedMessages.listening);
203
- };
204
-
205
- recognition.onresult = (event) => {
206
- let transcript = "";
207
- let hasFinalResult = false;
208
-
209
- for (let index = event.resultIndex; index < event.results.length; index += 1) {
210
- transcript += `${event.results[index][0].transcript} `;
211
- hasFinalResult = hasFinalResult || event.results[index].isFinal;
212
- }
213
-
214
- onValueChangeRef.current(mergeTranscript(baseValueRef.current, transcript));
215
- setError(null);
216
- setFeedback(hasFinalResult ? resolvedMessages.applied : resolvedMessages.listening);
217
- };
218
-
219
- recognition.onerror = (event) => {
220
- setIsListening(false);
221
- recognitionRef.current = null;
222
- setFeedback(null);
223
- setError(getSpeechRecognitionErrorMessage(event.error, resolvedMessages.errors));
224
- };
225
-
226
- recognition.onend = () => {
227
- setIsListening(false);
228
- recognitionRef.current = null;
229
- };
230
-
231
- recognitionRef.current = recognition;
232
-
233
- try {
234
- recognition.start();
235
- } catch {
236
- recognitionRef.current = null;
237
- setIsListening(false);
238
- setFeedback(null);
239
- setError(resolvedMessages.startFailed);
240
- }
241
- }, [lang, mergeTranscript, resolvedMessages]);
242
-
243
- const toggleListening = useCallback(() => {
244
- if (isListening) {
245
- stopListening();
246
- return;
247
- }
248
-
249
- startListening();
250
- }, [isListening, startListening, stopListening]);
251
-
252
- useEffect(
253
- () => () => {
254
- recognitionRef.current?.abort();
255
- recognitionRef.current = null;
256
- },
257
- [],
258
- );
259
-
260
- return {
261
- abortListening,
262
- clearStatus,
263
- error,
264
- feedback,
265
- isListening,
266
- isSupported,
267
- startListening,
268
- stopListening,
269
- toggleListening,
270
- };
271
- }