Shared Foundation Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 为后续 14 个模块打下同一套快照模型、HostAdapter 合同、模块开关和 Vitest 基建,且默认不改变现有设计器行为。
Architecture: 纯逻辑放在 designer3.0/src/modules/shared/。FcDesigner.vue 只增加 getSnapshot() 和把 config.adapter 往下传。测试用 Vitest,只覆盖新目录,不试图给 3700 行的设计器补历史单测。
Tech Stack: Vue3、现有 src/utils/sql.js、Vitest + jsdom。
Spec: docs/superpowers/specs/2026-08-23-innovation-requirements.md §3
File map
- Create:
designer3.0/vitest.config.js - Create:
designer3.0/src/modules/shared/types.js - Create:
designer3.0/src/modules/shared/snapshot.js - Create:
designer3.0/src/modules/shared/adapter.js - Create:
designer3.0/src/modules/shared/modePreset.js - Create:
designer3.0/tests/modules/shared/snapshot.spec.js - Create:
designer3.0/tests/modules/shared/adapter.spec.js - Modify:
designer3.0/package.json— 增加testscript 与 devDependencyvitest - Modify:
designer3.0/src/utils/sql.js— 导出buildSqlTables(现为文件内私有) - Modify:
designer3.0/src/designer/FcDesigner.vue—getSnapshot() - Modify:
designer3.0/types/index.d.ts—FormSnapshot、HostAdapter、getSnapshot、config.adapter
Task 1: 加上 Vitest
Files:
Create:
designer3.0/vitest.config.jsModify:
designer3.0/package.json[ ] Step 1: 增加测试脚本与依赖
在 designer3.0/package.json 的 scripts 中增加:
"test": "vitest run",
"test:watch": "vitest"在 devDependencies 增加 "vitest": "^2.1.9"。
- [ ] Step 2: 写 vitest 配置
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
include: ['tests/**/*.spec.js'],
},
});- [ ] Step 3: 安装并确认空跑通过
cd /Users/xaboy/Documents/git/form-create-package/designer3.0
pnpm add -D vitest@^2.1.9
pnpm testExpected: No test files found 或 0 files,exit 0 / 1 均可,但命令必须存在。随后 Task 2 会补上第一个测试。
- [ ] Step 4: Commit
git add package.json vitest.config.js
git commit -m "chore: add vitest for new platform modules"Task 2: 导出 buildSqlTables
Files:
Modify:
designer3.0/src/utils/sql.js:485Create:
designer3.0/tests/modules/shared/snapshot.spec.js(先写对 sql 的冒烟,下一步再扩)[ ] Step 1: 写失败测试
import { describe, it, expect } from 'vitest';
import { buildSqlTables } from '../../../src/utils/sql.js';
describe('buildSqlTables', () => {
it('builds a main table from input fields', () => {
const tables = buildSqlTables(
[{ type: 'input', field: 'name', title: '姓名', _fc_id: 'id_name', _fc_drag_tag: 'input' }],
{ input: { sqlType: 'string' } },
{ formName: 'leave_form' }
);
expect(tables[0].name).toBe('leave_form');
expect(tables[0].columns.some((c) => c.field === 'name')).toBe(true);
});
});- [ ] Step 2: 跑测试,确认因未导出而失败
pnpm test tests/modules/shared/snapshot.spec.jsExpected: FAIL buildSqlTables is not a function 或 import error。
- [ ] Step 3: 导出函数
把 sql.js 中的 function buildSqlTables 改为 export function buildSqlTables。不要改算法。
- [ ] Step 4: 再跑测试
pnpm test tests/modules/shared/snapshot.spec.jsExpected: PASS。若 formName 清理规则与预期不符,断言改成与 sanitizeName 一致(只允许字母数字下划线)。
- [ ] Step 5: Commit
git add src/utils/sql.js tests/modules/shared/snapshot.spec.js
git commit -m "feat: export buildSqlTables for snapshot module"Task 3: FormSnapshot 与 getSnapshot
Files:
Create:
designer3.0/src/modules/shared/snapshot.jsModify:
designer3.0/tests/modules/shared/snapshot.spec.jsModify:
designer3.0/src/designer/FcDesigner.vue(methods中getSQL附近,约 1985 行)Modify:
designer3.0/types/index.d.ts[ ] Step 1: 追加失败测试
import { buildSnapshot } from '../../../src/modules/shared/snapshot.js';
describe('buildSnapshot', () => {
it('embeds rule, options and schema', () => {
const snap = buildSnapshot({
formId: 'f1',
rule: [{ type: 'input', field: 'name', title: '姓名', _fc_id: 'id_name', _fc_drag_tag: 'input' }],
options: { formName: 'leave_form' },
dragRuleList: { input: { sqlType: 'string' } },
});
expect(snap.format).toBe('1.0.0');
expect(snap.formId).toBe('f1');
expect(snap.rule[0].field).toBe('name');
expect(Array.isArray(snap.schema)).toBe(true);
expect(snap.schema[0].name).toBe('leave_form');
});
});- [ ] Step 2: 跑测试确认失败
pnpm test tests/modules/shared/snapshot.spec.jsExpected: FAIL cannot find module snapshot.js
- [ ] Step 3: 实现 buildSnapshot
import { buildSqlTables } from '../../utils/sql.js';
export const SNAPSHOT_FORMAT = '1.0.0';
export function buildSnapshot({ formId, rule, options, dragRuleList, now = () => new Date().toISOString() }) {
const name = options.formCreateFormName || options.formName || 'fc_form';
return {
format: SNAPSHOT_FORMAT,
formId: formId || name,
name,
description: options.description || '',
rule,
options,
schema: buildSqlTables(rule, dragRuleList, options),
createdAt: now(),
};
}- [ ] Step 4: 在 FcDesigner 暴露 getSnapshot
在 getSQL() 旁增加:
getSnapshot() {
const options = designerForm.parseJson(methods.getOptionsJson());
return buildSnapshot({
formId: options.formId || options.formName,
rule: methods.getRule(),
options,
dragRuleList: data.dragRuleList || data.hiddenItem,
});
}dragRuleList 的实际字段以 getSQL() 内部用法为准:打开 getSQL 实现,把同一份 dragRuleList 传入,禁止猜一个不存在的 data 字段。
types/index.d.ts 的 expose 增加:
getSnapshot: () => FormSnapshot;并在文件中声明 FormSnapshot / SchemaTable / SchemaColumn(字段与 buildSqlTables 返回值对齐:name、comment、columns)。
- [ ] Step 5: 跑测试
pnpm test tests/modules/shared/snapshot.spec.jsExpected: PASS
- [ ] Step 6: Commit
git add src/modules/shared/snapshot.js src/designer/FcDesigner.vue types/index.d.ts tests/modules/shared/snapshot.spec.js
git commit -m "feat: add FormSnapshot and getSnapshot"Task 4: HostAdapter 合同
Files:
Create:
designer3.0/src/modules/shared/adapter.jsCreate:
designer3.0/tests/modules/shared/adapter.spec.jsModify:
designer3.0/types/index.d.ts—Config.adapter?: HostAdapter[ ] Step 1: 写失败测试
import { describe, it, expect } from 'vitest';
import { createMemoryAdapter, requireAdapter } from '../../../src/modules/shared/adapter.js';
describe('createMemoryAdapter', () => {
it('saves and lists versions in memory', async () => {
const adapter = createMemoryAdapter();
const saved = await adapter.saveForm({
snapshot: { format: '1.0.0', formId: 'f1', name: '请假', rule: [], options: {}, schema: [], createdAt: '2026-01-01T00:00:00.000Z' },
rule: '[]',
options: '{}',
});
expect(saved.id).toBeTruthy();
const versions = await adapter.listVersions(saved.id);
expect(versions).toHaveLength(1);
expect(versions[0].published).toBe(false);
});
});
describe('requireAdapter', () => {
it('throws a stable error when method missing', async () => {
await expect(requireAdapter({}, 'listRecords')({ page: 1 })).rejects.toThrow('[fc-adapter] listRecords is not implemented');
});
});- [ ] Step 2: 跑测试确认失败
pnpm test tests/modules/shared/adapter.spec.jsExpected: FAIL cannot find module
- [ ] Step 3: 实现 adapter
createMemoryAdapter 用闭包 Map 存 forms 与 versions。saveForm 若无 formId 则生成 form_ + 自增。listVersions 按 version 倒序。publishVersion 把对应项 published=true,并把同 form 其他项保持不变(允许多个 published,灰度解释权在宿主)。
requireAdapter(adapter, method) 返回:
export function requireAdapter(adapter, method) {
return (...args) => {
const fn = adapter && adapter[method];
if (typeof fn !== 'function') {
return Promise.reject(new Error(`[fc-adapter] ${method} is not implemented`));
}
return fn(...args);
};
}- [ ] Step 4: 跑测试
pnpm test tests/modules/shared/adapter.spec.jsExpected: PASS
- [ ] Step 5: Commit
git add src/modules/shared/adapter.js tests/modules/shared/adapter.spec.js types/index.d.ts
git commit -m "feat: add HostAdapter contract and memory adapter"Task 5: 业务模式预设(给 P1-5 复用)
Files:
Create:
designer3.0/src/modules/shared/modePreset.jsCreate:
designer3.0/tests/modules/shared/modePreset.spec.js[ ] Step 1: 写失败测试
import { describe, it, expect } from 'vitest';
import { resolveDesignerConfig } from '../../../src/modules/shared/modePreset.js';
describe('resolveDesignerConfig', () => {
it('hides developer surfaces in business mode', () => {
const cfg = resolveDesignerConfig({ mode: 'business' });
expect(cfg.showJsonPreview).toBe(false);
expect(cfg.showEventForm).toBe(false);
expect(cfg.showPreviewSfc).toBe(false);
expect(cfg.showAi).not.toBe(false);
expect(cfg.showPreviewForm).not.toBe(false);
});
it('keeps explicit overrides', () => {
const cfg = resolveDesignerConfig({ mode: 'business', showEventForm: true });
expect(cfg.showEventForm).toBe(true);
});
});- [ ] Step 2: 实现
const BUSINESS_DEFAULTS = {
showJsonPreview: false,
showEventForm: false,
showPreviewSfc: false,
showPreviewHtml: false,
showPreviewSql: false,
showPreviewComponent: false,
showCustomProps: false,
showShortcut: false,
};
export function resolveDesignerConfig(config = {}) {
if (config.mode !== 'business') {
return { ...config };
}
return { ...BUSINESS_DEFAULTS, ...config };
}调用点放到 P1-5 计划,本任务只交付纯函数。
- [ ] Step 3: 跑测试并提交
pnpm test tests/modules/shared/modePreset.spec.jsExpected: PASS
git add src/modules/shared/modePreset.js tests/modules/shared/modePreset.spec.js
git commit -m "feat: add business-mode config preset"

