@anhth2/spec-driven-dev-plugin 0.9.0 → 0.9.2
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/ARCHITECTURE.md +1 -1
- package/bin/index.js +1 -2
- package/commands/debug.md +2 -1
- package/commands/define-product.md +2 -1
- package/commands/fix-bug.md +2 -1
- package/commands/generate-bdd.md +2 -1
- package/commands/generate-code.md +2 -1
- package/commands/generate-design-spec.md +2 -1
- package/commands/generate-prd.md +41 -21
- package/commands/generate-prd.tmpl +39 -20
- package/commands/generate-spec-manifest.md +2 -1
- package/commands/generate-tech-docs.md +53 -12
- package/commands/generate-tech-docs.tmpl +51 -11
- package/commands/generate-tests.md +2 -1
- package/commands/learn.md +2 -1
- package/commands/propose-scenario.md +2 -1
- package/commands/refine-prd.md +11 -2
- package/commands/refine-prd.tmpl +9 -1
- package/commands/report-bug.md +2 -1
- package/commands/review-code.md +2 -1
- package/commands/review-context.md +10 -1
- package/commands/review-context.tmpl +8 -0
- package/commands/review-tech-docs.md +10 -1
- package/commands/review-tech-docs.tmpl +8 -0
- package/commands/run-tests.md +2 -1
- package/commands/smoke-test.md +2 -1
- package/commands/validate-traces.md +2 -1
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/debug.md +2 -1
- package/core/commands/define-product.md +2 -1
- package/core/commands/fix-bug.md +2 -1
- package/core/commands/generate-bdd.md +2 -1
- package/core/commands/generate-code.md +2 -1
- package/core/commands/generate-design-spec.md +2 -1
- package/core/commands/generate-prd.md +41 -21
- package/core/commands/generate-spec-manifest.md +2 -1
- package/core/commands/generate-tech-docs.md +53 -12
- package/core/commands/generate-tests.md +2 -1
- package/core/commands/learn.md +2 -1
- package/core/commands/propose-scenario.md +2 -1
- package/core/commands/refine-prd.md +11 -2
- package/core/commands/report-bug.md +2 -1
- package/core/commands/review-code.md +2 -1
- package/core/commands/review-context.md +10 -1
- package/core/commands/review-tech-docs.md +10 -1
- package/core/commands/run-tests.md +2 -1
- package/core/commands/smoke-test.md +2 -1
- package/core/commands/validate-traces.md +2 -1
- package/core/modules/android-compose/module.yaml +13 -0
- package/core/modules/android-compose/stack-profile.yaml +57 -0
- package/core/modules/flutter/module.yaml +14 -0
- package/core/modules/flutter/stack-profile.yaml +59 -0
- package/core/modules/ios-swiftui/module.yaml +13 -0
- package/core/modules/ios-swiftui/stack-profile.yaml +55 -0
- package/core/modules/nuxt/module.yaml +14 -0
- package/core/modules/nuxt/stack-profile.yaml +58 -0
- package/core/modules/react-native/module.yaml +14 -0
- package/core/modules/react-native/stack-profile.yaml +56 -0
- package/core/modules/vue/module.yaml +14 -0
- package/core/modules/vue/stack-profile.yaml +65 -0
- package/core/skills/code/SKILL.md +2 -1
- package/core/skills/debug/SKILL.md +2 -1
- package/core/skills/design-spec/SKILL.md +2 -1
- package/core/skills/discovery/SKILL.md +2 -1
- package/core/skills/test/SKILL.md +4 -2
- package/core/steps/context-loader.md +2 -1
- package/core/templates/prd.template.md +35 -20
- package/core/templates/product-definition.template.md +3 -3
- package/core/templates/project-context.yaml +4 -1
- package/modules/android-compose/module.yaml +13 -0
- package/modules/android-compose/stack-profile.yaml +57 -0
- package/modules/flutter/module.yaml +14 -0
- package/modules/flutter/stack-profile.yaml +59 -0
- package/modules/ios-swiftui/module.yaml +13 -0
- package/modules/ios-swiftui/stack-profile.yaml +55 -0
- package/modules/nuxt/module.yaml +14 -0
- package/modules/nuxt/stack-profile.yaml +58 -0
- package/modules/react-native/module.yaml +14 -0
- package/modules/react-native/stack-profile.yaml +56 -0
- package/modules/vue/module.yaml +14 -0
- package/modules/vue/stack-profile.yaml +65 -0
- package/package.json +9 -2
- package/skills/code/SKILL.md +2 -1
- package/skills/debug/SKILL.md +2 -1
- package/skills/design-spec/SKILL.md +2 -1
- package/skills/discovery/SKILL.md +2 -1
- package/skills/test/SKILL.md +4 -2
- package/steps/context-loader.md +2 -1
- package/templates/prd.template.md +35 -20
- package/templates/product-definition.template.md +3 -3
- package/templates/project-context.yaml +4 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
build:
|
|
2
|
+
compile: "npm run build"
|
|
3
|
+
test: "npm run test"
|
|
4
|
+
run: "npm run dev"
|
|
5
|
+
lint: "npm run lint"
|
|
6
|
+
|
|
7
|
+
architecture:
|
|
8
|
+
style: "Pages + Composables + Server routes (SSR/SSG)"
|
|
9
|
+
key_rules:
|
|
10
|
+
- "Pages in pages/ are route-level containers — no business logic"
|
|
11
|
+
- "Business logic in composables/ using useAsyncData or useFetch"
|
|
12
|
+
- "Server-side logic in server/api/ routes (nitro)"
|
|
13
|
+
- "Client-only state in Pinia stores; server state via useAsyncData"
|
|
14
|
+
- "Shared UI primitives in components/ui/, auto-imported by Nuxt"
|
|
15
|
+
- "Use useRoute/useRouter instead of $route/$router in Composition API"
|
|
16
|
+
- "'use client' equivalent: wrap client-only code in onMounted or <ClientOnly>"
|
|
17
|
+
folder_structure: |
|
|
18
|
+
├── components/
|
|
19
|
+
│ └── ui/ ← auto-imported UI primitives (BaseButton, BaseInput...)
|
|
20
|
+
├── composables/ ← auto-imported composables (useOrderList...)
|
|
21
|
+
├── pages/ ← file-based routing
|
|
22
|
+
├── server/
|
|
23
|
+
│ └── api/ ← nitro server routes (GET /api/orders.ts)
|
|
24
|
+
├── stores/ ← Pinia stores (auto-imported)
|
|
25
|
+
├── plugins/ ← Nuxt plugins
|
|
26
|
+
└── utils/ ← auto-imported utilities
|
|
27
|
+
|
|
28
|
+
coding_standards:
|
|
29
|
+
naming:
|
|
30
|
+
components: "PascalCase (auto-imported, e.g., OrderList, BaseButton)"
|
|
31
|
+
composables: "camelCase with 'use' prefix (auto-imported, e.g., useOrderList)"
|
|
32
|
+
stores: "camelCase + Store suffix via defineStore()"
|
|
33
|
+
server_routes: "method.path.ts (e.g., get.orders.ts or [id].get.ts)"
|
|
34
|
+
files:
|
|
35
|
+
component: "{Feature}.vue"
|
|
36
|
+
composable: "use{Feature}.ts"
|
|
37
|
+
store: "{feature}.store.ts"
|
|
38
|
+
server_route: "{resource}.get.ts / {resource}.post.ts"
|
|
39
|
+
patterns:
|
|
40
|
+
data_fetching: "useAsyncData() for SSR data, useFetch() for client fetches"
|
|
41
|
+
global_state: "Pinia stores"
|
|
42
|
+
forms: "VeeValidate + Zod"
|
|
43
|
+
api_client: "$fetch (ofetch) — built-in to Nuxt, SSR-compatible"
|
|
44
|
+
ssr_hydration: "useState() for shared SSR/client state to avoid hydration mismatch"
|
|
45
|
+
|
|
46
|
+
testing:
|
|
47
|
+
unit: "Vitest + @nuxt/test-utils"
|
|
48
|
+
e2e: "Playwright via @nuxt/test-utils/e2e"
|
|
49
|
+
patterns:
|
|
50
|
+
- "Use mountSuspended() for components that need Nuxt context"
|
|
51
|
+
- "Use registerEndpoint() to mock server routes in tests"
|
|
52
|
+
- "Test pages with renderSuspended() from @nuxt/test-utils"
|
|
53
|
+
|
|
54
|
+
trace_tags:
|
|
55
|
+
implements: "// @trace.implements={UC-ID}-SC{N}"
|
|
56
|
+
source: "// @trace.source=specs/bdd/{domain}/{UC-ID}.feature"
|
|
57
|
+
verifies: "// @trace.verifies={UC-ID}"
|
|
58
|
+
test_type: "// @trace.test_type=unit|integration"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: "React Native"
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: "Cross-platform mobile (iOS + Android) with React Native / Expo"
|
|
4
|
+
language: "TypeScript"
|
|
5
|
+
framework: "React Native"
|
|
6
|
+
stack_type: "mobile"
|
|
7
|
+
default_layer_order:
|
|
8
|
+
- Types / interfaces
|
|
9
|
+
- API client (React Query hooks)
|
|
10
|
+
- State store (Zustand)
|
|
11
|
+
- Custom hooks (business logic)
|
|
12
|
+
- UI components (presentational)
|
|
13
|
+
- Screen / feature components (container)
|
|
14
|
+
test_framework: "Jest + React Native Testing Library"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
build:
|
|
2
|
+
compile: "npx expo export / npx react-native build-android"
|
|
3
|
+
test: "jest"
|
|
4
|
+
run: "npx expo start / npx react-native run-ios"
|
|
5
|
+
lint: "eslint . && tsc --noEmit"
|
|
6
|
+
|
|
7
|
+
architecture:
|
|
8
|
+
style: "Feature-based (screens → hooks → queries → store)"
|
|
9
|
+
key_rules:
|
|
10
|
+
- "Business logic lives in custom hooks, not in screen components"
|
|
11
|
+
- "Server state managed by React Query (TanStack Query)"
|
|
12
|
+
- "Navigation state managed by React Navigation"
|
|
13
|
+
- "Native modules wrapped in a service layer — never called directly in components"
|
|
14
|
+
- "Shared UI primitives in src/components/ui/, feature screens in src/features/{name}/"
|
|
15
|
+
folder_structure: |
|
|
16
|
+
src/
|
|
17
|
+
├── api/ ← axios instance, interceptors
|
|
18
|
+
├── components/
|
|
19
|
+
│ └── ui/ ← reusable primitives (AppButton, AppInput...)
|
|
20
|
+
├── features/
|
|
21
|
+
│ └── {domain}/
|
|
22
|
+
│ ├── components/
|
|
23
|
+
│ ├── hooks/
|
|
24
|
+
│ ├── queries/
|
|
25
|
+
│ └── screens/
|
|
26
|
+
├── navigation/ ← React Navigation stacks/tabs
|
|
27
|
+
├── store/ ← Zustand slices
|
|
28
|
+
└── lib/ ← utils, formatters, constants
|
|
29
|
+
|
|
30
|
+
coding_standards:
|
|
31
|
+
naming:
|
|
32
|
+
components: "PascalCase (e.g., OrderListScreen, CreateOrderForm)"
|
|
33
|
+
hooks: "camelCase with 'use' prefix (e.g., useOrderList)"
|
|
34
|
+
screens: "PascalCase + Screen suffix (e.g., OrderDetailScreen)"
|
|
35
|
+
files:
|
|
36
|
+
screen: "{Feature}Screen.tsx"
|
|
37
|
+
component: "{Feature}.tsx"
|
|
38
|
+
hook: "use{Feature}.ts"
|
|
39
|
+
patterns:
|
|
40
|
+
state_management: "Zustand + React Query"
|
|
41
|
+
navigation: "React Navigation v6 (Stack + Tab + Drawer)"
|
|
42
|
+
networking: "Axios"
|
|
43
|
+
forms: "React Hook Form + Zod"
|
|
44
|
+
storage: "MMKV or AsyncStorage"
|
|
45
|
+
|
|
46
|
+
testing:
|
|
47
|
+
unit: "Jest + React Native Testing Library"
|
|
48
|
+
e2e: "Detox or Maestro"
|
|
49
|
+
patterns:
|
|
50
|
+
- "Test by accessibility label or testID — never by style/className"
|
|
51
|
+
- "Mock native modules in jest setup"
|
|
52
|
+
- "Use renderWithProviders() with NavigationContainer + QueryClient"
|
|
53
|
+
|
|
54
|
+
trace_tags:
|
|
55
|
+
implements: "// @trace.implements={UC-ID}-SC{N}"
|
|
56
|
+
source: "// @trace.source=specs/bdd/{domain}/{UC-ID}.feature"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: "Vue"
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: "Vue 3 SPA with Composition API, Pinia, and Vue Query"
|
|
4
|
+
language: "TypeScript"
|
|
5
|
+
framework: "Vue 3"
|
|
6
|
+
stack_type: "frontend"
|
|
7
|
+
default_layer_order:
|
|
8
|
+
- Types / interfaces
|
|
9
|
+
- API client (Vue Query / composables)
|
|
10
|
+
- State store (Pinia)
|
|
11
|
+
- Composables (business logic)
|
|
12
|
+
- UI components (presentational)
|
|
13
|
+
- Page / feature components (container)
|
|
14
|
+
test_framework: "Vitest + Vue Test Utils"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
build:
|
|
2
|
+
compile: "npm run build"
|
|
3
|
+
test: "npm run test"
|
|
4
|
+
run: "npm run dev"
|
|
5
|
+
lint: "npm run lint"
|
|
6
|
+
|
|
7
|
+
architecture:
|
|
8
|
+
style: "Feature-based (components → composables → queries → store)"
|
|
9
|
+
key_rules:
|
|
10
|
+
- "Business logic lives in composables, not in component setup()"
|
|
11
|
+
- "Server state managed by Vue Query (@tanstack/vue-query)"
|
|
12
|
+
- "Client-only UI state managed by Pinia stores"
|
|
13
|
+
- "Components must be pure — no direct API calls inside <template> or setup()"
|
|
14
|
+
- "Shared UI primitives in components/ui/, feature logic in features/{name}/"
|
|
15
|
+
- "Never fetch data directly in a component — use a composable"
|
|
16
|
+
- "Props defined with defineProps<{}>(), emits with defineEmits<{}>()"
|
|
17
|
+
folder_structure: |
|
|
18
|
+
src/
|
|
19
|
+
├── api/ ← axios instance, interceptors
|
|
20
|
+
├── components/
|
|
21
|
+
│ └── ui/ ← reusable primitives (BaseButton, BaseInput...)
|
|
22
|
+
├── features/
|
|
23
|
+
│ └── {domain}/
|
|
24
|
+
│ ├── components/ ← feature-specific UI
|
|
25
|
+
│ ├── composables/ ← useOrderList, useCreateOrder...
|
|
26
|
+
│ ├── queries/ ← Vue Query definitions
|
|
27
|
+
│ ├── store/ ← Pinia slice (if needed)
|
|
28
|
+
│ └── types.ts
|
|
29
|
+
├── pages/ ← route-level page components (Vue Router)
|
|
30
|
+
├── router/ ← route definitions
|
|
31
|
+
└── lib/ ← utilities, formatters, constants
|
|
32
|
+
|
|
33
|
+
coding_standards:
|
|
34
|
+
naming:
|
|
35
|
+
components: "PascalCase (e.g., OrderList, CreateOrderModal)"
|
|
36
|
+
composables: "camelCase with 'use' prefix (e.g., useOrderList, useCreateOrder)"
|
|
37
|
+
stores: "camelCase + Store suffix (e.g., useCartStore) — defined with defineStore()"
|
|
38
|
+
query_keys: "SCREAMING_SNAKE_CASE string/array (e.g., ['ORDER_LIST', customerId])"
|
|
39
|
+
files:
|
|
40
|
+
component: "{Feature}.vue"
|
|
41
|
+
composable: "use{Feature}.ts"
|
|
42
|
+
query: "{feature}.queries.ts"
|
|
43
|
+
store: "{feature}.store.ts"
|
|
44
|
+
types: "{feature}.types.ts"
|
|
45
|
+
patterns:
|
|
46
|
+
data_fetching: "Vue Query (TanStack Query v5 for Vue)"
|
|
47
|
+
global_state: "Pinia stores"
|
|
48
|
+
forms: "VeeValidate + Zod"
|
|
49
|
+
api_client: "Axios with interceptors for auth + error handling"
|
|
50
|
+
reactivity: "ref() for primitives, reactive() for objects, computed() for derived state"
|
|
51
|
+
|
|
52
|
+
testing:
|
|
53
|
+
unit: "Vitest + Vue Test Utils"
|
|
54
|
+
e2e: "Playwright or Cypress"
|
|
55
|
+
patterns:
|
|
56
|
+
- "Test behavior, not implementation — query by role/label via @testing-library/vue"
|
|
57
|
+
- "Mock Vue Query with VueQueryPlugin wrapper in test setup"
|
|
58
|
+
- "Use MSW (Mock Service Worker) to mock API calls in tests"
|
|
59
|
+
- "mountWithProviders() helper wraps component with Pinia + VueQuery + Router"
|
|
60
|
+
|
|
61
|
+
trace_tags:
|
|
62
|
+
implements: "// @trace.implements={UC-ID}-SC{N}"
|
|
63
|
+
source: "// @trace.source=specs/bdd/{domain}/{UC-ID}.feature"
|
|
64
|
+
verifies: "// @trace.verifies={UC-ID}"
|
|
65
|
+
test_type: "// @trace.test_type=unit|integration"
|
|
@@ -202,13 +202,14 @@ If `services` section is present:
|
|
|
202
202
|
**4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
|
|
203
203
|
- Override `paths.prd_dir` → `{spec_source}/specs/prd`
|
|
204
204
|
- Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
|
|
205
|
+
- Override `paths.tech_docs_dir` → `{spec_source}/specs/tech-docs` — **only if step 2 did not already route it to a service** (multi-service umbrellas keep per-service tech-docs). This publishes the BE-authored API contract into the shared spec repo so FE/App can read it via the spec submodule at `/generate-code --phase=integration`.
|
|
205
206
|
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
206
207
|
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
207
208
|
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
208
209
|
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
209
210
|
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
210
211
|
|
|
211
|
-
> **Why under `spec_source`:**
|
|
212
|
+
> **Why under `spec_source`:** PRD, design-spec, domain knowledge, the **API contract (tech-docs)**, and tester feedback are all **cross-team artifacts** — they must live in the **shared spec repo** so every umbrella (FE/App/BE) reads the same source via `/sync`. Tech-docs specifically: BE authors the tech-design (API contract), commits + pushes it into the spec submodule (2-layer commit), and FE/App pull it on their next `/sync` to wire the real API in `/generate-code --phase=integration`. In single-service mode (no `spec_source`), these default under the repo root — still shared, same repo.
|
|
212
213
|
|
|
213
214
|
---
|
|
214
215
|
|
|
@@ -117,13 +117,14 @@ If `services` section is present:
|
|
|
117
117
|
**4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
|
|
118
118
|
- Override `paths.prd_dir` → `{spec_source}/specs/prd`
|
|
119
119
|
- Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
|
|
120
|
+
- Override `paths.tech_docs_dir` → `{spec_source}/specs/tech-docs` — **only if step 2 did not already route it to a service** (multi-service umbrellas keep per-service tech-docs). This publishes the BE-authored API contract into the shared spec repo so FE/App can read it via the spec submodule at `/generate-code --phase=integration`.
|
|
120
121
|
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
121
122
|
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
122
123
|
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
123
124
|
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
124
125
|
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
125
126
|
|
|
126
|
-
> **Why under `spec_source`:**
|
|
127
|
+
> **Why under `spec_source`:** PRD, design-spec, domain knowledge, the **API contract (tech-docs)**, and tester feedback are all **cross-team artifacts** — they must live in the **shared spec repo** so every umbrella (FE/App/BE) reads the same source via `/sync`. Tech-docs specifically: BE authors the tech-design (API contract), commits + pushes it into the spec submodule (2-layer commit), and FE/App pull it on their next `/sync` to wire the real API in `/generate-code --phase=integration`. In single-service mode (no `spec_source`), these default under the repo root — still shared, same repo.
|
|
127
128
|
|
|
128
129
|
---
|
|
129
130
|
|
|
@@ -191,13 +191,14 @@ If `services` section is present:
|
|
|
191
191
|
**4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
|
|
192
192
|
- Override `paths.prd_dir` → `{spec_source}/specs/prd`
|
|
193
193
|
- Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
|
|
194
|
+
- Override `paths.tech_docs_dir` → `{spec_source}/specs/tech-docs` — **only if step 2 did not already route it to a service** (multi-service umbrellas keep per-service tech-docs). This publishes the BE-authored API contract into the shared spec repo so FE/App can read it via the spec submodule at `/generate-code --phase=integration`.
|
|
194
195
|
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
195
196
|
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
196
197
|
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
197
198
|
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
198
199
|
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
199
200
|
|
|
200
|
-
> **Why under `spec_source`:**
|
|
201
|
+
> **Why under `spec_source`:** PRD, design-spec, domain knowledge, the **API contract (tech-docs)**, and tester feedback are all **cross-team artifacts** — they must live in the **shared spec repo** so every umbrella (FE/App/BE) reads the same source via `/sync`. Tech-docs specifically: BE authors the tech-design (API contract), commits + pushes it into the spec submodule (2-layer commit), and FE/App pull it on their next `/sync` to wire the real API in `/generate-code --phase=integration`. In single-service mode (no `spec_source`), these default under the repo root — still shared, same repo.
|
|
201
202
|
|
|
202
203
|
---
|
|
203
204
|
|
|
@@ -96,13 +96,14 @@ If `services` section is present:
|
|
|
96
96
|
**4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
|
|
97
97
|
- Override `paths.prd_dir` → `{spec_source}/specs/prd`
|
|
98
98
|
- Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
|
|
99
|
+
- Override `paths.tech_docs_dir` → `{spec_source}/specs/tech-docs` — **only if step 2 did not already route it to a service** (multi-service umbrellas keep per-service tech-docs). This publishes the BE-authored API contract into the shared spec repo so FE/App can read it via the spec submodule at `/generate-code --phase=integration`.
|
|
99
100
|
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
100
101
|
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
101
102
|
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
102
103
|
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
103
104
|
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
104
105
|
|
|
105
|
-
> **Why under `spec_source`:**
|
|
106
|
+
> **Why under `spec_source`:** PRD, design-spec, domain knowledge, the **API contract (tech-docs)**, and tester feedback are all **cross-team artifacts** — they must live in the **shared spec repo** so every umbrella (FE/App/BE) reads the same source via `/sync`. Tech-docs specifically: BE authors the tech-design (API contract), commits + pushes it into the spec submodule (2-layer commit), and FE/App pull it on their next `/sync` to wire the real API in `/generate-code --phase=integration`. In single-service mode (no `spec_source`), these default under the repo root — still shared, same repo.
|
|
106
107
|
|
|
107
108
|
---
|
|
108
109
|
|
|
@@ -374,13 +374,14 @@ If `services` section is present:
|
|
|
374
374
|
**4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
|
|
375
375
|
- Override `paths.prd_dir` → `{spec_source}/specs/prd`
|
|
376
376
|
- Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
|
|
377
|
+
- Override `paths.tech_docs_dir` → `{spec_source}/specs/tech-docs` — **only if step 2 did not already route it to a service** (multi-service umbrellas keep per-service tech-docs). This publishes the BE-authored API contract into the shared spec repo so FE/App can read it via the spec submodule at `/generate-code --phase=integration`.
|
|
377
378
|
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
378
379
|
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
379
380
|
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
380
381
|
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
381
382
|
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
382
383
|
|
|
383
|
-
> **Why under `spec_source`:**
|
|
384
|
+
> **Why under `spec_source`:** PRD, design-spec, domain knowledge, the **API contract (tech-docs)**, and tester feedback are all **cross-team artifacts** — they must live in the **shared spec repo** so every umbrella (FE/App/BE) reads the same source via `/sync`. Tech-docs specifically: BE authors the tech-design (API contract), commits + pushes it into the spec submodule (2-layer commit), and FE/App pull it on their next `/sync` to wire the real API in `/generate-code --phase=integration`. In single-service mode (no `spec_source`), these default under the repo root — still shared, same repo.
|
|
384
385
|
|
|
385
386
|
---
|
|
386
387
|
|
|
@@ -777,13 +778,14 @@ If `services` section is present:
|
|
|
777
778
|
**4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
|
|
778
779
|
- Override `paths.prd_dir` → `{spec_source}/specs/prd`
|
|
779
780
|
- Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
|
|
781
|
+
- Override `paths.tech_docs_dir` → `{spec_source}/specs/tech-docs` — **only if step 2 did not already route it to a service** (multi-service umbrellas keep per-service tech-docs). This publishes the BE-authored API contract into the shared spec repo so FE/App can read it via the spec submodule at `/generate-code --phase=integration`.
|
|
780
782
|
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
781
783
|
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
782
784
|
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
783
785
|
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
784
786
|
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
785
787
|
|
|
786
|
-
> **Why under `spec_source`:**
|
|
788
|
+
> **Why under `spec_source`:** PRD, design-spec, domain knowledge, the **API contract (tech-docs)**, and tester feedback are all **cross-team artifacts** — they must live in the **shared spec repo** so every umbrella (FE/App/BE) reads the same source via `/sync`. Tech-docs specifically: BE authors the tech-design (API contract), commits + pushes it into the spec submodule (2-layer commit), and FE/App pull it on their next `/sync` to wire the real API in `/generate-code --phase=integration`. In single-service mode (no `spec_source`), these default under the repo root — still shared, same repo.
|
|
787
789
|
|
|
788
790
|
---
|
|
789
791
|
|
|
@@ -86,13 +86,14 @@ If `services` section is present:
|
|
|
86
86
|
**4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
|
|
87
87
|
- Override `paths.prd_dir` → `{spec_source}/specs/prd`
|
|
88
88
|
- Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
|
|
89
|
+
- Override `paths.tech_docs_dir` → `{spec_source}/specs/tech-docs` — **only if step 2 did not already route it to a service** (multi-service umbrellas keep per-service tech-docs). This publishes the BE-authored API contract into the shared spec repo so FE/App can read it via the spec submodule at `/generate-code --phase=integration`.
|
|
89
90
|
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
90
91
|
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
91
92
|
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
92
93
|
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
93
94
|
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
94
95
|
|
|
95
|
-
> **Why under `spec_source`:**
|
|
96
|
+
> **Why under `spec_source`:** PRD, design-spec, domain knowledge, the **API contract (tech-docs)**, and tester feedback are all **cross-team artifacts** — they must live in the **shared spec repo** so every umbrella (FE/App/BE) reads the same source via `/sync`. Tech-docs specifically: BE authors the tech-design (API contract), commits + pushes it into the spec submodule (2-layer commit), and FE/App pull it on their next `/sync` to wire the real API in `/generate-code --phase=integration`. In single-service mode (no `spec_source`), these default under the repo root — still shared, same repo.
|
|
96
97
|
|
|
97
98
|
---
|
|
98
99
|
|
|
@@ -102,9 +102,9 @@
|
|
|
102
102
|
- {Business value}→ Giá trị nghiệp vụ mang lại (lý do tại sao người dùng cần điều này)
|
|
103
103
|
-->
|
|
104
104
|
|
|
105
|
-
As a {User role}
|
|
106
|
-
I want to {User goal}
|
|
107
|
-
So that {Business value}
|
|
105
|
+
- **As a** {User role}
|
|
106
|
+
- **I want to** {User goal}
|
|
107
|
+
- **So that** {Business value}
|
|
108
108
|
|
|
109
109
|
## b. Phạm vi
|
|
110
110
|
|
|
@@ -119,7 +119,8 @@ So that {Business value}
|
|
|
119
119
|
- Viết ngắn gọn, súc tích, đủ để người đọc hiểu mà không cần giải thích thêm.
|
|
120
120
|
-->
|
|
121
121
|
|
|
122
|
-
In Scope
|
|
122
|
+
**In Scope**
|
|
123
|
+
|
|
123
124
|
- {Chức năng thuộc feature}
|
|
124
125
|
|
|
125
126
|
---
|
|
@@ -141,9 +142,9 @@ In Scope
|
|
|
141
142
|
- Chi tiết kỹ thuật hoặc logic xử lý nội bộ → thuộc Business Rule / Business Logic.
|
|
142
143
|
-->
|
|
143
144
|
|
|
144
|
-
AC1
|
|
145
|
-
AC2
|
|
146
|
-
AC3
|
|
145
|
+
- **AC1:** {Điều kiện chấp nhận}
|
|
146
|
+
- **AC2:** {Điều kiện chấp nhận}
|
|
147
|
+
- **AC3:** {Điều kiện chấp nhận}
|
|
147
148
|
|
|
148
149
|
---
|
|
149
150
|
|
|
@@ -183,15 +184,24 @@ AC3: {Điều kiện chấp nhận}
|
|
|
183
184
|
-->
|
|
184
185
|
|
|
185
186
|
#### {TICKET_ID}-UC1: {Tên Use Case}
|
|
186
|
-
Actor: {Người dùng thực hiện}
|
|
187
|
-
Description: {Mô tả ngắn gọn kịch bản nghiệp vụ}
|
|
188
|
-
Pre-condition: {Điều kiện cần trước khi Use Case bắt đầu}
|
|
189
|
-
Post-condition: {Kết quả sau khi Use Case hoàn thành}
|
|
190
187
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
- **Actor:** {Người dùng thực hiện}
|
|
189
|
+
- **Description:** {Mô tả ngắn gọn kịch bản nghiệp vụ}
|
|
190
|
+
- **Pre-condition:** {Điều kiện cần trước khi Use Case bắt đầu}
|
|
191
|
+
- **Post-condition:** {Kết quả sau khi Use Case hoàn thành}
|
|
192
|
+
|
|
193
|
+
**Business Rule**
|
|
194
|
+
|
|
195
|
+
| ID | Business Rule |
|
|
196
|
+
|----|---------------|
|
|
197
|
+
| {TICKET_ID}-UC1-BR1 | |
|
|
198
|
+
|
|
199
|
+
**Business Logic**
|
|
200
|
+
|
|
201
|
+
**{TICKET_ID}-UC1-BR1:**
|
|
202
|
+
- Logic 1
|
|
203
|
+
- Logic 2
|
|
204
|
+
- Logic 3
|
|
195
205
|
|
|
196
206
|
---
|
|
197
207
|
|
|
@@ -246,11 +256,16 @@ flowchart TD
|
|
|
246
256
|
|
|
247
257
|
**Screen N: {Tên màn hình}**
|
|
248
258
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
259
|
+
**Screen:** {Tên màn hình}
|
|
260
|
+
|
|
261
|
+
**Components:**
|
|
262
|
+
- {Component 1}
|
|
263
|
+
- {Component 2}
|
|
264
|
+
- {Component 3}
|
|
265
|
+
|
|
266
|
+
**Actions:**
|
|
267
|
+
- {Hành động 1} → {Kết quả}
|
|
268
|
+
- {Hành động 2} → {Kết quả}
|
|
254
269
|
|
|
255
270
|
<!-- Figma Design: {Link Figma — xóa dòng này nếu không có URL} -->
|
|
256
271
|
|
|
@@ -50,7 +50,9 @@ paths:
|
|
|
50
50
|
# .agent/project-context.yaml to ".agent/project-lessons.md" (resolved per service_root).
|
|
51
51
|
lessons_file: "specs/domain-knowledge/lessons-learned.md"
|
|
52
52
|
|
|
53
|
-
# Tech Docs
|
|
53
|
+
# Tech Docs (BE-authored API contract).
|
|
54
|
+
# In umbrella mode with spec_source set, context-loader auto-routes this to
|
|
55
|
+
# {spec_source}/specs/tech-docs so FE/App read the contract via the spec submodule.
|
|
54
56
|
tech_docs_dir: "tech-docs"
|
|
55
57
|
|
|
56
58
|
# Design Specs (FE/App platforms only — web, app)
|
|
@@ -94,6 +96,7 @@ domains:
|
|
|
94
96
|
# When spec_source is set, context-loader auto-derives:
|
|
95
97
|
# prd_dir → {spec_source}/specs/prd
|
|
96
98
|
# design_spec_dir → {spec_source}/specs/design-spec
|
|
99
|
+
# tech_docs_dir → {spec_source}/specs/tech-docs # shared API contract (per-service tech_docs_dir below wins in multi-service)
|
|
97
100
|
# domain_knowledge_dir → {spec_source}/specs/domain-knowledge
|
|
98
101
|
# (You can still override these manually in paths: section below.)
|
|
99
102
|
#
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: "Android (Jetpack Compose)"
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: "Native Android development with Jetpack Compose + Kotlin"
|
|
4
|
+
language: "Kotlin"
|
|
5
|
+
framework: "Jetpack Compose"
|
|
6
|
+
stack_type: "mobile"
|
|
7
|
+
default_layer_order:
|
|
8
|
+
- Domain models
|
|
9
|
+
- Repository (data layer)
|
|
10
|
+
- UseCase (domain logic)
|
|
11
|
+
- ViewModel (StateFlow<UiState>)
|
|
12
|
+
- Composable screens (presentation)
|
|
13
|
+
test_framework: "JUnit5 + MockK + Turbine"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
build:
|
|
2
|
+
compile: "./gradlew assembleRelease"
|
|
3
|
+
test: "./gradlew test"
|
|
4
|
+
run: "./gradlew installDebug / Open in Android Studio → Run"
|
|
5
|
+
lint: "./gradlew lint"
|
|
6
|
+
|
|
7
|
+
architecture:
|
|
8
|
+
style: "MVVM + Clean Architecture (Composable → ViewModel → UseCase → Repository)"
|
|
9
|
+
key_rules:
|
|
10
|
+
- "Composables are pure UI functions — no business logic, no direct suspend calls"
|
|
11
|
+
- "ViewModels expose StateFlow<UiState>; Composables collect via collectAsStateWithLifecycle()"
|
|
12
|
+
- "UseCases are single-responsibility classes injected into ViewModels"
|
|
13
|
+
- "Repositories are interfaces; implementations live in the data layer"
|
|
14
|
+
- "Dependency injection via Hilt"
|
|
15
|
+
- "Never launch coroutines from a Composable directly — use LaunchedEffect or ViewModel"
|
|
16
|
+
folder_structure: |
|
|
17
|
+
src/main/java/{package}/
|
|
18
|
+
├── core/
|
|
19
|
+
│ ├── network/ ← Retrofit instance, interceptors
|
|
20
|
+
│ ├── theme/ ← MaterialTheme, Color, Type, Shape
|
|
21
|
+
│ └── utils/
|
|
22
|
+
├── shared/
|
|
23
|
+
│ └── components/ ← reusable Composables (AppButton, AppTextField...)
|
|
24
|
+
├── features/
|
|
25
|
+
│ └── {domain}/
|
|
26
|
+
│ ├── ui/ ← Composable screens + components
|
|
27
|
+
│ ├── viewmodel/ ← ViewModel + UiState
|
|
28
|
+
│ ├── domain/ ← UseCases, domain models
|
|
29
|
+
│ └── data/ ← Repository impl, data sources
|
|
30
|
+
|
|
31
|
+
coding_standards:
|
|
32
|
+
naming:
|
|
33
|
+
composables: "PascalCase (e.g., OrderListScreen, CreateOrderForm)"
|
|
34
|
+
viewmodels: "PascalCase + ViewModel suffix (e.g., OrderListViewModel)"
|
|
35
|
+
usecases: "PascalCase + UseCase suffix (e.g., CreateOrderUseCase)"
|
|
36
|
+
files:
|
|
37
|
+
screen: "{Feature}Screen.kt"
|
|
38
|
+
viewmodel: "{Feature}ViewModel.kt"
|
|
39
|
+
usecase: "{Feature}UseCase.kt"
|
|
40
|
+
patterns:
|
|
41
|
+
state_management: "StateFlow<UiState> in ViewModel"
|
|
42
|
+
navigation: "Jetpack Navigation Compose"
|
|
43
|
+
networking: "Retrofit + OkHttp"
|
|
44
|
+
serialization: "Kotlinx Serialization or Gson"
|
|
45
|
+
di: "Hilt"
|
|
46
|
+
async: "Kotlin Coroutines + Flow"
|
|
47
|
+
|
|
48
|
+
testing:
|
|
49
|
+
unit: "JUnit5 + MockK + Turbine (Flow testing)"
|
|
50
|
+
ui: "Compose UI Test (composeTestRule)"
|
|
51
|
+
patterns:
|
|
52
|
+
- "Test ViewModel with fake repositories and TestCoroutineDispatcher"
|
|
53
|
+
- "UI tests use semantics matchers — set Modifier.testTag() on Composables"
|
|
54
|
+
|
|
55
|
+
trace_tags:
|
|
56
|
+
implements: "// @trace.implements={UC-ID}-SC{N}"
|
|
57
|
+
source: "// @trace.source=specs/bdd/{domain}/{UC-ID}.feature"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: "Flutter"
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: "Cross-platform mobile (iOS + Android) with Flutter/Dart"
|
|
4
|
+
language: "Dart"
|
|
5
|
+
framework: "Flutter"
|
|
6
|
+
stack_type: "mobile"
|
|
7
|
+
default_layer_order:
|
|
8
|
+
- Models / entities (domain)
|
|
9
|
+
- Repositories (data layer)
|
|
10
|
+
- Use cases (domain logic)
|
|
11
|
+
- BLoC / Cubit or Riverpod providers (state)
|
|
12
|
+
- Widgets (presentation)
|
|
13
|
+
- Pages / screens
|
|
14
|
+
test_framework: "flutter_test + mocktail"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
build:
|
|
2
|
+
compile: "flutter build apk / flutter build ios"
|
|
3
|
+
test: "flutter test"
|
|
4
|
+
run: "flutter run"
|
|
5
|
+
lint: "flutter analyze"
|
|
6
|
+
|
|
7
|
+
architecture:
|
|
8
|
+
style: "Feature-based (presentation → domain → data)"
|
|
9
|
+
key_rules:
|
|
10
|
+
- "Widget tree is pure UI — business logic lives in BLoC/Cubit or Riverpod providers"
|
|
11
|
+
- "Repositories abstract data sources; services contain domain logic"
|
|
12
|
+
- "State management: BLoC (complex flows) or Riverpod (simple/medium)"
|
|
13
|
+
- "Never call API directly inside a Widget build() method"
|
|
14
|
+
- "Shared UI widgets in lib/shared/widgets/, feature widgets in lib/features/{name}/presentation/"
|
|
15
|
+
- "Use const constructors wherever possible for performance"
|
|
16
|
+
folder_structure: |
|
|
17
|
+
lib/
|
|
18
|
+
├── core/
|
|
19
|
+
│ ├── theme/ ← AppTheme, colors, text styles
|
|
20
|
+
│ ├── router/ ← GoRouter or auto_route
|
|
21
|
+
│ └── utils/
|
|
22
|
+
├── shared/
|
|
23
|
+
│ └── widgets/ ← reusable UI widgets (AppButton, AppInput...)
|
|
24
|
+
├── features/
|
|
25
|
+
│ └── {domain}/
|
|
26
|
+
│ ├── data/ ← repositories, data sources, models
|
|
27
|
+
│ ├── domain/ ← entities, use cases, repo interfaces
|
|
28
|
+
│ └── presentation/ ← pages, widgets, BLoC/Cubit
|
|
29
|
+
└── main.dart
|
|
30
|
+
|
|
31
|
+
coding_standards:
|
|
32
|
+
naming:
|
|
33
|
+
widgets: "PascalCase (e.g., OrderListPage, CreateOrderForm)"
|
|
34
|
+
blocs: "PascalCase + Bloc/Cubit suffix (e.g., OrderListCubit)"
|
|
35
|
+
repositories: "PascalCase + Repository suffix (e.g., OrderRepository)"
|
|
36
|
+
files:
|
|
37
|
+
page: "{feature}_page.dart"
|
|
38
|
+
widget: "{feature}_widget.dart"
|
|
39
|
+
cubit: "{feature}_cubit.dart"
|
|
40
|
+
repository: "{feature}_repository.dart"
|
|
41
|
+
model: "{feature}_model.dart"
|
|
42
|
+
patterns:
|
|
43
|
+
state_management: "BLoC / Cubit (flutter_bloc) or Riverpod"
|
|
44
|
+
navigation: "GoRouter or auto_route"
|
|
45
|
+
networking: "Dio with interceptors"
|
|
46
|
+
serialization: "json_serializable / freezed"
|
|
47
|
+
|
|
48
|
+
testing:
|
|
49
|
+
unit: "flutter_test + mocktail"
|
|
50
|
+
widget: "flutter_test WidgetTester"
|
|
51
|
+
integration: "integration_test package"
|
|
52
|
+
patterns:
|
|
53
|
+
- "Test BLoC/Cubit in isolation with fake repositories"
|
|
54
|
+
- "Widget tests pump the widget tree and find by key or semantics label"
|
|
55
|
+
- "Use goldenFileComparator for snapshot tests of complex widgets"
|
|
56
|
+
|
|
57
|
+
trace_tags:
|
|
58
|
+
implements: "// @trace.implements={UC-ID}-SC{N}"
|
|
59
|
+
source: "// @trace.source=specs/bdd/{domain}/{UC-ID}.feature"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: "iOS (SwiftUI)"
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: "Native iOS development with SwiftUI + Swift"
|
|
4
|
+
language: "Swift"
|
|
5
|
+
framework: "SwiftUI"
|
|
6
|
+
stack_type: "mobile"
|
|
7
|
+
default_layer_order:
|
|
8
|
+
- Models / entities
|
|
9
|
+
- Repository (data sources)
|
|
10
|
+
- UseCase (business operations)
|
|
11
|
+
- ViewModel (ObservableObject state)
|
|
12
|
+
- View (SwiftUI presentation)
|
|
13
|
+
test_framework: "XCTest + Quick/Nimble"
|