@atlashub/smartstack-cli 1.37.0 → 2.1.0

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.
Files changed (123) hide show
  1. package/.documentation/agents.html +147 -40
  2. package/.documentation/apex.html +1 -1
  3. package/.documentation/business-analyse.html +3 -3
  4. package/.documentation/cli-commands.html +2 -2
  5. package/.documentation/commands.html +14 -14
  6. package/.documentation/efcore.html +14 -14
  7. package/.documentation/gitflow.html +12 -12
  8. package/.documentation/hooks.html +41 -3
  9. package/.documentation/index.html +1 -1
  10. package/.documentation/init.html +2 -2
  11. package/.documentation/installation.html +11 -11
  12. package/.documentation/js/app.js +1 -1
  13. package/.documentation/ralph-loop.html +1 -1
  14. package/.documentation/test-web.html +4 -4
  15. package/config/mcp-defaults.json +62 -0
  16. package/dist/index.js +58 -5
  17. package/dist/index.js.map +1 -1
  18. package/dist/mcp-entry.mjs +70010 -0
  19. package/dist/mcp-entry.mjs.map +1 -0
  20. package/package.json +14 -5
  21. package/templates/agents/gitflow/start.md +5 -4
  22. package/templates/agents/mcp-healthcheck.md +15 -13
  23. package/templates/mcp-scaffolding/component.tsx.hbs +298 -0
  24. package/templates/mcp-scaffolding/controller.cs.hbs +184 -0
  25. package/templates/mcp-scaffolding/entity-extension.cs.hbs +231 -0
  26. package/templates/mcp-scaffolding/frontend/api-client.ts.hbs +116 -0
  27. package/templates/mcp-scaffolding/frontend/nav-routes.ts.hbs +133 -0
  28. package/templates/mcp-scaffolding/frontend/routes.tsx.hbs +134 -0
  29. package/templates/mcp-scaffolding/migrations/seed-roles.cs.hbs +261 -0
  30. package/templates/mcp-scaffolding/service-extension.cs.hbs +53 -0
  31. package/templates/mcp-scaffolding/tests/controller.test.cs.hbs +413 -0
  32. package/templates/mcp-scaffolding/tests/entity.test.cs.hbs +239 -0
  33. package/templates/mcp-scaffolding/tests/repository.test.cs.hbs +441 -0
  34. package/templates/mcp-scaffolding/tests/security.test.cs.hbs +442 -0
  35. package/templates/mcp-scaffolding/tests/service.test.cs.hbs +390 -0
  36. package/templates/mcp-scaffolding/tests/validator.test.cs.hbs +428 -0
  37. package/templates/ralph/README.md +3 -3
  38. package/templates/ralph/ralph.config.yaml +2 -2
  39. package/templates/skills/admin/SKILL.md +42 -0
  40. package/templates/skills/business-analyse/_shared.md +79 -15
  41. package/templates/skills/business-analyse/questionnaire/01-context.md +4 -4
  42. package/templates/skills/business-analyse/questionnaire/02-stakeholders.md +3 -3
  43. package/templates/skills/business-analyse/questionnaire/03-scope.md +4 -4
  44. package/templates/skills/business-analyse/questionnaire/04-data.md +7 -7
  45. package/templates/skills/business-analyse/questionnaire/05-integrations.md +1 -1
  46. package/templates/skills/business-analyse/questionnaire/06-security.md +3 -3
  47. package/templates/skills/business-analyse/questionnaire/07-ui.md +1 -1
  48. package/templates/skills/business-analyse/questionnaire/08-performance.md +3 -3
  49. package/templates/skills/business-analyse/questionnaire/09-constraints.md +4 -4
  50. package/templates/skills/business-analyse/questionnaire/10-documentation.md +2 -2
  51. package/templates/skills/business-analyse/questionnaire/11-data-lifecycle.md +2 -2
  52. package/templates/skills/business-analyse/questionnaire/12-migration.md +1 -1
  53. package/templates/skills/business-analyse/questionnaire/13-cross-module.md +2 -2
  54. package/templates/skills/business-analyse/steps/step-01-discover.md +50 -25
  55. package/templates/skills/business-analyse/steps/step-03-specify.md +63 -0
  56. package/templates/skills/business-analyse/steps/step-04-validate.md +23 -1
  57. package/templates/skills/business-analyse/steps/step-05-handoff.md +248 -66
  58. package/templates/skills/business-analyse/templates/tpl-handoff.md +99 -23
  59. package/templates/skills/cc-agent/SKILL.md +129 -0
  60. package/templates/skills/cc-agent/references/agent-frontmatter.md +213 -0
  61. package/templates/skills/cc-agent/references/permission-modes.md +102 -0
  62. package/templates/skills/cc-agent/references/tools-reference.md +144 -0
  63. package/templates/skills/cc-agent/steps/step-00-init.md +134 -0
  64. package/templates/skills/cc-agent/steps/step-01-design.md +186 -0
  65. package/templates/skills/cc-agent/steps/step-02-generate.md +204 -0
  66. package/templates/skills/cc-agent/steps/step-03-validate.md +130 -0
  67. package/templates/skills/cc-agent/templates/agent-categorized.md +67 -0
  68. package/templates/skills/cc-agent/templates/agent-standalone.md +56 -0
  69. package/templates/skills/cc-agent/templates/agent-with-skills.md +94 -0
  70. package/templates/skills/cc-audit/SKILL.md +108 -0
  71. package/templates/skills/cc-audit/references/agent-checklist.md +91 -0
  72. package/templates/skills/cc-audit/references/hook-checklist.md +110 -0
  73. package/templates/skills/cc-audit/references/skill-checklist.md +70 -0
  74. package/templates/skills/cc-audit/steps/step-00-init.md +98 -0
  75. package/templates/skills/cc-audit/steps/step-01-scan.md +142 -0
  76. package/templates/skills/cc-audit/steps/step-02-analyze.md +158 -0
  77. package/templates/skills/cc-audit/steps/step-03-report.md +142 -0
  78. package/templates/skills/cc-skill/SKILL.md +134 -0
  79. package/templates/skills/cc-skill/references/best-practices.md +167 -0
  80. package/templates/skills/cc-skill/references/frontmatter-reference.md +182 -0
  81. package/templates/skills/cc-skill/references/skill-patterns.md +199 -0
  82. package/templates/skills/cc-skill/steps/step-00-init.md +119 -0
  83. package/templates/skills/cc-skill/steps/step-01-design.md +199 -0
  84. package/templates/skills/cc-skill/steps/step-02-generate.md +145 -0
  85. package/templates/skills/cc-skill/steps/step-03-steps.md +151 -0
  86. package/templates/skills/cc-skill/steps/step-04-validate.md +124 -0
  87. package/templates/skills/cc-skill/templates/skill-forked.md +85 -0
  88. package/templates/skills/cc-skill/templates/skill-progressive.md +102 -0
  89. package/templates/skills/cc-skill/templates/skill-simple.md +75 -0
  90. package/templates/skills/cc-skill/templates/step-template.md +82 -0
  91. package/templates/skills/check-version/SKILL.md +6 -0
  92. package/templates/skills/controller/templates.md +82 -0
  93. package/templates/skills/debug/SKILL.md +4 -0
  94. package/templates/skills/documentation/SKILL.md +1 -0
  95. package/templates/skills/efcore/SKILL.md +5 -0
  96. package/templates/skills/efcore/references/zero-downtime-patterns.md +227 -0
  97. package/templates/skills/efcore/steps/db/step-deploy.md +26 -5
  98. package/templates/skills/efcore/steps/migration/step-03-validate.md +19 -0
  99. package/templates/skills/efcore/steps/shared/step-00-init.md +21 -7
  100. package/templates/skills/explore/SKILL.md +28 -32
  101. package/templates/skills/feature-full/SKILL.md +1 -0
  102. package/templates/skills/gitflow/SKILL.md +8 -0
  103. package/templates/skills/gitflow/steps/step-start.md +45 -10
  104. package/templates/skills/mcp/SKILL.md +38 -18
  105. package/templates/skills/quick-search/SKILL.md +8 -1
  106. package/templates/skills/ralph-loop/SKILL.md +1 -1
  107. package/templates/skills/ralph-loop/steps/step-00-init.md +8 -68
  108. package/templates/skills/ralph-loop/steps/step-04-check.md +1 -1
  109. package/templates/skills/refactor/SKILL.md +1 -0
  110. package/templates/skills/review-code/SKILL.md +11 -3
  111. package/templates/skills/review-code/references/owasp-api-top10.md +243 -0
  112. package/templates/skills/review-code/references/security-checklist.md +86 -1
  113. package/templates/skills/review-code/references/smartstack-conventions.md +166 -0
  114. package/templates/skills/ui-components/SKILL.md +31 -438
  115. package/templates/skills/ui-components/accessibility.md +170 -0
  116. package/templates/skills/ui-components/patterns/data-table.md +39 -0
  117. package/templates/skills/ui-components/patterns/entity-card.md +77 -0
  118. package/templates/skills/ui-components/patterns/grid-layout.md +91 -0
  119. package/templates/skills/ui-components/patterns/kanban.md +43 -0
  120. package/templates/skills/ui-components/style-guide.md +86 -0
  121. package/templates/skills/utils/SKILL.md +1 -0
  122. package/templates/skills/validate/SKILL.md +1 -0
  123. package/templates/skills/workflow/SKILL.md +27 -0
