# Style Preset UI Only 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:** Make page style presets affect generated UI tokens only, without changing generated page canvas/layout. **Architecture:** Keep automatic layout selection inside `PageCompositionService.chooseLayout()`. Resolve the selected `PageStylePreset` only to write `stylePreset`, `styleTokens`, and composition metadata into layout JSON. Remove the canvas override path so presets cannot change table/card/split/dense layout structure. **Tech Stack:** Java, JUnit 4, Jackson, Spring service classes in `ruoyi-generator`. --- ## File Structure - Modify: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageCompositionServiceStylePresetTest.java` - Owns regression tests for `PageCompositionService` style preset behavior. - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/PageCompositionService.java` - Owns deterministic page canvas selection and layout JSON composition. - Modify: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageStylePresetRegistryTest.java` - Owns registry contract tests for style tokens, density, and fallback. - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/PageStylePresetRegistry.java` - Owns available visual preset definitions. ### Task 1: Lock Style Presets Out Of Canvas Selection **Files:** - Modify: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageCompositionServiceStylePresetTest.java` - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/PageCompositionService.java` - [ ] **Step 1: Write the failing frontend regression test** Replace `cardPortalPresetPrefersCardCanvasForFrontendLists` with: ```java @Test public void cardPortalPresetKeepsAutomaticallySelectedFrontendCanvas() { FrontProjectPageDesign design = design("frontend", "list"); service.compose(design, table(), Arrays.asList( column("title", "title", "1", "1", "1"), column("status", "status", "1", "1", "1")), null, null, true, "card_portal"); Map layout = readLayout(design); assertEquals("frontend-list-v1", layout.get("canvas")); assertEquals("card_portal", layout.get("stylePreset")); assertTrue(((Map) layout.get("styleTokens")).containsKey("primary")); Map composition = (Map) layout.get("composition"); assertEquals("card_portal", composition.get("stylePreset")); assertTrue(String.valueOf(composition.get("reasons")).contains("card_portal")); } ``` - [ ] **Step 2: Write the failing admin regression test** Replace `dataDensePresetPrefersDenseCanvasForAdminLists` with: ```java @Test public void dataDensePresetKeepsAutomaticallySelectedAdminCanvas() { FrontProjectPageDesign design = design("admin", "list"); service.compose(design, table(), Arrays.asList( column("code", "code", "1", "1", "1"), column("name", "name", "1", "1", "1")), null, null, true, "data_dense"); Map layout = readLayout(design); assertEquals("admin-list-v1", layout.get("canvas")); assertEquals("data_dense", layout.get("stylePreset")); assertTrue(((Map) layout.get("styleTokens")).containsKey("primary")); } ``` - [ ] **Step 3: Run tests to verify they fail** Run: ```bash mvn -pl ruoyi-generator -Dtest=PageCompositionServiceStylePresetTest test ``` Expected: both tests fail because the current implementation changes `canvas` to `frontend-list-card-v1` and `admin-list-dense-v1`. - [ ] **Step 4: Implement minimal service change** In `PageCompositionService.compose(...)`, replace: ```java stylePreset = stylePresetRegistry.resolve(stylePresetCode); applyStylePreset(decision, pageType, scope, stylePreset); ``` with: ```java stylePreset = stylePresetRegistry.resolve(stylePresetCode); decision.addReason("style preset " + stylePreset.getCode() + " applied visual tokens"); ``` Then remove the unused `applyStylePreset(...)` method. - [ ] **Step 5: Run tests to verify they pass** Run: ```bash mvn -pl ruoyi-generator -Dtest=PageCompositionServiceStylePresetTest test ``` Expected: `Tests run: 2, Failures: 0, Errors: 0`. ### Task 2: Remove Canvas Mapping From The Registry Contract **Files:** - Modify: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageStylePresetRegistryTest.java` - Modify: `ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/PageStylePresetRegistry.java` - [ ] **Step 1: Write the failing registry contract test** Replace `resolvesKnownPresetWithCanvasAndTokens` with: ```java @Test public void resolvesKnownPresetWithTokensOnly() { PageStylePresetRegistry registry = new PageStylePresetRegistry(); PageStylePresetRegistry.PageStylePreset preset = registry.resolve("card_portal"); assertEquals("card_portal", preset.getCode()); assertEquals("#167d83", preset.token("primary", "")); assertEquals("#f6c85b", preset.token("accent", "")); assertEquals("comfortable", preset.getDensity()); assertTrue(registry.options().size() >= 4); } ``` Replace `unknownPresetFallsBackToBusinessClean` with: ```java @Test public void unknownPresetFallsBackToBusinessCleanTokens() { PageStylePresetRegistry registry = new PageStylePresetRegistry(); PageStylePresetRegistry.PageStylePreset preset = registry.resolve("not_real"); assertEquals("business_clean", preset.getCode()); assertEquals("#167d83", preset.token("primary", "")); assertEquals("1200px", preset.token("contentWidth", "")); } ``` - [ ] **Step 2: Run registry test before implementation** Run: ```bash mvn -pl ruoyi-generator -Dtest=PageStylePresetRegistryTest test ``` Expected: test compilation fails after removing frontend/admin canvas assertions from tests only if production still exposes unused API is not a compile failure; if tests pass immediately, continue with the cleanup as refactor under the Task 1 green state. - [ ] **Step 3: Remove registry canvas API and definitions** In `PageStylePresetRegistry`, remove: ```java private final Map frontendCanvases = new LinkedHashMap(); private final Map adminCanvases = new LinkedHashMap(); ``` Remove all `.frontend(...)` and `.admin(...)` calls from preset definitions. Remove the private builder methods `frontend(...)` and `admin(...)`. Remove public methods `frontendCanvas(...)` and `adminCanvas(...)`. - [ ] **Step 4: Run registry tests** Run: ```bash mvn -pl ruoyi-generator -Dtest=PageStylePresetRegistryTest test ``` Expected: `Tests run: 2, Failures: 0, Errors: 0`. ### Task 3: Final Verification **Files:** - Test: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageCompositionServiceStylePresetTest.java` - Test: `ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageStylePresetRegistryTest.java` - [ ] **Step 1: Run focused tests together** Run: ```bash mvn -pl ruoyi-generator -Dtest=PageCompositionServiceStylePresetTest,PageStylePresetRegistryTest test ``` Expected: both test classes pass. - [ ] **Step 2: Inspect diff for scope** Run: ```bash git diff -- ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/PageCompositionService.java ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/PageStylePresetRegistry.java ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageCompositionServiceStylePresetTest.java ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/PageStylePresetRegistryTest.java ``` Expected: diff only changes style preset canvas coupling and corresponding tests.