agentic-dev 0.2.3 → 0.2.4
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/.claude/CLAUDE.md +1 -1
- package/.env.example +2 -2
- package/README.md +5 -5
- package/client/{platform → web}/Dockerfile +3 -3
- package/client/web/Dockerfile.dev +18 -0
- package/client/{platform → web}/README.md +3 -3
- package/client/{platform → web}/index.html +1 -1
- package/client/{platform → web}/package.json +7 -7
- package/client/{platform/scripts/ui-parity-platform-adapter.mjs → web/scripts/ui-parity-web-adapter.mjs} +7 -7
- package/client/{platform → web}/src/auth/AuthProvider.tsx +1 -1
- package/compose.yml +6 -6
- package/infra/compose/.env.dev.example +3 -3
- package/infra/compose/.env.prod.example +3 -3
- package/infra/compose/README.md +1 -1
- package/infra/compose/dev.yml +5 -5
- package/infra/compose/prod.yml +6 -6
- package/infra/terraform/openstack/dev/terraform.tfvars.example +3 -3
- package/infra/terraform/openstack/prod/terraform.tfvars.example +3 -3
- package/lib/scaffold.mjs +7 -7
- package/package.json +2 -2
- package/scripts/dev/audit_sdd_build_ast.py +9 -9
- package/sdd/01_planning/01_feature/auth_feature_spec.md +2 -2
- package/sdd/01_planning/01_feature/catalog_feature_spec.md +3 -3
- package/sdd/01_planning/01_feature/order_feature_spec.md +11 -11
- package/sdd/01_planning/02_screen/INDEX.md +2 -2
- package/sdd/01_planning/02_screen/README.md +2 -2
- package/sdd/01_planning/03_architecture/templates_system_architecture.md +3 -3
- package/sdd/01_planning/05_api/templates_api_contract.md +3 -3
- package/sdd/01_planning/06_iac/templates_runtime_and_cicd_baseline.md +1 -1
- package/sdd/01_planning/07_integration/templates_frontend_api_integration.md +3 -3
- package/sdd/01_planning/10_test/templates_test_strategy.md +2 -2
- package/sdd/01_planning/INDEX.md +1 -1
- package/sdd/02_plan/02_screen/INDEX.md +1 -1
- package/sdd/02_plan/02_screen/README.md +1 -1
- package/sdd/02_plan/03_architecture/build_ast_runtime_tree_governance.md +1 -1
- package/sdd/02_plan/03_architecture/repository_governance.md +1 -1
- package/sdd/02_plan/07_integration/frontend_live_integration.md +3 -3
- package/sdd/02_plan/10_test/templates/{ui_parity_platform_contract.template.yaml → ui_parity_web_contract.template.yaml} +1 -1
- package/sdd/03_build/01_feature/domain/account_and_access.md +1 -1
- package/sdd/03_build/01_feature/domain/catalog_and_inventory.md +1 -1
- package/sdd/03_build/01_feature/domain/ordering_and_fulfillment.md +1 -1
- package/sdd/03_build/01_feature/service/README.md +1 -1
- package/sdd/03_build/01_feature/service/{platform_surface.md → web_surface.md} +3 -3
- package/sdd/03_build/02_screen/README.md +1 -1
- package/sdd/03_build/02_screen/web/README.md +5 -0
- package/sdd/03_build/06_iac/template_runtime_delivery.md +1 -1
- package/sdd/03_build/07_integration/frontend_live_integration.md +1 -1
- package/sdd/04_verify/01_feature/service_verification.md +2 -2
- package/sdd/04_verify/02_screen/web/README.md +4 -0
- package/sdd/04_verify/06_iac/template_runtime_delivery.md +3 -3
- package/sdd/99_toolchain/01_automation/agentic-dev/assets/repo-contract.template.json +11 -11
- package/sdd/99_toolchain/01_automation/agentic-dev/repo-contract.json +13 -13
- package/sdd/99_toolchain/01_automation/agentic-parity-harness-design.md +5 -5
- package/sdd/99_toolchain/01_automation/capture_screen_assets.mjs +4 -4
- package/sdd/99_toolchain/01_automation/harness-layout.md +2 -2
- package/sdd/99_toolchain/01_automation/parity-execution-tooling-design.md +5 -5
- package/sdd/99_toolchain/01_automation/screen_spec_manifest.py +17 -17
- package/sdd/99_toolchain/01_automation/ui-parity/README.md +10 -10
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-artifact-layout.md +1 -1
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-route-gap-interface.md +2 -2
- package/sdd/99_toolchain/03_templates/playwright_exactness_manifest.example.py +1 -1
- package/server/data/README.md +1 -1
- package/client/platform/Dockerfile.dev +0 -18
- package/sdd/03_build/02_screen/platform/README.md +0 -5
- package/sdd/04_verify/02_screen/platform/README.md +0 -4
- /package/client/{platform → web}/.dockerignore +0 -0
- /package/client/{platform → web}/.env.example +0 -0
- /package/client/{platform → web}/postcss.config.js +0 -0
- /package/client/{platform → web}/src/api/client.ts +0 -0
- /package/client/{platform → web}/src/api/orders.ts +0 -0
- /package/client/{platform → web}/src/app/App.tsx +0 -0
- /package/client/{platform → web}/src/auth/ProtectedRoute.tsx +0 -0
- /package/client/{platform → web}/src/auth/auth-client.ts +0 -0
- /package/client/{platform → web}/src/auth/types.ts +0 -0
- /package/client/{platform → web}/src/components/AppShell.tsx +0 -0
- /package/client/{platform → web}/src/components/ui/button.tsx +0 -0
- /package/client/{platform → web}/src/components/ui/card.tsx +0 -0
- /package/client/{platform → web}/src/components/ui/input.tsx +0 -0
- /package/client/{platform → web}/src/lib/cn.ts +0 -0
- /package/client/{platform → web}/src/lib/specRouteCatalog.json +0 -0
- /package/client/{platform → web}/src/lib/specScreens.json +0 -0
- /package/client/{platform → web}/src/main.tsx +0 -0
- /package/client/{platform → web}/src/pages/DashboardPage.tsx +0 -0
- /package/client/{platform → web}/src/pages/LoginPage.tsx +0 -0
- /package/client/{platform → web}/src/pages/OrdersPage.tsx +0 -0
- /package/client/{platform → web}/src/styles/globals.css +0 -0
- /package/client/{platform → web}/src/theme-vars.ts +0 -0
- /package/client/{platform → web}/src/theme.ts +0 -0
- /package/client/{platform → web}/src/vite-env.d.ts +0 -0
- /package/client/{platform → web}/tailwind.config.js +0 -0
- /package/client/{platform → web}/tsconfig.json +0 -0
- /package/client/{platform → web}/vite.config.ts +0 -0
- /package/sdd/01_planning/02_screen/{platform_screen_spec.pdf → web_screen_spec.pdf} +0 -0
- /package/sdd/99_toolchain/01_automation/assets/{platform_screen_capture → web_screen_capture}/dashboard.png +0 -0
- /package/sdd/99_toolchain/01_automation/assets/{platform_screen_capture → web_screen_capture}/login.png +0 -0
- /package/sdd/99_toolchain/01_automation/assets/{platform_screen_capture → web_screen_capture}/orders.png +0 -0
package/.claude/CLAUDE.md
CHANGED
|
@@ -19,7 +19,7 @@ templates/
|
|
|
19
19
|
│ └── skills/ # Claude Code repo-local skills (.claude/skills/<name>/SKILL.md)
|
|
20
20
|
├── .codex/ # Codex 설정, 에이전트, 스킬
|
|
21
21
|
├── client/
|
|
22
|
-
│ ├──
|
|
22
|
+
│ ├── web/ # 일반 앱 템플릿
|
|
23
23
|
│ ├── admin/ # 어드민 템플릿
|
|
24
24
|
│ ├── mobile/ # 현장형 모바일 템플릿
|
|
25
25
|
│ └── landing/ # 랜딩 템플릿
|
package/.env.example
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
SERVER_HTTP_PORT=8000
|
|
2
2
|
CLIENT_LANDING_PORT=3000
|
|
3
|
-
|
|
3
|
+
CLIENT_WEB_PORT=3001
|
|
4
4
|
CLIENT_MOBILE_PORT=3002
|
|
5
5
|
CLIENT_ADMIN_PORT=4000
|
|
6
6
|
|
|
@@ -44,7 +44,7 @@ SERVER_BOOTSTRAP_OPERATOR_NAME=Template Operator
|
|
|
44
44
|
SERVER_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"]
|
|
45
45
|
|
|
46
46
|
CLIENT_LANDING_VITE_API_BASE_URL=http://127.0.0.1:8000/api/v1
|
|
47
|
-
|
|
47
|
+
CLIENT_WEB_VITE_API_BASE_URL=http://127.0.0.1:8000/api/v1
|
|
48
48
|
CLIENT_MOBILE_VITE_API_BASE_URL=http://127.0.0.1:8000/api/v1
|
|
49
49
|
CLIENT_ADMIN_VITE_API_BASE_URL=http://127.0.0.1:8000/api/v1
|
|
50
50
|
CLIENT_WATCH_USE_POLLING=false
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
포함 템플릿:
|
|
6
6
|
|
|
7
7
|
- [landing](./client/landing): 마케팅/브랜드 랜딩 패턴
|
|
8
|
-
- [
|
|
8
|
+
- [web](./client/web): 일반 제품형 웹 앱 shell, dashboard/list/detail 패턴
|
|
9
9
|
- [mobile](./client/mobile): 다국어/현장 업무형 모바일 IN workspace 패턴
|
|
10
10
|
- [admin](./client/admin): 운영 콘솔형 shell, sidebar/topbar/drawer/table 패턴
|
|
11
11
|
- [server](./server): HTTP 기반 hexagonal/DDD 서버 패턴
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
- 제품 DOM은 유지하고, 스타일 조정값은 `theme.ts` + CSS custom properties로 노출
|
|
18
18
|
- proof/spec 전용 DOM 복제 대신 fixture data + parameter surface로 정렬
|
|
19
19
|
- `server`는 hexagonal architecture 기준으로 `contracts + application + domain + infrastructure`를 사용
|
|
20
|
-
- `landing`, `
|
|
20
|
+
- `landing`, `web`, `mobile`, `admin`은 실제 `/api/v1/auth/login`과 `/api/v1/auth/me`를 사용하는 기준 템플릿이다.
|
|
21
21
|
- runtime baseline은 루트 `compose.yml`을 기준으로 유지하고, 여기서 4개 frontend surface, `server`, 기본 `postgres`, optional DB profile을 함께 올린다.
|
|
22
22
|
- agentic baseline은 `.claude`, `.codex`, `.agent`를 함께 유지하고 downstream repo가 role agent, skill alias, Ralph harness를 그대로 가져가도록 설계한다.
|
|
23
23
|
- `sdd/03_build`는 단순 구현 목록이 아니라 실제 runtime assembly를 따라 읽는 AST-style current-state 설명을 기준으로 유지한다.
|
|
@@ -42,12 +42,12 @@ SDD / delivery 원칙:
|
|
|
42
42
|
설치형 scaffold:
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
npx agentic-dev init my-app --template
|
|
45
|
+
npx agentic-dev init my-app --template web
|
|
46
46
|
cd my-app
|
|
47
47
|
cp .env.example .env
|
|
48
48
|
npm install -g pnpm
|
|
49
49
|
pnpm install
|
|
50
|
-
cd client/
|
|
50
|
+
cd client/web
|
|
51
51
|
npm run ui:parity:bootstrap
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -74,7 +74,7 @@ docker compose up --build
|
|
|
74
74
|
기본 compose 포트:
|
|
75
75
|
|
|
76
76
|
- `client/landing`: `3000`
|
|
77
|
-
- `client/
|
|
77
|
+
- `client/web`: `3001`
|
|
78
78
|
- `client/mobile`: `3002`
|
|
79
79
|
- `client/admin`: `4000`
|
|
80
80
|
- `server/http`: `8000`
|
|
@@ -3,13 +3,13 @@ FROM node:20-slim
|
|
|
3
3
|
WORKDIR /app
|
|
4
4
|
|
|
5
5
|
COPY pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
6
|
-
COPY client/
|
|
6
|
+
COPY client/web/package.json ./client/web/package.json
|
|
7
7
|
|
|
8
|
-
RUN npm install -g pnpm@10.32.0 && pnpm install --filter @do4ai/client-
|
|
8
|
+
RUN npm install -g pnpm@10.32.0 && pnpm install --filter @do4ai/client-web-template...
|
|
9
9
|
|
|
10
10
|
COPY . .
|
|
11
11
|
|
|
12
|
-
WORKDIR /app/client/
|
|
12
|
+
WORKDIR /app/client/web
|
|
13
13
|
|
|
14
14
|
EXPOSE 3001
|
|
15
15
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
FROM node:20-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
RUN npm install -g pnpm@10.32.0
|
|
6
|
+
|
|
7
|
+
COPY pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
8
|
+
COPY client/web/package.json ./client/web/package.json
|
|
9
|
+
|
|
10
|
+
RUN pnpm install --frozen-lockfile --filter @do4ai/client-web-template...
|
|
11
|
+
|
|
12
|
+
COPY client/web ./client/web
|
|
13
|
+
|
|
14
|
+
WORKDIR /app/client/web
|
|
15
|
+
|
|
16
|
+
EXPOSE 3001
|
|
17
|
+
|
|
18
|
+
CMD ["sh", "-lc", "pnpm exec vite --host 0.0.0.0 --port ${PORT:-3001}"]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# web
|
|
2
2
|
|
|
3
3
|
일반 사용자용 제품 앱 보일러플레이트다.
|
|
4
4
|
|
|
@@ -25,7 +25,7 @@ npm run dev
|
|
|
25
25
|
npm run ui:parity:init
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
이 단계는 repo-level contract, `
|
|
28
|
+
이 단계는 repo-level contract, `ui_parity_web_contract.yaml`, route-gap manifest를 생성한다.
|
|
29
29
|
|
|
30
30
|
첫 proof 부트스트랩:
|
|
31
31
|
|
|
@@ -44,4 +44,4 @@ npm run ui:parity:route-gap
|
|
|
44
44
|
npm run ui:parity:proof
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
이 템플릿은 repo root의 `sdd/99_toolchain/01_automation` 도구를 사용하고, `client/
|
|
47
|
+
이 템플릿은 repo root의 `sdd/99_toolchain/01_automation` 도구를 사용하고, `client/web/scripts/ui-parity-web-adapter.mjs`는 앱별 adapter 예시다.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@do4ai/client-
|
|
2
|
+
"name": "@do4ai/client-web-template",
|
|
3
3
|
"private": true,
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"type": "module",
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"dev": "vite --host 0.0.0.0 --port 3001",
|
|
9
9
|
"build": "tsc -b && vite build",
|
|
10
10
|
"preview": "vite preview --host 0.0.0.0 --port 4301",
|
|
11
|
-
"ui:parity:init": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/init_frontend_parity.sh ../..
|
|
12
|
-
"ui:parity:bootstrap": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/bootstrap_frontend_parity.sh ../..
|
|
13
|
-
"ui:parity:scaffold": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh scaffold ../..
|
|
14
|
-
"ui:parity:materialize-references": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh materialize_references ../..
|
|
15
|
-
"ui:parity:route-gap": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh route_gap ../..
|
|
16
|
-
"ui:parity:proof": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh proof ../..
|
|
11
|
+
"ui:parity:init": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/init_frontend_parity.sh ../.. web",
|
|
12
|
+
"ui:parity:bootstrap": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/bootstrap_frontend_parity.sh ../.. web",
|
|
13
|
+
"ui:parity:scaffold": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh scaffold ../.. web",
|
|
14
|
+
"ui:parity:materialize-references": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh materialize_references ../.. web",
|
|
15
|
+
"ui:parity:route-gap": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh route_gap ../.. web",
|
|
16
|
+
"ui:parity:proof": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh proof ../.. web",
|
|
17
17
|
"ui:parity": "npm run ui:parity:proof"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
@@ -13,7 +13,7 @@ const routes = JSON.parse(
|
|
|
13
13
|
const routeMap = new Map(routes.map((entry) => [entry.id, entry.route]));
|
|
14
14
|
|
|
15
15
|
export default {
|
|
16
|
-
service: "templates-
|
|
16
|
+
service: "templates-web",
|
|
17
17
|
targetBaseUrl: "http://127.0.0.1:4301",
|
|
18
18
|
viewport: {
|
|
19
19
|
width: 1440,
|
|
@@ -26,7 +26,7 @@ export default {
|
|
|
26
26
|
referenceImage: `sdd/04_verify/10_test/ui_parity/reference/${screen.id}.png`,
|
|
27
27
|
readySelector: "body",
|
|
28
28
|
readyTimeoutMs: 10000,
|
|
29
|
-
tags: ["template", "
|
|
29
|
+
tags: ["template", "web"],
|
|
30
30
|
})),
|
|
31
31
|
async preparePage(page, { route }) {
|
|
32
32
|
await page.route("**/auth/me", async (routeRequest) => {
|
|
@@ -34,8 +34,8 @@ export default {
|
|
|
34
34
|
status: 200,
|
|
35
35
|
contentType: "application/json",
|
|
36
36
|
body: JSON.stringify({
|
|
37
|
-
id: "tmpl-
|
|
38
|
-
name: "Template
|
|
37
|
+
id: "tmpl-web",
|
|
38
|
+
name: "Template Web User",
|
|
39
39
|
email: "operator@example.com",
|
|
40
40
|
role: "member",
|
|
41
41
|
}),
|
|
@@ -43,17 +43,17 @@ export default {
|
|
|
43
43
|
});
|
|
44
44
|
await page.addInitScript(() => {
|
|
45
45
|
window.localStorage.setItem(
|
|
46
|
-
"
|
|
46
|
+
"web.auth.token",
|
|
47
47
|
JSON.stringify({
|
|
48
48
|
access_token: "template-access-token",
|
|
49
49
|
token_type: "bearer",
|
|
50
|
-
user_id: "tmpl-
|
|
50
|
+
user_id: "tmpl-web",
|
|
51
51
|
}),
|
|
52
52
|
);
|
|
53
53
|
});
|
|
54
54
|
if (route === "/login") {
|
|
55
55
|
await page.addInitScript(() => {
|
|
56
|
-
window.localStorage.removeItem("
|
|
56
|
+
window.localStorage.removeItem("web.auth.token");
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
},
|
|
@@ -3,7 +3,7 @@ import { createContext, useContext, useEffect, useMemo, useState, type ReactNode
|
|
|
3
3
|
import { getMe, login as loginRequest } from "@/auth/auth-client";
|
|
4
4
|
import type { AuthToken, AuthUser, LoginCommand } from "@/auth/types";
|
|
5
5
|
|
|
6
|
-
const STORAGE_KEY = "
|
|
6
|
+
const STORAGE_KEY = "web.auth.token";
|
|
7
7
|
|
|
8
8
|
interface AuthContextValue {
|
|
9
9
|
user: AuthUser | null;
|
package/compose.yml
CHANGED
|
@@ -138,19 +138,19 @@ services:
|
|
|
138
138
|
networks:
|
|
139
139
|
- template-dev
|
|
140
140
|
|
|
141
|
-
client-
|
|
141
|
+
client-web:
|
|
142
142
|
build:
|
|
143
143
|
context: .
|
|
144
|
-
dockerfile: client/
|
|
144
|
+
dockerfile: client/web/Dockerfile.dev
|
|
145
145
|
network: host
|
|
146
146
|
environment:
|
|
147
|
-
PORT: ${
|
|
148
|
-
VITE_API_BASE_URL: ${
|
|
147
|
+
PORT: ${CLIENT_WEB_PORT:-3001}
|
|
148
|
+
VITE_API_BASE_URL: ${CLIENT_WEB_VITE_API_BASE_URL:-http://127.0.0.1:8000/api/v1}
|
|
149
149
|
CHOKIDAR_USEPOLLING: ${CLIENT_WATCH_USE_POLLING:-false}
|
|
150
150
|
ports:
|
|
151
|
-
- "${
|
|
151
|
+
- "${CLIENT_WEB_PORT:-3001}:${CLIENT_WEB_PORT:-3001}"
|
|
152
152
|
volumes:
|
|
153
|
-
- ./client/
|
|
153
|
+
- ./client/web:/app/client/web
|
|
154
154
|
depends_on:
|
|
155
155
|
server:
|
|
156
156
|
condition: service_started
|
|
@@ -15,14 +15,14 @@ DEV_SERVER_MONGODB_URL=mongodb://mongo:27017
|
|
|
15
15
|
DEV_SERVER_MONGODB_DATABASE=template
|
|
16
16
|
DEV_SERVER_JWT_SECRET=change-me
|
|
17
17
|
DEV_SERVER_ACCESS_TOKEN_TTL_MINUTES=120
|
|
18
|
-
DEV_SERVER_CORS_ORIGINS=https://dev-landing.example.com,https://dev-
|
|
18
|
+
DEV_SERVER_CORS_ORIGINS=https://dev-landing.example.com,https://dev-web.example.com,https://dev-mobile.example.com,https://dev-admin.example.com
|
|
19
19
|
|
|
20
20
|
DEV_CLIENT_LANDING_PORT=13000
|
|
21
|
-
|
|
21
|
+
DEV_CLIENT_WEB_PORT=13001
|
|
22
22
|
DEV_CLIENT_MOBILE_PORT=13002
|
|
23
23
|
DEV_CLIENT_ADMIN_PORT=14000
|
|
24
24
|
|
|
25
25
|
DEV_CLIENT_LANDING_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
26
|
-
|
|
26
|
+
DEV_CLIENT_WEB_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
27
27
|
DEV_CLIENT_MOBILE_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
28
28
|
DEV_CLIENT_ADMIN_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
@@ -16,14 +16,14 @@ PROD_SERVER_MONGODB_URL=mongodb://mongo:27017
|
|
|
16
16
|
PROD_SERVER_MONGODB_DATABASE=template
|
|
17
17
|
PROD_SERVER_JWT_SECRET=change-me
|
|
18
18
|
PROD_SERVER_ACCESS_TOKEN_TTL_MINUTES=120
|
|
19
|
-
PROD_SERVER_CORS_ORIGINS=https://landing.example.com,https://
|
|
19
|
+
PROD_SERVER_CORS_ORIGINS=https://landing.example.com,https://web.example.com,https://mobile.example.com,https://admin.example.com
|
|
20
20
|
|
|
21
21
|
PROD_CLIENT_LANDING_PORT=23000
|
|
22
|
-
|
|
22
|
+
PROD_CLIENT_WEB_PORT=23001
|
|
23
23
|
PROD_CLIENT_MOBILE_PORT=23002
|
|
24
24
|
PROD_CLIENT_ADMIN_PORT=24000
|
|
25
25
|
|
|
26
26
|
PROD_CLIENT_LANDING_VITE_API_BASE_URL=https://api.example.com/api/v1
|
|
27
|
-
|
|
27
|
+
PROD_CLIENT_WEB_VITE_API_BASE_URL=https://api.example.com/api/v1
|
|
28
28
|
PROD_CLIENT_MOBILE_VITE_API_BASE_URL=https://api.example.com/api/v1
|
|
29
29
|
PROD_CLIENT_ADMIN_VITE_API_BASE_URL=https://api.example.com/api/v1
|
package/infra/compose/README.md
CHANGED
|
@@ -30,6 +30,6 @@ docker compose --env-file infra/compose/.env.prod -f infra/compose/prod.yml up -
|
|
|
30
30
|
- `infra/compose/dev.yml`, `infra/compose/prod.yml`은 dedicated host/runtime split이 필요할 때 쓰는 overlay이며, root compose baseline을 대체하는 문서 기준선은 아니다.
|
|
31
31
|
- provider-first canonical delivery split은 `AWS edge/domain -> OpenStack backend compute -> AWS data plane`이고, 세부 구조는 `infra/terraform/README.md`를 기준으로 설명한다.
|
|
32
32
|
- `VITE_API_BASE_URL`은 컨테이너 내부 DNS가 아니라 브라우저가 도달 가능한 API URL이어야 한다.
|
|
33
|
-
- 포트 역할은 root compose baseline과 같은 순서를 따른다: landing,
|
|
33
|
+
- 포트 역할은 root compose baseline과 같은 순서를 따른다: landing, web, mobile, admin, server/http.
|
|
34
34
|
- PROD 웹 앱은 `pnpm build + pnpm preview`로 기동한다.
|
|
35
35
|
- OpenStack에서 자동 배포까지 묶고 싶으면 `infra/terraform/openstack/server` 또는 lower-level `openstack/dev`, `openstack/prod` root를 사용한다.
|
package/infra/compose/dev.yml
CHANGED
|
@@ -65,20 +65,20 @@ services:
|
|
|
65
65
|
networks:
|
|
66
66
|
- templates-dev
|
|
67
67
|
|
|
68
|
-
client-
|
|
68
|
+
client-web:
|
|
69
69
|
build:
|
|
70
70
|
context: ../..
|
|
71
|
-
dockerfile: client/
|
|
72
|
-
container_name: templates-client-
|
|
71
|
+
dockerfile: client/web/Dockerfile
|
|
72
|
+
container_name: templates-client-web-dev
|
|
73
73
|
restart: unless-stopped
|
|
74
74
|
depends_on:
|
|
75
75
|
server:
|
|
76
76
|
condition: service_started
|
|
77
77
|
environment:
|
|
78
|
-
VITE_API_BASE_URL: ${
|
|
78
|
+
VITE_API_BASE_URL: ${DEV_CLIENT_WEB_VITE_API_BASE_URL}
|
|
79
79
|
PORT: 3001
|
|
80
80
|
ports:
|
|
81
|
-
- "${
|
|
81
|
+
- "${DEV_CLIENT_WEB_PORT:-13001}:3001"
|
|
82
82
|
networks:
|
|
83
83
|
- templates-dev
|
|
84
84
|
|
package/infra/compose/prod.yml
CHANGED
|
@@ -43,7 +43,7 @@ services:
|
|
|
43
43
|
MONGODB_DATABASE: ${PROD_SERVER_MONGODB_DATABASE:-template}
|
|
44
44
|
JWT_SECRET: ${PROD_SERVER_JWT_SECRET:-change-me}
|
|
45
45
|
ACCESS_TOKEN_TTL_MINUTES: ${PROD_SERVER_ACCESS_TOKEN_TTL_MINUTES:-120}
|
|
46
|
-
CORS_ORIGINS: ${PROD_SERVER_CORS_ORIGINS:-https://landing.example.com,https://
|
|
46
|
+
CORS_ORIGINS: ${PROD_SERVER_CORS_ORIGINS:-https://landing.example.com,https://web.example.com,https://mobile.example.com,https://admin.example.com}
|
|
47
47
|
ports:
|
|
48
48
|
- "${PROD_SERVER_HTTP_PORT:-28000}:8000"
|
|
49
49
|
networks:
|
|
@@ -66,20 +66,20 @@ services:
|
|
|
66
66
|
networks:
|
|
67
67
|
- templates-prod
|
|
68
68
|
|
|
69
|
-
client-
|
|
69
|
+
client-web:
|
|
70
70
|
build:
|
|
71
71
|
context: ../..
|
|
72
|
-
dockerfile: client/
|
|
73
|
-
container_name: templates-client-
|
|
72
|
+
dockerfile: client/web/Dockerfile
|
|
73
|
+
container_name: templates-client-web-prod
|
|
74
74
|
restart: unless-stopped
|
|
75
75
|
depends_on:
|
|
76
76
|
server:
|
|
77
77
|
condition: service_started
|
|
78
78
|
command: ["sh", "-lc", "pnpm build && pnpm preview --host 0.0.0.0 --port 4301"]
|
|
79
79
|
environment:
|
|
80
|
-
VITE_API_BASE_URL: ${
|
|
80
|
+
VITE_API_BASE_URL: ${PROD_CLIENT_WEB_VITE_API_BASE_URL}
|
|
81
81
|
ports:
|
|
82
|
-
- "${
|
|
82
|
+
- "${PROD_CLIENT_WEB_PORT:-23001}:4301"
|
|
83
83
|
networks:
|
|
84
84
|
- templates-prod
|
|
85
85
|
|
|
@@ -42,13 +42,13 @@ compose_env_content = <<-ENV
|
|
|
42
42
|
DEV_SERVER_POSTGRES_URL=postgresql+psycopg://template:template@postgres:5432/template
|
|
43
43
|
DEV_SERVER_JWT_SECRET=change-me
|
|
44
44
|
DEV_SERVER_ACCESS_TOKEN_TTL_MINUTES=120
|
|
45
|
-
DEV_SERVER_CORS_ORIGINS=https://dev-landing.example.com,https://dev-
|
|
45
|
+
DEV_SERVER_CORS_ORIGINS=https://dev-landing.example.com,https://dev-web.example.com,https://dev-mobile.example.com,https://dev-admin.example.com
|
|
46
46
|
DEV_CLIENT_LANDING_PORT=13000
|
|
47
|
-
|
|
47
|
+
DEV_CLIENT_WEB_PORT=13001
|
|
48
48
|
DEV_CLIENT_MOBILE_PORT=13002
|
|
49
49
|
DEV_CLIENT_ADMIN_PORT=14000
|
|
50
50
|
DEV_CLIENT_LANDING_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
51
|
-
|
|
51
|
+
DEV_CLIENT_WEB_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
52
52
|
DEV_CLIENT_MOBILE_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
53
53
|
DEV_CLIENT_ADMIN_VITE_API_BASE_URL=https://dev-api.example.com/api/v1
|
|
54
54
|
ENV
|
|
@@ -43,13 +43,13 @@ compose_env_content = <<-ENV
|
|
|
43
43
|
PROD_SERVER_POSTGRES_URL=postgresql+psycopg://template:template@postgres:5432/template
|
|
44
44
|
PROD_SERVER_JWT_SECRET=change-me
|
|
45
45
|
PROD_SERVER_ACCESS_TOKEN_TTL_MINUTES=120
|
|
46
|
-
PROD_SERVER_CORS_ORIGINS=https://landing.example.com,https://
|
|
46
|
+
PROD_SERVER_CORS_ORIGINS=https://landing.example.com,https://web.example.com,https://mobile.example.com,https://admin.example.com
|
|
47
47
|
PROD_CLIENT_LANDING_PORT=23000
|
|
48
|
-
|
|
48
|
+
PROD_CLIENT_WEB_PORT=23001
|
|
49
49
|
PROD_CLIENT_MOBILE_PORT=23002
|
|
50
50
|
PROD_CLIENT_ADMIN_PORT=24000
|
|
51
51
|
PROD_CLIENT_LANDING_VITE_API_BASE_URL=https://api.example.com/api/v1
|
|
52
|
-
|
|
52
|
+
PROD_CLIENT_WEB_VITE_API_BASE_URL=https://api.example.com/api/v1
|
|
53
53
|
PROD_CLIENT_MOBILE_VITE_API_BASE_URL=https://api.example.com/api/v1
|
|
54
54
|
PROD_CLIENT_ADMIN_VITE_API_BASE_URL=https://api.example.com/api/v1
|
|
55
55
|
ENV
|
package/lib/scaffold.mjs
CHANGED
|
@@ -11,11 +11,11 @@ export const TEMPLATE_CONFIG = {
|
|
|
11
11
|
composeApiVar: "CLIENT_LANDING_VITE_API_BASE_URL",
|
|
12
12
|
defaultPort: 3000,
|
|
13
13
|
},
|
|
14
|
-
|
|
15
|
-
id: "
|
|
16
|
-
serviceName: "client-
|
|
17
|
-
composePortVar: "
|
|
18
|
-
composeApiVar: "
|
|
14
|
+
web: {
|
|
15
|
+
id: "web",
|
|
16
|
+
serviceName: "client-web",
|
|
17
|
+
composePortVar: "CLIENT_WEB_PORT",
|
|
18
|
+
composeApiVar: "CLIENT_WEB_VITE_API_BASE_URL",
|
|
19
19
|
defaultPort: 3001,
|
|
20
20
|
},
|
|
21
21
|
mobile: {
|
|
@@ -112,10 +112,10 @@ export function parseArgs(argv) {
|
|
|
112
112
|
export function usage() {
|
|
113
113
|
return [
|
|
114
114
|
"Usage:",
|
|
115
|
-
" agentic-dev init <target-dir> --template <landing|
|
|
115
|
+
" agentic-dev init <target-dir> --template <landing|web|mobile|admin>",
|
|
116
116
|
"",
|
|
117
117
|
"Examples:",
|
|
118
|
-
" npx agentic-dev init my-app --template
|
|
118
|
+
" npx agentic-dev init my-app --template web",
|
|
119
119
|
" npx agentic-dev my-app --template mobile",
|
|
120
120
|
"",
|
|
121
121
|
"Options:",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-dev",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Scaffold an agentic template repo with the selected frontend surface and shared toolchain assets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.32.0",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"pnpm-workspace.yaml"
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
|
-
"smoke:init": "node ./bin/agentic-dev.mjs init ./.tmp-agentic-smoke --template
|
|
31
|
+
"smoke:init": "node ./bin/agentic-dev.mjs init ./.tmp-agentic-smoke --template web --yes --force"
|
|
32
32
|
},
|
|
33
33
|
"keywords": [
|
|
34
34
|
"agentic",
|
|
@@ -12,7 +12,7 @@ ROOT = Path(__file__).resolve().parents[2]
|
|
|
12
12
|
|
|
13
13
|
SERVICE_DOCS = {
|
|
14
14
|
"mobile": ROOT / "sdd/03_build/01_feature/service/mobile_surface.md",
|
|
15
|
-
"
|
|
15
|
+
"web": ROOT / "sdd/03_build/01_feature/service/web_surface.md",
|
|
16
16
|
"admin": ROOT / "sdd/03_build/01_feature/service/admin_surface.md",
|
|
17
17
|
"landing": ROOT / "sdd/03_build/01_feature/service/landing_surface.md",
|
|
18
18
|
}
|
|
@@ -59,14 +59,14 @@ def ast_similarity() -> tuple[int, list[str]]:
|
|
|
59
59
|
else:
|
|
60
60
|
findings.append("mobile surface summary does not reflect the real provider/router/shell chain.")
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
web = read(SERVICE_DOCS["web"])
|
|
63
63
|
if contains_all(
|
|
64
|
-
|
|
64
|
+
web,
|
|
65
65
|
[
|
|
66
|
-
"client/
|
|
66
|
+
"client/web/src/main.tsx",
|
|
67
67
|
"AuthProvider",
|
|
68
68
|
"BrowserRouter",
|
|
69
|
-
"client/
|
|
69
|
+
"client/web/src/app/App.tsx",
|
|
70
70
|
"ProtectedRoute",
|
|
71
71
|
"AppShell",
|
|
72
72
|
"DashboardPage",
|
|
@@ -75,7 +75,7 @@ def ast_similarity() -> tuple[int, list[str]]:
|
|
|
75
75
|
):
|
|
76
76
|
points += 2.5
|
|
77
77
|
else:
|
|
78
|
-
findings.append("
|
|
78
|
+
findings.append("web surface summary does not reflect the real app shell route tree.")
|
|
79
79
|
|
|
80
80
|
admin = read(SERVICE_DOCS["admin"])
|
|
81
81
|
if contains_all(
|
|
@@ -139,9 +139,9 @@ def implementation_traceability() -> tuple[int, list[str]]:
|
|
|
139
139
|
else:
|
|
140
140
|
findings.append("mobile surface summary does not trace route leaves to backend contract leaves.")
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
web = read(SERVICE_DOCS["web"])
|
|
143
143
|
if contains_all(
|
|
144
|
-
|
|
144
|
+
web,
|
|
145
145
|
[
|
|
146
146
|
"server/main.py",
|
|
147
147
|
"server/api/http/app.py",
|
|
@@ -153,7 +153,7 @@ def implementation_traceability() -> tuple[int, list[str]]:
|
|
|
153
153
|
):
|
|
154
154
|
points += 2.0
|
|
155
155
|
else:
|
|
156
|
-
findings.append("
|
|
156
|
+
findings.append("web surface summary does not trace dashboard and orders routes to backend contracts.")
|
|
157
157
|
|
|
158
158
|
admin = read(SERVICE_DOCS["admin"])
|
|
159
159
|
if contains_all(
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
| Actor | Description | Appears In |
|
|
21
21
|
| --- | --- | --- |
|
|
22
|
-
| `
|
|
22
|
+
| `Web User` | web 서비스에서 주문/운영 기능에 접근하기 위해 인증 세션을 발급받는 사용자다. | `AUT-F001` |
|
|
23
23
|
| `Mobile Operator` | mobile 서비스에서 이행 작업을 수행하기 위해 로그인하는 현장 운영자다. | `AUT-F001` |
|
|
24
24
|
| `Admin Operator` | admin 서비스에서 카탈로그, 재고, 사용자 운영 명령을 수행하기 위해 관리자 세션을 발급받는 주체다. | `AUT-F001` |
|
|
25
25
|
| `Landing Member` | landing 서비스에서 회원 전용 자원이나 개인화 동작을 사용하기 위해 로그인하는 사용자다. | `AUT-F001` |
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
| Feature Code | Use Case | Actor | Bounded Context | Aggregate / Model | Type | Preconditions | Domain Outcome | Invariant / Business Rule |
|
|
50
50
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
51
|
-
| `AUT-F001` | 이메일/비밀번호로 로그인하고 access token을 발급한다 |
|
|
51
|
+
| `AUT-F001` | 이메일/비밀번호로 로그인하고 access token을 발급한다 | Web User, Mobile Operator, Admin Operator, Landing Member | Authentication & Session | `LoginCommand`, `AuthToken`, `AuthAccountRecord` | Command | 이메일과 비밀번호가 전달되고, 인증 계정 저장소에 해당 사용자가 존재해야 한다 | access token과 `user_id`가 발급된다 | credential이 일치하지 않으면 `401 Invalid credentials`를 반환한다 |
|
|
52
52
|
| `AUT-F002` | bearer token으로 현재 세션 사용자를 해석한다 | Authenticated Client | Authentication & Session | `AuthToken`, `AuthenticatedUser`, `AuthAccountRecord` | Query | 유효한 bearer token이 전달되고 token subject가 인증 계정 저장소에 존재해야 한다 | 현재 사용자 summary를 반환한다 | token이 위조되었거나 subject 사용자가 없으면 `401 Invalid token`을 반환한다 |
|
|
53
53
|
|
|
54
54
|
## 7. Notes
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| --- | --- | --- |
|
|
22
22
|
| `Landing Visitor` | 비로그인 상태로 공개 상품 카탈로그와 상품 상세를 탐색하는 방문자다. | `CAT-F001`, `CAT-F002` |
|
|
23
23
|
| `Landing Member` | 로그인된 landing 회원으로 공개 상품을 둘러보고 구매 전 탐색을 수행하는 사용자다. | `CAT-F001`, `CAT-F002` |
|
|
24
|
-
| `
|
|
24
|
+
| `Web User` | web 서비스에서 주문 생성이나 운영 판단을 위해 상품 정보를 조회하는 내부 사용자다. | `CAT-F001`, `CAT-F002` |
|
|
25
25
|
| `Admin Operator` | admin 서비스에서 상품을 등록, 수정, 상태 변경하는 운영 관리자다. | `CAT-F003`, `CAT-F004`, `CAT-F005` |
|
|
26
26
|
|
|
27
27
|
## 4. Bounded Context Summary
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
|
|
50
50
|
| Feature Code | Use Case | Actor | Bounded Context | Aggregate / Model | Type | Preconditions | Domain Outcome | Invariant / Business Rule |
|
|
51
51
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
52
|
-
| `CAT-F001` | 상품 카탈로그 목록을 조회한다 | Landing Visitor, Landing Member,
|
|
53
|
-
| `CAT-F002` | 단일 상품 상세를 조회한다 | Landing Visitor, Landing Member,
|
|
52
|
+
| `CAT-F001` | 상품 카탈로그 목록을 조회한다 | Landing Visitor, Landing Member, Web User | Product Catalog | `ProductSummary`, `ProductRecord` | Query | 상품 bootstrap 데이터가 존재해야 한다 | 공개 가능한 상품 목록을 필터와 검색 조건에 맞게 반환한다 | `status`, `category`, `q` 조건은 모두 현재 카탈로그 집합 안에서 계산한다 |
|
|
53
|
+
| `CAT-F002` | 단일 상품 상세를 조회한다 | Landing Visitor, Landing Member, Web User | Product Catalog | `ProductDetail`, `ProductRecord` | Query | 요청한 `product_id`가 저장소에 존재해야 한다 | 상세 페이지 구성을 위한 상품 전체 속성을 반환한다 | 존재하지 않는 `product_id`면 `404 Catalog product not found`를 반환한다 |
|
|
54
54
|
| `CAT-F003` | 관리자가 새 상품을 등록한다 | Admin Operator | Product Catalog | `CreateProductCommand`, `ProductDetail`, `ProductRecord` | Command | 관리자 토큰이 유효하고 slug, 이름, 가격, variant 정보가 전달되어야 한다 | 새 상품 레코드가 생성되어 카탈로그 목록에 합류한다 | `slug`는 카탈로그 내에서 유일해야 하며 variant는 최소 1개 이상이어야 한다 |
|
|
55
55
|
| `CAT-F004` | 관리자가 상품 속성을 수정한다 | Admin Operator | Product Catalog | `UpdateProductCommand`, `ProductDetail`, `ProductRecord` | Command | 관리자 토큰이 유효하고 요청한 `product_id`가 존재해야 한다 | 상품 속성이 부분 갱신되고 `updated_at`이 갱신된다 | 빈 수정 요청은 `400 No catalog product fields provided`, 중복 slug는 `409`를 반환한다 |
|
|
56
56
|
| `CAT-F005` | 관리자가 상품 상태를 변경한다 | Admin Operator | Product Catalog | `UpdateProductStatusCommand`, `ProductDetail`, `ProductRecord` | Command | 관리자 토큰이 유효하고 요청한 `product_id`가 존재해야 한다 | 상품 `status`가 `draft`, `active`, `archived` 중 하나로 전환된다 | 존재하지 않는 `product_id`면 `404 Catalog product not found`를 반환한다 |
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## 1. Purpose
|
|
6
6
|
|
|
7
|
-
`orders` bounded context가 제공하는
|
|
7
|
+
`orders` bounded context가 제공하는 web 주문 현황과 관리자 운영 큐 기능을 구현 기준으로 정리한다.
|
|
8
8
|
|
|
9
9
|
## 2. Scope
|
|
10
10
|
|
|
11
11
|
- 포함 범위:
|
|
12
|
-
-
|
|
12
|
+
- web 주문 overview/list read model과 주문 생성, 상태 전이 command
|
|
13
13
|
- admin 주문 overview/queue read model
|
|
14
14
|
- 제외 범위:
|
|
15
15
|
- 외부 결제 게이트웨이 정산이나 배송사 연동
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
| Actor | Description | Appears In |
|
|
21
21
|
| --- | --- | --- |
|
|
22
|
-
| `
|
|
22
|
+
| `Web User` | web 서비스에서 주문 현황을 조회하고 신규 주문 생성이나 주문 상태 갱신을 수행하는 운영 사용자다. | `ORD-F001`, `ORD-F002`, `ORD-F003`, `ORD-F004` |
|
|
23
23
|
| `Admin Operator` | admin 서비스에서 주문 KPI와 운영 큐를 모니터링하는 관리자다. | `ORD-F005`, `ORD-F006` |
|
|
24
24
|
|
|
25
25
|
## 4. Bounded Context Summary
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
| Aggregate / Model | Role |
|
|
38
38
|
| --- | --- |
|
|
39
39
|
| `OrderRecord` | bootstrap 기반 주문 원본 |
|
|
40
|
-
| `OrderOverview` |
|
|
41
|
-
| `OrderSummary` |
|
|
40
|
+
| `OrderOverview` | web dashboard 요약 읽기 모델 |
|
|
41
|
+
| `OrderSummary` | web orders 목록 읽기 모델 |
|
|
42
42
|
| `CreateOrderCommand` | 주문 생성 명령 |
|
|
43
43
|
| `UpdateOrderStatusCommand` | 주문 상태 전이 명령 |
|
|
44
44
|
| `OrderStatusTransition` | 주문 상태 전이 결과 |
|
|
@@ -49,15 +49,15 @@
|
|
|
49
49
|
|
|
50
50
|
| Feature Code | Use Case | Actor | Bounded Context | Aggregate / Model | Type | Preconditions | Domain Outcome | Invariant / Business Rule |
|
|
51
51
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
52
|
-
| `ORD-F001` |
|
|
53
|
-
| `ORD-F002` |
|
|
54
|
-
| `ORD-F003` | 신규 주문을 생성한다 |
|
|
55
|
-
| `ORD-F004` | 주문의 결제/이행 상태를 변경한다 |
|
|
56
|
-
| `ORD-F005` | 관리자용 주문 overview를 조회한다 | Admin Operator | Order Operations | `AdminOrderOverview`, `OrderRecord` | Query | 관리자 토큰이 유효하고 주문 bootstrap 데이터가 존재해야 한다 | 관리자 KPI와 stage 현황을 반환한다 | admin surface는
|
|
52
|
+
| `ORD-F001` | web 주문 overview를 조회한다 | Web User | Order Operations | `OrderOverview`, `OrderRecord` | Query | 인증 토큰이 유효하고 주문 bootstrap 데이터가 존재해야 한다 | 주문 카드, 최근 활동, 선택 주문 상세를 함께 반환한다 | overview는 최근 활동 3건과 선택 주문 1건을 항상 포함한다 |
|
|
53
|
+
| `ORD-F002` | web 주문 목록을 조회한다 | Web User | Order Operations | `OrderSummary`, `OrderRecord` | Query | 인증 토큰이 유효하고 주문 bootstrap 데이터가 존재해야 한다 | 주문 목록을 반환한다 | 목록 행은 `id`, `product_name`, `customer_name`, `status`를 유지한다 |
|
|
54
|
+
| `ORD-F003` | 신규 주문을 생성한다 | Web User | Order Operations | `CreateOrderCommand`, `OrderRecord` | Command | 인증 토큰이 유효하고 제품, 고객, 판매자, 금액 정보가 전달되어야 한다 | 새 `OrderRecord`가 생성되어 목록과 overview에 반영된다 | 새 주문은 문자열 ID를 부여받고 `Pending`과 `Queued`를 기본 상태로 사용한다 |
|
|
55
|
+
| `ORD-F004` | 주문의 결제/이행 상태를 변경한다 | Web User | Order Operations | `UpdateOrderStatusCommand`, `OrderStatusTransition`, `OrderRecord` | Command | 인증 토큰이 유효하고 요청한 `order_id`가 존재해야 한다 | 주문의 `status`, `fulfillment_status`, `stage`가 변경된다 | 존재하지 않는 `order_id`면 `404`를 반환한다 |
|
|
56
|
+
| `ORD-F005` | 관리자용 주문 overview를 조회한다 | Admin Operator | Order Operations | `AdminOrderOverview`, `OrderRecord` | Query | 관리자 토큰이 유효하고 주문 bootstrap 데이터가 존재해야 한다 | 관리자 KPI와 stage 현황을 반환한다 | admin surface는 web surface와 다른 운영형 read model을 사용한다 |
|
|
57
57
|
| `ORD-F006` | 관리자용 거래 큐를 조회한다 | Admin Operator | Order Operations | `AdminQueueItem`, `OrderRecord` | Query | 관리자 토큰이 유효하고 주문 bootstrap 데이터가 존재해야 한다 | 주문별 운영 큐 행을 반환한다 | 큐 행은 `order_id`, `product_name`, `customer_name`, `status`, `sla`를 유지한다 |
|
|
58
58
|
|
|
59
59
|
## 7. Notes
|
|
60
60
|
|
|
61
|
-
- `orders`는
|
|
61
|
+
- `orders`는 web surface와 admin surface에 서로 다른 read model을 제공한다.
|
|
62
62
|
- 운영 알람 feed는 별도 `alerts` context가 소유하고, `orders`는 주문 자체 read/write 모델만 유지한다.
|
|
63
63
|
- template baseline의 주문 상태 전이는 내부 mutation semantics까지만 다루며 외부 결제/이벤트 연동은 포함하지 않는다.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Screen Planning
|
|
2
2
|
|
|
3
3
|
- screen code format: `{SERVICE}-S{NNN}`
|
|
4
|
-
- canonical service code: `
|
|
4
|
+
- canonical service code: `WEB`, `ADM`, `MOB`, `LND`
|
|
5
5
|
|
|
6
|
-
- [
|
|
6
|
+
- [web_screen_spec.pdf](./web_screen_spec.pdf)
|
|
7
7
|
- [admin_screen_spec.pdf](./admin_screen_spec.pdf)
|
|
8
8
|
- [mobile_screen_spec.pdf](./mobile_screen_spec.pdf)
|
|
9
9
|
- [landing_screen_spec.pdf](./landing_screen_spec.pdf)
|