@@ -27,465 +27,59 @@ description: |
27
27
  | Keywords | "card", "grid", "table", "kanban", "tooltip" |
28
28
  | Disabled states | "Disable button with explanatory message" |
29
29
 
30
- ## MANDATORY COMPONENT: EntityCard
30
+ ## Detailed patterns
31
31
 
32
- **ALWAYS use `EntityCard` for entity cards. NEVER use custom cards with divs.**
32
+ - For EntityCard (mandatory): [patterns/entity-card.md](patterns/entity-card.md)
33
+ - For DataTable: [patterns/data-table.md](patterns/data-table.md)
34
+ - For Grid layouts: [patterns/grid-layout.md](patterns/grid-layout.md)
35
+ - For Kanban boards: [patterns/kanban.md](patterns/kanban.md)
36
+ - For styling rules: [style-guide.md](style-guide.md)
37
+ - For accessibility: [accessibility.md](accessibility.md)
38
+
39
+ ## CORE RULES (always apply)
33
40
 
41
+ ### EntityCard is Mandatory
42
+ **ALWAYS use `EntityCard` for entity cards. NEVER use custom cards with divs.**
34
43
  ```typescript
35
44
  import { EntityCard, ProviderCard, TemplateCard } from '@/components/ui/EntityCard';
36
45
  ```
