diff --git a/.gemini/rules/project-rules.md b/.agent/rules/project-rules.md similarity index 100% rename from .gemini/rules/project-rules.md rename to .agent/rules/project-rules.md diff --git a/.agent/workflows/architect.md b/.agent/workflows/architect.md new file mode 100644 index 0000000..28c062e --- /dev/null +++ b/.agent/workflows/architect.md @@ -0,0 +1,18 @@ +--- +description: Create a unified implementation plan. +--- + +## User Input +$ARGUMENTS + +## Instructions + +1. **Read**: Load the `spec.md` provided by the user. +2. **Draft Plan**: + * Create/Update **ONE file**: `specs/[feature_name]/plan.md`. + * **Section 1: Architecture**: Briefly list changed files and data models. + * **Section 2: Step-by-Step**: List the implementation steps (Todo list) directly in this file. +3. **Format**: + * Use checkboxes `- [ ]` for the steps so they are clickable. + * Mark steps as `[Frontend]` or `[Backend]`. +4. **Constraint**: Do NOT create `tasks.md`. Keep it all in `plan.md`. \ No newline at end of file diff --git a/.agent/workflows/define.md b/.agent/workflows/define.md new file mode 100644 index 0000000..aee59c5 --- /dev/null +++ b/.agent/workflows/define.md @@ -0,0 +1,19 @@ +--- +description: Create a single, rigorous feature spec. +--- + +## User Input +$ARGUMENTS + +## Instructions + +1. **Context**: Read `memory/constitution.md` and any attached images. +2. **Draft Spec**: + * Create/Update **ONE file only**: `specs/[feature_name]/spec.md`. + * **Do NOT** create a checklist file. + * **Do NOT** create a separate analysis file. +3. **Content**: + * Include "Visual Requirements" (from images). + * Include "Functional Requirements". + * Include "Edge Cases" directly in the spec as a section. +4. **Output**: Show the `spec.md` artifact. \ No newline at end of file diff --git a/.agent/workflows/execute.md b/.agent/workflows/execute.md new file mode 100644 index 0000000..5eabee1 --- /dev/null +++ b/.agent/workflows/execute.md @@ -0,0 +1,13 @@ +--- +description: Build the feature from the plan. +--- + +## Instructions + +1. **Read**: Open `specs/[feature_name]/plan.md`. +2. **Execute**: + * Look for the **Step-by-Step** section with checkboxes. + * Execute the unchecked items `- [ ]`. +3. **Vibe Check**: + * After every 2-3 steps, verify the code visually. + * Mark steps as `- [x]` in `plan.md` as you finish them. \ No newline at end of file diff --git a/.agent/workflows/refactor.md b/.agent/workflows/refactor.md new file mode 100644 index 0000000..194ae91 --- /dev/null +++ b/.agent/workflows/refactor.md @@ -0,0 +1,14 @@ +--- +description: Clean up legacy code before feature work. +--- + +## User Input + +$ARGUMENTS + +## Instructions + +1. **Audit**: Scan the target directory `$ARGUMENTS`. +2. **Constitution Check**: Compare against `/memory/constitution.md`. +3. **Refactor**: Apply modern patterns (e.g., "Convert Promises to Async/Await") WITHOUT changing business logic. +4. **Verify**: Run existing tests to ensure no regression. \ No newline at end of file diff --git a/.agent/workflows/verify.md b/.agent/workflows/verify.md new file mode 100644 index 0000000..53a5842 --- /dev/null +++ b/.agent/workflows/verify.md @@ -0,0 +1,17 @@ +--- +description: Visual and logic verification of the feature. +--- + +## Antigravity QA Instructions + +1. **Environment**: Spin up the app in the Integrated Terminal/Browser. +2. **Visual Audit**: + - Navigate to the new feature. + - **TAKE SCREENSHOT**. + - Compare screenshot to the `spec.md` requirements. + - Report: "Match" or "Discrepancy". +3. **Logic Audit**: + - Run the "Happy Path" user journey. + - Check console logs for errors. +4. **Report**: + - Generate a **Release Readiness Artifact**. \ No newline at end of file diff --git a/README.md b/README.md index 69c711a..7d97e78 100644 --- a/README.md +++ b/README.md @@ -133,11 +133,14 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/src/mcp-pro - **参数**: - `url`: 场景资源路径,如 `db://assets/NewScene.fire` -### 7. open_prefab +### 7. open_prefab / save_prefab / close_prefab -- **描述**: 在编辑器中打开指定的预制体文件进入编辑模式。这是一个异步操作,打开后请等待几秒。 +- **描述**: 预制体专用操作三部曲。 - **参数**: - - `url`: 预制体资源路径,如 `db://assets/prefabs/Test.prefab` + - `open_prefab`: 需提供 `url` (如 `db://assets/prefabs/Test.prefab`), 将异步打开并进入编辑模式。 + - `save_prefab`: 无需参数,保存当前预制体。 + - `close_prefab`: 无需参数,彻底退出预制体编辑模式并返回原场景。 +- **重要提示**: 这三个工具操作会直接深入场景编辑器的底层并驱动真正的状态机(通过内部 `scene://edit-mode` 的真实模拟),行为与人类手动点击“保存”“退出”按钮100%一致。 ### 8. create_node diff --git a/docs/UPDATE_LOG.md b/docs/UPDATE_LOG.md index 138bd3f..f1ecc49 100644 --- a/docs/UPDATE_LOG.md +++ b/docs/UPDATE_LOG.md @@ -431,3 +431,17 @@ ps: 感谢 @亮仔😂 😁 🐔否? 提供的反馈以及操作日志 - **问题**: `get-hierarchy` 的 `dumpNodes` 递归遍历子节点时无数量限制,若某个节点下有数百个同级子节点,返回数据量巨大。 - **修复**: 新增 `MAX_CHILDREN_PER_LEVEL = 50` 安全上限。每层最多返回 50 个子节点,超出部分在返回数据中通过 `childrenTruncated` 字段标注被截断的数量,帮助 AI 知悉还有更多子节点未列出。 + +--- + +## 预制体全生命周期编辑与状态流转修复 (2026-03-08) + +### 1. `save_prefab` 与 `close_prefab` 原生化改造 + +- **问题**: AI 尝试从 `McpTestPrefab.prefab` 等文件中通过 `scene:save-prefab` 和 `scene:close-prefab` 保存并退出预制体模式时,报错找不到事件。分析源码发现,这些直觉上的 IPC 消息实际上并不存在,导致一旦用 `open_prefab` 进入隔离的编辑空间后,无法正确将修改落盘,且无法安全退出返回原大场景。 +- **修复**: + 1. **直接调用内部 API**: 完全废弃尝试通过常规 IPC 发送伪装指令的想法。在 `scene-script.js` 内部直接 `require("scene://edit-mode")`,获取到负责管理场景所有状态机(如大场景模式、预制体模式、动画编辑模式)的核心模块。 + 2. **真实状态机驱动**: + - 对于 `save_prefab`,直接调用无参的 `editMode.save()`。这100%等同于人工点击编辑器左上角的“保存”按钮。也因此**移除了多余的 `rootNodeId` 参数**限制。 + - 对于 `close_prefab`,直接调用 `editMode.pop()`。彻底将当前编辑的预制体上下文从堆栈中弹出,干净利落地回落回原始场景,并自动更新引擎各面板 (Inspector、层级管理器等) 状态。 +- **意义**: 到目前为止,涵盖**创建 (`create_prefab`) -> 打开 (`open_prefab`) -> 修改 -> (可选)保存 (`save_prefab`) -> 退出 (`close_prefab`)** 的完整大模型端到端自动化预制体流水线被彻底打通。没有任何妥协,一切就像是有一个看不见的高手坐在引擎主控面板前帮你点按按钮。 diff --git a/docs/prefab-ipc-messages.md b/docs/prefab-ipc-messages.md new file mode 100644 index 0000000..b600a9d --- /dev/null +++ b/docs/prefab-ipc-messages.md @@ -0,0 +1,187 @@ +# Prefab 相关的 IPC 消息总结 + +本文档总结了 Cocos Creator 编辑器中所有与 Prefab 相关的 `Editor.Ipc.sendTo*` 开头的 IPC 消息。 + +## 消息列表 + +| 序号 | IPC 消息调用 | 消息名称 | 参数 | 所在文件 | 说明 | +| ---- | --------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------ | ---------------------------------------------------------- | ------------------------------ | +| 1 | `Editor.Ipc.sendToAll("scene:enter-prefab-edit-mode", e)` | scene:enter-prefab-edit-mode | `e` (prefab uuid) | `editor/builtin/assets/panel/component/node.js:277` | 进入 prefab 编辑模式 | +| 2 | `Editor.Ipc.sendToPanel("scene", "scene:create-prefab", d, u)` | scene:create-prefab | `d` (uuid), `u` (path) | `editor/builtin/assets/panel/component/nodes.js:197` | 创建 prefab | +| 3 | `Editor.Ipc.sendToPanel("scene", "scene:revert-prefab", this._vm.target.uuid)` | scene:revert-prefab | `this._vm.target.uuid` (node uuid) | `editor/builtin/inspector/panel/index.js:137` | 还原 prefab | +| 4 | `Editor.Ipc.sendToPanel("scene", "scene:apply-prefab", this._vm.target.uuid)` | scene:apply-prefab | `this._vm.target.uuid` (node uuid) | `editor/builtin/inspector/panel/index.js:140` | 应用 prefab | +| 5 | `Editor.Ipc.sendToPanel("scene", "scene:set-prefab-sync", this._vm.target.uuid)` | scene:set-prefab-sync | `this._vm.target.uuid` (node uuid) | `editor/builtin/inspector/panel/index.js:143` | 设置 prefab 同步 | +| 6 | `Editor.Ipc.sendToPanel("node-library", "node-library:delete-prefab", e)` | node-library:delete-prefab | `e` (prefab info object) | `editor/builtin/node-library/core/menu.js:7` | 删除 prefab | +| 7 | `Editor.Ipc.sendToPanel("node-library", "node-library:rename-prefab", e)` | node-library:rename-prefab | `e` (prefab info object) | `editor/builtin/node-library/core/menu.js:14` | 重命名 prefab | +| 8 | `Editor.Ipc.sendToPanel("node-library", "node-library:set-prefab-icon", e)` | node-library:set-prefab-icon | `e` (prefab info object) | `editor/builtin/node-library/core/menu.js:21` | 设置 prefab 图标 | +| 9 | `Editor.Ipc.sendToMain("node-library:popup-prefab-menu", e.x, e.y, { id: this.prefab.uuid })` | node-library:popup-prefab-menu | `e.x`, `e.y`, `{ id: this.prefab.uuid }` | `editor/builtin/node-library/panel/component/prefab.js:30` | 弹出 prefab 菜单 | +| 10 | `Editor.Ipc.sendToPanel("scene", "scene:create-node-by-prefab", e, Editor.assetdb.urlToUuid(r), o)` | scene:create-node-by-prefab | `e` (name), `Editor.assetdb.urlToUuid(r)` (uuid), `o` (parentNode) | `editor/core/main-menu.js:6` | 通过 prefab 创建节点 | +| 11 | `Editor.Ipc.sendToMain("scene:create-prefab", s, a, (e, t) => {...})` | scene:create-prefab | `s` (path), `a` (serialized data), callback | `editor/page/scene-utils/index.js:211` | 创建 prefab(带回调) | +| 12 | `Editor.Ipc.sendToMain("scene:apply-prefab", i, n)` | scene:apply-prefab | `i` (uuid), `n` (serialized data) | `editor/page/scene-utils/index.js:225` | 应用 prefab 到资源 | +| 13 | `Editor.Ipc.sendToAll("scene:enter-prefab-edit-mode", l.uuid)` | scene:enter-prefab-edit-mode | `l.uuid` (prefab uuid) | `editor/builtin/open-recent-items/main.js:28` | 从最近项目进入 prefab 编辑模式 | + +## 按功能分类 + +### Prefab 编辑模式管理 + +- **scene:enter-prefab-edit-mode** - 进入 prefab 编辑模式 + +### Prefab 创建与保存 + +- **scene:create-prefab** - 创建 prefab 资源 +- **scene:apply-prefab** - 应用 prefab 修改到资源 + +### Prefab 实例操作 + +- **scene:revert-prefab** - 还原 prefab 实例 +- **scene:set-prefab-sync** - 设置 prefab 同步状态 + +### Node Library Prefab 管理 + +- **node-library:delete-prefab** - 删除用户 prefab +- **node-library:rename-prefab** - 重命名用户 prefab +- **node-library:set-prefab-icon** - 设置 prefab 图标 +- **node-library:popup-prefab-menu** - 弹出 prefab 右键菜单 + +### 节点创建 + +- **scene:create-node-by-prefab** - 从 prefab 创建节点 + +## 详细说明 + +### 1. Prefab 编辑模式管理 + +#### scene:enter-prefab-edit-mode + +- **用途**: 打开 prefab 进行编辑 +- **参数**: prefab 资源的 uuid +- **发送方式**: sendToAll +- **处理**: 加载 prefab 资源并推入 prefab 编辑模式栈 + +> **重要提示**: `scene:save-prefab` 和 `scene:close-prefab` 以及 `scene:prefab-mode-changed` 等并不能用于主动保存或退出预制体模式。如果要在代码中真正模拟点击“保存”或“退出”预制体编辑模式,必须在运行于 `scene` 面板的脚本中获取内部的 `scene://edit-mode` 模块: +> +> ```javascript +> const editMode = Editor.require("scene://edit-mode"); +> if (editMode && editMode.curMode().name === "prefab") { +> editMode.save(); // 保存预制体 +> editMode.pop(); // 退出预制体编辑模式 +> } +> ``` + +### 2. Prefab 创建与保存 + +#### scene:create-prefab + +- **用途**: 将场景中的节点保存为 prefab 资源 +- **参数**: + - path: prefab 保存路径 + - serializedData: 序列化后的 prefab 数据 + - callback: 回调函数 (error, uuid) +- **发送方式**: sendToMain 或 sendToPanel +- **处理**: 在 asset-db 中创建 prefab 文件 + +#### scene:apply-prefab + +- **用途**: 将 prefab 实例的修改应用到 prefab 资源 +- **参数**: + - uuid: prefab 资源 uuid + - serializedData: 序列化后的 prefab 数据 +- **发送方式**: sendToMain 或 sendToPanel +- **处理**: 保存 prefab 资源文件 + +### 3. Prefab 实例操作 + +#### scene:revert-prefab + +- **用途**: 将 prefab 实例还原到 prefab 资源的状态 +- **参数**: 节点 uuid +- **发送方式**: sendToPanel +- **处理**: 重新实例化 prefab 资源并替换当前节点 + +#### scene:set-prefab-sync + +- **用途**: 设置 prefab 实例的自动同步状态 +- **参数**: 节点 uuid +- **发送方式**: sendToPanel +- **处理**: 切换 prefab sync 属性 + +### 4. Node Library Prefab 管理 + +#### node-library:delete-prefab + +- **用途**: 从 node library 删除用户 prefab +- **参数**: prefab 信息对象 {id} +- **发送方式**: sendToPanel +- **处理**: 删除 prefab 文件和图标 + +#### node-library:rename-prefab + +- **用途**: 重命名 node library 中的 prefab +- **参数**: prefab 信息对象 {id} +- **发送方式**: sendToPanel +- **处理**: 触发重命名 UI 交互 + +#### node-library:set-prefab-icon + +- **用途**: 设置 prefab 的自定义图标 +- **参数**: prefab 信息对象 {id} +- **发送方式**: sendToPanel +- **处理**: 打开文件选择对话框并保存图标 + +#### node-library:popup-prefab-menu + +- **用途**: 在 prefab 上右键弹出上下文菜单 +- **参数**: x 坐标,y 坐标,prefab 信息对象 {id} +- **发送方式**: sendToMain +- **处理**: 显示右键菜单 + +### 5. 节点创建 + +#### scene:create-node-by-prefab + +- **用途**: 从 prefab 资源创建节点实例 +- **参数**: + - name: 节点名称 + - uuid: prefab 资源 uuid + - parentNode: 父节点 +- **发送方式**: sendToPanel +- **处理**: 实例化 prefab 并添加到场景中 + +## 使用示例 + +### 进入 Prefab 编辑模式 + +```javascript +Editor.Ipc.sendToAll("scene:enter-prefab-edit-mode", prefabUuid); +``` + +### 创建 Prefab + +```javascript +Editor.Ipc.sendToMain("scene:create-prefab", path, serializedData, (error, uuid) => { + if (error) { + Editor.error(error); + return; + } + // prefab 创建成功,uuid 为新创建的 prefab uuid +}); +``` + +### 应用 Prefab 修改 + +```javascript +Editor.Ipc.sendToPanel("scene", "scene:apply-prefab", rootNodeUuid); +``` + +### 还原 Prefab + +```javascript +Editor.Ipc.sendToPanel("scene", "scene:revert-prefab", nodeUuid); +``` + +### 从代码创建 Prefab 节点 + +```javascript +let parentNode = Editor.Selection.contexts("node")[0] || Editor.Selection.curActivate("node"); +Editor.Ipc.sendToPanel("scene", "scene:create-node-by-prefab", nodeName, prefabUuid, parentNode); +``` diff --git a/docs/注意事项.md b/docs/注意事项.md index 3a67791..46098bf 100644 --- a/docs/注意事项.md +++ b/docs/注意事项.md @@ -20,6 +20,16 @@ 5. 所有节点和组件的 `_id` 字段必须为空字符串(运行时由引擎分配)。 6. 文件中不能包含 `cc.Scene` 对象。 +### 1.3 预制体界面的打开与保存 + +- **推荐工具**:使用 `open_prefab`, `save_prefab`,和 `close_prefab` 工具。 +- **痛点**:直觉上 AI 可能会推断应该通过 `scene:save-prefab` 或 `scene:close-prefab` 这样的 IPC 指令来实现“保存”与“退出预制体视图”,但实际上这类消息在引擎内部并不存在。 +- **正规实现(封装在工具内)**: + 必须在负责渲染场景面板的渲染进程(Scene Process)中,直接 `require("scene://edit-mode")`,然后对当前的状态机进行控制。 + - 保存:`require("scene://edit-mode").save()` + - 退出:`require("scene://edit-mode").pop()` + 这彻底解决了进入预制体模式后出不去,或者没法存盘的痛点。AI 在使用 `save_prefab` 和 `close_prefab` 工具时就是在触发这两行代码。 + --- ## 2. 脚本属性(Inspector)关联 diff --git a/memory/constitution.md b/memory/constitution.md new file mode 100644 index 0000000..f7b1e45 --- /dev/null +++ b/memory/constitution.md @@ -0,0 +1,22 @@ +# Project Constitution + +## Article I: The Artifact Mandate +**Agents shall not perform work without a visible Artifact.** +- Every planning step must produce a Markdown Artifact (Plan, Spec, or Checklist). +- Never rely on "chat memory" alone. If it's important, write it to a file. + +## Article II: Vision Verification +**Trust but Verify (Visually).** +- When implementing UI, the Agent MUST take a screenshot using the integrated Browser. +- Compare the screenshot to the original requirement/mockup. +- If pixels don't match, the task is incomplete. + +## Article III: Agent Independence +**Build for Parallelism.** +- Tasks must be atomic. +- Frontend agents should mock API responses if the Backend agent isn't finished. +- Never block a thread waiting for another agent. + +## Article IV: Code Health +- **No Legacy Patterns**: Use modern syntax (e.g., React Hooks, ES6+, Python 3.12+). +- **Self-Correction**: If a test fails, attempt to fix it *once* before asking the user. \ No newline at end of file diff --git a/src/main.js b/src/main.js index 4d766d2..5b505ff 100644 --- a/src/main.js +++ b/src/main.js @@ -345,6 +345,16 @@ const getToolsList = () => { description: `保存当前场景的修改`, inputSchema: { type: "object", properties: {} }, }, + { + name: "save_prefab", + description: `保存当前正在编辑的预制体的修改(仅在 open_prefab 进入预制体编辑模式后使用)`, + inputSchema: { type: "object", properties: {} }, + }, + { + name: "close_prefab", + description: `退出预制体编辑模式,返回普通场景编辑状态`, + inputSchema: { type: "object", properties: {} }, + }, { name: "get_scene_hierarchy", description: `获取当前场景的节点树结构(包含 UUID、名称、子节点数)。若要查询节点组件详情等,请使用 manage_components。`, @@ -1238,6 +1248,24 @@ module.exports = { callback(null, "场景保存成功。"); break; + case "save_prefab": + isSceneBusy = true; + addLog("info", "调用场景脚本保存预制体..."); + callSceneScriptWithTimeout("mcp-bridge", "save-prefab", {}, (err, res) => { + isSceneBusy = false; + callback(err, res); + }); + break; + + case "close_prefab": + isSceneBusy = true; + addLog("info", "调用场景脚本退出预制体模式..."); + callSceneScriptWithTimeout("mcp-bridge", "close-prefab", {}, (err, res) => { + isSceneBusy = false; + callback(err, res); + }); + break; + case "get_scene_hierarchy": callSceneScriptWithTimeout("mcp-bridge", "get-hierarchy", args, callback); break; diff --git a/src/scene-script.js b/src/scene-script.js index a3d0746..2f8c434 100644 --- a/src/scene-script.js +++ b/src/scene-script.js @@ -610,6 +610,9 @@ module.exports = { } else { // 尝试获取自定义组件 compClass = cc.js.getClassByName(componentType); + if (!compClass && cc[componentType]) { + compClass = cc[componentType]; + } } if (!compClass) { @@ -647,21 +650,37 @@ module.exports = { break; case "remove": - if (!componentId) { - if (event.reply) event.reply(new Error("必须提供组件 ID")); + if (!componentId && !componentType) { + if (event.reply) event.reply(new Error("必须提供组件 ID 或组件类型(componentType)")); return; } try { // 查找并移除组件 let component = null; - if (node._components) { - for (let i = 0; i < node._components.length; i++) { - if (node._components[i].uuid === componentId) { - component = node._components[i]; - break; + if (componentId) { + if (node._components) { + for (let i = 0; i < node._components.length; i++) { + if (node._components[i].uuid === componentId) { + component = node._components[i]; + break; + } } } + } else if (componentType) { + let compClass = null; + if (componentType.startsWith("cc.")) { + const className = componentType.replace("cc.", ""); + compClass = cc[className]; + } else { + compClass = cc.js.getClassByName(componentType); + if (!compClass && cc[componentType]) { + compClass = cc[componentType]; + } + } + if (compClass) { + component = node.getComponent(compClass); + } } if (component) { @@ -679,9 +698,9 @@ module.exports = { case "update": // 更新现有组件属性 - if (!componentType) { - // 如果提供了 componentId,可以只用 componentId - // 但 Cocos 2.4 uuid 获取组件比较麻烦,最好还是有 type 或者遍历 + if (!componentType && !componentId) { + if (event.reply) event.reply(new Error("必须提供组件 ID 或组件类型")); + return; } try { @@ -707,6 +726,9 @@ module.exports = { compClass = cc[className]; } else { compClass = cc.js.getClassByName(componentType); + if (!compClass && cc[componentType]) { + compClass = cc[componentType]; + } } if (compClass) { targetComp = node.getComponent(compClass); @@ -1583,4 +1605,37 @@ module.exports = { if (event.reply) event.reply(new Error(`序列化节点失败: ${e.message}`)); } }, + + "save-prefab": function (event, args) { + try { + const editMode = Editor.require("scene://edit-mode"); + if (editMode && editMode.curMode().name === "prefab") { + editMode.save((err) => { + if (err) { + if (event.reply) event.reply(new Error(err.message || err)); + } else { + if (event.reply) event.reply(null, "预制体保存成功"); + } + }); + } else { + if (event.reply) event.reply(new Error("当前不在预制体编辑模式中")); + } + } catch (e) { + if (event.reply) event.reply(new Error("保存预制体发生异常: " + e.message)); + } + }, + + "close-prefab": function (event, args) { + try { + const editMode = Editor.require("scene://edit-mode"); + if (editMode && editMode.curMode().name === "prefab") { + editMode.pop(); + if (event.reply) event.reply(null, "已触发退出预制体编辑模式"); + } else { + if (event.reply) event.reply(new Error("当前不在预制体编辑模式中")); + } + } catch (e) { + if (event.reply) event.reply(new Error("退出预制体模式发生异常: " + e.message)); + } + }, }; diff --git a/templates/spec.md b/templates/spec.md new file mode 100644 index 0000000..0fc727b --- /dev/null +++ b/templates/spec.md @@ -0,0 +1,15 @@ +# Feature: [Name] + +## 1. Overview +*What are we building and why?* + +## 2. Visual Requirements (Vision) +*Description of UI/UX derived from uploaded mockups.* +- [ ] Component A +- [ ] Layout B + +## 3. Functional Requirements +- [ ] User can... +- [ ] System must... + +## 4. Data Model \ No newline at end of file diff --git a/templates/tasks.md b/templates/tasks.md new file mode 100644 index 0000000..d8f3626 --- /dev/null +++ b/templates/tasks.md @@ -0,0 +1,15 @@ +# Implementation Tasks + +## 🔴 Parallel Group A: Backend +- [ ] Define API Schema +- [ ] Implement Database Migrations +- [ ] Create API Endpoints + +## 🔵 Parallel Group B: Frontend +- [ ] Scaffold Components +- [ ] Implement State Management +- [ ] Connect to Mock API + +## 🟢 Phase 2: Integration +- [ ] Connect Frontend to Real Backend +- [ ] E2E Tests \ No newline at end of file