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,72 +0,0 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
import { Navigate, useLocation } from "react-router-dom";
|
|
3
|
-
|
|
4
|
-
import { useAuth } from "@/auth/AuthProvider";
|
|
5
|
-
import { Button } from "@/components/ui/button";
|
|
6
|
-
import { Card } from "@/components/ui/card";
|
|
7
|
-
import { Input } from "@/components/ui/input";
|
|
8
|
-
import { appTheme } from "@/theme";
|
|
9
|
-
import { appThemeVars } from "@/theme-vars";
|
|
10
|
-
|
|
11
|
-
export function LoginPage() {
|
|
12
|
-
const { authenticating, login, user } = useAuth();
|
|
13
|
-
const location = useLocation();
|
|
14
|
-
const [email, setEmail] = useState("admin@example.com");
|
|
15
|
-
const [password, setPassword] = useState("");
|
|
16
|
-
const [error, setError] = useState<string | null>(null);
|
|
17
|
-
|
|
18
|
-
if (user) {
|
|
19
|
-
const destination = (location.state as { from?: { pathname?: string } } | null)?.from?.pathname ?? "/";
|
|
20
|
-
return <Navigate to={destination} replace />;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
|
24
|
-
event.preventDefault();
|
|
25
|
-
setError(null);
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
await login({ email, password });
|
|
29
|
-
} catch (submitError) {
|
|
30
|
-
setError(submitError instanceof Error ? submitError.message : "로그인에 실패했습니다.");
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<div className="min-h-screen bg-[var(--app-shell-bg)] px-6 py-12 text-[#22314d]" style={appThemeVars(appTheme)}>
|
|
36
|
-
<div className="mx-auto grid max-w-6xl gap-10 lg:grid-cols-[1.1fr_420px] lg:items-center">
|
|
37
|
-
<div>
|
|
38
|
-
<p className="inline-flex rounded-full bg-white px-4 py-2 text-sm font-semibold text-[#223a82] shadow-sm">Customer workspace</p>
|
|
39
|
-
<h1 className="mt-6 text-5xl font-black tracking-[-0.04em] text-[#16253f]">실제 API에 연결된 로그인 흐름</h1>
|
|
40
|
-
<p className="mt-5 max-w-xl text-lg leading-8 text-[#5f6e86]">
|
|
41
|
-
`VITE_API_BASE_URL/auth/login`으로 인증하고, 저장된 토큰으로 `auth/me`를 다시 호출해 앱 셸을 엽니다.
|
|
42
|
-
</p>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<Card className="border-[var(--app-border)] bg-white p-7 shadow-[0_24px_60px_rgba(31,58,138,0.1)]">
|
|
46
|
-
<form className="space-y-5" onSubmit={handleSubmit}>
|
|
47
|
-
<div>
|
|
48
|
-
<p className="text-2xl font-bold text-[#16253f]">Sign in</p>
|
|
49
|
-
<p className="mt-2 text-sm text-[#6b7890]">예시 계정 값이 기본으로 채워져 있습니다.</p>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
<label className="block space-y-2">
|
|
53
|
-
<span className="text-sm font-semibold text-[#314157]">Email</span>
|
|
54
|
-
<Input type="email" value={email} onChange={(event) => setEmail(event.target.value)} required />
|
|
55
|
-
</label>
|
|
56
|
-
|
|
57
|
-
<label className="block space-y-2">
|
|
58
|
-
<span className="text-sm font-semibold text-[#314157]">Password</span>
|
|
59
|
-
<Input type="password" value={password} onChange={(event) => setPassword(event.target.value)} required />
|
|
60
|
-
</label>
|
|
61
|
-
|
|
62
|
-
{error ? <p className="text-sm font-medium text-[#c53030]">{error}</p> : null}
|
|
63
|
-
|
|
64
|
-
<Button className="w-full" size="lg" type="submit" disabled={authenticating}>
|
|
65
|
-
{authenticating ? "Signing in..." : "Continue to app"}
|
|
66
|
-
</Button>
|
|
67
|
-
</form>
|
|
68
|
-
</Card>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import { Search } from "lucide-react";
|
|
3
|
-
|
|
4
|
-
import { useAuth } from "@/auth/AuthProvider";
|
|
5
|
-
import { fetchOrders, type OrderSummary } from "@/api/orders";
|
|
6
|
-
import { Button } from "@/components/ui/button";
|
|
7
|
-
import { Card } from "@/components/ui/card";
|
|
8
|
-
import { Input } from "@/components/ui/input";
|
|
9
|
-
|
|
10
|
-
export function OrdersPage() {
|
|
11
|
-
const { token } = useAuth();
|
|
12
|
-
const [orders, setOrders] = useState<OrderSummary[]>([]);
|
|
13
|
-
const [query, setQuery] = useState("");
|
|
14
|
-
const [loading, setLoading] = useState(true);
|
|
15
|
-
const [error, setError] = useState<string | null>(null);
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
if (!token?.access_token) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let cancelled = false;
|
|
23
|
-
|
|
24
|
-
setLoading(true);
|
|
25
|
-
setError(null);
|
|
26
|
-
|
|
27
|
-
fetchOrders(token.access_token)
|
|
28
|
-
.then((response) => {
|
|
29
|
-
if (!cancelled) {
|
|
30
|
-
setOrders(response);
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
.catch((nextError: Error) => {
|
|
34
|
-
if (!cancelled) {
|
|
35
|
-
setError(nextError.message);
|
|
36
|
-
setOrders([]);
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
.finally(() => {
|
|
40
|
-
if (!cancelled) {
|
|
41
|
-
setLoading(false);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
return () => {
|
|
46
|
-
cancelled = true;
|
|
47
|
-
};
|
|
48
|
-
}, [token?.access_token]);
|
|
49
|
-
|
|
50
|
-
const normalizedQuery = query.trim().toLowerCase();
|
|
51
|
-
const filteredOrders = orders.filter((order) =>
|
|
52
|
-
[order.id, order.product_name, order.customer_name, order.status].some((field) =>
|
|
53
|
-
field.toLowerCase().includes(normalizedQuery),
|
|
54
|
-
),
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div className="space-y-6">
|
|
59
|
-
<Card className="p-[var(--app-card-padding)]">
|
|
60
|
-
<div className="flex flex-wrap items-center gap-3">
|
|
61
|
-
<div className="relative min-w-[280px] flex-1">
|
|
62
|
-
<Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[#8d97a8]" />
|
|
63
|
-
<Input className="pl-9" placeholder="Search orders" value={query} onChange={(event) => setQuery(event.target.value)} />
|
|
64
|
-
</div>
|
|
65
|
-
<Button variant="outline" onClick={() => setQuery("")}>
|
|
66
|
-
Reset
|
|
67
|
-
</Button>
|
|
68
|
-
<Button>New order</Button>
|
|
69
|
-
</div>
|
|
70
|
-
<p className="mt-4 text-sm text-[var(--app-muted)]">
|
|
71
|
-
{loading ? "Loading order list..." : `Showing ${filteredOrders.length} of ${orders.length} orders`}
|
|
72
|
-
</p>
|
|
73
|
-
</Card>
|
|
74
|
-
|
|
75
|
-
<Card className="overflow-hidden">
|
|
76
|
-
<table className="w-full border-collapse text-sm">
|
|
77
|
-
<thead className="bg-[#f8fafe] text-left text-[#516174]">
|
|
78
|
-
<tr>
|
|
79
|
-
{["Order", "Product", "Customer", "Status"].map((cell) => (
|
|
80
|
-
<th key={cell} className="border-y border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] font-semibold">
|
|
81
|
-
{cell}
|
|
82
|
-
</th>
|
|
83
|
-
))}
|
|
84
|
-
</tr>
|
|
85
|
-
</thead>
|
|
86
|
-
<tbody>
|
|
87
|
-
{loading ? (
|
|
88
|
-
<tr>
|
|
89
|
-
<td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-muted)]" colSpan={4}>
|
|
90
|
-
Loading orders...
|
|
91
|
-
</td>
|
|
92
|
-
</tr>
|
|
93
|
-
) : null}
|
|
94
|
-
{error ? (
|
|
95
|
-
<tr>
|
|
96
|
-
<td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-danger)]" colSpan={4}>
|
|
97
|
-
{error}
|
|
98
|
-
</td>
|
|
99
|
-
</tr>
|
|
100
|
-
) : null}
|
|
101
|
-
{!loading && !error && !filteredOrders.length ? (
|
|
102
|
-
<tr>
|
|
103
|
-
<td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-muted)]" colSpan={4}>
|
|
104
|
-
No orders matched the current search.
|
|
105
|
-
</td>
|
|
106
|
-
</tr>
|
|
107
|
-
) : null}
|
|
108
|
-
{filteredOrders.map((order) => (
|
|
109
|
-
<tr key={order.id}>
|
|
110
|
-
<td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)] text-[var(--app-accent)]">{order.id}</td>
|
|
111
|
-
<td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)]">{order.product_name}</td>
|
|
112
|
-
<td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)]">{order.customer_name}</td>
|
|
113
|
-
<td className="border-b border-[var(--app-border)] px-[var(--app-table-cell-px)] py-[var(--app-table-cell-py)]">
|
|
114
|
-
<span className={order.status === "At risk" ? "text-[var(--app-danger)]" : "text-[#314157]"}>{order.status}</span>
|
|
115
|
-
</td>
|
|
116
|
-
</tr>
|
|
117
|
-
))}
|
|
118
|
-
</tbody>
|
|
119
|
-
</table>
|
|
120
|
-
</Card>
|
|
121
|
-
</div>
|
|
122
|
-
);
|
|
123
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
@tailwind base;
|
|
2
|
-
@tailwind components;
|
|
3
|
-
@tailwind utilities;
|
|
4
|
-
|
|
5
|
-
:root {
|
|
6
|
-
color-scheme: light;
|
|
7
|
-
font-family: "SUIT", "Pretendard", "Noto Sans KR", sans-serif;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
body {
|
|
11
|
-
margin: 0;
|
|
12
|
-
background: var(--app-shell-bg, #f5f7fb);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
* {
|
|
16
|
-
box-sizing: border-box;
|
|
17
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { CSSProperties } from "react";
|
|
2
|
-
|
|
3
|
-
import type { AppTheme } from "./theme";
|
|
4
|
-
|
|
5
|
-
export function appThemeVars(theme: AppTheme): CSSProperties {
|
|
6
|
-
return {
|
|
7
|
-
"--app-shell-bg": theme.shellBg,
|
|
8
|
-
"--app-card-radius": theme.cardRadius,
|
|
9
|
-
"--app-card-padding": theme.cardPadding,
|
|
10
|
-
"--app-border": theme.border,
|
|
11
|
-
"--app-accent": theme.accent,
|
|
12
|
-
"--app-danger": theme.danger,
|
|
13
|
-
"--app-muted": theme.muted,
|
|
14
|
-
"--app-table-cell-py": theme.tableCellPy,
|
|
15
|
-
"--app-table-cell-px": theme.tableCellPx,
|
|
16
|
-
"--app-panel-width": theme.panelWidth,
|
|
17
|
-
} as CSSProperties;
|
|
18
|
-
}
|
package/client/web/src/theme.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export type AppTheme = {
|
|
2
|
-
shellBg: string;
|
|
3
|
-
cardRadius: string;
|
|
4
|
-
cardPadding: string;
|
|
5
|
-
border: string;
|
|
6
|
-
accent: string;
|
|
7
|
-
danger: string;
|
|
8
|
-
muted: string;
|
|
9
|
-
tableCellPy: string;
|
|
10
|
-
tableCellPx: string;
|
|
11
|
-
panelWidth: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const appTheme: AppTheme = {
|
|
15
|
-
shellBg: "#f5f7fb",
|
|
16
|
-
cardRadius: "18px",
|
|
17
|
-
cardPadding: "20px",
|
|
18
|
-
border: "#e8edf5",
|
|
19
|
-
accent: "#496fe8",
|
|
20
|
-
danger: "#d95d4a",
|
|
21
|
-
muted: "#708097",
|
|
22
|
-
tableCellPy: "14px",
|
|
23
|
-
tableCellPx: "16px",
|
|
24
|
-
panelWidth: "340px",
|
|
25
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="vite/client" />
|
package/client/web/tsconfig.json
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"useDefineForClassFields": true,
|
|
5
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
-
"allowJs": false,
|
|
7
|
-
"skipLibCheck": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"allowSyntheticDefaultImports": true,
|
|
10
|
-
"strict": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"module": "ESNext",
|
|
13
|
-
"moduleResolution": "Node",
|
|
14
|
-
"resolveJsonModule": true,
|
|
15
|
-
"isolatedModules": true,
|
|
16
|
-
"noEmit": true,
|
|
17
|
-
"jsx": "react-jsx",
|
|
18
|
-
"baseUrl": ".",
|
|
19
|
-
"paths": {
|
|
20
|
-
"@/*": ["src/*"]
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"include": ["src"],
|
|
24
|
-
"references": []
|
|
25
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import react from "@vitejs/plugin-react";
|
|
3
|
-
import { fileURLToPath, URL } from "node:url";
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
plugins: [react()],
|
|
7
|
-
resolve: {
|
|
8
|
-
alias: {
|
|
9
|
-
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
});
|
package/server/.dockerignore
DELETED
package/server/.env.example
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
APP_NAME=Template Server
|
|
2
|
-
ENVIRONMENT=development
|
|
3
|
-
API_PREFIX=/api/v1
|
|
4
|
-
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001,http://localhost:3002,http://127.0.0.1:3002,http://localhost:4000,http://127.0.0.1:4000
|
|
5
|
-
DATABASE_BACKEND=postgres
|
|
6
|
-
POSTGRES_URL=postgresql+psycopg://template:template@postgres:5432/template
|
|
7
|
-
MYSQL_URL=mysql+pymysql://template:template@mysql:3306/template
|
|
8
|
-
MARIADB_URL=mysql+pymysql://template:template@mariadb:3306/template
|
|
9
|
-
MONGODB_URL=mongodb://mongo:27017
|
|
10
|
-
MONGODB_DATABASE=template
|
|
11
|
-
JWT_SECRET=change-me
|
|
12
|
-
JWT_ALGORITHM=HS256
|
|
13
|
-
ACCESS_TOKEN_TTL_MINUTES=120
|
|
14
|
-
BOOTSTRAP_ADMIN_EMAIL=admin@example.com
|
|
15
|
-
BOOTSTRAP_ADMIN_PASSWORD=<CHANGE_ME>
|
|
16
|
-
BOOTSTRAP_ADMIN_NAME=Template Admin
|
|
17
|
-
BOOTSTRAP_OPERATOR_EMAIL=operator@example.com
|
|
18
|
-
BOOTSTRAP_OPERATOR_PASSWORD=<CHANGE_ME>
|
|
19
|
-
BOOTSTRAP_OPERATOR_NAME=Template Operator
|
package/server/Dockerfile
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
FROM python:3.12-slim
|
|
2
|
-
|
|
3
|
-
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
4
|
-
PYTHONUNBUFFERED=1
|
|
5
|
-
|
|
6
|
-
WORKDIR /app
|
|
7
|
-
|
|
8
|
-
COPY pyproject.toml README.md ./
|
|
9
|
-
COPY api ./api
|
|
10
|
-
COPY contexts ./contexts
|
|
11
|
-
COPY shared ./shared
|
|
12
|
-
COPY data ./data
|
|
13
|
-
COPY config.py ./config.py
|
|
14
|
-
COPY main.py ./main.py
|
|
15
|
-
COPY tests ./tests
|
|
16
|
-
COPY .env.example ./.env.example
|
|
17
|
-
|
|
18
|
-
RUN pip install --no-cache-dir -e ".[dev]"
|
|
19
|
-
|
|
20
|
-
EXPOSE 8000
|
|
21
|
-
|
|
22
|
-
CMD ["uvicorn", "api.http.app:app", "--host", "0.0.0.0", "--port", "8000"]
|
package/server/Dockerfile.dev
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
FROM python:3.12-slim
|
|
2
|
-
|
|
3
|
-
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
4
|
-
PYTHONUNBUFFERED=1 \
|
|
5
|
-
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
6
|
-
|
|
7
|
-
WORKDIR /app
|
|
8
|
-
|
|
9
|
-
COPY server /app/server
|
|
10
|
-
|
|
11
|
-
RUN python -m pip install --no-cache-dir --upgrade pip && \
|
|
12
|
-
python -m pip install --no-cache-dir -e "/app/server[dev]" && \
|
|
13
|
-
chmod +x /app/server/docker-entrypoint.sh
|
|
14
|
-
|
|
15
|
-
WORKDIR /app/server
|
|
16
|
-
|
|
17
|
-
EXPOSE 8000
|
|
18
|
-
|
|
19
|
-
CMD ["bash", "/app/server/docker-entrypoint.sh"]
|
package/server/README.md
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# server
|
|
2
|
-
|
|
3
|
-
hexagonal/DDD 구조를 따르는 HTTP 서버 보일러플레이트다.
|
|
4
|
-
|
|
5
|
-
포함 패턴:
|
|
6
|
-
|
|
7
|
-
- `api/http`, `contexts`, `data`, `tests` root layout
|
|
8
|
-
- `contexts/*/(application|domain|infrastructure|contracts)` 중심 DDD 분리
|
|
9
|
-
- `contexts/auth`, `contexts/user`, `contexts/shipping`, `contexts/alerts` 예시 도메인과 실제 호출 가능한 sample logic
|
|
10
|
-
- HTTP 계약은 `contexts/*/contracts/http`에 둔다
|
|
11
|
-
- `shared/(application|infrastructure)` 공통 레이어
|
|
12
|
-
- `memory`, `postgres`, `mysql`, `mariadb`, `mongodb` adapter 선택 가능
|
|
13
|
-
- `api/http/app.py` FastAPI app entrypoint
|
|
14
|
-
- `config.py` settings cache
|
|
15
|
-
- `api/http/router.py` 중심의 HTTP router aggregation
|
|
16
|
-
- `/health`와 `/api/v1/*` 기본 계약
|
|
17
|
-
- `.env.example`와 pytest 기본 테스트
|
|
18
|
-
|
|
19
|
-
시작:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
uv sync --extra dev
|
|
23
|
-
uv run uvicorn api.http.app:app --reload
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
기본 인증 예시:
|
|
27
|
-
|
|
28
|
-
- `POST /api/v1/auth/login`
|
|
29
|
-
- `GET /api/v1/auth/me`
|
|
30
|
-
- `GET /api/v1/users`
|
|
31
|
-
- `GET /api/v1/users/{user_id}`
|
|
32
|
-
- `GET /api/v1/shipping/overview`
|
|
33
|
-
- `GET /api/v1/alerts`
|
package/server/__init__.py
DELETED
|
File without changes
|
package/server/api/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__all__ = ["http"]
|
package/server/api/http/app.py
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
from collections.abc import AsyncIterator
|
|
2
|
-
from contextlib import asynccontextmanager
|
|
3
|
-
|
|
4
|
-
from fastapi import FastAPI
|
|
5
|
-
from fastapi.middleware.cors import CORSMiddleware
|
|
6
|
-
|
|
7
|
-
from api.http.router import api_router
|
|
8
|
-
from config import get_settings
|
|
9
|
-
from contexts.alerts.application import prepare_alert_store
|
|
10
|
-
from contexts.auth.application import prepare_auth_store
|
|
11
|
-
from contexts.catalog.application import prepare_catalog_store
|
|
12
|
-
from contexts.fulfillment.application import prepare_fulfillment_store
|
|
13
|
-
from contexts.inventory.application import prepare_inventory_store
|
|
14
|
-
from contexts.orders.application import prepare_order_store
|
|
15
|
-
from contexts.shipping.application import prepare_shipping_store
|
|
16
|
-
from contexts.support.application import prepare_support_store
|
|
17
|
-
from contexts.user.application import prepare_user_store
|
|
18
|
-
from shared.application import health_response
|
|
19
|
-
|
|
20
|
-
settings = get_settings()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@asynccontextmanager
|
|
24
|
-
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
|
|
25
|
-
prepare_alert_store()
|
|
26
|
-
prepare_auth_store()
|
|
27
|
-
prepare_catalog_store()
|
|
28
|
-
prepare_fulfillment_store()
|
|
29
|
-
prepare_inventory_store()
|
|
30
|
-
prepare_order_store()
|
|
31
|
-
prepare_shipping_store()
|
|
32
|
-
prepare_support_store()
|
|
33
|
-
prepare_user_store()
|
|
34
|
-
yield
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
app = FastAPI(title=settings.app_name, version="0.1.0", lifespan=lifespan)
|
|
38
|
-
|
|
39
|
-
app.add_middleware(
|
|
40
|
-
CORSMiddleware,
|
|
41
|
-
allow_origins=settings.cors_origins,
|
|
42
|
-
allow_credentials=True,
|
|
43
|
-
allow_methods=["*"],
|
|
44
|
-
allow_headers=["*"],
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@app.get("/health")
|
|
49
|
-
def health() -> dict[str, str]:
|
|
50
|
-
return health_response()
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
app.include_router(api_router, prefix=settings.api_prefix)
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
from fastapi import APIRouter
|
|
2
|
-
|
|
3
|
-
from contexts.alerts.contracts.http.router import router as alerts_router
|
|
4
|
-
from contexts.auth.contracts.http.router import router as auth_router
|
|
5
|
-
from contexts.catalog.contracts.http.router import router as catalog_router
|
|
6
|
-
from contexts.fulfillment.contracts.http.router import router as fulfillment_router
|
|
7
|
-
from contexts.health.contracts.http.router import router as health_router
|
|
8
|
-
from contexts.inventory.contracts.http.router import router as inventory_router
|
|
9
|
-
from contexts.orders.contracts.http.router import router as orders_router
|
|
10
|
-
from contexts.shipping.contracts.http.router import router as shipping_router
|
|
11
|
-
from contexts.support.contracts.http.router import router as support_router
|
|
12
|
-
from contexts.user.contracts.http.router import router as user_router
|
|
13
|
-
|
|
14
|
-
api_router = APIRouter()
|
|
15
|
-
api_router.include_router(alerts_router)
|
|
16
|
-
api_router.include_router(auth_router)
|
|
17
|
-
api_router.include_router(catalog_router)
|
|
18
|
-
api_router.include_router(fulfillment_router)
|
|
19
|
-
api_router.include_router(health_router)
|
|
20
|
-
api_router.include_router(inventory_router)
|
|
21
|
-
api_router.include_router(orders_router)
|
|
22
|
-
api_router.include_router(shipping_router)
|
|
23
|
-
api_router.include_router(support_router)
|
|
24
|
-
api_router.include_router(user_router)
|
package/server/config.py
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
from functools import lru_cache
|
|
2
|
-
from typing import Literal
|
|
3
|
-
|
|
4
|
-
from pydantic import Field, field_validator
|
|
5
|
-
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Settings(BaseSettings):
|
|
9
|
-
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
|
|
10
|
-
|
|
11
|
-
app_name: str = "Template Server"
|
|
12
|
-
environment: str = "development"
|
|
13
|
-
api_prefix: str = "/api/v1"
|
|
14
|
-
database_backend: Literal["memory", "postgres", "mysql", "mariadb", "mongodb"] = "memory"
|
|
15
|
-
postgres_url: str = "postgresql+psycopg://template:template@postgres:5432/template"
|
|
16
|
-
mysql_url: str = "mysql+pymysql://template:template@mysql:3306/template"
|
|
17
|
-
mariadb_url: str = "mysql+pymysql://template:template@mariadb:3306/template"
|
|
18
|
-
mongodb_url: str = "mongodb://mongo:27017"
|
|
19
|
-
mongodb_database: str = "template"
|
|
20
|
-
jwt_secret: str = "change-me"
|
|
21
|
-
jwt_algorithm: str = "HS256"
|
|
22
|
-
access_token_ttl_minutes: int = 120
|
|
23
|
-
bootstrap_admin_email: str = "admin@example.com"
|
|
24
|
-
bootstrap_admin_password: str = "<CHANGE_ME>"
|
|
25
|
-
bootstrap_admin_name: str = "Template Admin"
|
|
26
|
-
bootstrap_operator_email: str = "operator@example.com"
|
|
27
|
-
bootstrap_operator_password: str = "<CHANGE_ME>"
|
|
28
|
-
bootstrap_operator_name: str = "Template Operator"
|
|
29
|
-
cors_origins: list[str] = Field(
|
|
30
|
-
default_factory=lambda: [
|
|
31
|
-
"http://localhost:3000",
|
|
32
|
-
"http://127.0.0.1:3000",
|
|
33
|
-
"http://localhost:3001",
|
|
34
|
-
"http://127.0.0.1:3001",
|
|
35
|
-
"http://localhost:3002",
|
|
36
|
-
"http://127.0.0.1:3002",
|
|
37
|
-
"http://localhost:4000",
|
|
38
|
-
"http://127.0.0.1:4000",
|
|
39
|
-
]
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
@field_validator("cors_origins", mode="before")
|
|
43
|
-
@classmethod
|
|
44
|
-
def parse_cors_origins(cls, value: str | list[str]) -> list[str]:
|
|
45
|
-
if isinstance(value, str):
|
|
46
|
-
return [item.strip() for item in value.split(",") if item.strip()]
|
|
47
|
-
return value
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@lru_cache
|
|
51
|
-
def get_settings() -> Settings:
|
|
52
|
-
return Settings()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__all__ = ["application", "contracts", "domain", "infrastructure"]
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
from contexts.alerts.domain import (
|
|
2
|
-
AlertItem,
|
|
3
|
-
AlertReadResult,
|
|
4
|
-
AlertsPayload,
|
|
5
|
-
AlertsReadAllResult,
|
|
6
|
-
)
|
|
7
|
-
from contexts.alerts.infrastructure import (
|
|
8
|
-
list_seed_alerts,
|
|
9
|
-
mark_all_seed_alerts_read,
|
|
10
|
-
mark_seed_alert_read,
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def _to_alert_item(record: AlertItem) -> AlertItem:
|
|
15
|
-
return AlertItem(**record.model_dump())
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def get_alerts() -> AlertsPayload:
|
|
19
|
-
records = list_seed_alerts()
|
|
20
|
-
return AlertsPayload(
|
|
21
|
-
unread_count=sum(1 for record in records if not record.read),
|
|
22
|
-
items=[_to_alert_item(record) for record in records],
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def mark_alert_read(alert_id: str) -> AlertReadResult:
|
|
27
|
-
record = mark_seed_alert_read(alert_id)
|
|
28
|
-
return AlertReadResult(**record.model_dump())
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def mark_all_alerts_read() -> AlertsReadAllResult:
|
|
32
|
-
updated_count = mark_all_seed_alerts_read()
|
|
33
|
-
unread_count = sum(1 for record in list_seed_alerts() if not record.read)
|
|
34
|
-
return AlertsReadAllResult(
|
|
35
|
-
updated_count=updated_count,
|
|
36
|
-
unread_count=unread_count,
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def prepare_alert_store() -> None:
|
|
41
|
-
list_seed_alerts()
|