37
46
 
38
- ### EntityCard Usage
47
+ ### CSS Variables (NEVER hardcode colors)
48
+ **NEVER use hardcoded Tailwind colors.** ALWAYS use CSS variables for theme compliance.
39
49
  ```tsx
40
- <EntityCard
41
- avatar={{ letter: 'O', color: '#10a37f' }}
42
- title="OpenAI" subtitle="openai"
43
- description="OpenAI GPT models"
44
- stats="15 model(s)"
45
- badge={{ icon: Shield, tooltip: 'Admin API supported' }}
46
- links={[{ icon: ExternalLink, label: 'Website', href: 'https://...' }]}
47
- actions={[{ label: 'Config', onClick: () => {}, variant: 'primary' }]}
48
- />
49
- ```
50
+ // CORRECT
51
+ <span className="bg-[var(--info-bg)] text-[var(--info-text)]">Badge</span>
50
52
 
51
- ### ProviderCard Usage (AI Providers)
52
- ```tsx
53
- <ProviderCard name="OpenAI" code="openai" description="..." modelCount={15} color="#10a37f"
54
- websiteUrl="..." docsUrl="..." apiKeyUrl="..." hasAdminKey />
53
+ // WRONG
54
+ <span className="bg-blue-500/10 text-blue-500">Badge</span>
55
55
  ```
56
56
 
57
- ### TemplateCard Usage (Templates)
57
+ ### Responsive Grid
58
58
  ```tsx
59
- <TemplateCard name="Welcome" code="welcome" category="Transactional" isActive isSystem
60
- icon={Mail} translationsCount={3} onClick={() => {}} onEdit={() => {}} onDelete={() => {}} />
61
- ```
62
-
63
- ### EntityCard Props
64
- | Prop | Type |
65
- |------|------|
66
- | `avatar` | `{ letter, color, imageUrl? }` |
67
- | `title`, `subtitle`, `description` | `string` |
68
- | `stats` | `string` |
69
- | `badge` | `{ icon?, tooltip?, color? }` |
70
- | `links` | `Array<{ icon, label, href?, onClick? }>` |
71
- | `actions` | `Array<{ label, href?, onClick?, variant, icon?, disabled? }>` |
72
-
73
- ### Action Variants (EntityCard)
74
- | Variant | Style |
75
- |---------|-------|
76
- | `primary` | `bg-[var(--color-accent-600)] text-white` |
77
- | `secondary` | `bg-[var(--bg-secondary)] text-[var(--text-secondary)]` |
78
- | `ghost` | `text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]` (NO border!) |
79
-
80
- ## RESPONSIVE GRID
81
-
82
- ```tsx
83
- // Standard
84
59
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
85
60
  {items.map(item => <EntityCard key={item.id} {...mapToCardProps(item)} />)}
86
61
  </div>
87
-
88
- // With empty state
89
- {items.length === 0 ? (
90
- <div className="text-center py-12"><p>No items</p></div>
91
- ) : (
92
- <div className="grid ...">...</div>
93
- )}
94
- ```
95
-
96
- ## CUSTOM CARDS (Status, Dashboard)
97
-
98
- Button alignment pattern at bottom (mandatory for custom cards):
99
-
100
- ```tsx
101
- // WARNING: h-full flex flex-col + flex-1 + mt-auto
102
- <div className="h-full flex flex-col rounded-[var(--radius-card)] border ...">
103
- {/* Header */}
104
- <div className="px-4 py-3 bg-gradient-to-r from-[var(--color-accent-500)]/10 ...">
105
- {/* ... */}
106
- </div>
107
- {/* Content with flex-1 */}
108
- <div className="flex-1 flex flex-col p-4">
109
- {/* Variable content */}
110
- {/* WARNING: mt-auto for button at bottom */}
111
- <button className="mt-auto w-full ...">Action</button>
112
- </div>
113
- </div>
114
- ```
115
-
116
- ## COMPONENT: DataTable
117
-
118
- ```tsx
119
- import { DataTable } from '@/components/ui/DataTable';
120
-
121
- <DataTable
122
- data={users}
123
- columns={[
124
- { key: 'name', label: 'Name', sortable: true },
125
- { key: 'role', label: 'Role', render: (user) => <Badge>{user.role}</Badge> }
126
- ]}
127
- pagination={{ pageSize: 10 }}
128
- searchable
129
- onRowClick={(user) => navigate(`/users/${user.id}`)}
130
- />
131
- ```
132
-
133
- ## COMPONENT: Tooltip
134
-
135
- ```tsx
136
- import { Tooltip } from '@/components/ui/Tooltip';
137
-
138
- // Variants: default, error, warning, success, info
139
- // Positions: top, bottom, left, right
140
-
141
- <Tooltip content="Permission required" variant="error">
142
- <button disabled>Protected action</button>
143
- </Tooltip>
144
62
  ```
