qualia-framework-v2 2.3.0 → 2.5.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.
- package/CLAUDE.md +4 -3
- package/README.md +10 -2
- package/agents/builder.md +23 -5
- package/agents/planner.md +14 -0
- package/agents/verifier.md +63 -0
- package/bin/cli.js +135 -7
- package/bin/install.js +51 -5
- package/hooks/auto-update.sh +56 -0
- package/package.json +1 -1
- package/rules/design-reference.md +179 -0
- package/rules/frontend.md +108 -15
- package/skills/qualia-learn/SKILL.md +84 -0
- package/skills/qualia-new/SKILL.md +38 -0
- package/skills/qualia-polish/SKILL.md +128 -26
- package/skills/qualia-report/SKILL.md +23 -2
- package/templates/DESIGN.md +137 -0
package/CLAUDE.md
CHANGED
|
@@ -51,9 +51,10 @@ No accumulated garbage. No context rot.
|
|
|
51
51
|
## Quality Gates (always active)
|
|
52
52
|
- **Frontend guard:** Read .planning/DESIGN.md before any frontend changes
|
|
53
53
|
- **Deploy guard:** tsc + lint + build + tests must pass before deploy
|
|
54
|
-
- **Branch guard:** Employees cannot push to main
|
|
55
|
-
- **Env guard:**
|
|
56
|
-
- **
|
|
54
|
+
- **Branch guard:** Employees cannot push to main (OWNER can)
|
|
55
|
+
- **Env guard:** Employees cannot edit .env files (OWNER can — add keys, configure secrets directly)
|
|
56
|
+
- **Sudo guard:** Employees cannot run sudo (OWNER can)
|
|
57
|
+
- **Intent verification:** Confirm before modifying 3+ files (OWNER: just do it)
|
|
57
58
|
|
|
58
59
|
## Tracking
|
|
59
60
|
`.planning/tracking.json` is updated on every push. The ERP reads it via git.
|
package/README.md
CHANGED
|
@@ -12,6 +12,12 @@ npx qualia-framework-v2 install
|
|
|
12
12
|
|
|
13
13
|
Enter your team code when prompted. Get your code from Fawzi.
|
|
14
14
|
|
|
15
|
+
**Other commands:**
|
|
16
|
+
```bash
|
|
17
|
+
npx qualia-framework-v2 version # Check installed version + updates
|
|
18
|
+
npx qualia-framework-v2 update # Update to latest (remembers your code)
|
|
19
|
+
```
|
|
20
|
+
|
|
15
21
|
## Usage
|
|
16
22
|
|
|
17
23
|
Open Claude Code in any project directory:
|
|
@@ -33,6 +39,7 @@ Open Claude Code in any project directory:
|
|
|
33
39
|
/qualia-handoff # Deliver to client
|
|
34
40
|
/qualia-pause # Save session, continue later
|
|
35
41
|
/qualia-resume # Pick up where you left off
|
|
42
|
+
/qualia-learn # Save a pattern, fix, or client pref
|
|
36
43
|
/qualia-report # Log your work (mandatory)
|
|
37
44
|
```
|
|
38
45
|
|
|
@@ -40,7 +47,7 @@ See `guide.md` for the full developer guide.
|
|
|
40
47
|
|
|
41
48
|
## What's Inside
|
|
42
49
|
|
|
43
|
-
- **
|
|
50
|
+
- **18 skills** — slash commands from setup to handoff, plus debugging, design, review, knowledge, and session management
|
|
44
51
|
- **3 agents** — planner, builder, verifier (each in fresh context)
|
|
45
52
|
- **7 hooks** — branch guard, pre-push tracking sync, env protection, migration guard, deploy gate, pre-compact state save, session start
|
|
46
53
|
- **3 rules** — security, frontend, deployment
|
|
@@ -85,10 +92,11 @@ npx qualia-framework-v2 install
|
|
|
85
92
|
|
|
|
86
93
|
v
|
|
87
94
|
~/.claude/
|
|
88
|
-
├── skills/
|
|
95
|
+
├── skills/ 18 slash commands
|
|
89
96
|
├── agents/ planner.md, builder.md, verifier.md
|
|
90
97
|
├── hooks/ 7 shell scripts (branch, env, migration, deploy, push, compact, session)
|
|
91
98
|
├── bin/ state.js (state machine with precondition enforcement)
|
|
99
|
+
├── knowledge/ learned-patterns.md, common-fixes.md, client-prefs.md
|
|
92
100
|
├── rules/ security.md, frontend.md, deployment.md
|
|
93
101
|
├── qualia-templates/ tracking.json, state.md, project.md, plan.md
|
|
94
102
|
├── CLAUDE.md global instructions (role-configured per team member)
|
package/agents/builder.md
CHANGED
|
@@ -83,10 +83,28 @@ Rule of thumb: If you can explain the change in one sentence in a commit message
|
|
|
83
83
|
- Always check auth server-side
|
|
84
84
|
- Enable RLS on every table
|
|
85
85
|
- Validate input with Zod at system boundaries
|
|
86
|
-
5. **Frontend standards:**
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
86
|
+
5. **Frontend standards (mandatory for any .tsx/.jsx/.css file):**
|
|
87
|
+
- Before writing any frontend code: read `.planning/DESIGN.md` if it exists — it's the design source of truth
|
|
88
|
+
- If no DESIGN.md, apply rules from `rules/frontend.md` (Qualia defaults)
|
|
89
|
+
- Distinctive fonts (never Inter, Roboto, Arial, system-ui, Space Grotesk)
|
|
90
|
+
- Cohesive color palette via CSS variables — sharp accent for CTAs
|
|
91
|
+
- All text: WCAG AA contrast (4.5:1 normal, 3:1 large text)
|
|
92
|
+
- Full-width fluid layouts — no hardcoded max-width caps
|
|
93
|
+
- Every interactive element needs ALL states: hover, focus (visible ring), active, disabled, loading, error, empty
|
|
94
|
+
- Semantic HTML (`nav`, `main`, `section`, `article`) — not div soup
|
|
95
|
+
- Keyboard accessible: Tab, Enter, Escape, Arrow keys work
|
|
96
|
+
- Touch targets: 44px minimum
|
|
97
|
+
- Form inputs: visible labels (not placeholder-only), error messages with `aria-describedby`
|
|
98
|
+
- Motion: 150–200ms hover, 250ms expand, stagger children on load, respect `prefers-reduced-motion`
|
|
99
|
+
- Mobile-first responsive: stack on mobile, expand on desktop, fluid typography
|
|
100
|
+
- Skip link on every page, heading hierarchy (one h1, sequential order)
|
|
101
|
+
- No emoji as icons — use SVGs
|
|
102
|
+
- `cursor: pointer` on all clickable elements
|
|
91
103
|
6. **No empty catch blocks.** At minimum, log the error.
|
|
92
104
|
7. **No dangerouslySetInnerHTML.** No eval().
|
|
105
|
+
8. **React/Next.js performance:**
|
|
106
|
+
- Server Components by default — only `'use client'` for state/effects/browser APIs
|
|
107
|
+
- Fetch data in parallel (`Promise.all`), not sequential waterfalls
|
|
108
|
+
- Import specific functions, not entire libraries — avoid barrel file re-exports
|
|
109
|
+
- Use `next/image` with explicit width/height
|
|
110
|
+
- Use `next/dynamic` for heavy below-fold components
|
package/agents/planner.md
CHANGED
|
@@ -85,6 +85,20 @@ If a task involves a library or API you're unsure about, use WebFetch to check t
|
|
|
85
85
|
|
|
86
86
|
**Self-check:** Before returning the plan, verify every task has specific file paths, concrete actions, and testable done-when criteria. If any task says "relevant files", "as needed", "implement X" (without details), or "ensure it works" — rewrite it with specifics.
|
|
87
87
|
|
|
88
|
+
## Design-Aware Planning
|
|
89
|
+
|
|
90
|
+
When a phase involves frontend work (pages, components, layouts, UI):
|
|
91
|
+
|
|
92
|
+
1. **Check for `.planning/DESIGN.md`** — if it exists, reference it in task Context fields: `@.planning/DESIGN.md`
|
|
93
|
+
2. **If no DESIGN.md and this is Phase 1** — add a Task 1 (Wave 1) to create it:
|
|
94
|
+
- Generate `.planning/DESIGN.md` from the design direction in PROJECT.md
|
|
95
|
+
- Use the template at `templates/DESIGN.md` — fill in: palette, typography (distinctive fonts), spacing, motion approach, component patterns
|
|
96
|
+
- Done when: DESIGN.md exists with concrete CSS variable values (not placeholders)
|
|
97
|
+
3. **Include design criteria in "Done when"** for frontend tasks:
|
|
98
|
+
- Not just "page renders" but "page renders with design system typography, proper color palette, all interactive states (hover/focus/loading/error/empty), semantic HTML, keyboard accessible"
|
|
99
|
+
- Include responsive: "works on 375px mobile and 1440px desktop"
|
|
100
|
+
4. **Reference `@.planning/DESIGN.md`** in the Context field of every frontend task so builders read it before coding
|
|
101
|
+
|
|
88
102
|
## Rules
|
|
89
103
|
|
|
90
104
|
1. **Plans complete within ~50% context.** More plans with smaller scope = consistent quality. 2-3 tasks per plan is ideal.
|
package/agents/verifier.md
CHANGED
|
@@ -148,6 +148,68 @@ Phase verdict:
|
|
|
148
148
|
|
|
149
149
|
Never round up. A PARTIAL is not a PASS. The goal of verification is to catch the work that LOOKS done but ISN'T.
|
|
150
150
|
|
|
151
|
+
## Design Verification (for phases with frontend work)
|
|
152
|
+
|
|
153
|
+
If the phase involved UI/frontend tasks, add a **Design Quality** section to the report:
|
|
154
|
+
|
|
155
|
+
### Check 1: Design System Compliance
|
|
156
|
+
```bash
|
|
157
|
+
# Generic fonts (should NOT appear)
|
|
158
|
+
grep -rn "font-family.*Inter\|font-family.*Roboto\|font-family.*Arial\|fontFamily.*Inter\|fontFamily.*Roboto" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
159
|
+
grep -rn "font-sans\|font-inter" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null
|
|
160
|
+
|
|
161
|
+
# Hardcoded max-width containers (should NOT appear)
|
|
162
|
+
grep -rn "max-w-\[1200\|max-w-\[1280\|max-width.*1200\|max-width.*1280\|max-w-7xl" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
163
|
+
|
|
164
|
+
# Hardcoded colors instead of CSS variables (check density)
|
|
165
|
+
grep -rn "color:.*#\|background:.*#\|bg-\[#" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | wc -l
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Check 2: Accessibility Basics
|
|
169
|
+
```bash
|
|
170
|
+
# Images without alt text
|
|
171
|
+
grep -rn "<img" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | grep -v "alt="
|
|
172
|
+
|
|
173
|
+
# Inputs without labels
|
|
174
|
+
grep -rn "<input\|<textarea\|<select" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | grep -v "aria-label\|aria-labelledby\|id=" | head -10
|
|
175
|
+
|
|
176
|
+
# outline:none without replacement focus style
|
|
177
|
+
grep -rn "outline.*none\|outline-none" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null | grep -v "focus-visible\|focus:\|focus-within"
|
|
178
|
+
|
|
179
|
+
# Missing lang attribute
|
|
180
|
+
grep -rn "<html" --include="*.tsx" --include="*.jsx" app/ 2>/dev/null | grep -v "lang="
|
|
181
|
+
|
|
182
|
+
# Heading hierarchy — check for h1 count
|
|
183
|
+
grep -rn "<h1\|<H1" --include="*.tsx" --include="*.jsx" app/ 2>/dev/null | wc -l
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Check 3: Interactive States
|
|
187
|
+
```bash
|
|
188
|
+
# Buttons/links without hover/focus styles — spot check
|
|
189
|
+
grep -rn "<button\|<Button\|<a " --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | head -5
|
|
190
|
+
# Verify these have hover/focus transitions in their styling
|
|
191
|
+
|
|
192
|
+
# Loading states — check for skeleton/spinner usage in pages with data fetching
|
|
193
|
+
grep -rn "fetch\|useQuery\|useSWR\|getServerSide\|async.*Component" --include="*.tsx" app/ 2>/dev/null | head -5
|
|
194
|
+
grep -rn "loading\|skeleton\|spinner\|Spinner\|Loading" --include="*.tsx" app/ components/ 2>/dev/null | wc -l
|
|
195
|
+
|
|
196
|
+
# Empty states — check lists/tables have empty handling
|
|
197
|
+
grep -rn "\.length.*===.*0\|\.length.*>.*0\|isEmpty\|no.*results\|no.*data" --include="*.tsx" app/ components/ 2>/dev/null | wc -l
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Check 4: Responsive
|
|
201
|
+
```bash
|
|
202
|
+
# Check for responsive utilities or media queries
|
|
203
|
+
grep -rn "sm:\|md:\|lg:\|xl:\|@media" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null | wc -l
|
|
204
|
+
# If 0 responsive declarations across multiple components → FAIL
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Scoring Design
|
|
208
|
+
- 0 generic fonts + 0 hardcoded max-widths + colors via variables = **PASS**
|
|
209
|
+
- Accessibility basics all present = **PASS**
|
|
210
|
+
- States and responsive present = **PASS**
|
|
211
|
+
- Any category failing = add to **Gaps** list with specific file:line
|
|
212
|
+
|
|
151
213
|
## Rules
|
|
152
214
|
|
|
153
215
|
1. **Never trust summaries.** Always grep the code yourself.
|
|
@@ -156,3 +218,4 @@ Never round up. A PARTIAL is not a PASS. The goal of verification is to catch th
|
|
|
156
218
|
4. **Stubs are failures.** `// TODO: implement` means the task wasn't done.
|
|
157
219
|
5. **Empty catch blocks are failures.** They hide real errors.
|
|
158
220
|
6. **Run tsc.** If TypeScript doesn't compile, nothing works.
|
|
221
|
+
7. **Design debt is a gap.** Generic fonts, missing states, inaccessible components, and hardcoded layouts are failures — not "nice to haves."
|
package/bin/cli.js
CHANGED
|
@@ -1,20 +1,148 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
|
|
3
7
|
const TEAL = "\x1b[38;2;0;206;209m";
|
|
8
|
+
const TG = "\x1b[38;2;0;170;175m";
|
|
4
9
|
const DIM = "\x1b[38;2;80;90;100m";
|
|
10
|
+
const GREEN = "\x1b[38;2;52;211;153m";
|
|
5
11
|
const WHITE = "\x1b[38;2;220;225;230m";
|
|
12
|
+
const YELLOW = "\x1b[38;2;234;179;8m";
|
|
13
|
+
const RED = "\x1b[38;2;239;68;68m";
|
|
6
14
|
const RESET = "\x1b[0m";
|
|
15
|
+
const BOLD = "\x1b[1m";
|
|
7
16
|
|
|
8
|
-
const
|
|
17
|
+
const CLAUDE_DIR = path.join(require("os").homedir(), ".claude");
|
|
18
|
+
const PKG = require("../package.json");
|
|
19
|
+
const CONFIG_FILE = path.join(CLAUDE_DIR, ".qualia-config.json");
|
|
20
|
+
|
|
21
|
+
function readConfig() {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
|
|
24
|
+
} catch {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function writeConfig(cfg) {
|
|
30
|
+
if (!fs.existsSync(CLAUDE_DIR)) fs.mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
31
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function banner() {
|
|
35
|
+
console.log("");
|
|
36
|
+
console.log(` ${TEAL}${BOLD}◆${RESET} ${WHITE}${BOLD}Qualia Framework${RESET} ${DIM}v${PKG.version}${RESET}`);
|
|
37
|
+
console.log(` ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
38
|
+
}
|
|
9
39
|
|
|
10
|
-
|
|
40
|
+
// ─── Commands ────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
function cmdInstall() {
|
|
11
43
|
require("./install.js");
|
|
12
|
-
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function cmdVersion() {
|
|
47
|
+
banner();
|
|
48
|
+
const cfg = readConfig();
|
|
49
|
+
|
|
50
|
+
console.log(` ${DIM}Installed:${RESET} ${WHITE}${PKG.version}${RESET}`);
|
|
51
|
+
if (cfg.installed_by) {
|
|
52
|
+
console.log(` ${DIM}User:${RESET} ${WHITE}${cfg.installed_by}${RESET} ${DIM}(${cfg.role})${RESET}`);
|
|
53
|
+
}
|
|
54
|
+
if (cfg.installed_at) {
|
|
55
|
+
console.log(` ${DIM}Date:${RESET} ${WHITE}${cfg.installed_at}${RESET}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check for updates
|
|
59
|
+
try {
|
|
60
|
+
const latest = execSync("npm view qualia-framework-v2 version 2>/dev/null", {
|
|
61
|
+
encoding: "utf8",
|
|
62
|
+
timeout: 5000,
|
|
63
|
+
}).trim();
|
|
64
|
+
const semverGt = (a, b) => {
|
|
65
|
+
const pa = a.split(".").map(Number), pb = b.split(".").map(Number);
|
|
66
|
+
for (let i = 0; i < 3; i++) { if (pa[i] > pb[i]) return true; if (pa[i] < pb[i]) return false; }
|
|
67
|
+
return false;
|
|
68
|
+
};
|
|
69
|
+
if (latest && semverGt(latest, PKG.version)) {
|
|
70
|
+
console.log("");
|
|
71
|
+
console.log(` ${YELLOW}Update available:${RESET} ${WHITE}${latest}${RESET}`);
|
|
72
|
+
console.log(` ${DIM}Run:${RESET} npx qualia-framework-v2 update`);
|
|
73
|
+
} else if (latest) {
|
|
74
|
+
console.log(` ${DIM}Latest:${RESET} ${GREEN}${latest} ✓${RESET} ${DIM}(up to date)${RESET}`);
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
console.log(` ${DIM}Latest:${RESET} ${DIM}(offline — couldn't check)${RESET}`);
|
|
78
|
+
}
|
|
13
79
|
console.log("");
|
|
14
|
-
|
|
15
|
-
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function cmdUpdate() {
|
|
83
|
+
banner();
|
|
84
|
+
const cfg = readConfig();
|
|
85
|
+
|
|
86
|
+
if (!cfg.code) {
|
|
87
|
+
console.log(` ${RED}✗${RESET} No install code saved. Run ${TEAL}install${RESET} first.`);
|
|
88
|
+
console.log("");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(` ${DIM}Current:${RESET} ${WHITE}${PKG.version}${RESET}`);
|
|
93
|
+
console.log(` ${DIM}Updating...${RESET}`);
|
|
16
94
|
console.log("");
|
|
17
|
-
|
|
18
|
-
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// Pull latest and reinstall with saved code
|
|
98
|
+
execSync(
|
|
99
|
+
`npx qualia-framework-v2@latest install <<< "${cfg.code}"`,
|
|
100
|
+
{ stdio: "inherit", shell: true, timeout: 60000 }
|
|
101
|
+
);
|
|
102
|
+
} catch (e) {
|
|
103
|
+
console.log(` ${RED}✗${RESET} Update failed. Run manually: npx qualia-framework-v2@latest install`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function cmdHelp() {
|
|
109
|
+
banner();
|
|
19
110
|
console.log("");
|
|
111
|
+
console.log(` ${WHITE}Commands:${RESET}`);
|
|
112
|
+
console.log(` npx qualia-framework-v2 ${TEAL}install${RESET} Install or reinstall the framework`);
|
|
113
|
+
console.log(` npx qualia-framework-v2 ${TEAL}update${RESET} Update to the latest version`);
|
|
114
|
+
console.log(` npx qualia-framework-v2 ${TEAL}version${RESET} Show installed version + check for updates`);
|
|
115
|
+
console.log("");
|
|
116
|
+
console.log(` ${WHITE}After install:${RESET}`);
|
|
117
|
+
console.log(` ${TG}/qualia${RESET} What should I do next?`);
|
|
118
|
+
console.log(` ${TG}/qualia-new${RESET} Set up a new project`);
|
|
119
|
+
console.log(` ${TG}/qualia-plan${RESET} Plan a phase`);
|
|
120
|
+
console.log(` ${TG}/qualia-build${RESET} Build it (parallel tasks)`);
|
|
121
|
+
console.log(` ${TG}/qualia-verify${RESET} Verify it works`);
|
|
122
|
+
console.log(` ${TG}/qualia-design${RESET} One-shot design fix`);
|
|
123
|
+
console.log(` ${TG}/qualia-debug${RESET} Structured debugging`);
|
|
124
|
+
console.log(` ${TG}/qualia-review${RESET} Production audit`);
|
|
125
|
+
console.log(` ${TG}/qualia-ship${RESET} Deploy to production`);
|
|
126
|
+
console.log(` ${TG}/qualia-report${RESET} Log your work`);
|
|
127
|
+
console.log("");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ─── Main ────────────────────────────────────────────────
|
|
131
|
+
const cmd = process.argv[2];
|
|
132
|
+
|
|
133
|
+
switch (cmd) {
|
|
134
|
+
case "install":
|
|
135
|
+
cmdInstall();
|
|
136
|
+
break;
|
|
137
|
+
case "version":
|
|
138
|
+
case "-v":
|
|
139
|
+
case "--version":
|
|
140
|
+
cmdVersion();
|
|
141
|
+
break;
|
|
142
|
+
case "update":
|
|
143
|
+
case "upgrade":
|
|
144
|
+
cmdUpdate();
|
|
145
|
+
break;
|
|
146
|
+
default:
|
|
147
|
+
cmdHelp();
|
|
20
148
|
}
|
package/bin/install.js
CHANGED
|
@@ -223,6 +223,46 @@ async function main() {
|
|
|
223
223
|
warn(`guide.md — ${e.message}`);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
// ─── Knowledge directory ─────────────────────────────────
|
|
227
|
+
log(`${WHITE}Knowledge${RESET}`);
|
|
228
|
+
const knowledgeDir = path.join(CLAUDE_DIR, "knowledge");
|
|
229
|
+
if (!fs.existsSync(knowledgeDir)) fs.mkdirSync(knowledgeDir, { recursive: true });
|
|
230
|
+
const knowledgeFiles = {
|
|
231
|
+
"learned-patterns.md": "# Learned Patterns\n\nPatterns discovered across projects. Updated by `/qualia-evolve` and manual notes.\n",
|
|
232
|
+
"common-fixes.md": "# Common Fixes\n\nRecurring issues and their solutions.\n",
|
|
233
|
+
"client-prefs.md": "# Client Preferences\n\nClient-specific preferences, design choices, and requirements.\n",
|
|
234
|
+
};
|
|
235
|
+
for (const [name, defaultContent] of Object.entries(knowledgeFiles)) {
|
|
236
|
+
const dest = path.join(knowledgeDir, name);
|
|
237
|
+
if (!fs.existsSync(dest)) {
|
|
238
|
+
fs.writeFileSync(dest, defaultContent);
|
|
239
|
+
ok(`${name} (created)`);
|
|
240
|
+
} else {
|
|
241
|
+
ok(`${name} (exists)`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ─── Save config (for update command) ──────────────────
|
|
246
|
+
const configFile = path.join(CLAUDE_DIR, ".qualia-config.json");
|
|
247
|
+
const config = {
|
|
248
|
+
code,
|
|
249
|
+
installed_by: member.name,
|
|
250
|
+
role: member.role,
|
|
251
|
+
version: require("../package.json").version,
|
|
252
|
+
installed_at: new Date().toISOString().split("T")[0],
|
|
253
|
+
};
|
|
254
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n");
|
|
255
|
+
|
|
256
|
+
// ─── ERP API key (for report uploads) ──────────────────
|
|
257
|
+
log(`${WHITE}ERP integration${RESET}`);
|
|
258
|
+
const erpKeyFile = path.join(CLAUDE_DIR, ".erp-api-key");
|
|
259
|
+
if (!fs.existsSync(erpKeyFile)) {
|
|
260
|
+
fs.writeFileSync(erpKeyFile, "qualia-claude-2026", { mode: 0o600 });
|
|
261
|
+
ok(".erp-api-key (created)");
|
|
262
|
+
} else {
|
|
263
|
+
ok(".erp-api-key (exists)");
|
|
264
|
+
}
|
|
265
|
+
|
|
226
266
|
// ─── Configure settings.json ───────────────────────────
|
|
227
267
|
console.log("");
|
|
228
268
|
log(`${WHITE}Configuring settings.json...${RESET}`);
|
|
@@ -292,6 +332,11 @@ async function main() {
|
|
|
292
332
|
{
|
|
293
333
|
matcher: "Bash",
|
|
294
334
|
hooks: [
|
|
335
|
+
{
|
|
336
|
+
type: "command",
|
|
337
|
+
command: `${hd}/auto-update.sh`,
|
|
338
|
+
timeout: 5,
|
|
339
|
+
},
|
|
295
340
|
{
|
|
296
341
|
type: "command",
|
|
297
342
|
if: "Bash(git push*)",
|
|
@@ -384,7 +429,7 @@ async function main() {
|
|
|
384
429
|
|
|
385
430
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
386
431
|
|
|
387
|
-
ok("Hooks: branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact");
|
|
432
|
+
ok("Hooks: auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact");
|
|
388
433
|
ok("Status line + spinner configured");
|
|
389
434
|
ok("Environment variables + permissions");
|
|
390
435
|
|
|
@@ -395,10 +440,11 @@ async function main() {
|
|
|
395
440
|
console.log(` ${WHITE}${member.name}${RESET} ${DIM}(${member.role})${RESET}`);
|
|
396
441
|
console.log(` Skills: ${WHITE}${skills.length}${RESET}`);
|
|
397
442
|
console.log(` Agents: ${WHITE}3${RESET} ${DIM}(planner, builder, verifier)${RESET}`);
|
|
398
|
-
console.log(` Hooks: ${WHITE}
|
|
399
|
-
console.log(` Rules: ${WHITE}
|
|
400
|
-
console.log(` Scripts: ${WHITE}1${RESET} ${DIM}(state.js)${RESET}`);
|
|
401
|
-
console.log(`
|
|
443
|
+
console.log(` Hooks: ${WHITE}7${RESET} ${DIM}(auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact)${RESET}`);
|
|
444
|
+
console.log(` Rules: ${WHITE}${fs.readdirSync(rulesDir).length}${RESET} ${DIM}(security, frontend, design-reference, deployment)${RESET}`);
|
|
445
|
+
console.log(` Scripts: ${WHITE}1${RESET} ${DIM}(state.js — state machine)${RESET}`);
|
|
446
|
+
console.log(` Knowledge: ${WHITE}3${RESET} ${DIM}(patterns, fixes, client prefs)${RESET}`);
|
|
447
|
+
console.log(` Templates: ${WHITE}${fs.readdirSync(tmplDir).length}${RESET}`);
|
|
402
448
|
console.log(` Status line: ${GREEN}✓${RESET}`);
|
|
403
449
|
console.log(` CLAUDE.md: ${GREEN}✓${RESET} ${DIM}(${member.role})${RESET}`);
|
|
404
450
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Qualia auto-update — checks once per day, updates silently in background
|
|
3
|
+
# Runs as PreToolUse hook. Cached so it's a no-op most of the time.
|
|
4
|
+
|
|
5
|
+
CLAUDE_DIR="$HOME/.claude"
|
|
6
|
+
CACHE_FILE="$CLAUDE_DIR/.qualia-last-update-check"
|
|
7
|
+
CONFIG_FILE="$CLAUDE_DIR/.qualia-config.json"
|
|
8
|
+
LOCK_FILE="$CLAUDE_DIR/.qualia-updating"
|
|
9
|
+
MAX_AGE=86400 # 24 hours in seconds
|
|
10
|
+
|
|
11
|
+
# Exit fast if recently checked (most common path — single stat call)
|
|
12
|
+
if [ -f "$CACHE_FILE" ]; then
|
|
13
|
+
LAST_CHECK=$(cat "$CACHE_FILE" 2>/dev/null || echo 0)
|
|
14
|
+
NOW=$(date +%s)
|
|
15
|
+
AGE=$((NOW - LAST_CHECK))
|
|
16
|
+
if [ "$AGE" -lt "$MAX_AGE" ]; then
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Exit if already updating
|
|
22
|
+
[ -f "$LOCK_FILE" ] && exit 0
|
|
23
|
+
|
|
24
|
+
# Update cache timestamp immediately (prevents concurrent checks)
|
|
25
|
+
date +%s > "$CACHE_FILE"
|
|
26
|
+
|
|
27
|
+
# Run the actual check + update in background so we don't block the user
|
|
28
|
+
(
|
|
29
|
+
trap 'rm -f "$LOCK_FILE"' EXIT
|
|
30
|
+
touch "$LOCK_FILE"
|
|
31
|
+
|
|
32
|
+
# Get installed version
|
|
33
|
+
INSTALLED=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$CONFIG_FILE','utf8')).version)}catch{console.log('0.0.0')}" 2>/dev/null)
|
|
34
|
+
[ -z "$INSTALLED" ] && INSTALLED="0.0.0"
|
|
35
|
+
|
|
36
|
+
# Get latest from npm (5s timeout)
|
|
37
|
+
LATEST=$(npm view qualia-framework-v2 version 2>/dev/null)
|
|
38
|
+
[ -z "$LATEST" ] && exit 0
|
|
39
|
+
|
|
40
|
+
# Compare versions
|
|
41
|
+
NEEDS_UPDATE=$(node -e "
|
|
42
|
+
const a='$LATEST'.split('.').map(Number), b='$INSTALLED'.split('.').map(Number);
|
|
43
|
+
for(let i=0;i<3;i++){if(a[i]>b[i]){console.log('yes');process.exit()}if(a[i]<b[i]){process.exit()}}
|
|
44
|
+
" 2>/dev/null)
|
|
45
|
+
|
|
46
|
+
if [ "$NEEDS_UPDATE" = "yes" ]; then
|
|
47
|
+
# Get saved install code
|
|
48
|
+
CODE=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$CONFIG_FILE','utf8')).code)}catch{}" 2>/dev/null)
|
|
49
|
+
[ -z "$CODE" ] && exit 0
|
|
50
|
+
|
|
51
|
+
# Run silent update
|
|
52
|
+
npx qualia-framework-v2@latest install <<< "$CODE" > /dev/null 2>&1
|
|
53
|
+
fi
|
|
54
|
+
) &
|
|
55
|
+
|
|
56
|
+
exit 0
|
package/package.json
CHANGED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: ["*.tsx", "*.jsx", "*.css", "*.scss"]
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Design Reference — Deep Specs
|
|
6
|
+
|
|
7
|
+
Detailed values for motion, accessibility, and responsive design. Loaded alongside `frontend.md` for frontend work.
|
|
8
|
+
|
|
9
|
+
## Motion Specification
|
|
10
|
+
|
|
11
|
+
### Duration Table
|
|
12
|
+
|
|
13
|
+
| Action | Duration | Easing | Example |
|
|
14
|
+
|--------|----------|--------|---------|
|
|
15
|
+
| Micro-feedback | 100ms | ease-out | Button press, checkbox toggle |
|
|
16
|
+
| Hover/focus | 150ms | ease-out | Color change, underline appear |
|
|
17
|
+
| Small reveal | 200ms | ease-out | Tooltip show, dropdown open |
|
|
18
|
+
| Expand/collapse | 250ms | ease-in-out | Accordion, panel slide |
|
|
19
|
+
| Page element enter | 300ms | cubic-bezier(0, 0, 0.2, 1) | Card fade-in, section reveal |
|
|
20
|
+
| Page transition | 400ms | cubic-bezier(0.4, 0, 0.2, 1) | Route change, modal open |
|
|
21
|
+
| Complex orchestration | 500–800ms | staggered | Page load sequence |
|
|
22
|
+
|
|
23
|
+
### Easing Curves (CSS)
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1); /* General movement */
|
|
27
|
+
--ease-decelerate: cubic-bezier(0, 0, 0.2, 1); /* Enter screen */
|
|
28
|
+
--ease-accelerate: cubic-bezier(0.4, 0, 1, 1); /* Exit screen */
|
|
29
|
+
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* Playful bounce */
|
|
30
|
+
--ease-smooth: cubic-bezier(0.25, 0.1, 0.25, 1); /* Subtle shift */
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Stagger Pattern
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
/* Stagger children on page load */
|
|
37
|
+
@keyframes fadeUp {
|
|
38
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
39
|
+
to { opacity: 1; transform: translateY(0); }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.stagger > * {
|
|
43
|
+
animation: fadeUp 300ms var(--ease-decelerate) both;
|
|
44
|
+
}
|
|
45
|
+
.stagger > *:nth-child(1) { animation-delay: 0ms; }
|
|
46
|
+
.stagger > *:nth-child(2) { animation-delay: 60ms; }
|
|
47
|
+
.stagger > *:nth-child(3) { animation-delay: 120ms; }
|
|
48
|
+
.stagger > *:nth-child(4) { animation-delay: 180ms; }
|
|
49
|
+
.stagger > *:nth-child(5) { animation-delay: 240ms; }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Reduced Motion
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
@media (prefers-reduced-motion: reduce) {
|
|
56
|
+
*, *::before, *::after {
|
|
57
|
+
animation-duration: 0.01ms !important;
|
|
58
|
+
animation-iteration-count: 1 !important;
|
|
59
|
+
transition-duration: 0.01ms !important;
|
|
60
|
+
scroll-behavior: auto !important;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## WCAG AA Checklist
|
|
66
|
+
|
|
67
|
+
### Perceivable
|
|
68
|
+
- [ ] All images have descriptive alt text (decorative: `alt=""` + `aria-hidden="true"`)
|
|
69
|
+
- [ ] Color contrast: 4.5:1 normal text, 3:1 large text (18px+ bold / 24px+)
|
|
70
|
+
- [ ] Color contrast: 3:1 for UI components and graphical objects
|
|
71
|
+
- [ ] Information not conveyed by color alone — icons, text, patterns as supplements
|
|
72
|
+
- [ ] Video/audio: captions or transcripts where applicable
|
|
73
|
+
- [ ] Text resizable to 200% without loss of content
|
|
74
|
+
- [ ] Content reflows at 320px viewport width (no horizontal scroll)
|
|
75
|
+
|
|
76
|
+
### Operable
|
|
77
|
+
- [ ] All functionality available via keyboard (Tab, Enter, Space, Escape, Arrows)
|
|
78
|
+
- [ ] No keyboard traps (except intentional focus traps in modals)
|
|
79
|
+
- [ ] Visible focus indicator: 2px+ ring, contrasting color, no `outline: none` without replacement
|
|
80
|
+
- [ ] Skip navigation link as first focusable element
|
|
81
|
+
- [ ] Touch targets: 44x44px minimum (48x48px recommended)
|
|
82
|
+
- [ ] No content that flashes more than 3 times per second
|
|
83
|
+
- [ ] Page titles are descriptive and unique
|
|
84
|
+
|
|
85
|
+
### Understandable
|
|
86
|
+
- [ ] Form inputs have visible labels (not placeholder-only)
|
|
87
|
+
- [ ] Error messages identify the field and describe the error
|
|
88
|
+
- [ ] Error suggestions explain how to fix the problem
|
|
89
|
+
- [ ] Required fields marked with `aria-required="true"` and visual indicator
|
|
90
|
+
- [ ] Language set: `<html lang="en">`
|
|
91
|
+
- [ ] Consistent navigation across pages
|
|
92
|
+
- [ ] No unexpected context changes on input
|
|
93
|
+
|
|
94
|
+
### Robust
|
|
95
|
+
- [ ] Valid HTML (no duplicate IDs, proper nesting)
|
|
96
|
+
- [ ] ARIA used correctly: `role`, `aria-label`, `aria-describedby`, `aria-expanded`, `aria-hidden`
|
|
97
|
+
- [ ] Dynamic content: `aria-live="polite"` for updates, `aria-live="assertive"` for errors
|
|
98
|
+
- [ ] Custom components have proper roles and keyboard interaction patterns
|
|
99
|
+
|
|
100
|
+
## Responsive Breakpoints
|
|
101
|
+
|
|
102
|
+
### Strategy: Mobile-First with Fluid Scaling
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
/* Base: mobile (320px–639px) */
|
|
106
|
+
/* sm: 640px+ — large phone / small tablet */
|
|
107
|
+
/* md: 768px+ — tablet */
|
|
108
|
+
/* lg: 1024px+ — laptop */
|
|
109
|
+
/* xl: 1280px+ — desktop */
|
|
110
|
+
/* 2xl: 1536px+ — large desktop */
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Common Patterns
|
|
114
|
+
|
|
115
|
+
| Pattern | Mobile | Tablet | Desktop |
|
|
116
|
+
|---------|--------|--------|---------|
|
|
117
|
+
| Navigation | Hamburger + drawer | Hamburger or condensed | Full horizontal |
|
|
118
|
+
| Grid | 1 column | 2 columns | 3–4 columns |
|
|
119
|
+
| Sidebar | Hidden, overlay | Collapsible | Always visible |
|
|
120
|
+
| Hero | Stacked, full-width | Stacked, padded | Side-by-side |
|
|
121
|
+
| Table | Card view or scroll | Scroll with sticky col | Full table |
|
|
122
|
+
| Modal | Full screen | Centered, 80% width | Centered, max-width |
|
|
123
|
+
| Form | Single column | Single column | Two column for long forms |
|
|
124
|
+
|
|
125
|
+
### Fluid Typography
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
/* Body */
|
|
129
|
+
font-size: clamp(1rem, 0.5rem + 1.5vw, 1.125rem);
|
|
130
|
+
|
|
131
|
+
/* H1 */
|
|
132
|
+
font-size: clamp(2rem, 1rem + 3vw, 3.75rem);
|
|
133
|
+
|
|
134
|
+
/* H2 */
|
|
135
|
+
font-size: clamp(1.5rem, 0.75rem + 2.25vw, 2.5rem);
|
|
136
|
+
|
|
137
|
+
/* H3 */
|
|
138
|
+
font-size: clamp(1.25rem, 0.75rem + 1.5vw, 1.875rem);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Fluid Spacing
|
|
142
|
+
|
|
143
|
+
```css
|
|
144
|
+
/* Section padding */
|
|
145
|
+
padding-inline: clamp(1rem, 5vw, 4rem);
|
|
146
|
+
padding-block: clamp(2rem, 8vw, 6rem);
|
|
147
|
+
|
|
148
|
+
/* Component gap */
|
|
149
|
+
gap: clamp(1rem, 3vw, 2rem);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## React/Next.js Performance (Critical)
|
|
153
|
+
|
|
154
|
+
### Priority 1: Eliminate Waterfalls
|
|
155
|
+
- Fetch data in parallel (`Promise.all`), not sequentially
|
|
156
|
+
- Use Suspense boundaries to stream content progressively
|
|
157
|
+
- Prefetch data on hover/focus for anticipated navigation
|
|
158
|
+
- Colocate data fetching with the component that needs it
|
|
159
|
+
|
|
160
|
+
### Priority 2: Bundle Size
|
|
161
|
+
- Import specific functions, not entire libraries (`import { format } from 'date-fns'`)
|
|
162
|
+
- Avoid barrel files (index.ts re-exports) — import directly from source
|
|
163
|
+
- Use `next/dynamic` for heavy components not needed on initial load
|
|
164
|
+
- Lazy-load below-fold content and non-critical features
|
|
165
|
+
|
|
166
|
+
### Priority 3: Rendering
|
|
167
|
+
- Server Components by default — only add `'use client'` when needed (state, effects, browser APIs)
|
|
168
|
+
- Avoid unnecessary `useEffect` — derive values during render when possible
|
|
169
|
+
- Use CSS `content-visibility: auto` for long scrollable lists
|
|
170
|
+
- Images: `next/image` with proper `width`/`height` to prevent layout shift
|
|
171
|
+
|
|
172
|
+
## Compound Component Patterns
|
|
173
|
+
|
|
174
|
+
When building reusable components:
|
|
175
|
+
- **No boolean prop proliferation** (`isCompact`, `showHeader`, `isRounded`) — use composition instead
|
|
176
|
+
- Compound components: `<Select>`, `<Select.Trigger>`, `<Select.Content>` with shared context
|
|
177
|
+
- Explicit variants: `<Alert.Destructive>` instead of `<Alert isDestructive>`
|
|
178
|
+
- Children over render props: `children` for composition, not `renderHeader`/`renderFooter`
|
|
179
|
+
- React 19: use `use()` instead of `useContext()`, skip `forwardRef` (ref is a regular prop)
|
package/rules/frontend.md
CHANGED
|
@@ -2,31 +2,124 @@
|
|
|
2
2
|
globs: ["*.tsx", "*.jsx", "*.css", "*.scss", "tailwind.config.*"]
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
# Frontend
|
|
5
|
+
# Frontend Design Standards
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Cohesive color palette with sharp accents
|
|
9
|
-
- CSS transitions, staggered animations
|
|
10
|
-
- Layered backgrounds, subtle gradients
|
|
11
|
-
- Avoid: card grids, generic heroes, blue-purple gradients
|
|
12
|
-
- Full-width layouts — no hardcoded 1200px/1280px caps. Use fluid widths that fill the viewport with sensible padding.
|
|
7
|
+
These are Qualia brand standards — mandatory for every frontend component. Not suggestions.
|
|
13
8
|
|
|
14
|
-
|
|
9
|
+
## Typography
|
|
10
|
+
|
|
11
|
+
**Never use:** Inter, Roboto, Arial, Helvetica, system-ui, Space Grotesk (overused by AI).
|
|
12
|
+
|
|
13
|
+
- Pair a distinctive display font with a refined body font
|
|
14
|
+
- Type scale: 12 / 14 / 16 / 18 / 20 / 24 / 30 / 36 / 48 / 60 / 72
|
|
15
|
+
- Body: 16px min, line-height 1.5–1.7
|
|
16
|
+
- Headings: line-height 1.1–1.3, letter-spacing -0.02em for large sizes
|
|
17
|
+
- Weight hierarchy: Regular (400) body, Medium (500) labels, Semibold (600) headings, Bold (700) display
|
|
18
|
+
- Prose max-width: 65ch. Everything else: fluid full-width
|
|
19
|
+
|
|
20
|
+
## Color
|
|
21
|
+
|
|
22
|
+
- Commit to a cohesive palette — define in CSS variables
|
|
23
|
+
- One dominant brand color with sharp accent for CTAs
|
|
24
|
+
- Never: blue-purple gradients, rainbow palettes, gray-on-gray
|
|
25
|
+
- Dark mode: not just inverted — rethink surfaces, reduce contrast slightly
|
|
26
|
+
- Semantic colors: success (green), warning (amber), error (red), info (blue) — always with non-color indicator too
|
|
27
|
+
- All text must meet **WCAG AA** contrast: 4.5:1 normal text, 3:1 large text (18px+ bold or 24px+)
|
|
28
|
+
|
|
29
|
+
## Layout
|
|
30
|
+
|
|
31
|
+
- Full-width layouts — no hardcoded `max-width: 1200px` or `1280px` caps
|
|
32
|
+
- Fluid padding: `clamp(1rem, 5vw, 4rem)` for horizontal, generous vertical
|
|
33
|
+
- 8px spacing grid: 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96
|
|
34
|
+
- Tight spacing within groups, generous between sections
|
|
35
|
+
- Asymmetry > symmetry. Overlap, diagonal flow, grid-breaking elements when appropriate
|
|
36
|
+
- No card grids — use varied layouts with visual hierarchy
|
|
37
|
+
- No generic hero sections — make them distinctive and purposeful
|
|
38
|
+
|
|
39
|
+
## Motion & Animation
|
|
40
|
+
|
|
41
|
+
- Hover/focus transitions: 150–200ms ease-out
|
|
42
|
+
- Expand/collapse: 200–300ms ease-in-out
|
|
43
|
+
- Page transitions: 300–500ms ease-out
|
|
44
|
+
- Staggered entrance animations: 50–80ms delay between items
|
|
45
|
+
- **Always** respect `prefers-reduced-motion: reduce` — disable non-essential animation
|
|
46
|
+
- Easing: `cubic-bezier(0.4, 0, 0.2, 1)` (standard), `cubic-bezier(0, 0, 0.2, 1)` (decelerate), `cubic-bezier(0.4, 0, 1, 1)` (accelerate)
|
|
47
|
+
- One well-orchestrated page load > scattered micro-interactions
|
|
48
|
+
- CSS-only for HTML projects, Motion library (`motion/react`) for React
|
|
49
|
+
|
|
50
|
+
## States (Every Interactive Element)
|
|
51
|
+
|
|
52
|
+
- **Loading:** Skeleton or spinner on async operations — never a blank void
|
|
53
|
+
- **Empty:** Helpful message + action when lists/data are empty — never "No results"
|
|
54
|
+
- **Error:** User-friendly message + recovery action — never raw error text
|
|
55
|
+
- **Hover:** Visual feedback within 100ms
|
|
56
|
+
- **Focus:** Visible focus ring (2px+ offset, high contrast) — never `outline: none` without replacement
|
|
57
|
+
- **Active/Pressed:** Scale down slightly or color shift
|
|
58
|
+
- **Disabled:** Reduced opacity (0.5) + `cursor: not-allowed` + `aria-disabled`
|
|
59
|
+
|
|
60
|
+
## Accessibility (WCAG AA Minimum)
|
|
61
|
+
|
|
62
|
+
- Semantic HTML: `<nav>`, `<main>`, `<article>`, `<section>`, `<aside>`, `<header>`, `<footer>` — not divs for everything
|
|
63
|
+
- Heading hierarchy: One `<h1>` per page, sequential order (no skipping h2→h4)
|
|
64
|
+
- All images: descriptive `alt` text (or `alt=""` + `aria-hidden` if decorative)
|
|
65
|
+
- All form inputs: visible `<label>` linked via `htmlFor` — not placeholder-only
|
|
66
|
+
- All interactive elements: keyboard accessible (Tab, Enter, Escape, Arrow keys)
|
|
67
|
+
- Touch targets: 44x44px minimum
|
|
68
|
+
- ARIA: use native HTML elements first. Only add ARIA when HTML semantics aren't enough
|
|
69
|
+
- Never rely solely on color to convey information — add icons, text, or patterns
|
|
70
|
+
- Skip link: `<a href="#main" class="sr-only focus:not-sr-only">` on every page
|
|
71
|
+
- Live regions: `aria-live="polite"` for dynamic content updates (toasts, form validation)
|
|
72
|
+
|
|
73
|
+
## Responsive Design
|
|
74
|
+
|
|
75
|
+
- Mobile-first: base styles for mobile, `@media (min-width)` for larger screens
|
|
76
|
+
- Breakpoints: `sm: 640px`, `md: 768px`, `lg: 1024px`, `xl: 1280px`, `2xl: 1536px`
|
|
77
|
+
- Fluid typography: `clamp(1rem, 0.5rem + 1.5vw, 1.25rem)` for body, scale up for headings
|
|
78
|
+
- Stack on mobile, expand on desktop — never force horizontal scroll
|
|
79
|
+
- Test: 320px (small phone), 375px (iPhone), 768px (tablet), 1024px (laptop), 1440px (desktop)
|
|
80
|
+
- Images: `max-width: 100%`, `height: auto`, use `srcset` for responsive images
|
|
81
|
+
- Navigation: hamburger menu on mobile, expanded on desktop
|
|
82
|
+
|
|
83
|
+
## Component Quality
|
|
84
|
+
|
|
85
|
+
- `cursor: pointer` on ALL clickable elements
|
|
86
|
+
- Smooth transitions (150–300ms) on all state changes
|
|
87
|
+
- No emoji as icons — use SVGs or icon libraries
|
|
88
|
+
- Buttons: clear visual hierarchy (primary, secondary, ghost, destructive)
|
|
89
|
+
- Inputs: visible borders, focus rings, error states with `aria-describedby`
|
|
90
|
+
- Links: distinguishable from text (underline or color + another indicator)
|
|
91
|
+
- Modals: trap focus, close on Escape, `aria-modal="true"`, restore focus on close
|
|
92
|
+
- Toast/notifications: `aria-live`, auto-dismiss with adequate time (5s+), dismissible
|
|
93
|
+
|
|
94
|
+
## Anti-Patterns (Kill on Sight)
|
|
95
|
+
|
|
96
|
+
- Card grids where every card looks identical → varied layouts
|
|
97
|
+
- Generic hero with stock photo → distinctive, purposeful hero
|
|
98
|
+
- Blue-purple gradients → brand colors
|
|
99
|
+
- Static pages with no motion → purposeful animation
|
|
100
|
+
- Fixed widths → fluid responsive
|
|
101
|
+
- Gray text on white (#999 on #fff fails WCAG) → proper contrast
|
|
102
|
+
- Placeholder text shipped to production → real content or proper empty states
|
|
103
|
+
- `outline: none` without focus replacement → visible focus indicators
|
|
104
|
+
- `div` soup → semantic HTML
|
|
105
|
+
- Hardcoded colors scattered in JSX → CSS variables or Tailwind config
|
|
106
|
+
|
|
107
|
+
## Design System Integration
|
|
108
|
+
|
|
109
|
+
If `.planning/DESIGN.md` exists in the project, it takes precedence over these defaults.
|
|
110
|
+
Read it before any frontend work. It contains project-specific: palette, typography, spacing, component patterns.
|
|
15
111
|
|
|
16
112
|
## Impeccable Design Skills (global)
|
|
17
|
-
|
|
18
|
-
- `/
|
|
19
|
-
- `/bolder` — Amplify safe/boring designs to be more striking
|
|
113
|
+
- `/polish` — Final detail pass before shipping
|
|
114
|
+
- `/bolder` — Amplify safe/boring designs
|
|
20
115
|
- `/design-quieter` — Tone down overly aggressive designs
|
|
21
|
-
- `/animate` — Add purposeful micro-interactions
|
|
116
|
+
- `/animate` — Add purposeful micro-interactions
|
|
22
117
|
- `/colorize` — Inject strategic color into monochrome UIs
|
|
23
118
|
- `/clarify` — Fix unclear UX copy, labels, error messages
|
|
24
|
-
- `/critique` — Design director-level review
|
|
119
|
+
- `/critique` — Design director-level review
|
|
25
120
|
- `/distill` — Strip unnecessary complexity
|
|
26
121
|
- `/delight` — Add memorable touches and personality
|
|
27
122
|
- `/harden` — Edge cases, overflow, i18n robustness
|
|
28
|
-
- `/onboard` — First-time user experience flows
|
|
29
|
-
- `/normalize` — Align with project design system
|
|
30
123
|
- `/responsive` — Cross-device responsive adaptation
|
|
31
124
|
|
|
32
125
|
### Recommended workflow
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qualia-learn
|
|
3
|
+
description: "Save a learning, pattern, fix, or client preference to the knowledge base. Persists across projects and sessions. Trigger on 'remember this', 'save this pattern', 'learned something', 'note for future', 'client prefers', 'qualia-learn'."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /qualia-learn — Save Knowledge
|
|
7
|
+
|
|
8
|
+
Persist learnings across projects and sessions. Saved to `~/.claude/knowledge/`.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
- `/qualia-learn` — Interactively save a learning
|
|
13
|
+
- `/qualia-learn {description}` — Save directly
|
|
14
|
+
|
|
15
|
+
## Knowledge Types
|
|
16
|
+
|
|
17
|
+
### Patterns (`learned-patterns.md`)
|
|
18
|
+
Recurring approaches that work (or don't). Architecture decisions, library choices, prompt patterns.
|
|
19
|
+
|
|
20
|
+
**Example:** "Supabase RLS policies need to be added in the same migration as the table — adding them later causes a window where data is unprotected."
|
|
21
|
+
|
|
22
|
+
### Fixes (`common-fixes.md`)
|
|
23
|
+
Problems you've solved before. Error messages and their solutions.
|
|
24
|
+
|
|
25
|
+
**Example:** "`next/font` crash on Vercel: caused by importing font in a client component that's also used server-side. Fix: move font import to layout.tsx."
|
|
26
|
+
|
|
27
|
+
### Client Prefs (`client-prefs.md`)
|
|
28
|
+
Client-specific preferences, design choices, requirements.
|
|
29
|
+
|
|
30
|
+
**Example:** "Acme Corp: prefers dark mode, hates rounded corners, logo must be SVG not PNG, primary color #FF6B00."
|
|
31
|
+
|
|
32
|
+
## Process
|
|
33
|
+
|
|
34
|
+
### 1. Classify
|
|
35
|
+
|
|
36
|
+
If description given, classify automatically. Otherwise ask:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
What did you learn?
|
|
40
|
+
1. Pattern — approach that works (or doesn't)
|
|
41
|
+
2. Fix — problem and its solution
|
|
42
|
+
3. Client preference — client-specific requirement
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Format Entry
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
### {Title} ({date})
|
|
49
|
+
**Project:** {current project name or "general"}
|
|
50
|
+
**Context:** {brief context — what you were building when you learned this}
|
|
51
|
+
|
|
52
|
+
{The learning — be specific enough that future-you understands without context}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. Append to Knowledge File
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Append to the right file
|
|
59
|
+
echo "{formatted entry}" >> ~/.claude/knowledge/{type}.md
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- Pattern → `~/.claude/knowledge/learned-patterns.md`
|
|
63
|
+
- Fix → `~/.claude/knowledge/common-fixes.md`
|
|
64
|
+
- Client pref → `~/.claude/knowledge/client-prefs.md`
|
|
65
|
+
|
|
66
|
+
### 4. Confirm
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
◆ Saved to {file}
|
|
70
|
+
"{title}"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Reading Knowledge
|
|
74
|
+
|
|
75
|
+
Skills can read knowledge files for context:
|
|
76
|
+
```bash
|
|
77
|
+
cat ~/.claude/knowledge/learned-patterns.md 2>/dev/null
|
|
78
|
+
cat ~/.claude/knowledge/common-fixes.md 2>/dev/null
|
|
79
|
+
cat ~/.claude/knowledge/client-prefs.md 2>/dev/null
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The `/qualia-debug` skill should check `common-fixes.md` before investigating.
|
|
83
|
+
The `/qualia-new` skill should check `client-prefs.md` when setting up client projects.
|
|
84
|
+
The `/qualia-plan` skill should check `learned-patterns.md` when planning phases.
|
|
@@ -223,6 +223,44 @@ Create Supabase project (via MCP or manual).
|
|
|
223
223
|
**`.planning/PROJECT.md`** — use template, fill from answers:
|
|
224
224
|
- Client, description, requirements (from features), out of scope, stack, design direction, decisions
|
|
225
225
|
|
|
226
|
+
### Step 8a. Create Design System
|
|
227
|
+
|
|
228
|
+
Generate **`.planning/DESIGN.md`** using `templates/DESIGN.md` as the template.
|
|
229
|
+
|
|
230
|
+
Fill in based on the design direction chosen in Step 3:
|
|
231
|
+
|
|
232
|
+
**Dark & Bold:**
|
|
233
|
+
- Palette: dark backgrounds (#0a0a0a, #141414), vibrant accent (teal #00d4aa, amber #f59e0b, etc.)
|
|
234
|
+
- Typography: bold display font + clean body font (e.g., "Plus Jakarta Sans" + "DM Sans")
|
|
235
|
+
- Effects: glass morphism, noise textures, glow effects
|
|
236
|
+
- Motion: expressive — staggered fades, parallax hints
|
|
237
|
+
|
|
238
|
+
**Clean & Minimal:**
|
|
239
|
+
- Palette: light backgrounds (#fafafa, #ffffff), single muted accent
|
|
240
|
+
- Typography: refined serif or geometric sans (e.g., "Outfit" + "Source Serif 4")
|
|
241
|
+
- Effects: subtle shadows, thin borders
|
|
242
|
+
- Motion: minimal — fades only, no stagger
|
|
243
|
+
|
|
244
|
+
**Colorful & Playful:**
|
|
245
|
+
- Palette: vibrant multi-color, warm backgrounds
|
|
246
|
+
- Typography: rounded friendly fonts (e.g., "Nunito" + "Quicksand")
|
|
247
|
+
- Effects: gradients, rounded shapes, illustrations
|
|
248
|
+
- Motion: expressive — bouncy spring easing, scale on hover
|
|
249
|
+
|
|
250
|
+
**Corporate / Professional:**
|
|
251
|
+
- Palette: navy/charcoal base, conservative accent (blue, green)
|
|
252
|
+
- Typography: trustworthy geometric (e.g., "Manrope" + "IBM Plex Sans")
|
|
253
|
+
- Effects: clean borders, subtle shadows, structured grids
|
|
254
|
+
- Motion: subtle — smooth fades, no bounce
|
|
255
|
+
|
|
256
|
+
**Always include in DESIGN.md:**
|
|
257
|
+
- Concrete CSS variable values (not placeholders)
|
|
258
|
+
- Google Fonts import URL
|
|
259
|
+
- Spacing scale (8px grid)
|
|
260
|
+
- Component patterns (buttons, inputs, cards)
|
|
261
|
+
- Responsive approach
|
|
262
|
+
- Anti-patterns to avoid
|
|
263
|
+
|
|
226
264
|
### Step 8b. Initialize State
|
|
227
265
|
|
|
228
266
|
```bash
|
|
@@ -14,39 +14,125 @@ Run after all feature phases are verified. Makes it look production-ready.
|
|
|
14
14
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
###
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
### 0. Load Design Context
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cat .planning/DESIGN.md 2>/dev/null || echo "NO_DESIGN"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If DESIGN.md exists → use it as the standard. If not → use Qualia defaults from `rules/frontend.md`.
|
|
24
|
+
|
|
25
|
+
Read EVERY frontend file before modifying. No blind edits.
|
|
26
|
+
|
|
27
|
+
### 1. Critique (Structured Audit)
|
|
28
|
+
|
|
29
|
+
Review the entire UI against this checklist. Check each item, note violations with file:line.
|
|
30
|
+
|
|
31
|
+
**Typography:**
|
|
32
|
+
- [ ] No generic fonts (Inter, Roboto, Arial, system-ui, Space Grotesk)
|
|
33
|
+
- [ ] Proper type scale with clear hierarchy (display → heading → body → caption)
|
|
34
|
+
- [ ] Body text: 16px+, line-height 1.5–1.7
|
|
35
|
+
- [ ] Headings: tighter line-height (1.1–1.3), negative letter-spacing for large sizes
|
|
36
|
+
- [ ] Prose max-width: 65ch
|
|
37
|
+
- [ ] Font weights used for hierarchy (Regular, Medium, Semibold, Bold)
|
|
38
|
+
|
|
39
|
+
**Color & Contrast:**
|
|
40
|
+
- [ ] Cohesive palette via CSS variables (not scattered hex values)
|
|
41
|
+
- [ ] All text passes WCAG AA contrast (4.5:1 normal, 3:1 large)
|
|
42
|
+
- [ ] CTA buttons use accent color — stand out from the page
|
|
43
|
+
- [ ] No blue-purple gradients, no rainbow palettes
|
|
44
|
+
- [ ] Dark mode: rethought surfaces (not just inverted)
|
|
45
|
+
- [ ] Semantic colors used consistently (success=green, error=red, warning=amber)
|
|
46
|
+
|
|
47
|
+
**Layout & Spacing:**
|
|
48
|
+
- [ ] Full-width fluid layouts — no hardcoded max-width caps
|
|
49
|
+
- [ ] 8px spacing grid followed consistently
|
|
50
|
+
- [ ] Tight spacing within groups, generous between sections
|
|
51
|
+
- [ ] Fluid padding: `clamp(1rem, 5vw, 4rem)` horizontal
|
|
52
|
+
- [ ] No identical card grids — varied visual hierarchy
|
|
53
|
+
- [ ] No generic heroes — purposeful, distinctive
|
|
54
|
+
|
|
55
|
+
**Interactive States:**
|
|
56
|
+
- [ ] Every button/link: hover (color shift, 150ms), focus (visible ring), active (press feedback), disabled
|
|
57
|
+
- [ ] Loading: skeleton or spinner on all async operations
|
|
58
|
+
- [ ] Empty: helpful message + action on empty lists/data
|
|
59
|
+
- [ ] Error: user-friendly message + recovery action on failed fetches
|
|
60
|
+
- [ ] Form validation: inline errors with `aria-describedby`
|
|
61
|
+
|
|
62
|
+
**Motion:**
|
|
63
|
+
- [ ] Hover/focus: 150–200ms transitions
|
|
64
|
+
- [ ] Page load: staggered entrance animations (50–80ms delay)
|
|
65
|
+
- [ ] Expand/collapse: 250ms ease-in-out
|
|
66
|
+
- [ ] `prefers-reduced-motion` respected (no animation for users who opt out)
|
|
67
|
+
- [ ] No jank: transforms and opacity only for animated properties
|
|
68
|
+
|
|
69
|
+
**Accessibility:**
|
|
70
|
+
- [ ] Semantic HTML: `nav`, `main`, `section`, `article`, `header`, `footer`
|
|
71
|
+
- [ ] One `h1` per page, sequential heading hierarchy
|
|
72
|
+
- [ ] All images: descriptive `alt` (or `alt=""` + `aria-hidden` if decorative)
|
|
73
|
+
- [ ] All form inputs: visible `<label>` with `htmlFor` — not placeholder-only
|
|
74
|
+
- [ ] All interactive elements: keyboard accessible (Tab/Enter/Escape)
|
|
75
|
+
- [ ] Touch targets: 44px minimum
|
|
76
|
+
- [ ] Skip link: `<a href="#main">` as first focusable element
|
|
77
|
+
- [ ] No `outline: none` without focus replacement
|
|
78
|
+
- [ ] `<html lang="en">` set
|
|
79
|
+
- [ ] Color not sole information carrier — icons/text as supplements
|
|
80
|
+
|
|
81
|
+
**Responsive:**
|
|
82
|
+
- [ ] Mobile-first approach (base styles for mobile, min-width breakpoints for larger)
|
|
83
|
+
- [ ] No horizontal scroll at 320px
|
|
84
|
+
- [ ] Navigation: hamburger on mobile, expanded on desktop
|
|
85
|
+
- [ ] Touch targets adequate on mobile (44px min)
|
|
86
|
+
- [ ] Fluid typography with `clamp()`
|
|
87
|
+
- [ ] Images: `max-width: 100%`, responsive srcset where needed
|
|
88
|
+
- [ ] Tables: card view or horizontal scroll on mobile
|
|
89
|
+
|
|
90
|
+
**Performance:**
|
|
91
|
+
- [ ] Server Components by default — `'use client'` only when needed
|
|
92
|
+
- [ ] Images via `next/image` with width/height
|
|
93
|
+
- [ ] No barrel file imports — direct imports from source
|
|
94
|
+
- [ ] Heavy components lazy-loaded with `next/dynamic`
|
|
95
|
+
- [ ] Data fetched in parallel, not sequentially
|
|
96
|
+
|
|
97
|
+
### 2. Fix Everything
|
|
98
|
+
|
|
99
|
+
Work through violations from the critique. Fix each category:
|
|
100
|
+
|
|
101
|
+
1. Typography first (sets the visual foundation)
|
|
102
|
+
2. Color & contrast (palette coherence)
|
|
103
|
+
3. Layout & spacing (structural fixes)
|
|
104
|
+
4. Interactive states (loading, empty, error, hover, focus)
|
|
105
|
+
5. Motion (transitions, entrance animations, reduced-motion)
|
|
106
|
+
6. Accessibility (semantic HTML, ARIA, keyboard, labels)
|
|
107
|
+
7. Responsive (mobile breakpoints, fluid sizing)
|
|
108
|
+
8. Performance (quick wins — image optimization, dynamic imports)
|
|
30
109
|
|
|
31
110
|
### 3. Harden
|
|
32
|
-
Edge cases and robustness:
|
|
33
|
-
- Empty states (no data, loading, error)
|
|
34
|
-
- Text overflow, long content
|
|
35
|
-
- Mobile responsive (check all breakpoints)
|
|
36
|
-
- Error messages (user-friendly, not technical)
|
|
37
111
|
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
112
|
+
After polish, stress-test edge cases:
|
|
113
|
+
- Long text content (overflow, truncation, word-break)
|
|
114
|
+
- Extremely long usernames or email addresses
|
|
115
|
+
- Empty data everywhere simultaneously
|
|
116
|
+
- Error state on every fetch simultaneously
|
|
117
|
+
- 320px viewport width
|
|
118
|
+
- Keyboard-only navigation through entire flow
|
|
119
|
+
- Screen reader landmarks check (semantic HTML)
|
|
120
|
+
- Right-to-left text (if i18n is planned)
|
|
121
|
+
- Slow network (loading states visible, no flash of empty content)
|
|
44
122
|
|
|
45
|
-
###
|
|
123
|
+
### 4. Verify
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx tsc --noEmit 2>&1 | head -20
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Fix any TypeScript errors before committing.
|
|
130
|
+
|
|
131
|
+
### 5. Commit & Transition
|
|
46
132
|
|
|
47
133
|
```bash
|
|
48
134
|
git add {changed files}
|
|
49
|
-
git commit -m "polish: design and UX pass"
|
|
135
|
+
git commit -m "polish: design and UX pass — typography, accessibility, responsive, states"
|
|
50
136
|
```
|
|
51
137
|
|
|
52
138
|
```bash
|
|
@@ -54,6 +140,22 @@ node ~/.claude/bin/state.js transition --to polished
|
|
|
54
140
|
```
|
|
55
141
|
Do NOT manually edit STATE.md or tracking.json — state.js handles both.
|
|
56
142
|
|
|
143
|
+
### 6. Report
|
|
144
|
+
|
|
57
145
|
```
|
|
146
|
+
◆ QUALIA ► POLISHED
|
|
147
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
148
|
+
Files modified: {N}
|
|
149
|
+
|
|
150
|
+
Typography ✓ {brief}
|
|
151
|
+
Color ✓ {brief}
|
|
152
|
+
Layout ✓ {brief}
|
|
153
|
+
States ✓ {brief}
|
|
154
|
+
Motion ✓ {brief}
|
|
155
|
+
Accessibility ✓ {brief}
|
|
156
|
+
Responsive ✓ {brief}
|
|
157
|
+
Performance ✓ {brief}
|
|
158
|
+
Hardening ✓ {brief}
|
|
159
|
+
|
|
58
160
|
→ Run: /qualia-ship
|
|
59
161
|
```
|
|
@@ -5,7 +5,7 @@ description: "Generate session report and commit to repo. Mandatory before clock
|
|
|
5
5
|
|
|
6
6
|
# /qualia-report — Session Report
|
|
7
7
|
|
|
8
|
-
Generate a concise report of what was done. Committed to git
|
|
8
|
+
Generate a concise report of what was done. Committed to git and uploaded to the ERP for clock-out.
|
|
9
9
|
|
|
10
10
|
## Process
|
|
11
11
|
|
|
@@ -69,7 +69,28 @@ git commit -m "report: session {YYYY-MM-DD}"
|
|
|
69
69
|
git push
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
### 5.
|
|
72
|
+
### 5. Upload to ERP
|
|
73
|
+
|
|
74
|
+
**This step is MANDATORY** — the clock-out modal requires the report to be uploaded.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
ERP_URL="https://portal.qualiasolutions.net"
|
|
78
|
+
API_KEY=$(cat ~/.claude/.erp-api-key 2>/dev/null)
|
|
79
|
+
REPORT_FILE=".planning/reports/report-{date}.md"
|
|
80
|
+
EMAIL=$(git config user.email)
|
|
81
|
+
PROJECT=$(basename $(pwd))
|
|
82
|
+
|
|
83
|
+
curl -s -X POST "$ERP_URL/api/claude/report-upload" \
|
|
84
|
+
-H "X-API-Key: $API_KEY" \
|
|
85
|
+
-F "file=@$REPORT_FILE" \
|
|
86
|
+
-F "employee_email=$EMAIL" \
|
|
87
|
+
-F "project_name=$PROJECT"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If the upload succeeds, print: "Report uploaded to ERP. You can now clock out."
|
|
91
|
+
If it fails (no API key, network error), print the error and tell the employee to ask Fawzi.
|
|
92
|
+
|
|
93
|
+
### 6. Update State
|
|
73
94
|
|
|
74
95
|
```bash
|
|
75
96
|
node ~/.claude/bin/state.js transition --to activity --notes "Session report generated"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Design System — {Project Name}
|
|
2
|
+
|
|
3
|
+
> Generated during project setup. This is the source of truth for all frontend work.
|
|
4
|
+
> Builder agents read this before writing any component. Update it as design evolves.
|
|
5
|
+
|
|
6
|
+
## Brand
|
|
7
|
+
|
|
8
|
+
- **Tone:** {dark-bold | clean-minimal | colorful-playful | corporate-professional}
|
|
9
|
+
- **Personality:** {1-2 sentences describing the feel — e.g., "Confident and technical, like a Bloomberg terminal meets a luxury brand"}
|
|
10
|
+
- **Industry:** {e.g., fintech, healthcare, SaaS, e-commerce}
|
|
11
|
+
|
|
12
|
+
## Color System
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
:root {
|
|
16
|
+
/* Primary — brand identity */
|
|
17
|
+
--color-primary: {value};
|
|
18
|
+
--color-primary-hover: {value};
|
|
19
|
+
--color-primary-subtle: {value}; /* backgrounds, badges */
|
|
20
|
+
|
|
21
|
+
/* Accent — CTAs, highlights */
|
|
22
|
+
--color-accent: {value};
|
|
23
|
+
--color-accent-hover: {value};
|
|
24
|
+
|
|
25
|
+
/* Neutral — text, borders, backgrounds */
|
|
26
|
+
--color-bg: {value};
|
|
27
|
+
--color-bg-subtle: {value}; /* cards, raised surfaces */
|
|
28
|
+
--color-bg-muted: {value}; /* disabled, secondary surfaces */
|
|
29
|
+
--color-text: {value};
|
|
30
|
+
--color-text-muted: {value}; /* secondary text */
|
|
31
|
+
--color-text-subtle: {value}; /* placeholders, hints */
|
|
32
|
+
--color-border: {value};
|
|
33
|
+
--color-border-subtle: {value};
|
|
34
|
+
|
|
35
|
+
/* Semantic */
|
|
36
|
+
--color-success: {value};
|
|
37
|
+
--color-warning: {value};
|
|
38
|
+
--color-error: {value};
|
|
39
|
+
--color-info: {value};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Dark mode overrides */
|
|
43
|
+
[data-theme="dark"] {
|
|
44
|
+
--color-bg: {value};
|
|
45
|
+
--color-bg-subtle: {value};
|
|
46
|
+
--color-text: {value};
|
|
47
|
+
/* ... override all tokens ... */
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Typography
|
|
52
|
+
|
|
53
|
+
```css
|
|
54
|
+
:root {
|
|
55
|
+
/* Font families */
|
|
56
|
+
--font-display: '{Display Font}', {fallback}; /* Hero text, page titles */
|
|
57
|
+
--font-heading: '{Heading Font}', {fallback}; /* Section headings */
|
|
58
|
+
--font-body: '{Body Font}', {fallback}; /* Paragraphs, UI text */
|
|
59
|
+
--font-mono: '{Mono Font}', monospace; /* Code, data */
|
|
60
|
+
|
|
61
|
+
/* Scale */
|
|
62
|
+
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.8rem);
|
|
63
|
+
--text-sm: clamp(0.875rem, 0.8rem + 0.4vw, 0.9rem);
|
|
64
|
+
--text-base: clamp(1rem, 0.5rem + 1.5vw, 1.125rem);
|
|
65
|
+
--text-lg: clamp(1.125rem, 0.75rem + 1.2vw, 1.25rem);
|
|
66
|
+
--text-xl: clamp(1.25rem, 0.75rem + 1.5vw, 1.5rem);
|
|
67
|
+
--text-2xl: clamp(1.5rem, 0.75rem + 2.25vw, 2rem);
|
|
68
|
+
--text-3xl: clamp(1.875rem, 1rem + 2.5vw, 2.5rem);
|
|
69
|
+
--text-4xl: clamp(2.25rem, 1rem + 3vw, 3rem);
|
|
70
|
+
--text-5xl: clamp(3rem, 1rem + 4vw, 4rem);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Google Fonts import:** `{URL}`
|
|
75
|
+
|
|
76
|
+
## Spacing Scale
|
|
77
|
+
|
|
78
|
+
Based on 8px grid: `4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96 / 128`
|
|
79
|
+
|
|
80
|
+
- **Within components:** 8–16px
|
|
81
|
+
- **Between related elements:** 16–24px
|
|
82
|
+
- **Between sections:** 48–96px
|
|
83
|
+
- **Page padding:** `clamp(1rem, 5vw, 4rem)` horizontal
|
|
84
|
+
|
|
85
|
+
## Motion
|
|
86
|
+
|
|
87
|
+
- **Approach:** {minimal | subtle | expressive}
|
|
88
|
+
- **Page load:** staggered fade-up, 60ms delay between elements
|
|
89
|
+
- **Hover/focus:** 150ms ease-out
|
|
90
|
+
- **Expand/collapse:** 250ms ease-in-out
|
|
91
|
+
- **Page transitions:** 400ms ease-out
|
|
92
|
+
- **Reduced motion:** all non-essential animations disabled
|
|
93
|
+
|
|
94
|
+
## Component Patterns
|
|
95
|
+
|
|
96
|
+
### Buttons
|
|
97
|
+
- **Primary:** solid {accent} background, white text, rounded-{radius}
|
|
98
|
+
- **Secondary:** bordered, transparent background
|
|
99
|
+
- **Ghost:** text-only, hover background
|
|
100
|
+
- **Destructive:** red variant for dangerous actions
|
|
101
|
+
- **Sizes:** sm (32px), md (40px), lg (48px)
|
|
102
|
+
|
|
103
|
+
### Inputs
|
|
104
|
+
- Border: 1px solid var(--color-border)
|
|
105
|
+
- Focus: 2px ring var(--color-primary)
|
|
106
|
+
- Error: red border + error text below with `aria-describedby`
|
|
107
|
+
- Height: 40px (md), 48px (lg)
|
|
108
|
+
|
|
109
|
+
### Cards/Surfaces
|
|
110
|
+
- Background: var(--color-bg-subtle)
|
|
111
|
+
- Border: 1px solid var(--color-border-subtle) or shadow
|
|
112
|
+
- Border-radius: {value}
|
|
113
|
+
- No identical card grids — vary layout and emphasis
|
|
114
|
+
|
|
115
|
+
## Responsive Approach
|
|
116
|
+
|
|
117
|
+
- **Strategy:** mobile-first
|
|
118
|
+
- **Primary breakpoints:** 768px (tablet), 1024px (desktop)
|
|
119
|
+
- **Navigation:** hamburger on mobile, expanded on desktop
|
|
120
|
+
- **Layout:** single column mobile → multi-column desktop
|
|
121
|
+
- **Touch targets:** 44px minimum on mobile
|
|
122
|
+
|
|
123
|
+
## Visual Effects
|
|
124
|
+
|
|
125
|
+
- {e.g., "Noise texture overlay at 3% opacity on hero sections"}
|
|
126
|
+
- {e.g., "Glass-morphism on floating elements: backdrop-blur-xl bg-white/80"}
|
|
127
|
+
- {e.g., "Gradient mesh on hero: radial-gradient from primary to transparent"}
|
|
128
|
+
- {e.g., "Decorative geometric shapes as background accents"}
|
|
129
|
+
|
|
130
|
+
## Anti-Patterns (Don't Do This)
|
|
131
|
+
|
|
132
|
+
- No Inter, Roboto, Arial, system-ui fonts
|
|
133
|
+
- No blue-purple gradients
|
|
134
|
+
- No identical card grids
|
|
135
|
+
- No generic stock-photo heroes
|
|
136
|
+
- No hardcoded max-width containers (use fluid layouts)
|
|
137
|
+
- No gray-on-gray low-contrast text
|