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.
- package/README.md +23 -8
- package/bin/agentic-dev.mjs +692 -55
- package/lib/scaffold.mjs +109 -6
- package/package.json +1 -1
- package/client/admin/.dockerignore +0 -3
- package/client/admin/.env.example +0 -1
- package/client/admin/Dockerfile +0 -16
- package/client/admin/Dockerfile.dev +0 -18
- package/client/admin/README.md +0 -20
- package/client/admin/index.html +0 -12
- package/client/admin/package.json +0 -41
- package/client/admin/postcss.config.js +0 -6
- package/client/admin/scripts/ui-parity-admin-adapter.mjs +0 -65
- package/client/admin/src/api/alerts.ts +0 -33
- package/client/admin/src/api/client.ts +0 -71
- package/client/admin/src/api/orders.ts +0 -33
- package/client/admin/src/api/support.ts +0 -11
- package/client/admin/src/app/App.tsx +0 -23
- package/client/admin/src/auth/AuthProvider.tsx +0 -122
- package/client/admin/src/auth/ProtectedRoute.tsx +0 -22
- package/client/admin/src/auth/auth-client.ts +0 -38
- package/client/admin/src/auth/types.ts +0 -18
- package/client/admin/src/components/AdminNotificationsDrawer.tsx +0 -162
- package/client/admin/src/components/AdminShell.tsx +0 -76
- package/client/admin/src/components/ui/button.tsx +0 -34
- package/client/admin/src/components/ui/input.tsx +0 -21
- package/client/admin/src/lib/cn.ts +0 -6
- package/client/admin/src/lib/specRouteCatalog.json +0 -30
- package/client/admin/src/lib/specScreens.json +0 -22
- package/client/admin/src/main.tsx +0 -17
- package/client/admin/src/pages/AdminDashboardPage.tsx +0 -171
- package/client/admin/src/pages/AdminLoginPage.tsx +0 -75
- package/client/admin/src/pages/AdminQueuePage.tsx +0 -107
- package/client/admin/src/pages/AdminSupportPage.tsx +0 -61
- package/client/admin/src/styles/globals.css +0 -17
- package/client/admin/src/theme-vars.ts +0 -18
- package/client/admin/src/theme.ts +0 -25
- package/client/admin/src/vite-env.d.ts +0 -1
- package/client/admin/tailwind.config.js +0 -8
- package/client/admin/tsconfig.json +0 -25
- package/client/admin/vite.config.ts +0 -12
- package/client/landing/.dockerignore +0 -3
- package/client/landing/.env.example +0 -1
- package/client/landing/Dockerfile +0 -16
- package/client/landing/Dockerfile.dev +0 -18
- package/client/landing/README.md +0 -18
- package/client/landing/index.html +0 -12
- package/client/landing/package.json +0 -41
- package/client/landing/postcss.config.js +0 -6
- package/client/landing/scripts/ui-parity-landing-adapter.mjs +0 -65
- package/client/landing/src/App.tsx +0 -21
- package/client/landing/src/api/catalog.ts +0 -30
- package/client/landing/src/api/client.ts +0 -30
- package/client/landing/src/auth/AuthProvider.tsx +0 -122
- package/client/landing/src/auth/ProtectedRoute.tsx +0 -22
- package/client/landing/src/auth/auth-client.ts +0 -38
- package/client/landing/src/auth/types.ts +0 -18
- package/client/landing/src/components/LandingShell.tsx +0 -34
- package/client/landing/src/lib/specRouteCatalog.json +0 -23
- package/client/landing/src/lib/specScreens.json +0 -17
- package/client/landing/src/main.tsx +0 -17
- package/client/landing/src/pages/LandingHomePage.tsx +0 -215
- package/client/landing/src/pages/LandingLoginPage.tsx +0 -90
- package/client/landing/src/pages/LandingWorkspacePage.tsx +0 -126
- package/client/landing/src/styles/globals.css +0 -17
- package/client/landing/src/theme-vars.ts +0 -16
- package/client/landing/src/theme.ts +0 -21
- package/client/landing/src/vite-env.d.ts +0 -1
- package/client/landing/tailwind.config.js +0 -8
- package/client/landing/tsconfig.json +0 -25
- package/client/landing/vite.config.ts +0 -12
- package/client/mobile/.dockerignore +0 -2
- package/client/mobile/.env.example +0 -1
- package/client/mobile/Dockerfile +0 -16
- package/client/mobile/Dockerfile.dev +0 -18
- package/client/mobile/README.md +0 -19
- package/client/mobile/index.html +0 -12
- package/client/mobile/package.json +0 -42
- package/client/mobile/postcss.config.js +0 -6
- package/client/mobile/scripts/ui-parity-mobile-adapter.mjs +0 -67
- package/client/mobile/src/App.tsx +0 -1
- package/client/mobile/src/api/client.ts +0 -62
- package/client/mobile/src/api/fulfillment.ts +0 -55
- package/client/mobile/src/api/shipping.ts +0 -56
- package/client/mobile/src/app/App.tsx +0 -23
- package/client/mobile/src/auth/AuthProvider.tsx +0 -122
- package/client/mobile/src/auth/ProtectedRoute.tsx +0 -27
- package/client/mobile/src/auth/auth-client.ts +0 -38
- package/client/mobile/src/auth/types.ts +0 -18
- package/client/mobile/src/components/InShell.tsx +0 -74
- package/client/mobile/src/components/ui/button.tsx +0 -35
- package/client/mobile/src/components/ui/card.tsx +0 -15
- package/client/mobile/src/components/ui/input.tsx +0 -21
- package/client/mobile/src/lib/cn.ts +0 -6
- package/client/mobile/src/lib/specRouteCatalog.json +0 -26
- package/client/mobile/src/lib/specScreens.json +0 -22
- package/client/mobile/src/lib/useSpeechRecognitionInput.ts +0 -271
- package/client/mobile/src/main.tsx +0 -17
- package/client/mobile/src/pages/DashboardPage.tsx +0 -172
- package/client/mobile/src/pages/FulfillmentPage.tsx +0 -138
- package/client/mobile/src/pages/LoginPage.tsx +0 -74
- package/client/mobile/src/pages/ShippingPage.tsx +0 -338
- package/client/mobile/src/styles/globals.css +0 -23
- package/client/mobile/src/theme-vars.ts +0 -16
- package/client/mobile/src/theme.ts +0 -21
- package/client/mobile/src/vite-env.d.ts +0 -1
- package/client/mobile/tailwind.config.js +0 -8
- package/client/mobile/tsconfig.json +0 -25
- package/client/mobile/vite.config.ts +0 -12
- package/client/web/.dockerignore +0 -3
- package/client/web/.env.example +0 -1
- package/client/web/Dockerfile +0 -16
- package/client/web/Dockerfile.dev +0 -18
- package/client/web/README.md +0 -47
- package/client/web/index.html +0 -12
- package/client/web/package.json +0 -42
- package/client/web/postcss.config.js +0 -6
- package/client/web/scripts/ui-parity-web-adapter.mjs +0 -66
- package/client/web/src/api/client.ts +0 -30
- package/client/web/src/api/orders.ts +0 -42
- package/client/web/src/app/App.tsx +0 -21
- package/client/web/src/auth/AuthProvider.tsx +0 -122
- package/client/web/src/auth/ProtectedRoute.tsx +0 -22
- package/client/web/src/auth/auth-client.ts +0 -38
- package/client/web/src/auth/types.ts +0 -18
- package/client/web/src/components/AppShell.tsx +0 -59
- package/client/web/src/components/ui/button.tsx +0 -35
- package/client/web/src/components/ui/card.tsx +0 -7
- package/client/web/src/components/ui/input.tsx +0 -21
- package/client/web/src/lib/cn.ts +0 -6
- package/client/web/src/lib/specRouteCatalog.json +0 -23
- package/client/web/src/lib/specScreens.json +0 -17
- package/client/web/src/main.tsx +0 -17
- package/client/web/src/pages/DashboardPage.tsx +0 -158
- package/client/web/src/pages/LoginPage.tsx +0 -72
- package/client/web/src/pages/OrdersPage.tsx +0 -123
- package/client/web/src/styles/globals.css +0 -17
- package/client/web/src/theme-vars.ts +0 -18
- package/client/web/src/theme.ts +0 -25
- package/client/web/src/vite-env.d.ts +0 -1
- package/client/web/tailwind.config.js +0 -8
- package/client/web/tsconfig.json +0 -25
- package/client/web/vite.config.ts +0 -12
- package/server/.dockerignore +0 -4
- package/server/.env.example +0 -19
- package/server/Dockerfile +0 -22
- package/server/Dockerfile.dev +0 -19
- package/server/README.md +0 -33
- package/server/__init__.py +0 -0
- package/server/api/__init__.py +0 -1
- package/server/api/http/__init__.py +0 -4
- package/server/api/http/app.py +0 -53
- package/server/api/http/router.py +0 -24
- package/server/config.py +0 -52
- package/server/contexts/__init__.py +0 -12
- package/server/contexts/alerts/__init__.py +0 -1
- package/server/contexts/alerts/application/__init__.py +0 -13
- package/server/contexts/alerts/application/services.py +0 -41
- package/server/contexts/alerts/contracts/__init__.py +0 -3
- package/server/contexts/alerts/contracts/http/__init__.py +0 -3
- package/server/contexts/alerts/contracts/http/router.py +0 -37
- package/server/contexts/alerts/domain/__init__.py +0 -15
- package/server/contexts/alerts/domain/models.py +0 -29
- package/server/contexts/alerts/infrastructure/__init__.py +0 -11
- package/server/contexts/alerts/infrastructure/repository.py +0 -41
- package/server/contexts/auth/__init__.py +0 -1
- package/server/contexts/auth/application/__init__.py +0 -3
- package/server/contexts/auth/application/ports.py +0 -10
- package/server/contexts/auth/application/services.py +0 -64
- package/server/contexts/auth/contracts/__init__.py +0 -4
- package/server/contexts/auth/contracts/http/__init__.py +0 -4
- package/server/contexts/auth/contracts/http/dependencies.py +0 -37
- package/server/contexts/auth/contracts/http/router.py +0 -19
- package/server/contexts/auth/domain/__init__.py +0 -3
- package/server/contexts/auth/domain/models.py +0 -24
- package/server/contexts/auth/infrastructure/__init__.py +0 -4
- package/server/contexts/auth/infrastructure/adapters/memory.py +0 -19
- package/server/contexts/auth/infrastructure/adapters/mongodb.py +0 -24
- package/server/contexts/auth/infrastructure/adapters/sqlalchemy.py +0 -74
- package/server/contexts/auth/infrastructure/repository.py +0 -28
- package/server/contexts/catalog/__init__.py +0 -1
- package/server/contexts/catalog/application/__init__.py +0 -28
- package/server/contexts/catalog/application/ports.py +0 -15
- package/server/contexts/catalog/application/services.py +0 -154
- package/server/contexts/catalog/contracts/__init__.py +0 -3
- package/server/contexts/catalog/contracts/http/__init__.py +0 -3
- package/server/contexts/catalog/contracts/http/router.py +0 -60
- package/server/contexts/catalog/domain/__init__.py +0 -45
- package/server/contexts/catalog/domain/models.py +0 -113
- package/server/contexts/catalog/infrastructure/__init__.py +0 -4
- package/server/contexts/catalog/infrastructure/adapters/memory.py +0 -62
- package/server/contexts/catalog/infrastructure/repository.py +0 -8
- package/server/contexts/fulfillment/__init__.py +0 -1
- package/server/contexts/fulfillment/application/__init__.py +0 -13
- package/server/contexts/fulfillment/application/ports.py +0 -20
- package/server/contexts/fulfillment/application/services.py +0 -85
- package/server/contexts/fulfillment/contracts/__init__.py +0 -3
- package/server/contexts/fulfillment/contracts/http/__init__.py +0 -3
- package/server/contexts/fulfillment/contracts/http/router.py +0 -40
- package/server/contexts/fulfillment/domain/__init__.py +0 -25
- package/server/contexts/fulfillment/domain/models.py +0 -73
- package/server/contexts/fulfillment/infrastructure/__init__.py +0 -13
- package/server/contexts/fulfillment/infrastructure/adapters/memory.py +0 -43
- package/server/contexts/fulfillment/infrastructure/repository.py +0 -97
- package/server/contexts/health/__init__.py +0 -1
- package/server/contexts/health/application/__init__.py +0 -3
- package/server/contexts/health/application/services.py +0 -2
- package/server/contexts/health/contracts/__init__.py +0 -3
- package/server/contexts/health/contracts/http/__init__.py +0 -3
- package/server/contexts/health/contracts/http/router.py +0 -10
- package/server/contexts/inventory/__init__.py +0 -1
- package/server/contexts/inventory/application/__init__.py +0 -28
- package/server/contexts/inventory/application/ports.py +0 -11
- package/server/contexts/inventory/application/services.py +0 -214
- package/server/contexts/inventory/contracts/__init__.py +0 -3
- package/server/contexts/inventory/contracts/http/__init__.py +0 -3
- package/server/contexts/inventory/contracts/http/router.py +0 -82
- package/server/contexts/inventory/domain/__init__.py +0 -33
- package/server/contexts/inventory/domain/models.py +0 -93
- package/server/contexts/inventory/infrastructure/__init__.py +0 -4
- package/server/contexts/inventory/infrastructure/adapters/memory.py +0 -24
- package/server/contexts/inventory/infrastructure/repository.py +0 -8
- package/server/contexts/orders/__init__.py +0 -1
- package/server/contexts/orders/application/__init__.py +0 -19
- package/server/contexts/orders/application/services.py +0 -127
- package/server/contexts/orders/contracts/__init__.py +0 -3
- package/server/contexts/orders/contracts/http/__init__.py +0 -3
- package/server/contexts/orders/contracts/http/router.py +0 -82
- package/server/contexts/orders/domain/__init__.py +0 -29
- package/server/contexts/orders/domain/models.py +0 -95
- package/server/contexts/orders/infrastructure/__init__.py +0 -7
- package/server/contexts/orders/infrastructure/repository.py +0 -104
- package/server/contexts/shipping/__init__.py +0 -1
- package/server/contexts/shipping/application/__init__.py +0 -13
- package/server/contexts/shipping/application/services.py +0 -92
- package/server/contexts/shipping/contracts/__init__.py +0 -3
- package/server/contexts/shipping/contracts/http/__init__.py +0 -3
- package/server/contexts/shipping/contracts/http/router.py +0 -40
- package/server/contexts/shipping/domain/__init__.py +0 -19
- package/server/contexts/shipping/domain/models.py +0 -48
- package/server/contexts/shipping/infrastructure/__init__.py +0 -9
- package/server/contexts/shipping/infrastructure/repository.py +0 -50
- package/server/contexts/support/__init__.py +0 -1
- package/server/contexts/support/application/__init__.py +0 -13
- package/server/contexts/support/application/services.py +0 -29
- package/server/contexts/support/contracts/__init__.py +0 -3
- package/server/contexts/support/contracts/http/__init__.py +0 -3
- package/server/contexts/support/contracts/http/router.py +0 -40
- package/server/contexts/support/domain/__init__.py +0 -13
- package/server/contexts/support/domain/models.py +0 -27
- package/server/contexts/support/infrastructure/__init__.py +0 -11
- package/server/contexts/support/infrastructure/repository.py +0 -70
- package/server/contexts/user/__init__.py +0 -1
- package/server/contexts/user/application/__init__.py +0 -3
- package/server/contexts/user/application/ports.py +0 -11
- package/server/contexts/user/application/services.py +0 -44
- package/server/contexts/user/contracts/__init__.py +0 -3
- package/server/contexts/user/contracts/http/__init__.py +0 -3
- package/server/contexts/user/contracts/http/router.py +0 -26
- package/server/contexts/user/domain/__init__.py +0 -3
- package/server/contexts/user/domain/models.py +0 -22
- package/server/contexts/user/infrastructure/__init__.py +0 -3
- package/server/contexts/user/infrastructure/adapters/memory.py +0 -27
- package/server/contexts/user/infrastructure/adapters/mongodb.py +0 -41
- package/server/contexts/user/infrastructure/adapters/sqlalchemy.py +0 -94
- package/server/contexts/user/infrastructure/factory.py +0 -28
- package/server/data/README.md +0 -24
- package/server/data/bootstrap/alerts.json +0 -38
- package/server/data/bootstrap/auth_accounts.json +0 -18
- package/server/data/bootstrap/catalog_products.json +0 -179
- package/server/data/bootstrap/fulfillment_events.json +0 -5
- package/server/data/bootstrap/fulfillment_notes.json +0 -5
- package/server/data/bootstrap/fulfillment_tasks.json +0 -50
- package/server/data/bootstrap/inventory_levels.json +0 -80
- package/server/data/bootstrap/orders.json +0 -62
- package/server/data/bootstrap/shipping_shipments.json +0 -50
- package/server/data/bootstrap/support_faqs.json +0 -26
- package/server/data/bootstrap/users.json +0 -20
- package/server/data/bootstrap_loader.py +0 -15
- package/server/docker-entrypoint.sh +0 -56
- package/server/main.py +0 -3
- package/server/pyproject.toml +0 -36
- package/server/shared/__init__.py +0 -1
- package/server/shared/application/__init__.py +0 -3
- package/server/shared/application/health.py +0 -2
- package/server/shared/infrastructure/__init__.py +0 -10
- package/server/shared/infrastructure/runtime.py +0 -6
- package/server/shared/infrastructure/security.py +0 -33
- package/server/tests/e2e/test_domain_feature_flows.py +0 -483
- package/server/tests/test_health.py +0 -49
- 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,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,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,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,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,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,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,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,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,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,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
|