145
63
 
146
- ### Disabled Button with Explanation Pattern
64
+ ### Ghost Buttons: NO BORDER
147
65
  ```tsx
148
- const canExecute = hasPermission('module.action.execute');
149
- <Tooltip content={!canExecute ? t('errors.noPermission') : undefined} variant="error" disabled={canExecute}>
150
- <button disabled={!canExecute}>Action</button>
151
- </Tooltip>
152
- ```
153
-
154
- ## WHEN TO USE EntityCard vs Custom
155
-
156
- | EntityCard for | Custom for |
157
- |----------------|------------|
158
- | Homogeneous entity lists | Dashboard stats cards |
159
- | Catalogs | Cards with complex interactive states |
160
- | Clickable grids | Cards with integrated forms |
161
-
162
- ## CRITICAL: CSS VARIABLES (NEVER HARDCODE COLORS)
163
-
164
- **NEVER use hardcoded Tailwind colors.** ALWAYS use CSS variables for theme compliance.
165
-
166
- ### Status Colors
167
- | Status | Background | Text | Border | Dot (solid) |
168
- |--------|------------|------|--------|-------------|
169
- | **Info** (Pending, Business) | `--info-bg` | `--info-text` | `--info-border` | `--info-dot` |
170
- | **Success** (Active) | `--success-bg` | `--success-text` | `--success-border` | `--success-dot` |
171
- | **Warning** (Suspended, Owner) | `--warning-bg` | `--warning-text` | `--warning-border` | `--warning-dot` |
172
- | **Error** (Danger, Archive) | `--error-bg` | `--error-text` | `--error-border` | `--error-dot` |
173
- | **Accent** (Personal, Primary) | `--accent-bg` | `--accent-text` | `--accent-border` | `--color-accent-500` |
174
-
175
- ### Badge Pattern
176
- ```tsx
177
- // ✅ CORRECT - Uses CSS variables
178
- <span className="px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--info-bg)] text-[var(--info-text)]">
179
- Info Badge
180
- </span>
181
-
182
- // ❌ WRONG - Hardcoded Tailwind colors
183
- <span className="bg-blue-500/10 text-blue-500">Info Badge</span>
184
- ```
185
-
186
- ### Status Config Pattern
187
- ```tsx
188
- // ✅ CORRECT
189
- const STATUS_CONFIG = {
190
- Pending: { bgColor: 'bg-[var(--info-bg)]', color: 'text-[var(--info-text)]', borderColor: 'border-[var(--info-border)]' },
191
- Active: { bgColor: 'bg-[var(--success-bg)]', color: 'text-[var(--success-text)]', borderColor: 'border-[var(--success-border)]' },
192
- Suspended: { bgColor: 'bg-[var(--warning-bg)]', color: 'text-[var(--warning-text)]', borderColor: 'border-[var(--warning-border)]' },
193
- Archived: { bgColor: 'bg-[var(--bg-tertiary)]', color: 'text-[var(--text-tertiary)]', borderColor: 'border-[var(--border-color)]' }
194
- };
195
-
196
- // ❌ WRONG - dark: variants are obsolete
197
- const STATUS_CONFIG = {
198
- Active: { bgColor: 'bg-emerald-50 dark:bg-emerald-900/20', ... }
199
- };
200
- ```
201
-
202
- ## BUTTON VARIANTS
203
-
204
- ### Action Buttons (Status changes)
205
- ```tsx
206
- // Success action (Activate)
207
- <button className="px-4 py-2 rounded-[var(--radius-button)] bg-[var(--success-dot)] text-white hover:opacity-90">
208
- Activate
209
- </button>
210
-
211
- // Warning action (Suspend)
212
- <button className="px-4 py-2 rounded-[var(--radius-button)] bg-[var(--warning-dot)] text-white hover:opacity-90">
213
- Suspend
214
- </button>
215
-
216
- // Danger action (Archive/Delete)
217
- <button className="px-4 py-2 rounded-[var(--radius-button)] bg-[var(--error-dot)] text-white hover:opacity-90">
218
- Archive
219
- </button>
220
-
221
- // Primary action
222
- <button className="px-4 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)]">
223
- Save
224
- </button>
225
-
226
66
  // Ghost action (NO BORDER!)
227
- <button className="px-4 py-2 rounded-[var(--radius-button)] text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]">
228
- Refresh
229
- </button>
230
-
231
- // Secondary action
232
- <button className="px-4 py-2 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]">
233
- Cancel
234
- </button>
235
- ```
236
-
237
- ### Button Rules
238
- | Variant | Background | Text | Border | Hover |
239
- |---------|------------|------|--------|-------|
240
- | **Primary** | `--color-accent-600` | `white` | none | `--color-accent-700` |
241
- | **Success** | `--success-dot` | `white` | none | `opacity-90` |
242
- | **Warning** | `--warning-dot` | `white` | none | `opacity-90` |
243
- | **Danger** | `--error-dot` | `white` | none | `opacity-90` |
244
- | **Secondary** | `--bg-secondary` | `--text-secondary` | none | `--bg-hover` |
245
- | **Ghost** | transparent | `--text-secondary` | **NONE** | `--bg-hover` |
246
-
247
- ## DETAIL PAGE TEMPLATE
248
-
249
- ### Structure
250
- ```tsx
251
- <div className="container mx-auto px-4 py-6 max-w-7xl space-y-6">
252
- {/* Header */}
253
- <div className="flex items-center gap-4">
254
- <button onClick={() => navigate(-1)} className="p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)]">
255
- <ArrowLeft className="w-5 h-5 text-[var(--text-secondary)]" />
256
- </button>
257
- <div className="flex-1">
258
- <h1 className="text-xl sm:text-2xl font-bold text-[var(--text-primary)]">{title}</h1>
259
- <p className="text-sm text-[var(--text-secondary)]">{subtitle}</p>
260
- </div>
261
- <div className="flex items-center gap-2">
262
- {/* Status badges */}
263
- </div>
264
- </div>
265
-
266
- {/* Pill Tabs */}
267
- <div className="flex gap-1 p-1 bg-[var(--bg-secondary)] rounded-[var(--radius-card)] border border-[var(--border-color)]">
268
- {tabs.map(tab => (
269
- <button
270
- key={tab.id}
271
- className={`px-4 py-2 rounded-[var(--radius-button)] font-medium ${
272
- activeTab === tab.id
273
- ? 'bg-[var(--color-accent-600)] text-white'
274
- : 'text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'
275
- }`}
276
- >
277
- {tab.label}
278
- </button>
279
- ))}
280
- </div>
281
-
282
- {/* Tab Content */}
283
- <div className="min-h-[400px]">{/* ... */}</div>
284
- </div>
285
- ```
286
-
287
- ### Info Card Pattern
288
- ```tsx
289
- <div className="p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]">
290
- <div className="flex items-center justify-between mb-4">
291
- <h3 className="text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2">
292
- <Icon className="w-5 h-5" />
293
- {title}
294
- </h3>
295
- <button className="flex items-center gap-1 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]">
296
- <Edit3 className="w-4 h-4" />
297
- {t('common:edit')}
298
- </button>
299
- </div>
300
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
301
- <div className="p-3 rounded-lg bg-[var(--bg-secondary)]">
302
- <p className="text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1">{label}</p>
303
- <p className="text-sm text-[var(--text-primary)] font-medium">{value}</p>
304
- </div>
305
- </div>
306
- </div>
307
- ```
308
-
309
- ### Error Display Pattern
310
- ```tsx
311
- {error && (
312
- <div className="p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]">
313
- <div className="flex items-center gap-2 text-[var(--error-text)]">
314
- <AlertTriangle className="w-5 h-5" />
315
- <span>{error}</span>
316
- </div>
317
- </div>
318
- )}
319
- ```
320
-
321
- ## TYPESCRIPT INTERFACES (MANDATORY)
322
-
323
- **ALWAYS define explicit TypeScript interfaces for component props.**
324
-
325
- ```typescript
326
- // ✅ CORRECT - Explicit interface with all props typed
327
- interface UserCardProps {
328
- user: User;
329
- onSelect?: (user: User) => void;
330
- isSelected?: boolean;
331
- variant?: 'default' | 'compact';
332
- }
333
-
334
- export const UserCard: React.FC<UserCardProps> = ({
335
- user,
336
- onSelect,
337
- isSelected = false,
338
- variant = 'default'
339
- }) => {
340
- // ...
341
- };
342
-
343
- // ❌ WRONG - Missing interface, inline types, or any
344
- export const UserCard = ({ user, onSelect }: any) => { ... }
345
- export const UserCard = (props: { user: any }) => { ... }
346
- ```
347
-
348
- ### State Typing
349
- ```typescript
350
- // ✅ CORRECT - Explicit state types
351
- const [users, setUsers] = useState<User[]>([]);
352
- const [selectedId, setSelectedId] = useState<string | null>(null);
353
- const [status, setStatus] = useState<'idle' | 'loading' | 'error'>('idle');
354
-
355
- // ❌ WRONG - Implicit or missing types
356
- const [users, setUsers] = useState([]);
357
- const [data, setData] = useState();
358
- ```
359
-
360
- ## SEMANTIC HTML (ACCESSIBILITY)
361
-
362
- **ALWAYS use semantic HTML elements instead of divs with roles.**
363
-
364
- ```tsx
365
- // ✅ CORRECT - Native button element
366
- <button type="button" onClick={handleClick} disabled={isDisabled}>
367
- Click me
67
+ <button className="px-4 py-2 rounded-[var(--radius-button)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]">
68
+ Action
368
69
  </button>
369
-
370
- // ❌ WRONG - div with role (S6819)
371
- <div role="button" onClick={handleClick} tabIndex={0}>
372
- Click me
373
- </div>
374
- ```
375
-
376
- ### Interactive Elements Mapping
377
-
378
- | Use Case | Correct Element | Wrong Pattern |
379
- |----------|----------------|---------------|
380
- | Clickable action | `<button type="button">` | `<div role="button">` |
381
- | Navigation link | `<a href="...">` or `<Link>` | `<div onClick={navigate}>` |
382
- | Form submission | `<button type="submit">` | `<div onClick={submit}>` |
383
- | Expandable section | `<details><summary>` | `<div onClick={toggle}>` |
384
- | List of items | `<ul><li>` with `<button>` inside | `<div role="listitem">` |
385
-
386
- ### Clickable Cards Pattern
387
- ```tsx
388
- // ✅ CORRECT - Card with button inside
389
- <div className="rounded-[var(--radius-card)] border ...">
390
- <div className="p-4">
391
- <h3>{title}</h3>
392
- <p>{description}</p>
393
- </div>
394
- <button
395
- type="button"
396
- onClick={() => onSelect(item)}
397
- className="w-full px-4 py-2 border-t ..."
398
- >
399
- Select
400
- </button>
401
- </div>
402
-
403
- // ✅ CORRECT - Entire card as link
404
- <Link to={`/items/${item.id}`} className="block rounded-[var(--radius-card)] ...">
405
- <div className="p-4">...</div>
406
- </Link>
407
-
408
- // ❌ WRONG - div with click handler
409
- <div onClick={() => onSelect(item)} className="cursor-pointer ...">
410
- ...
411
- </div>
412
- ```
413
-
414
- ## PERFORMANCE OPTIMIZATION
415
-
416
- ### React.memo for Pure Components
417
- ```tsx
418
- import { memo, useCallback, useMemo } from 'react';
419
-
420
- // ✅ CORRECT - Memoized component for lists
421
- export const UserCard = memo(({ user, onSelect }: UserCardProps) => {
422
- return (
423
- <div className="...">
424
- <h3>{user.name}</h3>
425
- <button onClick={() => onSelect(user)}>Select</button>
426
- </div>
427
- );
428
- });
429
- UserCard.displayName = 'UserCard';
430
- ```
431
-
432
- ### useCallback for Event Handlers
433
- ```tsx
434
- // ✅ CORRECT - Stable callback reference
435
- const handleSelect = useCallback((item: Item) => {
436
- onSelect?.(item);
437
- setSelectedId(item.id);
438
- }, [onSelect]);
439
-
440
- // ❌ WRONG - New function on every render
441
- const handleSelect = (item: Item) => {
442
- onSelect?.(item);
443
- };
444
70
  ```
