4.4 KiB
4.4 KiB
Tasks: enterprise-react-rule-builder
Change ID: enterprise-react-rule-builder
Package: @suaveplan/react-rule-builder
Target path: react/forms/react-rule-builder
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/react-dnd, @suaveplan/react-translate, @suaveplan/react-ui
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Scaffold
- Create directory tree per proposal layout.
- Write
package.jsonat0.1.0with"sideEffects": false, exports map. - Dependencies:
@suaveplan/error workspace:^,@suaveplan/react-dnd workspace:^,@suaveplan/react-translate workspace:^,@suaveplan/react-ui workspace:^,zod catalog:forms,@opentelemetry/api catalog:observability,tslib catalog:build. - Write
tsconfig.json,vitest.config.ts, scripts. - Confirm
src/mocks/directory is NOT created — no mocks under any circumstance.
2. Error codes and types
- Define
RuleBuilderErrorextendingSuaveplanError; codes:RULE_BUILDER_INVALID_PATH,RULE_BUILDER_INVALID_RULE. - Define
FieldDefinition,OperatorOption,SelectOption,RuleBuilderProps,LogicGroupProps,ConditionRowProps,OnRuleChange. - Define
DEFAULT_OPERATORSconstant. - Write
RuleSchemaZod schema for the rule AST.
3. Utils (src/utils/rule-helpers/)
- Implement
createEmptyCondition(fieldDefs),createEmptyGroup(). - Implement
getApplicableOperators(field, fieldDefs),getRuleAtPath(rule, path),insertRuleAtPath(rule, path, item),removeRuleAtPath(rule, path),updateRuleAtPath(rule, path, updates). - Validate paths in
get/insert/remove/update— throwRuleBuilderError(RULE_BUILDER_INVALID_PATH)on invalid path. - Write
rule-helpers.test.ts(≤500 lines): each helper, nested paths, invalid path throws.{ timeout: 5000 }. - Write
rule-helpers.md.
4. Hook — useRuleBuilder
- Manages
rulestate; exposesaddCondition(path),addGroup(path),removeItem(path),updateCondition(path, updates),toggleLogic(path),moveItem(from, to). - Validates rule via
RuleSchemabefore callingonRuleChange; on failure throwsRuleBuilderError(RULE_BUILDER_INVALID_RULE). - Write
use-rule-builder.test.ts: add, remove, update, move — all using realuseRuleBuilder.{ timeout: 5000 }. - Write
use-rule-builder.md.
5. Components
ConditionRow
- Field selector (from
FieldDefinition[]), operator selector (fromgetApplicableOperators), value input. Uses@suaveplan/react-uiSelect+Input. - Write test (real
@suaveplan/react-uiprovider), stories (default, all-operators, playground), md.
LogicGroup
- AND/OR/NOT toggle (uses
@suaveplan/react-uiToggleGroup); renders children recursively; add-condition + add-group buttons; drag handle wired to@suaveplan/react-dndDraggable. - Write test (nested groups, drag reorder triggers
moveItem), stories (default, nested, drag-reorder, playground), md.
RuleBuilder
- Top-level: renders root
LogicGroup; wrapsuseRuleBuilder; wiresDndProviderfrom@suaveplan/react-dnd. - Write test (full render with real deps), stories (default, with-field-definitions, nested-groups, drag-reorder, playground), md.
6. E2E
e2e/rule-builder.spec.ts— Playwright:- Add a condition, set field + operator + value, verify AST.
- Add nested group, verify nesting.
- Drag condition to reorder, verify
moveItemreflected in AST.
7. Verify and publish
bunx turbo lint typecheck test --filter=@suaveplan/react-rule-builder— green.bunx turbo test:coverage --filter=@suaveplan/react-rule-builder— 100%.bun scripts/publish.ts --package @suaveplan/react-rule-builder.- Archive change folder.