siesa-agents 2.1.94 → 2.1.96
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.
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sa-screen-layout-refactor
|
|
3
|
+
description: Homologate existing SIESA frontend screens to approved HTML mockups by rebuilding their UI with siesa-ui-kit components — and, when no mockup exists for a screen, do it from a learned design memory built by scanning the mockup corpus. The mockup (or the memory synthesized from the corpus) dictates distribution and element inventory (N buttons, grids, checks, labels); the installed siesa-ui-kit dictates the implementation — kit molecules and compositions of them, almost never hand-rolled HTML. Behavior never changes — no new fields, validations, endpoints or logic. Use this skill whenever the user mentions refactoring or reorganizing a screen's layout, applying an HTML mockup or a `design-artifacts` mockup to an existing page, homologating a screen to the UI kit, "reorganizar pantallas", "aplicar el mockup", "refactor de layout", "refactorizar", "redistribuir la pantalla", refactoring a module "basado en las plantillas" or "con los patrones aprendidos", scanning/updating the design memory ("escanea los prototipos", "actualiza las memorias de diseño"), or wants existing screens rebuilt with siesa-ui-kit components — even if they never use the word "refactor", even without a mockup for that screen, and even when they hand over a whole folder of mockups at once.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Screen → UI-Kit Homologation (SIESA Frontend)
|
|
7
|
+
|
|
8
|
+
You rebuild the UI of existing screens with siesa-ui-kit components so they
|
|
9
|
+
match an approved mockup. You never change what the screen does.
|
|
10
|
+
|
|
11
|
+
Read the mockup as a **component inventory and a distribution plan** — it tells
|
|
12
|
+
you *what* is on the screen (a grid, five checkbox columns, two buttons, a
|
|
13
|
+
summary bar) and *where* it sits. It does NOT tell you *how* to build it: the
|
|
14
|
+
mockup's own HTML is throwaway Tailwind from a design tool, and copying its
|
|
15
|
+
markup or classes into the app is the failure mode this skill exists to
|
|
16
|
+
prevent. The *how* always comes from siesa-ui-kit:
|
|
17
|
+
|
|
18
|
+
- Every widget the mockup draws is realized with a kit component ("molecule"):
|
|
19
|
+
a checkbox is the kit `Checkbox`, a data grid is the kit `Table`, a tag is
|
|
20
|
+
`Badge`, a menu is `Dropdown`.
|
|
21
|
+
- When no single molecule fits, **compose** molecules: a permission matrix is
|
|
22
|
+
`Table` whose column `render` returns kit `Checkbox`es — not a hand-rolled
|
|
23
|
+
grid of styled `div`s. The kit is rich enough that most screens need zero
|
|
24
|
+
burned widget HTML.
|
|
25
|
+
- Plain HTML + Tailwind is allowed only for **inert structure**: flex/grid
|
|
26
|
+
wrappers, spacing, the page scaffold of UX spec §4.3. Anything a user reads,
|
|
27
|
+
clicks, focuses or toggles belongs to the kit.
|
|
28
|
+
- Existing hand-rolled widgets in the current screen ("HTML quemado") are not
|
|
29
|
+
something to preserve or restyle — they are precisely what this refactor
|
|
30
|
+
replaces with kit molecules, rewiring the existing handlers and state onto
|
|
31
|
+
the kit component's props.
|
|
32
|
+
|
|
33
|
+
The integrity boundary is unchanged and non-negotiable: every field, label,
|
|
34
|
+
validation, hook, query, mutation, handler and type that existed before still
|
|
35
|
+
exists after, with the same name and the same behaviour. Only the rendering
|
|
36
|
+
vocabulary and the distribution change. A homologation that quietly adds a
|
|
37
|
+
field or drops a validation is a feature change in costume, and the diff must
|
|
38
|
+
be defensible line by line against that accusation.
|
|
39
|
+
|
|
40
|
+
## Sources of truth
|
|
41
|
+
|
|
42
|
+
The paths below are **defaults**, resolved at setup step 0a — an explicit user
|
|
43
|
+
argument or a discovered location overrides them; a path that resolves to
|
|
44
|
+
nothing or to several candidates is asked about, never guessed.
|
|
45
|
+
|
|
46
|
+
| What | Where | Role |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| Mockup queue | `_bmad-output/design-artifacts/html-and-design/*.html` (one `.html` = one screen) | WHAT is on the screen and WHERE it sits |
|
|
49
|
+
| Design memory | `_bmad-output/design-artifacts/design-memory/` (`manifest.yaml` + `*.md`) | Learned distribution/composition patterns — stands in for WHAT/WHERE **only when no mockup exists**, and only per `references/design-memory.md` |
|
|
50
|
+
| Installed kit exports | `apps/Frontend/node_modules/siesa-ui-kit/dist/index.d.ts` | WHICH components exist — the only authority |
|
|
51
|
+
| Component props | `apps/Frontend/node_modules/siesa-ui-kit/dist/components/<Name>/<Name>.types.d.ts` | The REAL props — never guess a prop name |
|
|
52
|
+
| Storybook | https://siesa-ui-kit.pages.dev | Visual catalog of variants/stories — never proof a component is importable |
|
|
53
|
+
| UX spec | `_bmad-output/planning-artifacts/ux-design-specification.md` | Styles, tokens, page structure, selection priority, language rules — nothing is inferred |
|
|
54
|
+
| Binding style rules | `rules/*.md` in this skill's directory | Complementary rules every generated line must obey (colors as CSS variables, rem not px, no inline styles, …) |
|
|
55
|
+
| Tests | `apps/Frontend/test/unit/<module-slug>/` | The behavior contract (vitest only includes `test/unit/**`, NOT files colocated in `src/`) |
|
|
56
|
+
| Reports | `_bmad-output/screen-layout-refactor/` | Per-screen and final reports |
|
|
57
|
+
|
|
58
|
+
Key definitions you take from the UX spec instead of inferring:
|
|
59
|
+
|
|
60
|
+
- **§2.1 Component Selection Priority** (mandatory order): 1) a siesa-ui-kit
|
|
61
|
+
molecule, 2) a **composition** of kit molecules, 3) **shadcn as the
|
|
62
|
+
fallback** when neither expresses the widget — used directly, flagged in the
|
|
63
|
+
report (`⚠️ shadcn fallback: <widget>`) so the team can later decide whether
|
|
64
|
+
to promote it into the kit. Hand-rolled HTML widgets are never an option at
|
|
65
|
+
any step. A shadcn component obeys the same `rules/` as everything else:
|
|
66
|
+
design-system token classes, rem, no inline styles — restyled to the design
|
|
67
|
+
system, never left on shadcn defaults.
|
|
68
|
+
- **§1 Design System Foundation**: brand palette (primary `#0e79fd`), semantic
|
|
69
|
+
colors, surfaces; neutrals are `slate.*`, never the secondary brand scale.
|
|
70
|
+
- **§4.3 Page Structure**: the standard page scaffold (header with title +
|
|
71
|
+
actions, content in a bordered rounded container).
|
|
72
|
+
- **§7 Language**: all user-visible text in Spanish; never invent copy.
|
|
73
|
+
- **§6 Accessibility**: WCAG 2.1 AA — the homologated screen keeps or improves
|
|
74
|
+
the accessible behavior of what it replaces.
|
|
75
|
+
|
|
76
|
+
Off limits — never edit these:
|
|
77
|
+
|
|
78
|
+
- `apps/Frontend/src/routes/**` (TanStack file routes, thin wrappers over pages)
|
|
79
|
+
- `apps/Frontend/src/app/**`, `providers/**`, `main.tsx`, `spa.tsx` (MFE shell, single-spa, auth)
|
|
80
|
+
- `apps/Frontend/src/modules/*/application|domain|infrastructure/**` (hooks, schemas, services, API)
|
|
81
|
+
- The app shell (sidebar, top nav) drawn inside a mockup — mockups include it
|
|
82
|
+
for context; the screen you refactor starts at the page content.
|
|
83
|
+
|
|
84
|
+
You work inside `presentation/` only. If a homologation seems to require
|
|
85
|
+
touching anything above — say, the mockup shows data the page's hook doesn't
|
|
86
|
+
provide — that is a signal to flag, not to widen the diff.
|
|
87
|
+
|
|
88
|
+
## Design memory
|
|
89
|
+
|
|
90
|
+
The skill maintains a memory of the design language learned from the mockup
|
|
91
|
+
corpus, so a screen **without** a mockup can still be homologated from
|
|
92
|
+
precedent. Full protocol — directory layout, `manifest.yaml` schema, SHA-256
|
|
93
|
+
sync algorithm, extraction layers, file templates, memory-driven mode — lives
|
|
94
|
+
in `references/design-memory.md` in this skill's directory. **Read it whenever
|
|
95
|
+
memory is built, refreshed, or consumed.** The load-bearing rules, which also
|
|
96
|
+
appear there:
|
|
97
|
+
|
|
98
|
+
- Memory captures what only the corpus teaches: shell anatomy, screen
|
|
99
|
+
archetypes, widget → kit-composition patterns, layout rhythm. It never
|
|
100
|
+
stores hex, px, mockup theme classes, or kit prop signatures — colors and
|
|
101
|
+
measures are governed by the UX spec + `rules/`, and props are always
|
|
102
|
+
re-read from the installed typings.
|
|
103
|
+
- `manifest.yaml` registers every source `.html` with its SHA-256. At setup
|
|
104
|
+
the hashes are re-checked: missing manifest → full build; new/changed
|
|
105
|
+
sources → incremental update of the attributed sections; removed sources →
|
|
106
|
+
flagged, never silently forgotten.
|
|
107
|
+
- Memory is the **most junior** source of truth: an explicit mockup for the
|
|
108
|
+
target screen always outranks it, and it never overrides the UX spec, the
|
|
109
|
+
typings, or the domain.
|
|
110
|
+
- A memory-driven run executes directly — no plan is printed to chat and no
|
|
111
|
+
approval turn is spent. The synthesized plan (pattern ids, homologation
|
|
112
|
+
map, distribution) is embedded in the screen's report file on disk: that is
|
|
113
|
+
the audit trail replacing the mockup link.
|
|
114
|
+
|
|
115
|
+
## Anti-hallucination protocol
|
|
116
|
+
|
|
117
|
+
This is the discipline that keeps the refactor honest, and it is checked in
|
|
118
|
+
review:
|
|
119
|
+
|
|
120
|
+
1. A kit component "exists" only if the **installed** `dist/index.d.ts`
|
|
121
|
+
exports it. Storybook routinely runs ahead of the installed package — it
|
|
122
|
+
has shown `Card` and `ButtonGroup` while the installed build exported
|
|
123
|
+
neither. If Storybook has it and the typings don't, this run realizes the
|
|
124
|
+
widget via a kit composition or the shadcn fallback (flagged, with the
|
|
125
|
+
note "or bump siesa-ui-kit and re-run this mockup") — never an import that
|
|
126
|
+
won't compile and never a hand-rolled imitation.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
grep -oE "^export \{[^}]+\}" apps/Frontend/node_modules/siesa-ui-kit/dist/index.d.ts
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
2. Props come only from the component's `.types.d.ts`. Read it before writing
|
|
133
|
+
the first JSX attribute; a prop you "remember" from another design system is
|
|
134
|
+
a compile error at best and a silent no-op at worst.
|
|
135
|
+
|
|
136
|
+
3. Variants come from Storybook stories (e.g. Table: "Con Bordes", "Filas
|
|
137
|
+
Alternas", "Con Render Personalizado"; Checkbox: sizes, `labelPosition`,
|
|
138
|
+
`description`) — use them to pick the variant that matches the mockup, then
|
|
139
|
+
confirm the enabling props in the typings.
|
|
140
|
+
|
|
141
|
+
4. Styling comes from the UX spec (§1 tokens, §4.3 scaffold), the binding
|
|
142
|
+
`rules/` files, and what the kit component already renders. The mockup's
|
|
143
|
+
hex values and its private Tailwind theme (`surface-container-low`,
|
|
144
|
+
`on-surface-variant`, …) never enter the codebase — per `style-rules.md`
|
|
145
|
+
they are converted on entry: hex → design-system CSS variable (via its
|
|
146
|
+
Tailwind token class), px → rem (1rem = 16px, `44px → 2.75rem`), inline
|
|
147
|
+
styles → Tailwind classes.
|
|
148
|
+
|
|
149
|
+
## Pre-gate: directory validation and design memory
|
|
150
|
+
|
|
151
|
+
Before asking for a target, the skill validates the two key directories and
|
|
152
|
+
offers to refresh the design memory.
|
|
153
|
+
|
|
154
|
+
**1. Validate `_bmad-output/design-artifacts/html-and-design`**
|
|
155
|
+
|
|
156
|
+
- **Does not exist** → create it, then tell the user:
|
|
157
|
+
|
|
158
|
+
> `📁 Directorio creado: _bmad-output/design-artifacts/html-and-design`
|
|
159
|
+
> `Por favor pega en ese directorio las plantillas HTML antes de continuar.`
|
|
160
|
+
|
|
161
|
+
Stop here. The directory is the input for memory generation; proceeding
|
|
162
|
+
without templates would produce an empty memory.
|
|
163
|
+
|
|
164
|
+
- **Exists** → continue.
|
|
165
|
+
|
|
166
|
+
**2. Validate `_bmad-output/design-artifacts/design-memory`**
|
|
167
|
+
|
|
168
|
+
- **Does not exist** → create it empty and continue (no user action needed).
|
|
169
|
+
- **Exists** → continue.
|
|
170
|
+
|
|
171
|
+
**3. Authorization for memory generation**
|
|
172
|
+
|
|
173
|
+
Use `AskUserQuestion` with the following exact text:
|
|
174
|
+
|
|
175
|
+
> *"Procederé a inspeccionar las plantillas para generar/actualizar las memorias
|
|
176
|
+
> de diseño, ¿Autorizas esta acción? Esto podría tardar unos minutos."*
|
|
177
|
+
|
|
178
|
+
Options: **Aceptar** / **Cancelar**.
|
|
179
|
+
|
|
180
|
+
- **Aceptar** → run the full sync algorithm from `references/design-memory.md`
|
|
181
|
+
("Sync algorithm"): hash every `.html` in `html-and-design`, compare against
|
|
182
|
+
`design-memory/manifest.yaml`, build or update only what changed. Report one
|
|
183
|
+
line: `🧠 Memory: current (N sources)` or
|
|
184
|
+
`🧠 Memory: rebuilt/updated (+A new, B changed, C removed)`.
|
|
185
|
+
- **Cancelar** → explain to the user why this step matters, then stop:
|
|
186
|
+
|
|
187
|
+
> Las memorias de diseño son el insumo que permite homologar pantallas sin
|
|
188
|
+
> un mockup directo y mantener los patrones de diseño sincronizados con las
|
|
189
|
+
> plantillas más recientes. Omitir esta actualización puede causar que el
|
|
190
|
+
> refactor use patrones desactualizados o incompletos. Por este motivo, la
|
|
191
|
+
> skill no puede continuar sin ejecutar o tener memorias válidas.
|
|
192
|
+
> `❌ DETENIDO: generación de memorias cancelada por el usuario.`
|
|
193
|
+
|
|
194
|
+
After this step, proceed to the Gate.
|
|
195
|
+
|
|
196
|
+
## Gate: explicit target, before anything else
|
|
197
|
+
|
|
198
|
+
The run starts blind and stays blind until the user names the target. The
|
|
199
|
+
skill NEVER infers what to refactor — not from the queue folder's contents,
|
|
200
|
+
not from recently touched files, not from the conversation's vibe. Before any
|
|
201
|
+
setup step executes, the invocation must contain, or the user must answer:
|
|
202
|
+
|
|
203
|
+
1. **Which module/feature of the front** is being refactored (e.g. "usuarios",
|
|
204
|
+
"conceptos", "roles y permisos"). An explicit "todo el directorio de
|
|
205
|
+
mockups" / "procesa toda la cola" counts as an answer — it is the user
|
|
206
|
+
declaring full scope, which is different from the skill assuming it.
|
|
207
|
+
2. Optionally, scope modifiers (content area only, a single mockup path, a
|
|
208
|
+
custom memory dir).
|
|
209
|
+
|
|
210
|
+
If the target is missing, ask (AskUserQuestion when available: "¿Qué módulo o
|
|
211
|
+
feature quieres refactorizar?" listing the modules detected under the resolved
|
|
212
|
+
frontend's `src/modules/` and the mockups present in the queue as options)
|
|
213
|
+
and **stop until answered** — no path resolution beyond what the question
|
|
214
|
+
needs, no memory build, no queue listing, no edits. Unattended with no target:
|
|
215
|
+
`❌ BLOCKED: no target — a module/feature name is required to run`.
|
|
216
|
+
|
|
217
|
+
Everything the user declares here defines the run's scope: mockups in the
|
|
218
|
+
queue that fall outside it are reported as skipped (`⏭️ out of scope`), never
|
|
219
|
+
processed "while we're at it".
|
|
220
|
+
|
|
221
|
+
## Setup, once per run
|
|
222
|
+
|
|
223
|
+
0a. **Resolve paths — never trust the burned-in defaults blindly.** Resolution
|
|
224
|
+
order for every path in the Sources-of-truth table: 1) an explicit user
|
|
225
|
+
argument, 2) what `design-memory/manifest.yaml` recorded on a previous run
|
|
226
|
+
(`sources_dir`, `memory_dir`, `frontend_dir`), 3) auto-discovery, 4) the
|
|
227
|
+
table's default.
|
|
228
|
+
|
|
229
|
+
**Frontend dir:** by team directive every app lives under `apps/` (backend
|
|
230
|
+
and frontend side by side), so discovery is anchored there and never
|
|
231
|
+
assumes the folder's name. The frontend is **the app that depends on
|
|
232
|
+
siesa-ui-kit** — the folder name (`Frontend`, `web`, `portal`) proves
|
|
233
|
+
nothing, the dependency does:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
grep -l '"siesa-ui-kit"' apps/*/package.json | xargs -r -n1 dirname
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
If it resolves but `node_modules/siesa-ui-kit/dist/index.d.ts` is missing
|
|
240
|
+
inside it, the kit isn't installed — tell the user to install before
|
|
241
|
+
continuing (the typings are the component authority; without them nothing
|
|
242
|
+
downstream is trustworthy). **Artifacts:**
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
find . -maxdepth 5 -type d -path "*design-artifacts/html-and-design" -not -path "*/node_modules/*"
|
|
246
|
+
find . -maxdepth 5 -name "ux-design-specification.md" -not -path "*/node_modules/*"
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Exactly one hit → use it (and record it in the manifest so the next run
|
|
250
|
+
skips discovery). Zero or multiple hits → interactively, ask the user;
|
|
251
|
+
unattended, `❌ BLOCKED: path resolution — <what> → <candidates found>`.
|
|
252
|
+
Everything downstream (`tsc`, vitest, module mapping, off-limits globs)
|
|
253
|
+
uses the **resolved** frontend dir; the literal `apps/Frontend` in this
|
|
254
|
+
skill's examples is just the reference layout.
|
|
255
|
+
0. Read every `.md` in this skill's `rules/` directory. Each file there is a
|
|
256
|
+
binding rule set for all code this run generates or modifies — currently
|
|
257
|
+
`style-rules.md` (colors only via design-system CSS variables, all measures
|
|
258
|
+
in rem at 1rem = 16px, everything scales from the root font-size, no inline
|
|
259
|
+
styles, px/hex from specs are converted on entry, never copied). New rule
|
|
260
|
+
files dropped there later bind exactly the same way, without editing this
|
|
261
|
+
skill.
|
|
262
|
+
0b. **Design memory** — already synced in the pre-gate step; skip. If the
|
|
263
|
+
user provided a custom memory path via argument, record it in
|
|
264
|
+
`manifest.yaml` now so the next run picks it up.
|
|
265
|
+
1. List the queue: every `.html` in the resolved mockup dir, sorted by name —
|
|
266
|
+
that is the FIFO processing order — then **filter it to the target declared
|
|
267
|
+
at the gate**: only mockups matching the named module/feature stay in the
|
|
268
|
+
run (full-scope declarations keep everything). Out-of-scope mockups are
|
|
269
|
+
listed as `⏭️ out of scope`. A single mockup passed as an argument is a
|
|
270
|
+
one-item queue, wherever it sits on disk. Arguments may also scope the work
|
|
271
|
+
(e.g. "content area only, skip the app shell") — honor them.
|
|
272
|
+
2. Confirm the kit typings are readable (`dist/index.d.ts` above). Do not wait
|
|
273
|
+
on Storybook; grep the typings.
|
|
274
|
+
3. Capture the type-check baseline **before** editing anything and let it
|
|
275
|
+
finish — a killed run undercounts and you will later read your own errors
|
|
276
|
+
as pre-existing:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
cd apps/Frontend && npx tsc -p tsconfig.json 2>&1 | grep -c "error TS"
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Whatever the count is (0 on a green branch, dozens on a stale one), *that*
|
|
283
|
+
is the number Step 5 compares against.
|
|
284
|
+
4. Branching: the git repo is the **monorepo root** (`apps/Frontend` is not its
|
|
285
|
+
own repo). Never work on `main` or `develop` — from those, create
|
|
286
|
+
`refactor/screen-layout-<slug>` at the moment of the first real edit. If the
|
|
287
|
+
session is already on a feature branch, stay on it and record that in the
|
|
288
|
+
report; yanking a user's in-flight branch around is worse than sharing it.
|
|
289
|
+
5. Report the queue to the user (screen count and names), then start screen #1.
|
|
290
|
+
|
|
291
|
+
## Per screen: six steps, in order
|
|
292
|
+
|
|
293
|
+
### Step 1 — Validate inputs
|
|
294
|
+
|
|
295
|
+
Resolve the mockup to a real screen file. In order:
|
|
296
|
+
|
|
297
|
+
1. An explicit target comment in the mockup wins:
|
|
298
|
+
`<!-- target: src/modules/concepts/presentation/pages/ConceptsPage.tsx -->`
|
|
299
|
+
2. Otherwise map by convention: mockup slug → module folder
|
|
300
|
+
`apps/Frontend/src/modules/<module-slug>/presentation/pages/` → the
|
|
301
|
+
`*Page.tsx` in it. Sibling `*.layout.tsx` / `*.fields.tsx` files are part of
|
|
302
|
+
the screen but not the entry point.
|
|
303
|
+
3. A filename that matches no module is not automatically blocked — read the
|
|
304
|
+
mockup's content: titles and field ids usually name the module outright
|
|
305
|
+
(`roles_view_edit.html` names roles/permissions → the administracion
|
|
306
|
+
permission editor). This inference resolves a **file** inside the scope the
|
|
307
|
+
user already declared at the gate; it never decides *what* gets
|
|
308
|
+
refactored — a content match pointing outside the declared target is
|
|
309
|
+
`⏭️ out of scope`, not a new work item.
|
|
310
|
+
|
|
311
|
+
If the module doesn't exist or the mapping is ambiguous (several `*Page.tsx`
|
|
312
|
+
and no target comment), the screen is `❌ BLOCKED: <screen> — <what is
|
|
313
|
+
missing>`. Log it, move on. Never guess a target; a refactor applied to the
|
|
314
|
+
wrong file is worse than a skipped one.
|
|
315
|
+
|
|
316
|
+
**If the mockup is missing but the target module is clear** (the user asked
|
|
317
|
+
"refactoriza el módulo de usuarios" and no `usuarios*.html` exists), do not
|
|
318
|
+
block automatically — enter **memory-driven mode** per
|
|
319
|
+
`references/design-memory.md`: check memory coverage against the current
|
|
320
|
+
screen's widget census, synthesize the homologation map and distribution from
|
|
321
|
+
the memory patterns (citing pattern ids), record that plan in the screen's
|
|
322
|
+
report, and proceed straight to Step 4 — no approval turn. Only if the memory doesn't exist, or has no precedent for
|
|
323
|
+
the screen's archetype, is the screen `❌ BLOCKED: <screen> — no mockup and no
|
|
324
|
+
memory precedent`. Steps 2–6 then run identically, with the synthesized plan
|
|
325
|
+
standing in for the mockup.
|
|
326
|
+
|
|
327
|
+
### Step 2 — Build the homologation map
|
|
328
|
+
|
|
329
|
+
Inventory every widget the mockup draws — buttons, checkboxes, data grids,
|
|
330
|
+
tabs, badges, dropdown menus, inputs, labels with descriptions, pagination,
|
|
331
|
+
dividers, avatars — and map **each one** to its kit realization before touching
|
|
332
|
+
code. The map has three possible values per element:
|
|
333
|
+
|
|
334
|
+
1. **A kit molecule** — the direct case. Common mappings against the currently
|
|
335
|
+
installed kit (re-verify each against `index.d.ts`; the kit grows):
|
|
336
|
+
|
|
337
|
+
| Mockup shows | Kit realization |
|
|
338
|
+
|---|---|
|
|
339
|
+
| Checkbox (with label / description) | `Checkbox` (`label`, `description`, `labelPosition`, `indeterminate`) |
|
|
340
|
+
| Data grid / table of rows | `Table` (`TableColumn.render`, `sortable`, `align`, `width`, pagination props) |
|
|
341
|
+
| Master catalog with CRUD affordances | `MasterCrud` (the mandated orchestrator for master modules, UX spec §2.2) |
|
|
342
|
+
| Button, icon button | `Button` |
|
|
343
|
+
| Tag / status chip | `Badge` |
|
|
344
|
+
| Toggle | `Switch` |
|
|
345
|
+
| Radio group | `Radio` |
|
|
346
|
+
| Text/number/email input | `Input`, `Textarea`, `Quantity` |
|
|
347
|
+
| Dropdown / kebab menu | `Dropdown` (+ `DropdownItemHeading`, `DropdownItemCollapsible`) |
|
|
348
|
+
| Fixed-list select / async master lookup | `Select` / `LookupField` (R-LF-001: backend data is always `lookup`) |
|
|
349
|
+
| Tabs | `Tabs` |
|
|
350
|
+
| Key–value detail block | `DescriptionList` |
|
|
351
|
+
| Inline message / banner | `Alert`, `Info` |
|
|
352
|
+
| Ephemeral feedback | `Toast` |
|
|
353
|
+
| Count badge | `Notification` |
|
|
354
|
+
| Section separator | `Divider` |
|
|
355
|
+
| Pager | `Pagination` |
|
|
356
|
+
| User avatar | `Avatar` |
|
|
357
|
+
|
|
358
|
+
2. **A composition** — when no single molecule fits, compose them and say so in
|
|
359
|
+
the map. The canonical example: a module × action permission matrix is
|
|
360
|
+
`Table` with one column per action whose `render` returns a `Checkbox`
|
|
361
|
+
wired to the existing toggle callback — header, borders, row hover and
|
|
362
|
+
responsive behavior come free and consistent. Before composing, check
|
|
363
|
+
`design-memory/component-patterns.md` for a learned pattern that already
|
|
364
|
+
names this composition (cite its pattern id in the map), and search the
|
|
365
|
+
repo for a sibling module that already solved it — follow precedent instead
|
|
366
|
+
of inventing a second dialect:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
grep -rln "<pattern>" apps/Frontend/src/modules/*/presentation apps/Frontend/src/shared
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
3. **Shadcn fallback** — neither a molecule nor a reasonable composition of
|
|
373
|
+
kit molecules expresses the widget. Use the shadcn component that does,
|
|
374
|
+
record it in the map as `<widget> → shadcn <Component> (⚠️ fallback)`, and
|
|
375
|
+
carry the flag into the screen report so the team can evaluate promoting it
|
|
376
|
+
into siesa-ui-kit later. The shadcn piece is restyled to the design system
|
|
377
|
+
per `rules/` (token classes, rem, no inline styles) and its props/behavior
|
|
378
|
+
are wired to the screen's existing handlers exactly as a kit molecule would
|
|
379
|
+
be. A screen no longer blocks for a missing kit component; it blocks only
|
|
380
|
+
if not even shadcn covers the widget — then
|
|
381
|
+
`❌ BLOCKED: <screen> — <widget> has no kit or shadcn realization`. What you
|
|
382
|
+
never do is hand-roll the widget out of `div`s — a local reimplementation
|
|
383
|
+
looks fine in the PR and then diverges from the design system forever.
|
|
384
|
+
|
|
385
|
+
Decorative appshell chrome in the mockup (sidebar, top nav, breadcrumbs that
|
|
386
|
+
belong to the shell) is out of scope — do not inventory it.
|
|
387
|
+
|
|
388
|
+
Close the step with the verdict: `✅ HOMOLOGATION MAP READY` (list it) or the
|
|
389
|
+
blocked line.
|
|
390
|
+
|
|
391
|
+
### Step 3 — Analyze the gap
|
|
392
|
+
|
|
393
|
+
With the map in hand, audit the **current** screen and write down:
|
|
394
|
+
|
|
395
|
+
- **Current implementation census** — for each widget on the screen today: is
|
|
396
|
+
it already a kit molecule, or burned HTML (a styled `div` grid, a native
|
|
397
|
+
`<input type="checkbox">`, a hand-rolled table)? The burned ones are the
|
|
398
|
+
refactor targets; the kit ones may only need re-distribution or variant
|
|
399
|
+
changes.
|
|
400
|
+
- **Target distribution** — where the mockup puts things (columns, order,
|
|
401
|
+
grouping, alignment, which elements sit in the header vs the body).
|
|
402
|
+
- **Changes needed** — element by element: replace X with kit Y, move Z into W.
|
|
403
|
+
- **Stays identical** — every field name, validation, hook call, query,
|
|
404
|
+
mutation, handler, prop and type; every aria-label and accessible behavior.
|
|
405
|
+
|
|
406
|
+
Two asymmetries, both flagged, never silently resolved:
|
|
407
|
+
|
|
408
|
+
- A mockup element with **no counterpart in the current screen** (an extra
|
|
409
|
+
column, a summary bar over data the page doesn't have, a subtitle showing
|
|
410
|
+
data no hook provides) is new functionality, not layout: `⚠️ WARNING` it in
|
|
411
|
+
the report and leave it out.
|
|
412
|
+
- A current element with **no place in the mockup** (a bulk-toggle row, an
|
|
413
|
+
extra action column, an alert region) stays rendered somewhere sensible and
|
|
414
|
+
gets flagged. Deleting functionality to satisfy a drawing is a functional
|
|
415
|
+
change disguised as layout. The mockup is not automatically right — one once
|
|
416
|
+
drew a status switch that would have opened a second, wrong write path.
|
|
417
|
+
|
|
418
|
+
### Step 4 — Refactor
|
|
419
|
+
|
|
420
|
+
Decide which kind of screen you are holding; the tactic differs:
|
|
421
|
+
|
|
422
|
+
**(a) Hand-written JSX** (pages that compose their own components). Execute the
|
|
423
|
+
homologation map: replace each burned widget with its kit molecule or
|
|
424
|
+
composition, rewiring the **existing** handlers, state, refs and accessible
|
|
425
|
+
names onto the kit component's real props. The page's hooks, services and
|
|
426
|
+
callbacks are untouched — only the rendering layer changes vocabulary. Keep
|
|
427
|
+
whole subtrees where they already use the kit; retyped markup is where dropped
|
|
428
|
+
props and renamed fields come from. Structure the page per UX spec §4.3.
|
|
429
|
+
|
|
430
|
+
**(b) Kit-driven form** — one `<MasterCrud>` plus a declarative `fields[]`
|
|
431
|
+
array. There is no widget HTML to replace: the kit renders the form. Do NOT
|
|
432
|
+
rewrite fields — take over only the layout via `renderForm`:
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
renderForm={(formProps) => {
|
|
436
|
+
const { renderField } = formProps as RenderContentArgs
|
|
437
|
+
return <MyScreenFormLayout renderField={renderField as RenderField} t={t} />
|
|
438
|
+
}}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
The hard-won mechanics, worth understanding rather than copying:
|
|
442
|
+
|
|
443
|
+
- `renderForm` is not a slot for a form: the kit forwards it into its internal
|
|
444
|
+
`MasterCrudForm` as `renderContent`. Return **only the field-area content**;
|
|
445
|
+
the kit keeps its own `<form>`, save ref, header and Cancelar/Guardar footer.
|
|
446
|
+
Mounting another `<MasterCrudForm>` inside is the trap — nested forms, save
|
|
447
|
+
reads one state while fields write another: everything renders, nothing
|
|
448
|
+
saves, and no kit-mocked test notices.
|
|
449
|
+
- `renderField(accessorKey)` with **no second argument** uses the kit's own
|
|
450
|
+
renderer, so every `validate`, `disabled` predicate, lookup config and
|
|
451
|
+
calculated field survives untouched. Your layout module decides only *where*
|
|
452
|
+
each `accessorKey` is painted, and `fields[]` stays complete so submit
|
|
453
|
+
validation keeps iterating every field, visible or not.
|
|
454
|
+
- Two kit-side type frictions, fixed at the boundary with a comment, never by
|
|
455
|
+
loosening your types:
|
|
456
|
+
`type RenderContentArgs = Parameters<NonNullable<MasterCrudFormProps<T>['renderContent']>>[0]`
|
|
457
|
+
(the declared parameter omits `renderField`), and
|
|
458
|
+
`renderField as RenderField` where `RenderField = (accessorKey: string) => ReactNode`
|
|
459
|
+
(`inputRenderer` is typed required though omitting it is what triggers the
|
|
460
|
+
kit renderer).
|
|
461
|
+
- Put the layout in a sibling `<screen>.layout.tsx` that imports no services
|
|
462
|
+
and declares no fields. If that file ever needs a validation or an API call,
|
|
463
|
+
the change stopped being layout — back to Step 3.
|
|
464
|
+
|
|
465
|
+
Whichever kind: keep field `name`s/`accessorKey`s, react-hook-form
|
|
466
|
+
registrations and resolvers, zod schemas, TanStack Query/Router bindings,
|
|
467
|
+
`useEffect` dependencies, event handlers, i18n keys and TypeScript types
|
|
468
|
+
intact. New user-visible strings only where the new structure needs an
|
|
469
|
+
accessible name (a tablist label, a collapse button), in Spanish, per UX spec
|
|
470
|
+
§7 — never invented copy for a mockup's decorative headings.
|
|
471
|
+
|
|
472
|
+
Every line you write obeys the `rules/` files: colors only through
|
|
473
|
+
design-system variables (their Tailwind token classes — `bg-primary`,
|
|
474
|
+
`border-border` — never `bg-[#hex]`), measures in rem via Tailwind's scale
|
|
475
|
+
(arbitrary values in rem when the scale falls short, never `w-[240px]`), no
|
|
476
|
+
`style` attribute (runtime-computed values are the one commented exception),
|
|
477
|
+
and any absolute value a spec or mockup hands you is converted before it
|
|
478
|
+
enters the code. Burned HTML you are homologating loses its inline styles and
|
|
479
|
+
hardcoded values in the same pass — translating them to kit props and Tailwind
|
|
480
|
+
token classes is part of the replacement, not a follow-up.
|
|
481
|
+
|
|
482
|
+
#### Delegating the implementation
|
|
483
|
+
|
|
484
|
+
Steps 1–3 are this skill's job; a large Step 4 does not have to be. When the
|
|
485
|
+
refactor spans several files, hand it to the `sa-dev-story` workflow with a
|
|
486
|
+
brief that cannot drift: the target file, the homologation map, the
|
|
487
|
+
distribution from Step 3, the mechanics above, and the Never list. Delegating
|
|
488
|
+
the typing does not delegate the verdict — you still own Steps 5 and 6. Keep it
|
|
489
|
+
inline when the change is one file and a handful of edits.
|
|
490
|
+
|
|
491
|
+
### Step 5 — Self-verify
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
cd apps/Frontend && npx tsc -p tsconfig.json 2>&1 | grep "error TS" > "$TEMP/after.txt"
|
|
495
|
+
wc -l < "$TEMP/after.txt" # compare with the setup baseline
|
|
496
|
+
grep -E "<module-slug>|<new files>" "$TEMP/after.txt" # must print nothing
|
|
497
|
+
cd apps/Frontend && npx vitest run --pool=threads test/unit/<module-slug>
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
The error count is not expected to be zero — it is expected to be **the
|
|
501
|
+
baseline**, with zero hits in files you touched. Tests live under
|
|
502
|
+
`test/unit/<module-slug>/` (the vitest config does not include `src/`);
|
|
503
|
+
`--pool=threads` works around fork-pool spawn timeouts on Windows — that
|
|
504
|
+
failure is environmental, not a red test.
|
|
505
|
+
|
|
506
|
+
Then enforce the `rules/` files mechanically over every file you touched —
|
|
507
|
+
each grep must print nothing (a hit that predates your diff and sits outside
|
|
508
|
+
the lines you changed is reported, not silently fixed):
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
grep -nE "#[0-9a-fA-F]{3,8}\b|rgb\(|hsl\(" <touched files> # R1: no hardcoded colors
|
|
512
|
+
grep -nE "\[[0-9.]+px\]|: ?'?[0-9.]+px" <touched files> # R2: no px in arbitrary values or style objects
|
|
513
|
+
grep -nE "style=\{|style=\"" <touched files> # R4: no inline styles (commented runtime exception aside)
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Reading test failures after a homologation:
|
|
517
|
+
|
|
518
|
+
- A **behavioral** assertion gone red — a value that no longer saves, a label
|
|
519
|
+
gone missing, a toggle that stopped toggling, keyboard/focus behavior lost —
|
|
520
|
+
means the refactor dropped something. Fix the refactor, never the assertion.
|
|
521
|
+
- A **structural** assertion pinned to the exact markup you replaced (a
|
|
522
|
+
`data-*` attribute on a hand-rolled grid, a class name, a DOM shape) may
|
|
523
|
+
legitimately need updating *because the markup it pinned no longer exists*.
|
|
524
|
+
Update it to pin the same behavior on the kit-rendered DOM, and list every
|
|
525
|
+
such change in the report — silently weakening a test is how regressions
|
|
526
|
+
ship.
|
|
527
|
+
|
|
528
|
+
**On a kit-driven form the existing unit test cannot verify your work**: those
|
|
529
|
+
screens mock `siesa-ui-kit` wholesale and a mocked kit never invokes
|
|
530
|
+
`renderForm`. Add one RTL test against the **real** kit that: opens the form
|
|
531
|
+
and asserts the new structure; types into fields on two different
|
|
532
|
+
panels/sections, switches between them and asserts values survive; submits and
|
|
533
|
+
asserts the intercepted request body carries values **from both**. That last
|
|
534
|
+
assertion is the only proof the regrouping did not sever a field from form
|
|
535
|
+
state — the first real run of this skill caught exactly that failure. Do not
|
|
536
|
+
report ✅ Done on a kit-driven form without it.
|
|
537
|
+
|
|
538
|
+
Then read your own diff (`git diff -- <files>`):
|
|
539
|
+
|
|
540
|
+
- [ ] Distribution matches the mockup; every widget is a kit molecule or a declared composition
|
|
541
|
+
- [ ] No burned widget HTML remains in the touched area (structure wrappers are fine)
|
|
542
|
+
- [ ] No mockup markup or mockup theme classes copied in
|
|
543
|
+
- [ ] No field added, none removed; no validation added or modified
|
|
544
|
+
- [ ] No new or changed API call; hooks and services untouched
|
|
545
|
+
- [ ] Kit components used with real props (from `.types.d.ts`)
|
|
546
|
+
- [ ] `rules/` compliance: colors only via token classes, measures in rem, no
|
|
547
|
+
inline styles, spec px/hex converted — the three greps above print nothing
|
|
548
|
+
- [ ] Accessible behavior preserved (names, focus, keyboard) — §6
|
|
549
|
+
- [ ] All user-visible text in Spanish — §7
|
|
550
|
+
- [ ] Route wrapper and MFE/single-spa registration untouched
|
|
551
|
+
- [ ] Types at baseline, module tests green (with any structural-assertion updates listed)
|
|
552
|
+
|
|
553
|
+
### Step 6 — Report
|
|
554
|
+
|
|
555
|
+
Append to `_bmad-output/screen-layout-refactor/<screen>.md` and keep going:
|
|
556
|
+
|
|
557
|
+
```md
|
|
558
|
+
## Screen: <name>
|
|
559
|
+
**File:** <path>
|
|
560
|
+
**Mode:** 📐 mockup-driven (<mockup file>) / 🧠 memory-driven (patterns: <ids>)
|
|
561
|
+
**Status:** ✅ Done / ❌ Blocked / ⚠️ Warning
|
|
562
|
+
|
|
563
|
+
### Homologation map
|
|
564
|
+
- <mockup element> → <kit component / composition>
|
|
565
|
+
|
|
566
|
+
### Layout changes applied
|
|
567
|
+
- ...
|
|
568
|
+
|
|
569
|
+
### Preserved unchanged
|
|
570
|
+
- ...
|
|
571
|
+
|
|
572
|
+
### Test updates (structural only, with reason)
|
|
573
|
+
- ...
|
|
574
|
+
|
|
575
|
+
### Issues / warnings
|
|
576
|
+
- ...
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## Queue behaviour
|
|
580
|
+
|
|
581
|
+
Process FIFO, write each screen's report before starting the next, and let a
|
|
582
|
+
blocked screen block only itself. A missing kit component no longer blocks —
|
|
583
|
+
it falls back to shadcn with its flag; a screen blocks only for unresolvable
|
|
584
|
+
targets, memory gaps, or widgets not even shadcn covers. Keep going until the
|
|
585
|
+
queue is empty.
|
|
586
|
+
|
|
587
|
+
Run one full build at the end rather than per screen
|
|
588
|
+
(`cd apps/Frontend && npm run build`) — per-screen `tsc` already catches type
|
|
589
|
+
breakage and the Vite build is slow enough that repeating it wastes the run.
|
|
590
|
+
|
|
591
|
+
## Deliverables when the queue is empty
|
|
592
|
+
|
|
593
|
+
`_bmad-output/screen-layout-refactor/FINAL_REFACTOR_REPORT.md`:
|
|
594
|
+
|
|
595
|
+
```md
|
|
596
|
+
| Screen | Status | Kit components used | shadcn fallbacks | Blocked reason |
|
|
597
|
+
|--------|--------|---------------------|------------------|----------------|
|
|
598
|
+
|
|
599
|
+
Summary:
|
|
600
|
+
- Total screens processed: X
|
|
601
|
+
- 🧠 Memory: <current / rebuilt> (N sources in manifest) — memory-driven screens: X
|
|
602
|
+
- ✅ Homologated: X
|
|
603
|
+
- ⚠️ shadcn fallbacks used: X — candidates to promote into siesa-ui-kit
|
|
604
|
+
- ❌ Blocked: X — list them
|
|
605
|
+
- ⚠️ Warnings requiring team review: X
|
|
606
|
+
- Final build: pass / fail
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
`_bmad-output/screen-layout-refactor/INSTRUCTIVE.md` — how another team reruns
|
|
610
|
+
this for their module: preparing a mockup (one `.html` per screen, optional
|
|
611
|
+
`<!-- target: ... -->` comment), dropping mockups into the queue folder,
|
|
612
|
+
invoking the skill, reading the report, what a `⚠️ shadcn fallback` means
|
|
613
|
+
(working screen today; evaluate promoting the component into siesa-ui-kit,
|
|
614
|
+
publish, bump the dependency, optionally re-run only that mockup), and what to
|
|
615
|
+
do with a blocked screen.
|
|
616
|
+
|
|
617
|
+
## Never
|
|
618
|
+
|
|
619
|
+
- Copy the mockup's HTML, classes or theme tokens into the app — the mockup is
|
|
620
|
+
a drawing, not source code
|
|
621
|
+
- Hand-roll a widget the kit owns, or restyle existing burned HTML instead of
|
|
622
|
+
replacing it with the kit molecule
|
|
623
|
+
- Reach for shadcn while a kit molecule or a composition of kit molecules
|
|
624
|
+
covers the widget — shadcn is strictly the third option
|
|
625
|
+
- Use a shadcn fallback without flagging it in the map and the report, or
|
|
626
|
+
leave it on shadcn default styling instead of the design-system tokens
|
|
627
|
+
- Import a component the **installed** typings don't export, or use a prop not
|
|
628
|
+
in its `.types.d.ts` — Storybook is a catalog, not proof
|
|
629
|
+
- Infer colors, spacing or typography — the UX spec and the kit's own rendering
|
|
630
|
+
decide
|
|
631
|
+
- Hardcode a color (hex/rgb/hsl, including `bg-[#…]`): colors exist only as
|
|
632
|
+
design-system CSS variables consumed through their token classes
|
|
633
|
+
- Write a fixed px measure: rem always (1rem = 16px), Tailwind's scale first,
|
|
634
|
+
arbitrary rem values second
|
|
635
|
+
- Use the `style` attribute: Tailwind classes only, with runtime-computed
|
|
636
|
+
values as the sole commented exception
|
|
637
|
+
- Add a field, input or form element; add or change a validation
|
|
638
|
+
- Add or modify an endpoint, service, schema or backend contract
|
|
639
|
+
- Remove existing functionality to make a mockup fit
|
|
640
|
+
- Touch routes, navigation, MFE shell or auth layers
|
|
641
|
+
- Work directly on `main` or `develop`
|
|
642
|
+
- Restate a field's definition in a layout module: on a kit-driven form,
|
|
643
|
+
hand-writing inputs instead of calling `renderField` is a rewrite in costume
|
|
644
|
+
- Weaken what a test verifies. Updating a structural assertion whose markup you
|
|
645
|
+
replaced is legitimate (and reported); loosening a behavioral assertion to
|
|
646
|
+
get green is not
|
|
647
|
+
- Start a run without an explicit user-declared target (a module/feature name,
|
|
648
|
+
or an explicit full-scope instruction) — inferring what to refactor is
|
|
649
|
+
forbidden; process anything the declared scope doesn't cover
|
|
650
|
+
- Treat the mockup as automatically right — it can contradict the domain, and
|
|
651
|
+
domain wins
|
|
652
|
+
- Store hex, px, mockup theme classes or kit prop signatures in a memory file —
|
|
653
|
+
memories speak design-system vocabulary only, converted on entry
|
|
654
|
+
- Use the memory when an explicit mockup for the target exists — the mockup
|
|
655
|
+
outranks it
|
|
656
|
+
- Hide a memory-driven run's provenance — the synthesized plan, the pattern
|
|
657
|
+
ids used, and any `⚠️ ambiguous` resolution always go in the screen's report
|
|
658
|
+
- Silently drop learned patterns when a source mockup disappears — flag it and
|
|
659
|
+
let a human retire the pattern
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Design Memory Protocol
|
|
2
|
+
|
|
3
|
+
Full protocol for building, refreshing and consuming the design memory. Read
|
|
4
|
+
this file whenever the SKILL.md sends you here: at memory sync (setup) and
|
|
5
|
+
before any memory-driven refactor.
|
|
6
|
+
|
|
7
|
+
## Purpose and hard boundary
|
|
8
|
+
|
|
9
|
+
The memory lets the skill refactor a screen **whose mockup does not exist**,
|
|
10
|
+
by generalizing the distribution and composition patterns learned from the
|
|
11
|
+
approved mockup corpus. It never replaces the other sources of truth:
|
|
12
|
+
|
|
13
|
+
- Colors, typography, spacing tokens → **UX spec §1 + `rules/style-rules.md`
|
|
14
|
+
(R1–R5)**. The memory NEVER stores hex values, px, or the mockup's private
|
|
15
|
+
Tailwind theme classes (`surface-container-low`, `on-surface-variant`, …).
|
|
16
|
+
If an observation involves a measure or color, record it already converted
|
|
17
|
+
exactly as the rules mandate for code: color → the design-system utility
|
|
18
|
+
class derived from its `@theme` CSS variable (`bg-primary`,
|
|
19
|
+
`text-muted-foreground`) per R1; measure → rem at `1rem = 16px`, Tailwind
|
|
20
|
+
scale first, arbitrary rem second, per R2. If a mockup color has **no**
|
|
21
|
+
existing variable, the memory records the nearest semantic variable and the
|
|
22
|
+
finding `⚠️ design-system gap: <observed color>` (R1's gap rule) — it never
|
|
23
|
+
invents or approximates a hex.
|
|
24
|
+
- Which components exist and their props → **installed typings**
|
|
25
|
+
(`dist/index.d.ts`, `.types.d.ts`). The memory records that a pattern *maps
|
|
26
|
+
to* `Table` + `Checkbox`; it never records prop signatures — those are
|
|
27
|
+
re-read from typings at use time, because the kit grows.
|
|
28
|
+
- Behavior → the existing screen. Memory-driven mode changes distribution and
|
|
29
|
+
rendering vocabulary only; the integrity boundary of the skill is unchanged.
|
|
30
|
+
|
|
31
|
+
A memory entry is valid only if it is written in **design-system vocabulary**:
|
|
32
|
+
kit component names, compositions of them, UX-spec section references, token
|
|
33
|
+
classes, rem. Mockup markup pasted into a memory file is a protocol violation.
|
|
34
|
+
|
|
35
|
+
## Directory layout
|
|
36
|
+
|
|
37
|
+
Default root (overridable by the user; if they give another path, use it and
|
|
38
|
+
record it in the manifest):
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
_bmad-output/design-artifacts/design-memory/
|
|
42
|
+
├── manifest.yaml # registry of sources → memories (sync state)
|
|
43
|
+
├── design-dna.md # global principles + shell anatomy
|
|
44
|
+
├── component-patterns.md # recurring widget → kit realizations, with attribution
|
|
45
|
+
└── layout-rhythm.md # grid/spacing/grouping conventions (token classes, rem)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## manifest.yaml schema
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
version: 1
|
|
52
|
+
skill: sa-screen-layout-refactor
|
|
53
|
+
sources_dir: _bmad-output/design-artifacts/html-and-design
|
|
54
|
+
memory_dir: _bmad-output/design-artifacts/design-memory
|
|
55
|
+
frontend_dir: apps/Frontend # the app under apps/ whose package.json depends on siesa-ui-kit (setup 0a)
|
|
56
|
+
updated_at: "2026-08-06T14:30:00Z"
|
|
57
|
+
kit_version: "1.8.3" # from apps/Frontend/node_modules/siesa-ui-kit/package.json
|
|
58
|
+
sources:
|
|
59
|
+
- path: roles_view_edit.html
|
|
60
|
+
sha256: "3f5a…"
|
|
61
|
+
analyzed_at: "2026-08-06T14:30:00Z"
|
|
62
|
+
patterns: [shell, header-actions, permission-matrix, tabs-detail]
|
|
63
|
+
- path: concepts_master.html
|
|
64
|
+
sha256: "9b21…"
|
|
65
|
+
analyzed_at: "2026-08-06T14:30:00Z"
|
|
66
|
+
patterns: [shell, master-crud-list, lookup-filters]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Rules:
|
|
70
|
+
|
|
71
|
+
- `sha256` is of the raw file bytes: `sha256sum <file> | cut -d' ' -f1`.
|
|
72
|
+
- `patterns` is the list of pattern ids this source contributed. Every pattern
|
|
73
|
+
section in a memory file carries the same ids, so a changed source can be
|
|
74
|
+
traced to the exact sections it feeds.
|
|
75
|
+
- `kit_version` is recorded so a major kit bump can prompt re-verification of
|
|
76
|
+
the component mappings (the mapping names may still be valid; their props
|
|
77
|
+
are always re-read from typings anyway).
|
|
78
|
+
|
|
79
|
+
## Sync algorithm (setup, every run)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
SRC=_bmad-output/design-artifacts/html-and-design
|
|
83
|
+
MEM=_bmad-output/design-artifacts/design-memory
|
|
84
|
+
mkdir -p "$MEM"
|
|
85
|
+
for f in "$SRC"/*.html; do sha256sum "$f"; done
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Compare against `manifest.yaml`:
|
|
89
|
+
|
|
90
|
+
| State | Detection | Action |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| No manifest | `manifest.yaml` missing | **Full build**: run the extraction protocol over every `.html`, write the three memory files + manifest |
|
|
93
|
+
| New source | hash present on disk, path absent in manifest | Analyze that file only; **merge** its patterns into the memory files (add sections or extend existing ones, with attribution); append to manifest |
|
|
94
|
+
| Changed source | path present, hash differs | Re-analyze that file; update every memory section attributed to it; refresh its manifest entry |
|
|
95
|
+
| Removed source | path in manifest, file gone | Do NOT silently delete learned patterns. Mark the affected sections `⚠️ source removed: <file>` and flag it in the run report — a human decides whether the pattern is retired |
|
|
96
|
+
| All hashes match | — | Memory is current; skip straight to the queue |
|
|
97
|
+
|
|
98
|
+
Merging discipline: prefer **generalizing** an existing pattern over adding a
|
|
99
|
+
near-duplicate ("header with title + 2 actions" and "header with title + 3
|
|
100
|
+
actions" are one pattern with a variable action count, not two). When two
|
|
101
|
+
sources contradict each other (one groups filters above the table, another in
|
|
102
|
+
a side panel), record both variants with their sources and the condition that
|
|
103
|
+
selects each, if inferable; otherwise mark `⚠️ ambiguous` — memory-driven mode
|
|
104
|
+
must surface the ambiguity to the user instead of picking silently.
|
|
105
|
+
|
|
106
|
+
Sync is cheap when nothing changed (a hash pass), so it runs unconditionally
|
|
107
|
+
at setup. Report the outcome in one line: `🧠 Memory: current (12 sources)` or
|
|
108
|
+
`🧠 Memory: rebuilt/updated (+2 new, 1 changed, 0 removed)`.
|
|
109
|
+
|
|
110
|
+
## Extraction protocol (per source file)
|
|
111
|
+
|
|
112
|
+
Read the `.html` and extract three layers. You are reverse-engineering the
|
|
113
|
+
*decisions*, not the markup — every finding is recorded in design-system
|
|
114
|
+
vocabulary, converted on entry exactly as `style-rules.md` mandates for code.
|
|
115
|
+
|
|
116
|
+
**Layer 1 — Shell & scaffold anatomy.** How the screen is framed: does it
|
|
117
|
+
follow UX spec §4.3 (header with title + actions, content in bordered rounded
|
|
118
|
+
container)? Where do primary vs secondary actions sit? Where do filters,
|
|
119
|
+
breadcrumb-adjacent info, summary bars live? Ignore appshell chrome (sidebar,
|
|
120
|
+
top nav) — same exclusion as Step 2 of the main flow.
|
|
121
|
+
|
|
122
|
+
**Layer 2 — Component patterns.** Inventory the widgets exactly as Step 2
|
|
123
|
+
does, and record the *recurring realizations*: "master list screens = kit
|
|
124
|
+
`Table` with kebab `Dropdown` per row + `Pagination` below, page header hosts
|
|
125
|
+
the create `Button`", "permission matrix = `Table` whose action columns
|
|
126
|
+
`render` kit `Checkbox`es", "detail blocks = `DescriptionList`, never label/
|
|
127
|
+
value divs". Each pattern gets: an id (slug), the mockup evidence (which
|
|
128
|
+
files, which region), the kit realization, and any variant conditions. A
|
|
129
|
+
pattern whose realization is a shadcn fallback is recorded with
|
|
130
|
+
`**Kit realization:** shadcn <Component> (⚠️ provisional — promote to kit?)`
|
|
131
|
+
and re-checked against the installed typings on every sync: the moment the
|
|
132
|
+
kit exports a covering molecule, the pattern is updated and the flag dropped.
|
|
133
|
+
|
|
134
|
+
**Layer 3 — Rhythm & grouping.** Constant structural choices translated to
|
|
135
|
+
tokens per R2/R5: column counts and breakpoints of form grids, gap scale
|
|
136
|
+
between sections vs between fields (as Tailwind scale steps / rem), grouping
|
|
137
|
+
logic (what gets a bordered container vs a plain block, when sections become
|
|
138
|
+
`Tabs`), density (labels above vs beside inputs). If the mockup says `24px`,
|
|
139
|
+
the memory says `gap-6` (1.5rem); if a value has no exact scale step, record
|
|
140
|
+
the arbitrary rem (`gap-[0.8125rem]`), preserving the design's proportions —
|
|
141
|
+
R5 forbids eyeballing to a nearby token that changes the visual ratio, and a
|
|
142
|
+
non-1:1 conversion is noted in the entry.
|
|
143
|
+
|
|
144
|
+
Reasoning ("why") is welcome when it is inferable and useful for improvising
|
|
145
|
+
new screens — e.g. "destructive actions are always rightmost and ghost-style"
|
|
146
|
+
— but never invent rationale; unlabeled observations are fine.
|
|
147
|
+
|
|
148
|
+
## Memory file templates
|
|
149
|
+
|
|
150
|
+
`design-dna.md`:
|
|
151
|
+
|
|
152
|
+
```markdown
|
|
153
|
+
# Design DNA — <project>
|
|
154
|
+
_Manifest: see manifest.yaml. Vocabulary: siesa-ui-kit + UX spec tokens only._
|
|
155
|
+
|
|
156
|
+
## Visual principles
|
|
157
|
+
- <principle> (evidence: <files>)
|
|
158
|
+
|
|
159
|
+
## Shell & scaffold
|
|
160
|
+
- <observation, referencing UX spec §4.3 where it matches> (evidence: …)
|
|
161
|
+
|
|
162
|
+
## Screen archetypes
|
|
163
|
+
- **master-crud-list** — <one-line anatomy> → details in component-patterns.md
|
|
164
|
+
- **detail-edit** — …
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`component-patterns.md` (one section per pattern id):
|
|
168
|
+
|
|
169
|
+
```markdown
|
|
170
|
+
## pattern: permission-matrix
|
|
171
|
+
**Sources:** roles_view_edit.html
|
|
172
|
+
**Mockup shows:** module × action grid of checkboxes with sticky first column
|
|
173
|
+
**Kit realization:** `Table` — one column per action, `TableColumn.render`
|
|
174
|
+
returns `Checkbox` wired to the existing toggle handler; first column plain
|
|
175
|
+
text.
|
|
176
|
+
**Variants / conditions:** —
|
|
177
|
+
**Notes:** re-verify `Table`/`Checkbox` props in `.types.d.ts` at use time.
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`layout-rhythm.md`:
|
|
181
|
+
|
|
182
|
+
```markdown
|
|
183
|
+
## Form grids
|
|
184
|
+
- 2-column `grid-cols-2 gap-x-6 gap-y-4`, collapsing to 1 below `md` (evidence: …)
|
|
185
|
+
|
|
186
|
+
## Section spacing
|
|
187
|
+
- Between page sections: `gap-8`; inside a bordered container: `p-6` (evidence: …)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Memory-driven mode (no mockup for the target)
|
|
191
|
+
|
|
192
|
+
Entered from Step 1 of the main flow when the user asks to refactor a module
|
|
193
|
+
that has no `.html` in the queue, and memories exist.
|
|
194
|
+
|
|
195
|
+
1. **Coverage check.** Census the current screen (Step 3's inventory, done
|
|
196
|
+
early) and match it against memory patterns. Every widget class on the
|
|
197
|
+
screen must be covered by a pattern, by the Step 2 molecule table, or by
|
|
198
|
+
the shadcn fallback (Step 2 case 3 — flagged as always).
|
|
199
|
+
- Full coverage → proceed.
|
|
200
|
+
- A screen archetype the memory has never seen (e.g. a wizard, when all
|
|
201
|
+
sources are master lists) → `❌ BLOCKED: <screen> — no memory precedent
|
|
202
|
+
for <archetype>; provide a mockup or approve pattern extrapolation`.
|
|
203
|
+
Individual unfamiliar widgets don't block (kit table or shadcn covers
|
|
204
|
+
them); an unfamiliar *whole-screen shape* does, because there is no
|
|
205
|
+
precedent to synthesize the distribution from.
|
|
206
|
+
2. **Synthesize the plan.** Build the homologation map (Step 2) from
|
|
207
|
+
`component-patterns.md`, and the target distribution (Step 3) from
|
|
208
|
+
`design-dna.md` + `layout-rhythm.md`, citing pattern ids for every
|
|
209
|
+
decision. This synthesized plan plays the role the mockup normally plays.
|
|
210
|
+
Ambiguous patterns (`⚠️ ambiguous`) are resolved by majority evidence and
|
|
211
|
+
flagged in the report, never silently.
|
|
212
|
+
3. **Execute directly — no approval turn.** Do not print the plan to chat or
|
|
213
|
+
wait for a go/no-go; that spends tokens and a round-trip per screen. The
|
|
214
|
+
synthesized plan is written into the screen's report file instead. An
|
|
215
|
+
`⚠️ ambiguous` pattern is resolved by the variant with the most source
|
|
216
|
+
evidence and the choice is flagged in the report — never silently.
|
|
217
|
+
4. **Execute** Steps 4–6 exactly as the main flow, same integrity boundary,
|
|
218
|
+
same greps, same tests.
|
|
219
|
+
5. **Report** with `Mode: 🧠 memory-driven`, the pattern ids used, and the
|
|
220
|
+
synthesized plan embedded — that is the audit trail replacing the mockup
|
|
221
|
+
link, and it is where a reviewer validates the run after the fact.
|
|
222
|
+
Recommend generating the mockup a posteriori if the team wants the corpus
|
|
223
|
+
to stay canonical.
|
|
224
|
+
|
|
225
|
+
## Never (memory-specific)
|
|
226
|
+
|
|
227
|
+
- Store hex, px, or mockup theme classes in a memory file — convert on entry
|
|
228
|
+
(R1: variable/utility class; R2: rem ÷ 16; R5: proportions preserved) and
|
|
229
|
+
flag `⚠️ design-system gap` when no variable covers the observed color
|
|
230
|
+
- Store kit prop signatures — typings are read live, memory only names components
|
|
231
|
+
- Print a memory-driven plan to chat or wait for approval — execution is
|
|
232
|
+
direct; the plan, pattern ids and ambiguity resolutions live in the report
|
|
233
|
+
- Silently drop patterns when a source file disappears — flag, let a human retire
|
|
234
|
+
- Let memory override the UX spec, the typings, or the domain — memory is the
|
|
235
|
+
most junior source of truth in the table
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Reglas complementarias de estilo — VINCULANTES
|
|
2
|
+
|
|
3
|
+
Estas reglas aplican a **todo** el código que la skill genere o modifique, sin
|
|
4
|
+
excepción y sin necesidad de que el usuario las repita. Se leen al inicio de
|
|
5
|
+
cada ejecución, junto con cualquier otro archivo que exista en este directorio
|
|
6
|
+
`rules/` (todo archivo aquí es igualmente vinculante; agregar una regla nueva
|
|
7
|
+
es soltar un `.md` aquí).
|
|
8
|
+
|
|
9
|
+
Cuando una regla de este archivo choque con lo que dibuja un mockup o con lo
|
|
10
|
+
que dice una spec en valores absolutos, **la regla gana**: se convierte el
|
|
11
|
+
valor, nunca se copia.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## R1 — Colores: nunca hexadecimales hardcodeados
|
|
16
|
+
|
|
17
|
+
- Prohibido escribir colores en hexadecimal, `rgb()`, `hsl()` o nombres CSS
|
|
18
|
+
(`#889911`, `rgb(14 121 253)`, `red`) en JSX, CSS o valores arbitrarios de
|
|
19
|
+
Tailwind (`bg-[#0e79fd]` está prohibido igual que `style="color:#0e79fd"`).
|
|
20
|
+
- Todo color se consume desde una **variable CSS del sistema de diseño**
|
|
21
|
+
(`--color-primary`, `--color-border`, `--color-muted-foreground`, …).
|
|
22
|
+
- En este codebase las variables viven en el `@theme` de
|
|
23
|
+
`apps/Frontend/src/index.css` (Tailwind v4), y se consumen por su clase
|
|
24
|
+
utilitaria derivada: `bg-primary`, `text-muted-foreground`, `border-border`,
|
|
25
|
+
`bg-card`. Esa clase ES la variable — no hay paso manual de `var()`.
|
|
26
|
+
- Si el color que pide el diseño no existe como variable, **no se inventa ni
|
|
27
|
+
se aproxima con un hex**: se reporta como brecha del sistema de diseño
|
|
28
|
+
(⚠️ en el reporte) y se usa la variable semántica más cercana ya definida.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
// ❌ Prohibido
|
|
32
|
+
<span className="text-[#64748b] bg-[#f8fafc]">…</span>
|
|
33
|
+
<div style={{ borderColor: '#e2e8f0' }}>…</div>
|
|
34
|
+
|
|
35
|
+
// ✅ Correcto
|
|
36
|
+
<span className="text-muted-foreground bg-muted">…</span>
|
|
37
|
+
<div className="border-border">…</div>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## R2 — Unidades: rem, nunca px
|
|
41
|
+
|
|
42
|
+
- Prohibidos los valores fijos en píxeles en clases arbitrarias, CSS y props
|
|
43
|
+
de estilo. Toda medida se expresa en **rem**, asumiendo `1rem = 16px`.
|
|
44
|
+
- Conversión: `px ÷ 16 = rem`. Ejemplos: `44px → 2.75rem`, `24px → 1.5rem`,
|
|
45
|
+
`12px → 0.75rem`, `2px → 0.125rem`.
|
|
46
|
+
- La escala estándar de Tailwind ya emite rem — `p-4` (1rem), `w-48` (12rem),
|
|
47
|
+
`text-sm` (0.875rem) — así que la regla en la práctica es: **usa la escala
|
|
48
|
+
de Tailwind primero**; si no alcanza, valor arbitrario en rem
|
|
49
|
+
(`w-[2.75rem]`), jamás en px (`w-[44px]`).
|
|
50
|
+
- Excepción única: propiedades donde el px es semánticamente correcto e
|
|
51
|
+
independiente de la tipografía (`border` de 1px vía `border`,
|
|
52
|
+
`outline-offset` de hairlines). Ante la duda, rem.
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// ❌ Prohibido
|
|
56
|
+
<div className="w-[240px] gap-[16px] text-[13px]">…</div>
|
|
57
|
+
|
|
58
|
+
// ✅ Correcto
|
|
59
|
+
<div className="w-60 gap-4 text-[0.8125rem]">…</div>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## R3 — Escalabilidad: todo cuelga del font-size raíz
|
|
63
|
+
|
|
64
|
+
- El diseño completo debe escalar modificando únicamente el `font-size`
|
|
65
|
+
global del documento. Esa es la razón de R2: un layout en rem escala solo;
|
|
66
|
+
un layout en px queda congelado.
|
|
67
|
+
- No fijar `font-size` en `html`/`:root` desde código de pantalla, ni usar
|
|
68
|
+
unidades que rompan la cadena (px en tipografía, alturas de línea
|
|
69
|
+
absolutas).
|
|
70
|
+
- Al componer con el ui-kit esto sale gratis (el kit ya respeta el root); la
|
|
71
|
+
regla protege los wrappers estructurales y valores arbitrarios que la skill
|
|
72
|
+
escriba.
|
|
73
|
+
|
|
74
|
+
## R4 — Sin estilos inline: solo clases de Tailwind
|
|
75
|
+
|
|
76
|
+
- Prohibido el atributo `style` (`style="…"` / `style={{ … }}`) en el código
|
|
77
|
+
generado. Todo estilo se expresa con clases de Tailwind.
|
|
78
|
+
- Si un estilo llega inline (de un mockup, de código existente que se está
|
|
79
|
+
homologando), se **traduce** a su clase Tailwind equivalente en el mismo
|
|
80
|
+
cambio.
|
|
81
|
+
- Excepción única y justificada en comentario: valores imposibles de expresar
|
|
82
|
+
como clase porque son datos en runtime (p. ej. `gridTemplateColumns`
|
|
83
|
+
calculado sobre N columnas dinámicas, posiciones medidas). Debe quedar
|
|
84
|
+
comentado por qué, y el valor sigue obedeciendo R1/R2 (variables y rem).
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// ❌ Prohibido
|
|
88
|
+
<div style={{ display: 'flex', gap: '16px', color: '#0e79fd' }}>…</div>
|
|
89
|
+
|
|
90
|
+
// ✅ Correcto
|
|
91
|
+
<div className="flex gap-4 text-primary">…</div>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## R5 — Consistencia con UX: convertir, no copiar
|
|
95
|
+
|
|
96
|
+
- Cuando una spec de UX, un mockup o un diseño entregue valores en px o
|
|
97
|
+
colores absolutos, se convierten **automáticamente** al entrar al código:
|
|
98
|
+
px → rem (R2), hex → variable del sistema (R1), inline → Tailwind (R4).
|
|
99
|
+
- La conversión respeta las **proporciones** del diseño original: un espaciado
|
|
100
|
+
del doble en el mockup sigue siendo el doble en rem; no se "redondea" a ojo
|
|
101
|
+
a un token que cambie la relación visual.
|
|
102
|
+
- El resultado se declara en el reporte cuando la conversión no fue 1:1 (p.
|
|
103
|
+
ej. un px sin token exacto que se resolvió al paso más cercano de la escala).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
**Entrega siempre código limpio, consistente y alineado con estas reglas.**
|
|
108
|
+
Un diff que las viole no se reporta como ✅ Done: la verificación del Step 5
|
|
109
|
+
de la skill incluye greps que las hacen cumplir.
|