445
71
 
446
- ### useMemo for Expensive Computations
447
- ```tsx
448
- // ✅ CORRECT - Memoized filtered list
449
- const filteredItems = useMemo(() =>
450
- items.filter(item => item.status === filter),
451
- [items, filter]
452
- );
453
-
454
- // ❌ WRONG - Recomputed on every render
455
- const filteredItems = items.filter(item => item.status === filter);
456
- ```
72
+ ### TypeScript Interfaces
73
+ **ALWAYS define explicit TypeScript interfaces for component props.** Never use `any`.
457
74
 
458
- ## LIST RENDERING (UNIQUE KEYS)
459
-
460
- **NEVER use array index as React key. ALWAYS use unique identifiers.**
461
-
462
- ```tsx
463
- // ✅ CORRECT - Unique ID from data
464
- {items.map(item => (
465
- <EntityCard key={item.id} {...mapToCardProps(item)} />
466
- ))}
467
-
468
- // ✅ CORRECT - Composite key when needed
469
- {items.map(item => (
470
- <Row key={`${item.tenantId}-${item.id}`} data={item} />
471
- ))}
472
-
473
- // ❌ WRONG - Array index as key (S6479)
474
- {items.map((item, index) => (
475
- <EntityCard key={index} {...mapToCardProps(item)} />
476
- ))}
477
-
478
- // ❌ WRONG - Random key
479
- {items.map(item => (
480
- <EntityCard key={Math.random()} {...mapToCardProps(item)} />
481
- ))}
482
- ```
75
+ ### Semantic HTML
76
+ **ALWAYS use `<button>` for click actions, `<a>` or `<Link>` for navigation.** Never use `<div role="button">`.
483
77
 
