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,92 +0,0 @@
1
- from contexts.shipping.domain import (
2
- ShippingCarrierLoad,
3
- ShippingOverview,
4
- ShippingStat,
5
- ShipmentStatusTransition,
6
- ShipmentSummary,
7
- UpdateShipmentStatusCommand,
8
- )
9
- from contexts.shipping.infrastructure import (
10
- list_seed_shipments,
11
- transition_seed_shipment_status,
12
- )
13
-
14
-
15
- def get_shipping_overview() -> ShippingOverview:
16
- records = list_seed_shipments()
17
- in_transit_count = sum(
18
- 1
19
- for record in records
20
- if record.status in {"In transit", "Out for delivery", "Delayed"}
21
- )
22
- delayed_count = sum(1 for record in records if record.status == "Delayed")
23
- delivered_today_count = sum(1 for record in records if record.delivered_today)
24
-
25
- carrier_names = sorted({record.carrier for record in records})
26
- carriers = []
27
- for carrier in carrier_names:
28
- carrier_records = [record for record in records if record.carrier == carrier]
29
- delayed_for_carrier = sum(
30
- 1 for record in carrier_records if record.status == "Delayed"
31
- )
32
- carriers.append(
33
- ShippingCarrierLoad(
34
- label=carrier,
35
- value=f"{len(carrier_records)}건 · 지연 {delayed_for_carrier}건",
36
- )
37
- )
38
-
39
- highlighted = next(
40
- (record for record in records if record.status == "Delayed"),
41
- records[0],
42
- )
43
-
44
- return ShippingOverview(
45
- stats=[
46
- ShippingStat(
47
- label="배송 중",
48
- value=str(in_transit_count),
49
- tone="text-[var(--in-accent)]",
50
- ),
51
- ShippingStat(
52
- label="지연",
53
- value=str(delayed_count),
54
- tone="text-[#c4663a]",
55
- ),
56
- ShippingStat(
57
- label="오늘 완료",
58
- value=str(delivered_today_count),
59
- tone="text-[#245f92]",
60
- ),
61
- ],
62
- carriers=carriers,
63
- highlighted_route=(
64
- f"{highlighted.route_name} · {highlighted.last_event}"
65
- ),
66
- )
67
-
68
-
69
- def get_shipment_list() -> list[ShipmentSummary]:
70
- return [
71
- ShipmentSummary(
72
- shipment_id=record.shipment_id,
73
- order_id=record.order_id,
74
- carrier=record.carrier,
75
- destination=record.destination,
76
- tracking_number=record.tracking_number,
77
- status=record.status,
78
- eta=record.eta,
79
- last_event=record.last_event,
80
- )
81
- for record in list_seed_shipments()
82
- ]
83
-
84
-
85
- def transition_shipment_status(
86
- shipment_id: str, command: UpdateShipmentStatusCommand
87
- ) -> ShipmentStatusTransition:
88
- return transition_seed_shipment_status(shipment_id, command)
89
-
90
-
91
- def prepare_shipping_store() -> None:
92
- list_seed_shipments()
@@ -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"]
@@ -1,40 +0,0 @@
1
- from fastapi import APIRouter, Depends, HTTPException
2
-
3
- from contexts.auth.contracts.http.dependencies import require_authenticated_user
4
- from contexts.shipping.application import (
5
- get_shipment_list,
6
- get_shipping_overview,
7
- transition_shipment_status,
8
- )
9
- from contexts.shipping.domain import (
10
- ShippingOverview,
11
- ShipmentStatusTransition,
12
- ShipmentSummary,
13
- UpdateShipmentStatusCommand,
14
- )
15
-
16
- router = APIRouter(
17
- prefix="/shipping",
18
- tags=["shipping"],
19
- dependencies=[Depends(require_authenticated_user)],
20
- )
21
-
22
-
23
- @router.get("/overview", response_model=ShippingOverview)
24
- def shipping_overview() -> ShippingOverview:
25
- return get_shipping_overview()
26
-
27
-
28
- @router.get("/shipments", response_model=list[ShipmentSummary])
29
- def list_shipments() -> list[ShipmentSummary]:
30
- return get_shipment_list()
31
-
32
-
33
- @router.patch("/shipments/{shipment_id}/status", response_model=ShipmentStatusTransition)
34
- def patch_shipment_status(
35
- shipment_id: str, command: UpdateShipmentStatusCommand
36
- ) -> ShipmentStatusTransition:
37
- try:
38
- return transition_shipment_status(shipment_id, command)
39
- except LookupError as exc:
40
- raise HTTPException(status_code=404, detail=str(exc)) from exc
@@ -1,19 +0,0 @@
1
- from .models import (
2
- ShippingCarrierLoad,
3
- ShippingOverview,
4
- ShippingStat,
5
- ShipmentRecord,
6
- ShipmentStatusTransition,
7
- ShipmentSummary,
8
- UpdateShipmentStatusCommand,
9
- )
10
-
11
- __all__ = [
12
- "ShippingCarrierLoad",
13
- "ShippingOverview",
14
- "ShippingStat",
15
- "ShipmentRecord",
16
- "ShipmentStatusTransition",
17
- "ShipmentSummary",
18
- "UpdateShipmentStatusCommand",
19
- ]
@@ -1,48 +0,0 @@
1
- from pydantic import BaseModel
2
-
3
-
4
- class ShippingStat(BaseModel):
5
- label: str
6
- value: str
7
- tone: str | None = None
8
-
9
-
10
- class ShippingCarrierLoad(BaseModel):
11
- label: str
12
- value: str
13
-
14
-
15
- class ShippingOverview(BaseModel):
16
- stats: list[ShippingStat]
17
- carriers: list[ShippingCarrierLoad]
18
- highlighted_route: str
19
-
20
-
21
- class ShipmentSummary(BaseModel):
22
- shipment_id: str
23
- order_id: str
24
- carrier: str
25
- destination: str
26
- tracking_number: str
27
- status: str
28
- eta: str
29
- last_event: str
30
-
31
-
32
- class ShipmentRecord(ShipmentSummary):
33
- route_name: str
34
- delivered_today: bool
35
-
36
-
37
- class UpdateShipmentStatusCommand(BaseModel):
38
- status: str
39
- last_event: str
40
- eta: str | None = None
41
-
42
-
43
- class ShipmentStatusTransition(BaseModel):
44
- shipment_id: str
45
- previous_status: str
46
- status: str
47
- previous_last_event: str
48
- last_event: str
@@ -1,9 +0,0 @@
1
- from .repository import (
2
- list_seed_shipments,
3
- transition_seed_shipment_status,
4
- )
5
-
6
- __all__ = [
7
- "list_seed_shipments",
8
- "transition_seed_shipment_status",
9
- ]
@@ -1,50 +0,0 @@
1
- from contexts.shipping.domain import (
2
- ShipmentRecord,
3
- ShipmentStatusTransition,
4
- UpdateShipmentStatusCommand,
5
- )
6
- from data.bootstrap_loader import load_bootstrap_json
7
-
8
- _shipment_store: list[ShipmentRecord] | None = None
9
-
10
-
11
- def _get_shipment_store() -> list[ShipmentRecord]:
12
- global _shipment_store
13
- if _shipment_store is None:
14
- _shipment_store = [
15
- ShipmentRecord(**entry)
16
- for entry in load_bootstrap_json("shipping_shipments.json")
17
- ]
18
- return _shipment_store
19
-
20
-
21
- def list_seed_shipments() -> list[ShipmentRecord]:
22
- return [record.model_copy(deep=True) for record in _get_shipment_store()]
23
-
24
-
25
- def transition_seed_shipment_status(
26
- shipment_id: str, command: UpdateShipmentStatusCommand
27
- ) -> ShipmentStatusTransition:
28
- records = _get_shipment_store()
29
- for index, record in enumerate(records):
30
- if record.shipment_id != shipment_id:
31
- continue
32
-
33
- updated_record = record.model_copy(
34
- update={
35
- "status": command.status,
36
- "last_event": command.last_event,
37
- "eta": command.eta or record.eta,
38
- "delivered_today": command.status == "Delivered",
39
- }
40
- )
41
- records[index] = updated_record
42
- return ShipmentStatusTransition(
43
- shipment_id=updated_record.shipment_id,
44
- previous_status=record.status,
45
- status=updated_record.status,
46
- previous_last_event=record.last_event,
47
- last_event=updated_record.last_event,
48
- )
49
-
50
- raise LookupError(f"Shipment {shipment_id} not found")
@@ -1 +0,0 @@
1
- __all__ = ["application", "contracts", "domain", "infrastructure"]
@@ -1,13 +0,0 @@
1
- from .services import (
2
- change_faq_visibility,
3
- create_support_faq,
4
- get_support_faqs,
5
- prepare_support_store,
6
- )
7
-
8
- __all__ = [
9
- "change_faq_visibility",
10
- "create_support_faq",
11
- "get_support_faqs",
12
- "prepare_support_store",
13
- ]
@@ -1,29 +0,0 @@
1
- from contexts.support.domain import (
2
- ChangeFaqVisibilityCommand,
3
- CreateSupportFaqCommand,
4
- SupportFaq,
5
- SupportFaqRecord,
6
- )
7
- from contexts.support.infrastructure import (
8
- create_seed_support_faq,
9
- list_seed_support_faqs,
10
- update_seed_support_faq_visibility,
11
- )
12
-
13
-
14
- def get_support_faqs() -> list[SupportFaq]:
15
- return list_seed_support_faqs()
16
-
17
-
18
- def create_support_faq(command: CreateSupportFaqCommand) -> SupportFaqRecord:
19
- return create_seed_support_faq(command)
20
-
21
-
22
- def change_faq_visibility(
23
- faq_id: str, command: ChangeFaqVisibilityCommand
24
- ) -> SupportFaqRecord:
25
- return update_seed_support_faq_visibility(faq_id, command)
26
-
27
-
28
- def prepare_support_store() -> None:
29
- list_seed_support_faqs()
@@ -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"]
@@ -1,40 +0,0 @@
1
- from fastapi import APIRouter, Depends, HTTPException
2
-
3
- from contexts.auth.contracts.http.dependencies import require_admin_user
4
- from contexts.support.application import (
5
- change_faq_visibility,
6
- create_support_faq,
7
- get_support_faqs,
8
- )
9
- from contexts.support.domain import (
10
- ChangeFaqVisibilityCommand,
11
- CreateSupportFaqCommand,
12
- SupportFaq,
13
- SupportFaqRecord,
14
- )
15
-
16
- router = APIRouter(
17
- prefix="/support",
18
- tags=["support"],
19
- dependencies=[Depends(require_admin_user)],
20
- )
21
-
22
-
23
- @router.get("/faqs", response_model=list[SupportFaq])
24
- def support_faqs() -> list[SupportFaq]:
25
- return get_support_faqs()
26
-
27
-
28
- @router.post("/faqs", response_model=SupportFaqRecord, status_code=201)
29
- def create_support_faq_entry(command: CreateSupportFaqCommand) -> SupportFaqRecord:
30
- return create_support_faq(command)
31
-
32
-
33
- @router.patch("/faqs/{faq_id}/visibility", response_model=SupportFaqRecord)
34
- def change_support_faq_visibility(
35
- faq_id: str, command: ChangeFaqVisibilityCommand
36
- ) -> SupportFaqRecord:
37
- try:
38
- return change_faq_visibility(faq_id, command)
39
- except LookupError as exc:
40
- raise HTTPException(status_code=404, detail=str(exc)) from exc
@@ -1,13 +0,0 @@
1
- from .models import (
2
- ChangeFaqVisibilityCommand,
3
- CreateSupportFaqCommand,
4
- SupportFaq,
5
- SupportFaqRecord,
6
- )
7
-
8
- __all__ = [
9
- "ChangeFaqVisibilityCommand",
10
- "CreateSupportFaqCommand",
11
- "SupportFaq",
12
- "SupportFaqRecord",
13
- ]
@@ -1,27 +0,0 @@
1
- from pydantic import BaseModel
2
-
3
-
4
- class SupportFaq(BaseModel):
5
- id: str
6
- question: str
7
- visibility: str
8
-
9
-
10
- class SupportFaqRecord(BaseModel):
11
- id: str
12
- question: str
13
- answer: str
14
- category: str
15
- visibility: str
16
- updated_at: str
17
-
18
-
19
- class CreateSupportFaqCommand(BaseModel):
20
- question: str
21
- answer: str
22
- category: str = "General"
23
- visibility: str = "노출"
24
-
25
-
26
- class ChangeFaqVisibilityCommand(BaseModel):
27
- visibility: str
@@ -1,11 +0,0 @@
1
- from .repository import (
2
- create_seed_support_faq,
3
- list_seed_support_faqs,
4
- update_seed_support_faq_visibility,
5
- )
6
-
7
- __all__ = [
8
- "create_seed_support_faq",
9
- "list_seed_support_faqs",
10
- "update_seed_support_faq_visibility",
11
- ]
@@ -1,70 +0,0 @@
1
- from datetime import date
2
-
3
- from contexts.support.domain import (
4
- ChangeFaqVisibilityCommand,
5
- CreateSupportFaqCommand,
6
- SupportFaq,
7
- SupportFaqRecord,
8
- )
9
- from data.bootstrap_loader import load_bootstrap_json
10
-
11
- _support_faq_store: list[SupportFaqRecord] | None = None
12
-
13
-
14
- def _get_support_faq_store() -> list[SupportFaqRecord]:
15
- global _support_faq_store
16
- if _support_faq_store is None:
17
- _support_faq_store = [
18
- SupportFaqRecord(**entry)
19
- for entry in load_bootstrap_json("support_faqs.json")
20
- ]
21
- return _support_faq_store
22
-
23
-
24
- def _copy_support_faq(record: SupportFaqRecord) -> SupportFaqRecord:
25
- return record.model_copy(deep=True)
26
-
27
-
28
- def _next_faq_number(records: list[SupportFaqRecord]) -> int:
29
- return max((int(record.id.split("-")[-1]) for record in records), default=0) + 1
30
-
31
-
32
- def list_seed_support_faqs() -> list[SupportFaq]:
33
- return [
34
- SupportFaq(id=record.id, question=record.question, visibility=record.visibility)
35
- for record in _get_support_faq_store()
36
- ]
37
-
38
-
39
- def create_seed_support_faq(command: CreateSupportFaqCommand) -> SupportFaqRecord:
40
- records = _get_support_faq_store()
41
- record = SupportFaqRecord(
42
- id=f"faq-{_next_faq_number(records)}",
43
- question=command.question,
44
- answer=command.answer,
45
- category=command.category,
46
- visibility=command.visibility,
47
- updated_at=date.today().isoformat(),
48
- )
49
- records.insert(0, record)
50
- return _copy_support_faq(record)
51
-
52
-
53
- def update_seed_support_faq_visibility(
54
- faq_id: str, command: ChangeFaqVisibilityCommand
55
- ) -> SupportFaqRecord:
56
- records = _get_support_faq_store()
57
- for index, record in enumerate(records):
58
- if record.id != faq_id:
59
- continue
60
-
61
- updated_record = record.model_copy(
62
- update={
63
- "visibility": command.visibility,
64
- "updated_at": date.today().isoformat(),
65
- }
66
- )
67
- records[index] = updated_record
68
- return _copy_support_faq(updated_record)
69
-
70
- raise LookupError(f"Support FAQ {faq_id} not found")
@@ -1 +0,0 @@
1
- __all__ = ["contracts", "application", "domain", "infrastructure"]
@@ -1,3 +0,0 @@
1
- from .services import get_user_or_404, list_user_summaries, prepare_user_store, update_user_status_or_404
2
-
3
- __all__ = ["get_user_or_404", "list_user_summaries", "prepare_user_store", "update_user_status_or_404"]
@@ -1,11 +0,0 @@
1
- from typing import Protocol
2
-
3
- from contexts.user.domain import UserRecord, UserSummary
4
-
5
-
6
- class UserRepository(Protocol):
7
- def initialize(self) -> None: ...
8
- def seed_users(self, users: list[UserRecord]) -> None: ...
9
- def get_by_id(self, user_id: str) -> UserRecord | None: ...
10
- def list_summaries(self) -> list[UserSummary]: ...
11
- def update_status(self, user_id: str, status: str) -> UserRecord | None: ...
@@ -1,44 +0,0 @@
1
- from fastapi import HTTPException, status
2
-
3
- from contexts.user.domain import UpdateUserStatusCommand, UserDetail, UserRecord, UserSummary
4
- from contexts.user.infrastructure import get_user_repository
5
- from data.bootstrap_loader import load_bootstrap_json
6
-
7
-
8
- def list_user_summaries() -> list[UserSummary]:
9
- repository = get_user_repository()
10
- return repository.list_summaries()
11
-
12
-
13
- def get_user_or_404(user_id: str) -> UserDetail:
14
- repository = get_user_repository()
15
- user = repository.get_by_id(user_id)
16
- if user is None:
17
- raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
18
- return UserDetail(**user.model_dump())
19
-
20
-
21
- def update_user_status_or_404(user_id: str, command: UpdateUserStatusCommand) -> UserDetail:
22
- repository = get_user_repository()
23
- user = repository.update_status(user_id, command.status)
24
- if user is None:
25
- raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
26
- return UserDetail(**user.model_dump())
27
-
28
-
29
- def prepare_user_store() -> None:
30
- repository = get_user_repository()
31
- repository.initialize()
32
- records = [
33
- UserRecord(
34
- id=entry["id"],
35
- name=entry["name"],
36
- email=entry["email"],
37
- role=entry["role"],
38
- status=entry["status"],
39
- timezone=entry["timezone"],
40
- last_login_at=entry["last_login_at"],
41
- )
42
- for entry in load_bootstrap_json("users.json")
43
- ]
44
- repository.seed_users(records)
@@ -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"]
@@ -1,26 +0,0 @@
1
- from fastapi import APIRouter, Depends
2
-
3
- from contexts.auth.contracts.http.dependencies import require_admin_user
4
- from contexts.user.application import get_user_or_404, list_user_summaries, update_user_status_or_404
5
- from contexts.user.domain import UpdateUserStatusCommand, UserDetail, UserSummary
6
-
7
- router = APIRouter(
8
- prefix="/users",
9
- tags=["users"],
10
- dependencies=[Depends(require_admin_user)],
11
- )
12
-
13
-
14
- @router.get("", response_model=list[UserSummary])
15
- def list_users() -> list[UserSummary]:
16
- return list_user_summaries()
17
-
18
-
19
- @router.get("/{user_id}", response_model=UserDetail)
20
- def get_user(user_id: str) -> UserDetail:
21
- return get_user_or_404(user_id)
22
-
23
-
24
- @router.patch("/{user_id}/status", response_model=UserDetail)
25
- def update_user_status(user_id: str, command: UpdateUserStatusCommand) -> UserDetail:
26
- return update_user_status_or_404(user_id, command)
@@ -1,3 +0,0 @@
1
- from .models import UpdateUserStatusCommand, UserDetail, UserRecord, UserSummary
2
-
3
- __all__ = ["UserSummary", "UserDetail", "UserRecord", "UpdateUserStatusCommand"]
@@ -1,22 +0,0 @@
1
- from pydantic import BaseModel, EmailStr
2
-
3
-
4
- class UserSummary(BaseModel):
5
- id: str
6
- name: str
7
- email: EmailStr
8
- role: str
9
- status: str
10
-
11
-
12
- class UserDetail(UserSummary):
13
- timezone: str
14
- last_login_at: str
15
-
16
-
17
- class UserRecord(UserDetail):
18
- pass
19
-
20
-
21
- class UpdateUserStatusCommand(BaseModel):
22
- status: str
@@ -1,3 +0,0 @@
1
- from .factory import get_user_repository
2
-
3
- __all__ = ["get_user_repository"]
@@ -1,27 +0,0 @@
1
- from contexts.user.domain import UserRecord, UserSummary
2
-
3
-
4
- class MemoryUserRepository:
5
- def __init__(self) -> None:
6
- self._users: dict[str, UserRecord] = {}
7
-
8
- def initialize(self) -> None:
9
- return None
10
-
11
- def seed_users(self, users: list[UserRecord]) -> None:
12
- for user in users:
13
- self._users[user.id] = user
14
-
15
- def get_by_id(self, user_id: str) -> UserRecord | None:
16
- return self._users.get(user_id)
17
-
18
- def list_summaries(self) -> list[UserSummary]:
19
- return [UserSummary(**user.model_dump(exclude={"timezone", "last_login_at"})) for user in self._users.values()]
20
-
21
- def update_status(self, user_id: str, status: str) -> UserRecord | None:
22
- user = self._users.get(user_id)
23
- if user is None:
24
- return None
25
- updated_user = user.model_copy(update={"status": status})
26
- self._users[user_id] = updated_user
27
- return updated_user