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,93 +0,0 @@
1
- from typing import Literal, TypeAlias
2
-
3
- from pydantic import BaseModel, Field, model_validator
4
-
5
- InventoryAvailabilityStatus = Literal["in_stock", "low_stock", "out_of_stock"]
6
- InventoryMutationAction = Literal["adjusted", "reserved", "released", "set"]
7
-
8
-
9
- class InventoryLevelRecord(BaseModel):
10
- sku: str = Field(min_length=1)
11
- product_id: str = Field(min_length=1)
12
- product_name: str = Field(min_length=1)
13
- variant_name: str = Field(min_length=1)
14
- location_id: str = Field(min_length=1)
15
- location_name: str = Field(min_length=1)
16
- on_hand: int = Field(ge=0)
17
- reserved: int = Field(ge=0)
18
- safety_stock: int = Field(ge=0)
19
- reorder_point: int = Field(ge=0)
20
- updated_at: str
21
-
22
- @model_validator(mode="after")
23
- def validate_stock_levels(self) -> "InventoryLevelRecord":
24
- if self.reserved > self.on_hand:
25
- raise ValueError("reserved stock cannot exceed on-hand stock")
26
- return self
27
-
28
-
29
- class InventoryLevelView(BaseModel):
30
- sku: str
31
- product_id: str
32
- product_name: str
33
- variant_name: str
34
- location_id: str
35
- location_name: str
36
- on_hand: int
37
- reserved: int
38
- available_to_sell: int
39
- safety_stock: int
40
- reorder_point: int
41
- needs_reorder: bool
42
- status: InventoryAvailabilityStatus
43
- updated_at: str
44
-
45
-
46
- class AdjustInventoryCommand(BaseModel):
47
- quantity_delta: int
48
- reason: str = Field(min_length=1)
49
- reference_id: str | None = Field(default=None, min_length=1)
50
-
51
-
52
- class ReserveInventoryCommand(BaseModel):
53
- quantity: int = Field(gt=0)
54
- reference_id: str = Field(min_length=1)
55
- channel: str | None = Field(default=None, min_length=1)
56
-
57
-
58
- class ReleaseInventoryCommand(BaseModel):
59
- quantity: int = Field(gt=0)
60
- reference_id: str = Field(min_length=1)
61
- reason: str | None = Field(default=None, min_length=1)
62
-
63
-
64
- class SetInventoryLevelCommand(BaseModel):
65
- on_hand: int = Field(ge=0)
66
- reserved: int = Field(ge=0)
67
- safety_stock: int = Field(ge=0)
68
- reorder_point: int = Field(ge=0)
69
- reason: str | None = Field(default=None, min_length=1)
70
- reference_id: str | None = Field(default=None, min_length=1)
71
-
72
- @model_validator(mode="after")
73
- def validate_stock_levels(self) -> "SetInventoryLevelCommand":
74
- if self.reserved > self.on_hand:
75
- raise ValueError("reserved stock cannot exceed on-hand stock")
76
- return self
77
-
78
-
79
- class InventoryMutationReceipt(BaseModel):
80
- action: InventoryMutationAction
81
- sku: str
82
- location_id: str
83
- quantity: int
84
- reference_id: str | None = None
85
- reason: str | None = None
86
- level: InventoryLevelView
87
-
88
-
89
- InventoryLevel = InventoryLevelView
90
- InventoryAdjustmentCommand: TypeAlias = AdjustInventoryCommand
91
- InventoryReservationCommand: TypeAlias = ReserveInventoryCommand
92
- InventoryReleaseCommand: TypeAlias = ReleaseInventoryCommand
93
- InventorySetLevelCommand: TypeAlias = SetInventoryLevelCommand
@@ -1,4 +0,0 @@
1
- from .adapters.memory import MemoryInventoryRepository
2
- from .repository import get_inventory_repository
3
-
4
- __all__ = ["MemoryInventoryRepository", "get_inventory_repository"]
@@ -1,24 +0,0 @@
1
- from contexts.inventory.domain import InventoryLevelRecord
2
-
3
-
4
- class MemoryInventoryRepository:
5
- def __init__(self) -> None:
6
- self._levels: dict[tuple[str, str], InventoryLevelRecord] = {}
7
-
8
- def initialize(self) -> None:
9
- return None
10
-
11
- def seed_levels(self, levels: list[InventoryLevelRecord]) -> None:
12
- for level in levels:
13
- self._levels[(level.sku, level.location_id)] = level.model_copy(deep=True)
14
-
15
- def list_levels(self) -> list[InventoryLevelRecord]:
16
- return [level.model_copy(deep=True) for level in self._levels.values()]
17
-
18
- def get_level(self, sku: str, location_id: str) -> InventoryLevelRecord | None:
19
- level = self._levels.get((sku, location_id))
20
- return level.model_copy(deep=True) if level is not None else None
21
-
22
- def upsert_level(self, level: InventoryLevelRecord) -> InventoryLevelRecord:
23
- self._levels[(level.sku, level.location_id)] = level.model_copy(deep=True)
24
- return level.model_copy(deep=True)
@@ -1,8 +0,0 @@
1
- from functools import lru_cache
2
-
3
- from contexts.inventory.infrastructure.adapters.memory import MemoryInventoryRepository
4
-
5
-
6
- @lru_cache
7
- def get_inventory_repository() -> MemoryInventoryRepository:
8
- return MemoryInventoryRepository()
@@ -1 +0,0 @@
1
- __all__ = ["application", "contracts", "domain", "infrastructure"]
@@ -1,19 +0,0 @@
1
- from .services import (
2
- create_order,
3
- get_admin_order_overview,
4
- get_admin_queue,
5
- get_order_list,
6
- get_order_overview,
7
- prepare_order_store,
8
- update_order_status,
9
- )
10
-
11
- __all__ = [
12
- "create_order",
13
- "get_admin_order_overview",
14
- "get_admin_queue",
15
- "get_order_list",
16
- "get_order_overview",
17
- "prepare_order_store",
18
- "update_order_status",
19
- ]
@@ -1,127 +0,0 @@
1
- from contexts.orders.domain import (
2
- AdminOrderOverview,
3
- AdminQueueItem,
4
- CreateOrderCommand,
5
- DashboardStat,
6
- OrderActivity,
7
- OrderDetail,
8
- OrderOverview,
9
- OrderRecord,
10
- OrderStatusTransition,
11
- OrderSummary,
12
- StageStatus,
13
- UpdateOrderStatusCommand,
14
- )
15
- from contexts.orders.infrastructure import (
16
- create_seed_order,
17
- list_seed_orders,
18
- update_seed_order_status,
19
- )
20
-
21
-
22
- def get_order_overview() -> OrderOverview:
23
- records = list_seed_orders()
24
- at_risk = [record for record in records if record.risk == "risk"]
25
- revenue_total = sum(record.amount_krw for record in records)
26
- recent_activity = [
27
- OrderActivity(
28
- order_id=record.id,
29
- date=record.created_at,
30
- customer=record.customer_name,
31
- status=record.status,
32
- )
33
- for record in records[:3]
34
- ]
35
- selected = at_risk[0] if at_risk else records[0]
36
-
37
- return OrderOverview(
38
- stats=[
39
- DashboardStat(
40
- label="Active orders", value=str(len(records)), tone="text-[#22314d]"
41
- ),
42
- DashboardStat(
43
- label="At risk",
44
- value=str(len(at_risk)),
45
- tone="text-[var(--app-danger)]",
46
- ),
47
- DashboardStat(
48
- label="Revenue",
49
- value=f"₩{revenue_total // 1_000_000}M",
50
- tone="text-[var(--app-accent)]",
51
- ),
52
- ],
53
- recent_activity=recent_activity,
54
- selected_order=OrderDetail(
55
- product_name=selected.product_name,
56
- customer_name=selected.customer_name,
57
- status=selected.status,
58
- amount=f"₩{selected.amount_krw:,}",
59
- ),
60
- )
61
-
62
-
63
- def get_order_list() -> list[OrderSummary]:
64
- return [
65
- OrderSummary(
66
- id=record.id,
67
- product_name=record.product_name,
68
- customer_name=record.customer_name,
69
- status=record.status,
70
- )
71
- for record in list_seed_orders()
72
- ]
73
-
74
-
75
- def get_admin_order_overview() -> AdminOrderOverview:
76
- records = list_seed_orders()
77
- pending = sum(1 for record in records if record.status == "Pending")
78
- risky = sum(1 for record in records if record.risk == "risk")
79
- new_today = sum(1 for record in records if record.is_new_today)
80
- stage_counts: dict[str, int] = {}
81
- for record in records:
82
- stage_counts[record.stage] = stage_counts.get(record.stage, 0) + 1
83
-
84
- return AdminOrderOverview(
85
- cards=[
86
- DashboardStat(label="대기 거래", value=str(pending), tone=None),
87
- DashboardStat(
88
- label="위험 거래", value=str(risky), tone="text-[var(--admin-danger)]"
89
- ),
90
- DashboardStat(
91
- label="오늘 신규",
92
- value=str(new_today),
93
- tone="text-[var(--admin-accent)]",
94
- ),
95
- ],
96
- stage_statuses=[
97
- StageStatus(label=label, value=f"{count}건")
98
- for label, count in stage_counts.items()
99
- ],
100
- )
101
-
102
-
103
- def get_admin_queue() -> list[AdminQueueItem]:
104
- return [
105
- AdminQueueItem(
106
- order_id=record.id,
107
- product_name=record.product_name,
108
- customer_name=record.customer_name,
109
- status=record.fulfillment_status,
110
- sla=record.sla,
111
- )
112
- for record in list_seed_orders()
113
- ]
114
-
115
-
116
- def create_order(command: CreateOrderCommand) -> OrderRecord:
117
- return create_seed_order(command)
118
-
119
-
120
- def update_order_status(
121
- order_id: str, command: UpdateOrderStatusCommand
122
- ) -> OrderStatusTransition:
123
- return update_seed_order_status(order_id, command)
124
-
125
-
126
- def prepare_order_store() -> None:
127
- list_seed_orders()
@@ -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,82 +0,0 @@
1
- from fastapi import APIRouter, Depends, HTTPException
2
-
3
- from contexts.auth.contracts.http.dependencies import (
4
- require_admin_user,
5
- require_authenticated_user,
6
- )
7
- from contexts.orders.application import (
8
- create_order as create_order_service,
9
- get_admin_order_overview,
10
- get_admin_queue,
11
- get_order_list,
12
- get_order_overview,
13
- update_order_status as update_order_status_service,
14
- )
15
- from contexts.orders.domain import (
16
- AdminOrderOverview,
17
- AdminQueueItem,
18
- CreateOrderCommand,
19
- OrderOverview,
20
- OrderRecord,
21
- OrderStatusTransition,
22
- OrderSummary,
23
- UpdateOrderStatusCommand,
24
- )
25
-
26
- router = APIRouter(prefix="/orders", tags=["orders"])
27
-
28
-
29
- @router.get(
30
- "/overview",
31
- response_model=OrderOverview,
32
- dependencies=[Depends(require_authenticated_user)],
33
- )
34
- def order_overview() -> OrderOverview:
35
- return get_order_overview()
36
-
37
-
38
- @router.get("", response_model=list[OrderSummary], dependencies=[Depends(require_authenticated_user)])
39
- def list_orders() -> list[OrderSummary]:
40
- return get_order_list()
41
-
42
-
43
- @router.post(
44
- "",
45
- response_model=OrderRecord,
46
- status_code=201,
47
- dependencies=[Depends(require_authenticated_user)],
48
- )
49
- def create_order(command: CreateOrderCommand) -> OrderRecord:
50
- return create_order_service(command)
51
-
52
-
53
- @router.get(
54
- "/admin/overview",
55
- response_model=AdminOrderOverview,
56
- dependencies=[Depends(require_admin_user)],
57
- )
58
- def admin_order_overview() -> AdminOrderOverview:
59
- return get_admin_order_overview()
60
-
61
-
62
- @router.get(
63
- "/admin/queue",
64
- response_model=list[AdminQueueItem],
65
- dependencies=[Depends(require_admin_user)],
66
- )
67
- def admin_queue() -> list[AdminQueueItem]:
68
- return get_admin_queue()
69
-
70
-
71
- @router.patch(
72
- "/{order_id}/status",
73
- response_model=OrderStatusTransition,
74
- dependencies=[Depends(require_authenticated_user)],
75
- )
76
- def update_order_status(
77
- order_id: str, command: UpdateOrderStatusCommand
78
- ) -> OrderStatusTransition:
79
- try:
80
- return update_order_status_service(order_id, command)
81
- except LookupError as exc:
82
- raise HTTPException(status_code=404, detail=str(exc)) from exc
@@ -1,29 +0,0 @@
1
- from .models import (
2
- AdminOrderOverview,
3
- AdminQueueItem,
4
- CreateOrderCommand,
5
- DashboardStat,
6
- OrderActivity,
7
- OrderDetail,
8
- OrderOverview,
9
- OrderRecord,
10
- OrderStatusTransition,
11
- OrderSummary,
12
- StageStatus,
13
- UpdateOrderStatusCommand,
14
- )
15
-
16
- __all__ = [
17
- "AdminOrderOverview",
18
- "AdminQueueItem",
19
- "CreateOrderCommand",
20
- "DashboardStat",
21
- "OrderActivity",
22
- "OrderDetail",
23
- "OrderOverview",
24
- "OrderRecord",
25
- "OrderStatusTransition",
26
- "OrderSummary",
27
- "StageStatus",
28
- "UpdateOrderStatusCommand",
29
- ]
@@ -1,95 +0,0 @@
1
- from pydantic import BaseModel
2
-
3
-
4
- class OrderRecord(BaseModel):
5
- id: str
6
- product_id: str
7
- product_name: str
8
- customer_name: str
9
- seller_name: str
10
- status: str
11
- fulfillment_status: str
12
- created_at: str
13
- amount_krw: int
14
- risk: str
15
- stage: str
16
- sla: str
17
- is_new_today: bool
18
-
19
-
20
- class DashboardStat(BaseModel):
21
- label: str
22
- value: str
23
- tone: str | None = None
24
-
25
-
26
- class OrderActivity(BaseModel):
27
- order_id: str
28
- date: str
29
- customer: str
30
- status: str
31
-
32
-
33
- class OrderDetail(BaseModel):
34
- product_name: str
35
- customer_name: str
36
- status: str
37
- amount: str
38
-
39
-
40
- class OrderOverview(BaseModel):
41
- stats: list[DashboardStat]
42
- recent_activity: list[OrderActivity]
43
- selected_order: OrderDetail
44
-
45
-
46
- class OrderSummary(BaseModel):
47
- id: str
48
- product_name: str
49
- customer_name: str
50
- status: str
51
-
52
-
53
- class StageStatus(BaseModel):
54
- label: str
55
- value: str
56
-
57
-
58
- class AdminOrderOverview(BaseModel):
59
- cards: list[DashboardStat]
60
- stage_statuses: list[StageStatus]
61
-
62
-
63
- class AdminQueueItem(BaseModel):
64
- order_id: str
65
- product_name: str
66
- customer_name: str
67
- status: str
68
- sla: str
69
-
70
-
71
- class CreateOrderCommand(BaseModel):
72
- product_id: str
73
- product_name: str
74
- customer_name: str
75
- seller_name: str
76
- amount_krw: int
77
- stage: str = "결제 대기"
78
- status: str = "Pending"
79
- fulfillment_status: str = "Queued"
80
- sla: str = "55 min"
81
-
82
-
83
- class UpdateOrderStatusCommand(BaseModel):
84
- status: str
85
- fulfillment_status: str | None = None
86
- stage: str | None = None
87
-
88
-
89
- class OrderStatusTransition(BaseModel):
90
- id: str
91
- previous_status: str
92
- status: str
93
- fulfillment_status: str
94
- risk: str
95
- stage: str
@@ -1,7 +0,0 @@
1
- from .repository import create_seed_order, list_seed_orders, update_seed_order_status
2
-
3
- __all__ = [
4
- "create_seed_order",
5
- "list_seed_orders",
6
- "update_seed_order_status",
7
- ]
@@ -1,104 +0,0 @@
1
- from datetime import date
2
-
3
- from contexts.orders.domain import (
4
- CreateOrderCommand,
5
- OrderRecord,
6
- OrderStatusTransition,
7
- UpdateOrderStatusCommand,
8
- )
9
- from data.bootstrap_loader import load_bootstrap_json
10
-
11
- _order_store: list[OrderRecord] | None = None
12
-
13
-
14
- def _get_order_store() -> list[OrderRecord]:
15
- global _order_store
16
- if _order_store is None:
17
- _order_store = [
18
- OrderRecord(**entry) for entry in load_bootstrap_json("orders.json")
19
- ]
20
- return _order_store
21
-
22
-
23
- def _copy_orders(records: list[OrderRecord]) -> list[OrderRecord]:
24
- return [record.model_copy(deep=True) for record in records]
25
-
26
-
27
- def _next_order_number(records: list[OrderRecord]) -> int:
28
- return max((int(record.id.split("-")[-1]) for record in records), default=24050) + 1
29
-
30
-
31
- def _derive_fulfillment_status(status: str, current_status: str | None = None) -> str:
32
- fulfillment_status_map = {
33
- "Pending": "Queued",
34
- "Paid": "Picking",
35
- "At risk": "Exception",
36
- "Completed": "Delivered",
37
- "Cancelled": "Cancelled",
38
- }
39
- return fulfillment_status_map.get(status, current_status or "Queued")
40
-
41
-
42
- def _derive_risk(status: str, current_risk: str | None = None) -> str:
43
- if status == "At risk":
44
- return "risk"
45
- if status in {"Approved", "Completed"}:
46
- return "ok"
47
- return current_risk or "ok"
48
-
49
-
50
- def list_seed_orders() -> list[OrderRecord]:
51
- return _copy_orders(_get_order_store())
52
-
53
-
54
- def create_seed_order(command: CreateOrderCommand) -> OrderRecord:
55
- records = _get_order_store()
56
- next_order_number = _next_order_number(records)
57
- today = date.today().strftime("%Y.%m.%d")
58
- record = OrderRecord(
59
- id=f"ORD-{next_order_number:05d}",
60
- product_id=command.product_id,
61
- product_name=command.product_name,
62
- customer_name=command.customer_name,
63
- seller_name=command.seller_name,
64
- status=command.status,
65
- fulfillment_status=command.fulfillment_status,
66
- created_at=today,
67
- amount_krw=command.amount_krw,
68
- risk=_derive_risk(command.status),
69
- stage=command.stage,
70
- sla=command.sla,
71
- is_new_today=True,
72
- )
73
- records.insert(0, record)
74
- return record.model_copy(deep=True)
75
-
76
-
77
- def update_seed_order_status(
78
- order_id: str, command: UpdateOrderStatusCommand
79
- ) -> OrderStatusTransition:
80
- records = _get_order_store()
81
- for index, record in enumerate(records):
82
- if record.id != order_id:
83
- continue
84
-
85
- updated_record = record.model_copy(
86
- update={
87
- "status": command.status,
88
- "fulfillment_status": command.fulfillment_status
89
- or _derive_fulfillment_status(command.status, record.fulfillment_status),
90
- "risk": _derive_risk(command.status, record.risk),
91
- "stage": command.stage or record.stage,
92
- }
93
- )
94
- records[index] = updated_record
95
- return OrderStatusTransition(
96
- id=updated_record.id,
97
- previous_status=record.status,
98
- status=updated_record.status,
99
- fulfillment_status=updated_record.fulfillment_status,
100
- risk=updated_record.risk,
101
- stage=updated_record.stage,
102
- )
103
-
104
- raise LookupError(f"Order {order_id} not found")
@@ -1 +0,0 @@
1
- __all__ = ["application", "contracts", "domain", "infrastructure"]
@@ -1,13 +0,0 @@
1
- from .services import (
2
- get_shipment_list,
3
- get_shipping_overview,
4
- prepare_shipping_store,
5
- transition_shipment_status,
6
- )
7
-
8
- __all__ = [
9
- "get_shipment_list",
10
- "get_shipping_overview",
11
- "prepare_shipping_store",
12
- "transition_shipment_status",
13
- ]