484
- ### Why Index Keys Are Problematic
485
- - Causes unnecessary re-renders when list order changes
486
- - Breaks component state (inputs, animations)
487
- - Causes visual glitches with drag-and-drop
488
- - Makes reconciliation inefficient
78
+ ### Performance
79
+ - `memo()` for list item components
80
+ - `useCallback` for event handlers passed as props
81
+ - `useMemo` for expensive computations
82
+ - Unique `id` for list keys (NEVER array index)
489
83
 
490
84
  ## ABSOLUTE RULES
491
85
 
@@ -493,10 +87,9 @@ const filteredItems = items.filter(item => item.status === filter);
493
87
  |----|-------|
494
88
  | CSS variables for ALL colors | Hardcoded Tailwind colors (`bg-blue-500`) |
495
89
  | `--success-dot`, `--warning-dot`, `--error-dot` for action buttons | `bg-emerald-500`, `bg-amber-500`, `bg-red-500` |
496
- | `--info-bg`, `--success-bg`, etc. for badges | `bg-blue-500/10 dark:bg-blue-900/20` |
497
90
  | Ghost buttons WITHOUT border | `border border-[var(--border-color)]` on ghost |
498
91
  | EntityCard for entities | Custom cards with manual divs |
499
- | Responsive grid 1234 | Fixed non-responsive grid |
92
+ | Responsive grid 1->2->3->4 | Fixed non-responsive grid |
500
93
  | h-full + flex-1 + mt-auto | Unaligned buttons in grid |
