@educa-corp/sdd-framework 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/commands/debug.md +4 -1
  2. package/commands/define-product.md +38 -1
  3. package/commands/define-product.tmpl +34 -0
  4. package/commands/dev-gen-test.md +4 -1
  5. package/commands/dev-run-test.md +4 -1
  6. package/commands/dev-smoke-test.md +4 -1
  7. package/commands/fix-bug.md +4 -1
  8. package/commands/generate-architecture.md +4 -1
  9. package/commands/generate-bdd.md +4 -1
  10. package/commands/generate-code.md +80 -26
  11. package/commands/generate-code.tmpl +76 -25
  12. package/commands/generate-design-spec.md +4 -1
  13. package/commands/generate-prd.md +4 -1
  14. package/commands/generate-spec-manifest.md +4 -1
  15. package/commands/generate-tech-docs.md +4 -1
  16. package/commands/learn.md +4 -1
  17. package/commands/map-testids.md +4 -1
  18. package/commands/propose-scenario.md +4 -1
  19. package/commands/qc-analyze.md +4 -1
  20. package/commands/qc-design-test.md +4 -1
  21. package/commands/qc-plan.md +4 -1
  22. package/commands/qc-report.md +4 -1
  23. package/commands/qc-review.md +4 -1
  24. package/commands/qc-run-test.md +4 -1
  25. package/commands/refine-prd.md +4 -1
  26. package/commands/report-bug.md +4 -1
  27. package/commands/review-code.md +4 -1
  28. package/commands/review-context.md +4 -1
  29. package/commands/review-tech-docs.md +4 -1
  30. package/commands/setup-ai-first.md +2 -1
  31. package/commands/validate-traces.md +4 -1
  32. package/core/FRAMEWORK_VERSION +1 -1
  33. package/core/commands/debug.md +4 -1
  34. package/core/commands/define-product.md +38 -1
  35. package/core/commands/dev-gen-test.md +4 -1
  36. package/core/commands/dev-run-test.md +4 -1
  37. package/core/commands/dev-smoke-test.md +4 -1
  38. package/core/commands/fix-bug.md +4 -1
  39. package/core/commands/generate-architecture.md +4 -1
  40. package/core/commands/generate-bdd.md +4 -1
  41. package/core/commands/generate-code.md +80 -26
  42. package/core/commands/generate-design-spec.md +4 -1
  43. package/core/commands/generate-prd.md +4 -1
  44. package/core/commands/generate-spec-manifest.md +4 -1
  45. package/core/commands/generate-tech-docs.md +4 -1
  46. package/core/commands/learn.md +4 -1
  47. package/core/commands/map-testids.md +4 -1
  48. package/core/commands/propose-scenario.md +4 -1
  49. package/core/commands/qc-analyze.md +4 -1
  50. package/core/commands/qc-design-test.md +4 -1
  51. package/core/commands/qc-plan.md +4 -1
  52. package/core/commands/qc-report.md +4 -1
  53. package/core/commands/qc-review.md +4 -1
  54. package/core/commands/qc-run-test.md +4 -1
  55. package/core/commands/refine-prd.md +4 -1
  56. package/core/commands/report-bug.md +4 -1
  57. package/core/commands/review-code.md +4 -1
  58. package/core/commands/review-context.md +4 -1
  59. package/core/commands/review-tech-docs.md +4 -1
  60. package/core/commands/setup-ai-first.md +2 -1
  61. package/core/commands/validate-traces.md +4 -1
  62. package/core/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +646 -0
  63. package/core/modules/phaser-game/module.yaml +15 -0
  64. package/core/modules/phaser-game/stack-profile.yaml +90 -0
  65. package/core/steps/context-loader.md +2 -0
  66. package/core/steps/gate.md +2 -1
  67. package/core/templates/project-context.yaml +6 -0
  68. package/docs/02-concepts/pipeline-steps/06-code.md +7 -4
  69. package/docs/03-guides/developer.md +6 -3
  70. package/docs/explain/09-generate-code.md +41 -3
  71. package/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +646 -0
  72. package/modules/phaser-game/module.yaml +15 -0
  73. package/modules/phaser-game/stack-profile.yaml +90 -0
  74. package/package.json +1 -1
  75. package/steps/context-loader.md +2 -0
  76. package/steps/gate.md +2 -1
  77. package/templates/project-context.yaml +6 -0