501
94
  | Empty and loading states | Native HTML tooltip |
502
95
  | Explicit TypeScript interfaces | `any` or implicit types |
@@ -0,0 +1,170 @@
1
+ # Accessibility & Best Practices
2
+
3
+ ## TYPESCRIPT INTERFACES (MANDATORY)
4
+
5
+ **ALWAYS define explicit TypeScript interfaces for component props.**
6
+
7
+ ```typescript
8
+ // CORRECT - Explicit interface with all props typed
9
+ interface UserCardProps {
10
+ user: User;
11
+ onSelect?: (user: User) => void;
12
+ isSelected?: boolean;
13
+ variant?: 'default' | 'compact';
14
+ }
15
+
16
+ export const UserCard: React.FC<UserCardProps> = ({
17
+ user,
18
+ onSelect,
19
+ isSelected = false,
20
+ variant = 'default'
21
+ }) => {
22
+ // ...
23
+ };
24
+
25
+ // WRONG - Missing interface, inline types, or any
26
+ export const UserCard = ({ user, onSelect }: any) => { ... }
27
+ export const UserCard = (props: { user: any }) => { ... }
28
+ ```
29
+
30
+ ### State Typing
31
+ ```typescript
32
+ // CORRECT - Explicit state types
33
+ const [users, setUsers] = useState<User[]>([]);
34
+ const [selectedId, setSelectedId] = useState<string | null>(null);
35
+ const [status, setStatus] = useState<'idle' | 'loading' | 'error'>('idle');
36
+
37
+ // WRONG - Implicit or missing types
38
+ const [users, setUsers] = useState([]);
39
+ const [data, setData] = useState();
40
+ ```
41
+
42
+ ## SEMANTIC HTML (ACCESSIBILITY)
43
+
44
+ **ALWAYS use semantic HTML elements instead of divs with roles.**
45
+
46
+ ```tsx
47
+ // CORRECT - Native button element
48
+ <button type="button" onClick={handleClick} disabled={isDisabled}>
49
+ Click me
50
+ </button>
51
+
52
+ // WRONG - div with role (S6819)
53
+ <div role="button" onClick={handleClick} tabIndex={0}>
54
+ Click me
55
+ </div>
56
+ ```
57
+
58
+ ### Interactive Elements Mapping
59
+
60
+ | Use Case | Correct Element | Wrong Pattern |
61
+ |----------|----------------|---------------|
62
+ | Clickable action | `<button type="button">` | `<div role="button">` |
63
+ | Navigation link | `<a href="...">` or `<Link>` | `<div onClick={navigate}>` |
64
+ | Form submission | `<button type="submit">` | `<div onClick={submit}>` |
65
+ | Expandable section | `<details><summary>` | `<div onClick={toggle}>` |
66
+ | List of items | `<ul><li>` with `<button>` inside | `<div role="listitem">` |
67
+
68
+ ### Clickable Cards Pattern
69
+ ```tsx
70
+ // CORRECT - Card with button inside
71
+ <div className="rounded-[var(--radius-card)] border ...">
72
+ <div className="p-4">
73
+ <h3>{title}</h3>
74
+ <p>{description}</p>
75
+ </div>
76
+ <button
77
+ type="button"
78
+ onClick={() => onSelect(item)}
79
+ className="w-full px-4 py-2 border-t ..."
80
+ >
81
+ Select
82
+ </button>
83
+ </div>
84
+
85
+ // CORRECT - Entire card as link
86
+ <Link to={`/items/${item.id}`} className="block rounded-[var(--radius-card)] ...">
87
+ <div className="p-4">...</div>
88
+ </Link>
89
+
90
+ // WRONG - div with click handler
91
+ <div onClick={() => onSelect(item)} className="cursor-pointer ...">
92
+ ...
93
+ </div>
94
+ ```
95
+
96
+ ## PERFORMANCE OPTIMIZATION
97
+
98
+ ### React.memo for Pure Components
99
+ ```tsx
100
+ import { memo, useCallback, useMemo } from 'react';
101
+
102
+ // CORRECT - Memoized component for lists
103
+ export const UserCard = memo(({ user, onSelect }: UserCardProps) => {
104
+ return (
105
+ <div className="...">
106
+ <h3>{user.name}</h3>
107
+ <button onClick={() => onSelect(user)}>Select</button>
108
+ </div>
109
+ );
110
+ });
111
+ UserCard.displayName = 'UserCard';
112
+ ```
113
+
114
+ ### useCallback for Event Handlers
115
+ ```tsx
116
+ // CORRECT - Stable callback reference
117
+ const handleSelect = useCallback((item: Item) => {
118
+ onSelect?.(item);
119
+ setSelectedId(item.id);
120
+ }, [onSelect]);
121
+
122
+ // WRONG - New function on every render
123
+ const handleSelect = (item: Item) => {
124
+ onSelect?.(item);
125
+ };
126
+ ```
127
+
128
+ ### useMemo for Expensive Computations
129
+ ```tsx
130
+ // CORRECT - Memoized filtered list
131
+ const filteredItems = useMemo(() =>
132
+ items.filter(item => item.status === filter),
133
+ [items, filter]
134
+ );
135
+
136
+ // WRONG - Recomputed on every render
137
+ const filteredItems = items.filter(item => item.status === filter);
138
+ ```
139
+
140
+ ## LIST RENDERING (UNIQUE KEYS)
141
+
142
+ **NEVER use array index as React key. ALWAYS use unique identifiers.**
143
+
144
+ ```tsx
145
+ // CORRECT - Unique ID from data
146
+ {items.map(item => (
147
+ <EntityCard key={item.id} {...mapToCardProps(item)} />
148
+ ))}
149
+
150
+ // CORRECT - Composite key when needed
151
+ {items.map(item => (
152
+ <Row key={`${item.tenantId}-${item.id}`} data={item} />
153
+ ))}
154
+
155
+ // WRONG - Array index as key (S6479)
156
+ {items.map((item, index) => (
157
+ <EntityCard key={index} {...mapToCardProps(item)} />
158
+ ))}
159
+
160
+ // WRONG - Random key
161
+ {items.map(item => (
162
+ <EntityCard key={Math.random()} {...mapToCardProps(item)} />
163
+ ))}
164
+ ```
165
+
166
+ ### Why Index Keys Are Problematic
167
+ - Causes unnecessary re-renders when list order changes
168
+ - Breaks component state (inputs, animations)
169
+ - Causes visual glitches with drag-and-drop
170
+ - Makes reconciliation inefficient