@@ -0,0 +1,90 @@
1
+ build:
2
+ compile: "tsc --noEmit && vite build" # type-check, then bundle to dist/ (base './')
3
+ test: "vitest run"
4
+ run: "vite" # dev server with HMR
5
+ lint: "eslint . --ext .ts"
6
+
7
+ architecture:
8
+ style: "Phaser 3 scene state machine + framework-free domain logic + direct backend API (token injected by host) + thin native window bridge"
9
+ key_rules:
10
+ - "Keep GAME LOGIC that can be pure (scoring, spawn tables, weight/physics math) in framework-free TS modules under src/domain/ — no Phaser imports there, so it unit-tests in Node"
11
+ - "Scenes orchestrate; they call domain functions and drive Phaser objects — they do NOT hold complex business math inline"
12
+ - "One responsibility per scene: BootScene (read host config), PreloadScene (load assets + game data), MenuScene, GameScene, GameOverScene, UIScene (HUD overlay run in parallel)"
13
+ - "Game objects (Miner, Hook, Gold) are Phaser.GameObjects subclasses (prefabs) — reusable, self-contained"
14
+ - "APPROACH A: the game calls the backend DIRECTLY (fetch). Host (Flutter) injects a HostConfig (apiBase, token, userId, sessionId) into the WebView BEFORE load — the game never hard-codes URLs or tokens"
15
+ - "All backend I/O goes through ONE API client (src/api/) that reads the token from HostConfig and sets the Authorization header — never scatter raw fetch() across scenes"
16
+ - "The native bridge (GameContract) is thin: window CONTROL only (onReady, onClose/back). Data does NOT go through native in Approach A — it goes over HTTP"
17
+ - "Tuning numbers live in src/config/constants.ts, never hard-coded in scenes"
18
+ - "Vite base MUST be './' so the built bundle works from file:// inside a WebView"
19
+ - "Use Phaser Arcade Physics for collision/overlap; avoid hand-rolled loops unless the mechanic needs it"
20
+ - "Cross-scene / game↔UI communication uses an event emitter (this.game.events or a shared EventBus), not direct scene references"
21
+ - "Debug console (eruda) is loaded ONLY when the URL has ?debug=1 — never bundled into the default runtime path"
22
+ - "Never trust HostConfig blindly — validate it at boot (BootScene) and fail loudly (call onClose) if apiBase/token is missing"
23
+ folder_structure: |
24
+ .
25
+ ├── index.html ← <div id="game"> + <script type="module" src="/src/main.ts">
26
+ ├── vite.config.ts ← base: './', @vitejs/plugin-legacy for old WebView
27
+ ├── tsconfig.json
28
+ ├── public/assets/ ← images, audio, atlases, tilemaps (copied as-is)
29
+ ├── src/
30
+ │ ├── main.ts ← Phaser.Game config + scene list, mount debug bridge
31
+ │ ├── contracts/
32
+ │ │ ├── game-contract.ts ← GameContract (window control) + HostConfig shape
33
+ │ │ └── api.dto.ts ← backend request/response DTOs (GameDataDto, ResultDto)
34
+ │ ├── config/
35
+ │ │ ├── constants.ts ← GRAVITY, HOOK_SPEED, SPAWN_TABLE...
36
+ │ │ ├── host-config.ts ← read + validate window.GAME_CONFIG injected by Flutter
37
+ │ │ └── game-config.ts ← Phaser.Types.Core.GameConfig
38
+ │ ├── api/ ← client.ts (fetch + auth header), game.api.ts (loadData, submitResult)
39
+ │ ├── domain/ ← PURE TS, no Phaser: scoring.ts, spawn.ts, hook-physics.ts
40
+ │ ├── scenes/ ← BootScene.ts, PreloadScene.ts, MenuScene.ts, GameScene.ts, GameOverScene.ts, UIScene.ts
41
+ │ ├── objects/ ← Miner.ts, Hook.ts, Gold.ts (Phaser.GameObjects prefabs)
42
+ │ ├── bridge/ ← native-bridge.ts (onReady/onClose), event-bus.ts
43
+ │ └── debug/ ← eruda.ts (lazy-loaded when ?debug=1)
44
+ └── tests/ ← *.test.ts (Vitest → domain/) + e2e/*.spec.ts (Playwright)
45
+
46
+ coding_standards:
47
+ naming:
48
+ scenes: "PascalCase + 'Scene' suffix (BootScene, GameScene, UIScene)"
49
+ game_objects: "PascalCase prefab class (Miner, Hook, Gold)"
50
+ domain_functions: "camelCase pure functions (calcScore, rollSpawn, retractSpeed)"
51
+ contracts: "PascalCase interface, 'Contract'/'Dto' suffix (GameContract, ScoreDto)"
52
+ constants: "SCREAMING_SNAKE_CASE (GRAVITY, HOOK_SPEED, SPAWN_TABLE)"
53
+ scene_keys: "kebab or PascalCase string key matching class (scene.start('GameScene'))"
54
+ files:
55
+ scene: "{Name}Scene.ts"
56
+ object: "{Object}.ts"
57
+ domain: "{topic}.ts"
58
+ contract: "game-contract.ts / {topic}.dto.ts"
59
+ test: "{unit}.test.ts"
60
+ patterns:
61
+ scenes: "Phaser scene lifecycle: init(data) → preload() → create() → update(t, dt); transition via this.scene.start('Key', data)"
62
+ hud: "UIScene launched in parallel (this.scene.launch('UIScene')) and rendered above GameScene"
63
+ physics: "Arcade Physics — this.physics.add.overlap(hook, goldGroup, onGrab)"
64
+ assets: "Load everything in PreloadScene with a progress bar; reference by key afterwards"
65
+ animation: "Tweens (this.tweens.add) for hook swing/retract easing; sprite sheet anims for characters"
66
+ state_transfer: "Pass data between scenes via scene.start('Key', payload); load game data once in PreloadScene via the API client, then hand it to GameScene"
67
+ host_config: "Flutter injects window.GAME_CONFIG = { apiBase, token, userId, sessionId } via initialUserScripts/evaluateJavascript BEFORE the page loads; read + validate it once in host-config.ts"
68
+ api_client: "APPROACH A — game calls backend directly. One fetch wrapper sets Authorization: Bearer <token> from HostConfig; game.api.ts exposes loadData()/submitResult() returning typed DTOs; handle 401/timeout and surface to the player"
69
+ native_bridge: "Thin GameContract = window control only. onReady() when boot ok; onClose() on back/X button → Flutter pops the WebView. NO data over the bridge in Approach A"
70
+ events: "EventBus (Phaser.Events.EventEmitter) for game→HUD updates (score changed, time left)"
71
+ webview: "Vite base './' + @vitejs/plugin-legacy + core-js for ES5 WebViews; toggle legacy per Android min-SDK"
72
+ debug: "eruda (or vConsole) lazy-imported only when new URLSearchParams(location.search).get('debug') === '1'"
73
+
74
+ testing:
75
+ unit: "Vitest — target src/domain/ pure functions (scoring, spawn rolls, retract speed by weight). No Phaser, no DOM, no canvas mock needed"
76
+ e2e: "Playwright — run vite preview, load the page, drive canvas via keyboard/pointer, assert on the HUD DOM overlay or exposed window.__gameState"
77
+ patterns:
78
+ - "Split logic so the testable part imports zero Phaser — Phaser scenes stay thin wrappers"
79
+ - "Inject a seeded RNG into spawn functions so tests are deterministic"
80
+ - "Expose a minimal window.__gameState (score, scene) in dev/e2e builds for Playwright assertions"
81
+ - "Mock the native bridge with a fake GameContract in tests; assert onReady/onClose are called"
82
+ - "Mock fetch (or the API client) in unit tests; assert loadData()/submitResult() send the right URL, auth header, and payload"
83
+ - "In e2e, stub window.GAME_CONFIG and intercept backend routes with Playwright page.route() so tests need no real server"
84
+ - "Do not pixel-diff the canvas — assert on state and HUD text instead"
85
+
86
+ trace_tags:
87
+ implements: "// @trace.implements={UC-ID}-SC{N}"
88
+ source: "// @trace.source=specs/{domain}/{prd-slug}/bdd/{UC-ID}.feature"
89
+ verifies: "// @trace.verifies={UC-ID}"
90
+ test_type: "// @trace.test_type=unit|integration"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@educa-corp/sdd-framework",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Spec Driven Development workflow framework for Claude Code",
5
5
  "bin": {
6
6
  "sdd-framework": "./bin/index.js"
@@ -42,6 +42,7 @@ Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nh
42
42
  - `paths.business_dictionary` → path tới business-dictionary.md
43
43
  - `paths.core_entities` → path tới core-entities.md
44
44
  - `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
45
+ - `paths.src_dir` → gốc mã nguồn (nơi generate-code đặt & quét code; nguồn chính cho FE + phạm vi reuse-scan của DS5)
45
46
  - `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)
46
47
 
47
48
  Nếu không có section `paths`, dùng các giá trị mặc định:
@@ -54,6 +55,7 @@ Nếu không có section `paths`, dùng các giá trị mặc định:
54
55
  - `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
55
56
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
56
57
  - `tech_docs_dir` = `specs`
58
+ - `src_dir` = `src`
57
59
  - `trace_dir` = `.trace`
58
60
 
59
61
  Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.
package/steps/gate.md CHANGED
@@ -49,7 +49,8 @@ Hiển thị và chờ phản hồi:
49
49
 
50
50
  ## Bước 1 — Xác định Target File
51
51
 
52
- 1. Nếu `$ARGUMENTS` được cung cấp trỏ tới một file tồn tại dùng trực tiếp làm target.
52
+ 0. **Tách cờ trước khi resolve target.** `$ARGUMENTS` thể lẫn các `--flag` (vd `--phase=integration`, `--comment`, `--fix`). **Loại bỏ mọi token bắt đầu bằng `--`** ra khỏi phần dùng để tìm target — chỉ giữ phần path/UC-ID/ticket. (Các flag đó do phần logic riêng của lệnh parse ở bước sau, KHÔNG phải tên file.)
53
+ 1. Nếu `$ARGUMENTS` (đã tách cờ) được cung cấp và trỏ tới một file tồn tại → dùng trực tiếp làm target.
53
54
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
54
55
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
55
56
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
@@ -35,6 +35,12 @@ paths:
35
35
  # prd-slug is derived from the PRD folder path — not a separate config variable.
36
36
  specs_dir: "specs"
37
37
  templates_dir: "specs/templates"
38
+
39
+ # Source code root — gốc mã nguồn của service/app này (nơi generate-code đặt & quét code).
40
+ # BE thường suy vị trí từ CLAUDE.md §2 (code_base_package + layer); src_dir là gốc chung,
41
+ # và là NGUỒN CHÍNH cho FE (component/hook/service/adapter) + phạm vi quét reuse (DS5).
42
+ # Ví dụ: "src" (mono FE), "app/src", "src/main/java" (BE). Chỉnh theo layout thật của repo.
43
+ src_dir: "src"
38
44
  feature_template: ".agent/templates/feature.template" # SoT skeleton .feature (dùng bởi /generate-bdd qua {{include}})
39
45
  bdd_writing_guide: "specs/templates/bdd-writing-guide.md"
40
46
  trace_report: "specs/.trace/trace-report.md"