feat: add new skills for coding standards, continuous learning, detail layout, form layout, project guidelines, security review, and verification loop
- Introduced coding standards for TypeScript and React in SKILL.md. - Added continuous learning skill with configuration and evaluation scripts. - Created detail layout guidelines for read-only pages. - Established form layout rules for data-entry forms. - Documented project guidelines for the frontend monorepo. - Implemented security review checklist for frontend/Electron applications. - Developed a verification loop skill for comprehensive session checks. This commit enhances the skill set available for developers, ensuring adherence to best practices and improving code quality.
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: coding-standards
|
||||
description: Coding standards for TypeScript and React in this pnpm monorepo. Use for style, immutability, React, and @repo/* import conventions.
|
||||
---
|
||||
|
||||
# Coding Standards & Best Practices
|
||||
|
||||
Standards for this TypeScript/React frontend. Not a NestJS API.
|
||||
|
||||
## Code Quality Principles
|
||||
|
||||
### 1. Readability First
|
||||
|
||||
- Code is read more than written
|
||||
- Clear variable and function names
|
||||
- Self-documenting code over comments
|
||||
- Consistent formatting
|
||||
|
||||
### 2. KISS
|
||||
|
||||
- Simplest solution that works
|
||||
- No premature optimization
|
||||
- Easy to understand over clever code
|
||||
|
||||
### 3. DRY
|
||||
|
||||
- Extract shared logic into functions or `@repo/ui` / `src/core/`
|
||||
- Do not copy-paste modules; copy `example/full-page` then change names
|
||||
|
||||
### 4. YAGNI
|
||||
|
||||
- Do not promote to `packages/` until a second app needs it
|
||||
- Start in the module; lift to `src/core/` when a second module needs it
|
||||
|
||||
## TypeScript
|
||||
|
||||
### Naming
|
||||
|
||||
```typescript
|
||||
const searchQuery = 'widget'
|
||||
const isAuthenticated = true
|
||||
|
||||
async function fetchVehicleType(id: string) {}
|
||||
function isValidCode(code: string): boolean {}
|
||||
```
|
||||
|
||||
### Immutability (CRITICAL)
|
||||
|
||||
```typescript
|
||||
const updated = { ...row, name: 'New' }
|
||||
const nextItems = [...items, newItem]
|
||||
```
|
||||
|
||||
Never mutate: no `push`, `splice`, or in-place property assignment on shared state.
|
||||
|
||||
### Errors
|
||||
|
||||
Handle failures; do not swallow. User-facing text via i18n, not raw `error.message` from HTTP.
|
||||
|
||||
### Types
|
||||
|
||||
No `any`. Prefer entity types in `domain/entities` and DTOs next to transformers.
|
||||
|
||||
## React
|
||||
|
||||
- Functional components with typed props
|
||||
- State updates via functional `setState(prev => …)`
|
||||
- Avoid nested ternaries; split into early returns
|
||||
- Lazy-load module routes from the presentation factory
|
||||
|
||||
## Imports (this repo)
|
||||
|
||||
```ts
|
||||
import { Button, Text } from '@repo/ui/components'
|
||||
import { FieldTextInput } from '@repo/ui/form'
|
||||
import { EnterpriseModuleProvider } from '@repo/ui/foundations'
|
||||
import { compose, required } from '@repo/ui/validators'
|
||||
import { createHttpClient } from '@repo/core-api/http-client'
|
||||
import { CommonRemoteDataServices } from '@repo/core-api/data-services'
|
||||
```
|
||||
|
||||
Do not import `@mantine/core` or axios in `apps/web` feature code.
|
||||
|
||||
## Validation
|
||||
|
||||
Zod + `@repo/ui/validators` (`compose`, `required`, `rangeLength`). No class-validator DTOs.
|
||||
|
||||
## File layout
|
||||
|
||||
- Web features: `apps/web/src/apps/main/modules/<group>/<feature>/` with `data/`, `domain/`, `presentation/`
|
||||
- Shared in one app: `apps/web/src/core/`
|
||||
- Shared across apps: `packages/`
|
||||
|
||||
Files: 200–400 lines typical, 800 max. Functions under ~50 lines.
|
||||
|
||||
## Performance
|
||||
|
||||
- `useMemo` / `useCallback` only when measured or lists are large
|
||||
- Lazy-load heavy pages
|
||||
- No N+1 UI fetches; use the module data service list endpoint
|
||||
|
||||
## Testing
|
||||
|
||||
Vitest AAA pattern. Descriptive names. See `tdd-workflow`.
|
||||
|
||||
## Code smells
|
||||
|
||||
- Functions > 50 lines — split
|
||||
- Nesting > 4 — early return
|
||||
- Magic numbers — named constants
|
||||
- `console.log` in production
|
||||
- Raw Mantine, raw axios, `import.meta.env` in components
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
name: continuous-learning
|
||||
description: Automatically extract reusable patterns from Cursor sessions and save them as learned skills for future use.
|
||||
---
|
||||
|
||||
# Continuous Learning Skill
|
||||
|
||||
Automatically evaluates Cursor sessions on end to extract reusable patterns that can be saved as learned skills.
|
||||
|
||||
## How It Works
|
||||
|
||||
This skill runs as a **sessionEnd hook** at the end of each session:
|
||||
|
||||
1. **Session Evaluation**: Checks if session has enough messages (default: 10+)
|
||||
2. **Pattern Detection**: Identifies extractable patterns from the session
|
||||
3. **Skill Extraction**: Saves useful patterns to `.agents/skills/learned/`
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit `config.json` to customize:
|
||||
|
||||
```json
|
||||
{
|
||||
"min_session_length": 10,
|
||||
"extraction_threshold": "medium",
|
||||
"auto_approve": false,
|
||||
"learned_skills_path": ".agents/skills/learned/",
|
||||
"patterns_to_detect": [
|
||||
"error_resolution",
|
||||
"user_corrections",
|
||||
"workarounds",
|
||||
"debugging_techniques",
|
||||
"project_specific"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"simple_typos",
|
||||
"one_time_fixes",
|
||||
"external_api_issues"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern Types
|
||||
|
||||
| Pattern | Description |
|
||||
|---------|-------------|
|
||||
| `error_resolution` | How specific errors were resolved |
|
||||
| `user_corrections` | Patterns from user corrections |
|
||||
| `workarounds` | Solutions to framework/library quirks |
|
||||
| `debugging_techniques` | Effective debugging approaches |
|
||||
| `project_specific` | Project-specific conventions |
|
||||
|
||||
## Hook Setup
|
||||
|
||||
Already wired in `.cursor/hooks.json` as a `sessionEnd` command:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"sessionEnd": [
|
||||
{
|
||||
"command": "node .cursor/scripts/hooks/evaluate-session.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Why Stop Hook?
|
||||
|
||||
- **Lightweight**: Runs once at session end
|
||||
- **Non-blocking**: Doesn't add latency to every message
|
||||
- **Complete context**: Has access to full session transcript
|
||||
|
||||
## Related
|
||||
|
||||
- [The Longform Guide](https://x.com/affaanmustafa/status/2014040193557471352) - Section on continuous learning
|
||||
- `/learn` command - Manual pattern extraction mid-session
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"min_session_length": 10,
|
||||
"extraction_threshold": "medium",
|
||||
"auto_approve": false,
|
||||
"learned_skills_path": ".agents/skills/learned/",
|
||||
"patterns_to_detect": [
|
||||
"error_resolution",
|
||||
"user_corrections",
|
||||
"workarounds",
|
||||
"debugging_techniques",
|
||||
"project_specific"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"simple_typos",
|
||||
"one_time_fixes",
|
||||
"external_api_issues"
|
||||
]
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
# Continuous Learning - Session Evaluator
|
||||
# Runs on sessionEnd to extract reusable patterns from Cursor sessions
|
||||
#
|
||||
# Configured in .cursor/hooks.json:
|
||||
# sessionEnd -> node .cursor/scripts/hooks/evaluate-session.js
|
||||
# This shell version is a fallback.
|
||||
#
|
||||
# Extracted skills saved to: .agents/skills/learned/
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
||||
CONFIG_FILE="$SCRIPT_DIR/config.json"
|
||||
LEARNED_SKILLS_PATH="${ROOT}/.agents/skills/learned"
|
||||
MIN_SESSION_LENGTH=10
|
||||
|
||||
# Load config if exists
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
MIN_SESSION_LENGTH=$(jq -r '.min_session_length // 10' "$CONFIG_FILE")
|
||||
configured_path=$(jq -r '.learned_skills_path // empty' "$CONFIG_FILE")
|
||||
if [ -n "$configured_path" ]; then
|
||||
LEARNED_SKILLS_PATH=$(echo "$configured_path" | sed "s|~|$HOME|")
|
||||
case "$LEARNED_SKILLS_PATH" in
|
||||
/*) ;;
|
||||
*) LEARNED_SKILLS_PATH="${ROOT}/${LEARNED_SKILLS_PATH}" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure learned skills directory exists
|
||||
mkdir -p "$LEARNED_SKILLS_PATH"
|
||||
|
||||
# Get transcript path from environment (set by Claude Code)
|
||||
transcript_path="${CLAUDE_TRANSCRIPT_PATH:-}"
|
||||
|
||||
if [ -z "$transcript_path" ] || [ ! -f "$transcript_path" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Count messages in session
|
||||
message_count=$(grep -c '"type":"user"' "$transcript_path" 2>/dev/null || echo "0")
|
||||
|
||||
# Skip short sessions
|
||||
if [ "$message_count" -lt "$MIN_SESSION_LENGTH" ]; then
|
||||
echo "[ContinuousLearning] Session too short ($message_count messages), skipping" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Signal to Claude that session should be evaluated for extractable patterns
|
||||
echo "[ContinuousLearning] Session has $message_count messages - evaluate for extractable patterns" >&2
|
||||
echo "[ContinuousLearning] Save learned skills to: $LEARNED_SKILLS_PATH" >&2
|
||||
@@ -0,0 +1,261 @@
|
||||
---
|
||||
name: detail-layout
|
||||
description: Use whenever building or editing a read-only detail / show page in the ERP project (entity detail screens, master-data detail, transaction detail, device/asset detail, contract-style detail with tabs). Governs LAYOUT ONLY — page vertical stack, identity/hero placement, section card stacking, key-value grids vs label/value rows, status metric blocks, summary multi-column blocks, workflow steppers, horizontal tabs for many data categories, embedded tables/lists, and action placement. Does not govern colors, fonts, border-radius, shadows, or other visual styling. Trigger this any time a detail page, detail section, FieldValue grid, detail tab, or related-list table on a detail page is added or restructured — including when the user says "build a detail page", "show entity data", or explicitly asks for tabs.
|
||||
---
|
||||
|
||||
# Detail Layout
|
||||
|
||||
Layout rules for **read-only detail / show pages**, derived from this project's detail references:
|
||||
|
||||
- [references/web-device-detail.png](references/web-device-detail.png) — desktop stacked section cards + key-value grid
|
||||
- [references/mobile-device-detail.png](references/mobile-device-detail.png) — narrow stacked cards + label/value rows
|
||||
- [references/web-contract-detail-tabs.png](references/web-contract-detail-tabs.png) — top summary + stepper + horizontal tabs for many categories
|
||||
|
||||
These rules are about **structure and position**, not visual style (color, weight, radius, shadows belong to the design system / `@repo/ui`, not this skill).
|
||||
|
||||
Every detail page decision should be made by walking the steps below, in order.
|
||||
|
||||
## Project chrome (do not rebuild)
|
||||
|
||||
Detail routes already render inside `EnterpriseDetailPageProvider` → `ModulePageHeader` / `CorePageContainer`. That chrome owns:
|
||||
|
||||
- Breadcrumbs
|
||||
- Page title (+ optional highlight key, e.g. code/id)
|
||||
- Status badge next to the title
|
||||
- Global page actions (Edit, Duplicate, Delete, lifecycle actions, Create)
|
||||
|
||||
**Do not** re-implement those in the detail body. This skill governs the **children** of `EnterpriseDetailPageProvider` — the detail content below the module header.
|
||||
|
||||
Optional **identity / hero** (§3) is an extra content block when the entity benefits from an avatar/image + display name stack; it is not a second page header.
|
||||
|
||||
## 1. Pick the page body mode
|
||||
|
||||
Look at **how many distinct data categories** the entity has — that decides stacked vs tabbed body:
|
||||
|
||||
| Detail type | Body mode |
|
||||
| --- | --- |
|
||||
| Few categories (≤3–4 section cards; e.g. Branch, User, simple master data) | **Stacked sections** — vertical stack of section cards under the header |
|
||||
| Many categories (>3–4 distinct groups) **or** the user explicitly asks for tabs | **Tabbed body** — keep a slim always-visible top (identity / summary / stepper), then a horizontal tab bar; each tab owns one category's content |
|
||||
| Narrow / mobile viewport | Same mode as desktop; only the **internal** key-value and status layouts collapse (§13) |
|
||||
|
||||
Once a page picks stacked vs tabbed, stay consistent — don't mix an ad-hoc tab region with an ad-hoc long scroll of the same categories.
|
||||
|
||||
**Force tabs when:**
|
||||
|
||||
1. The user prompt says to use tab(s), **or**
|
||||
2. Showing every section at once would produce a long scroll of ≥4–5 independent category cards (e.g. Basic / Attachments / Milestone / Payment / Approvals / History).
|
||||
|
||||
## 2. Vertical structure of the detail page
|
||||
|
||||
Top → bottom, never reorder:
|
||||
|
||||
1. **Module chrome** — already provided by `EnterpriseDetailPageProvider` (breadcrumbs, title, status, global actions).
|
||||
2. **Identity / hero** (optional, §3) — only when an image/avatar + primary display name is part of the entity story.
|
||||
3. **Summary block** (optional, §7) — high-level at-a-glance metadata / parties / key facts in a multi-column grid. Prefer this on tabbed pages so critical facts stay visible while tabs switch.
|
||||
4. **Workflow stepper** (optional, §8) — only for entities with a linear lifecycle.
|
||||
5. **Body** — either:
|
||||
- **Stacked:** section cards (§4) in category order, or
|
||||
- **Tabbed:** tab bar (§9) then the active tab panel (§10).
|
||||
|
||||
Gap between these major bands uses the largest rhythm gap (§12).
|
||||
|
||||
## 3. Identity / hero (optional content block)
|
||||
|
||||
Use when the entity has a meaningful visual (device photo, avatar, logo). Skip for plain master-data rows where the module header title is enough.
|
||||
|
||||
### Desktop / wide
|
||||
|
||||
Single horizontal row inside one section surface:
|
||||
|
||||
| Left | Middle (flex grow) | Right |
|
||||
| --- | --- | --- |
|
||||
| Leading media (fixed square/circle) | Title stack: primary name (+ id if not already in chrome), then one short subtitle/category line | Primary content action if it belongs to this block (usually omit — Edit lives in module chrome) |
|
||||
|
||||
- Media left-aligned; title stack left-aligned next to media; any block-level action right-aligned on the same row.
|
||||
- Do not center the hero on wide layouts.
|
||||
|
||||
### Narrow / mobile
|
||||
|
||||
Vertical centered stack: media → title → subtitle → optional full-width outline action.
|
||||
|
||||
- Center alignment is correct on narrow widths only.
|
||||
- Primary action, if shown here, is full width under the subtitle — not beside the title.
|
||||
|
||||
## 4. Section cards (category containers)
|
||||
|
||||
Every logical data group is its own section container (e.g. "Device Details", "Security & OS Details", "Documents"):
|
||||
|
||||
- Sections **stack vertically** with consistent gap (§12) — never side-by-side category cards for independent groups.
|
||||
- Inside each section, top row is a **section header band**:
|
||||
- **Left:** section title (bold text only — no input).
|
||||
- **Right (optional):** section-scoped action (e.g. "Upload a document") — text/link or secondary control, right-aligned on the same baseline as the title.
|
||||
- Body of the section is one of: key-value grid (§5), key-value list (§5), status metric row/stack (§6), embedded table (§11), or a short summary + table combo (§10).
|
||||
- One section = one job. Don't dump unrelated fields into the same card.
|
||||
|
||||
## 5. Key-value fields
|
||||
|
||||
Use `FieldValue` (or equivalent) for static metadata. Choose orientation by viewport / density:
|
||||
|
||||
### A. Label-above grid (default on desktop / wide)
|
||||
|
||||
Matches the web device-detail reference and current `SimpleGrid` + `FieldValue` usage:
|
||||
|
||||
- Multi-column grid, typically **3–5 columns** on wide (`md+`), **2** on `sm`, **1** on `base`.
|
||||
- Each cell is a vertical stack: **label on top**, **value underneath** (this is what `FieldValue` already does).
|
||||
- Fill left → right, top → bottom in reading order.
|
||||
- Prefer equal column tracks; a short leftover row leaves trailing cells empty — do not stretch the last field full width just to fill space.
|
||||
- Long free-text (address, notes) may span 2 columns or the full section width when the value would wrap awkwardly in a single track.
|
||||
|
||||
### B. Label-left / value-right rows (default on narrow / mobile)
|
||||
|
||||
Matches the mobile device-detail reference:
|
||||
|
||||
- One field per row: label left-aligned, value right-aligned.
|
||||
- Rows stack vertically inside the section; no multi-column grid on the narrow breakpoint.
|
||||
- Status-colored values and link values stay in the **value** slot (right side) — they do not move to a new row.
|
||||
|
||||
**Do not** mix A and B inside the same section at the same breakpoint. Responsive collapse (§13) switches A → B on narrow widths.
|
||||
|
||||
## 6. Status / metric blocks
|
||||
|
||||
Use when each item is a **named capability or check** with its own status (e.g. Antivirus / MDM / Encryption / OS), not a flat field list.
|
||||
|
||||
### Desktop / wide
|
||||
|
||||
Horizontal row of equal sub-blocks inside the section:
|
||||
|
||||
Each sub-block, top → bottom:
|
||||
|
||||
1. Icon + small category label (same row)
|
||||
2. Primary value (software name / version)
|
||||
3. Status badge / tag under the value
|
||||
|
||||
### Narrow / mobile
|
||||
|
||||
Same sub-blocks, stacked vertically. Inside each sub-block:
|
||||
|
||||
1. Icon + small category label (top row)
|
||||
2. Primary value on the next row, with status badge **on the same row to the right** of the value
|
||||
|
||||
Don't use this pattern for ordinary scalar fields — those stay in §5.
|
||||
|
||||
## 7. Summary multi-column block (optional, top of body)
|
||||
|
||||
Use on complex / tabbed details when several **at-a-glance groups** must stay visible above tabs (e.g. dates/value metadata | Party A | Party B):
|
||||
|
||||
- Full-width band under identity (or under module chrome if no identity).
|
||||
- **2–3 equal columns** on wide; each column is a titled group of compact key-value rows (label then value on one line, or icon + label + value).
|
||||
- Columns are peer groups, not a key-value grid of unrelated fields — if fields aren't grouped into 2–3 stories, use a normal §5 section instead.
|
||||
- Collapses to a vertical stack of the same groups on narrow widths (§13).
|
||||
|
||||
## 8. Workflow stepper (optional)
|
||||
|
||||
Only for entities with a **linear lifecycle** (Draft → Review → … → Active):
|
||||
|
||||
- Full-width band under summary (or under identity / chrome).
|
||||
- Horizontal sequence left → right; completed → current → upcoming order must match domain order.
|
||||
- Label the band with a short section title above the stepper (e.g. "Status update").
|
||||
- On narrow widths, keep sequence order; may scroll horizontally or show a compact current-step focus — never reorder stages.
|
||||
|
||||
## 9. Horizontal tabs (many-data body)
|
||||
|
||||
When §1 selects tabbed body:
|
||||
|
||||
- Tab bar sits **below** identity / summary / stepper and **above** the active panel — never above the module chrome, never below the first content card of a stacked page.
|
||||
- Tabs are a single horizontal list of category labels (Basic details, Attachments, Milestone, Payment, …).
|
||||
- One active tab at a time; switching tabs replaces the panel content — do not keep all tab panels mounted as a long scroll underneath.
|
||||
- Prefer **≤8–9** tabs; if more categories exist, merge related ones or keep rare ones behind a secondary entry inside a tab.
|
||||
- Tab labels are short nouns/phrases; order tabs by user-task frequency (overview / basics first, history last).
|
||||
- Use project `Tabs` from `@repo/ui/components` (see showcase forms demo for list/panel structure) — layout concern only: `Tabs.List` then `Tabs.Panel`s.
|
||||
|
||||
### What stays outside tabs
|
||||
|
||||
Always-visible above the tab bar (when present): identity (§3), summary (§7), stepper (§8). Do **not** put the only copy of critical status / party / date facts exclusively inside a tab if the user needs them while browsing other tabs.
|
||||
|
||||
## 10. Tab panel content
|
||||
|
||||
Each panel is laid out as if it were a small stacked detail of its own:
|
||||
|
||||
1. Optional **panel sub-header** — section title left; optional summary metrics split left/right on the same row (e.g. "Total invoice value" left, "Total estimated project value" right).
|
||||
2. Optional **visual summary** (progress bar / distribution) full width under the sub-header — position only; styling is design-system.
|
||||
3. One or more **section cards** (§4) and/or an **embedded table** (§11).
|
||||
|
||||
Do not nest a second tab bar inside a panel.
|
||||
|
||||
## 11. Embedded tables / related lists
|
||||
|
||||
For collections (documents, payment proofs, line history):
|
||||
|
||||
- Table lives inside a section card (§4).
|
||||
- Section header band: title left, section action(s) right — filters and "Add …" sit on the **right of the header**, same row as the title (or immediately under the title row if filters + primary action don't fit).
|
||||
- Column headers above rows; text/id columns left-aligned; numeric columns right-aligned; status as an inline indicator in its cell; row actions in a fixed trailing column (ellipsis / menu) — same width every row.
|
||||
- Empty state stays inside the table/section body — don't relocate the section action.
|
||||
|
||||
## 12. Vertical rhythm
|
||||
|
||||
Define three consistent gap sizes and use them the same way on every detail page:
|
||||
|
||||
1. **Label → value** (smallest): binds a field's label to its value (`FieldValue` gap).
|
||||
2. **Field → next field / sub-block → next sub-block** (medium): separates peers inside a section.
|
||||
3. **Section → section, and major band → next band** (largest): separates cards, summary, stepper, and tab bar from each other.
|
||||
|
||||
Horizontal gaps inside grids match the medium rhythm. Don't invent a fourth gap tier per page.
|
||||
|
||||
## 13. Responsive collapse
|
||||
|
||||
| Wide layout | Narrow collapse |
|
||||
| --- | --- |
|
||||
| Identity hero row (media \| title \| action) | Centered vertical stack (media → title → subtitle → full-width action) |
|
||||
| Key-value label-above grid (§5A) | Label-left / value-right rows (§5B) |
|
||||
| Status metric horizontal row (§6) | Stacked metric sub-blocks; badge beside value |
|
||||
| Summary 2–3 columns (§7) | Stacked column groups, same order |
|
||||
| Tab list | Horizontally scrollable tab list; panels still one-at-a-time |
|
||||
| Table | Horizontal scroll inside the section **or** stacked label/value per row — pick one strategy per table type and keep it project-wide |
|
||||
|
||||
Never re-pair fields into different logical groups on collapse — only column count / orientation changes.
|
||||
|
||||
## 14. Action placement (position only)
|
||||
|
||||
| Action scope | Position |
|
||||
| --- | --- |
|
||||
| Global entity actions (Edit, Delete, Activate, …) | Module header actions via `EnterpriseDetailPageProvider` — top-right of chrome |
|
||||
| Section-scoped action (Upload, Add record) | Right side of that section's header band (§4 / §11) |
|
||||
| Section filters | Right side of the table/section header, before or beside the section primary action |
|
||||
| Row action | Trailing column of that row only |
|
||||
|
||||
Do not duplicate Edit in the body if the provider already exposes it, unless a mobile identity block needs a full-width local affordance (§3 narrow).
|
||||
|
||||
## 15. Checklist before finalizing any detail page
|
||||
|
||||
- [ ] Did you choose stacked vs tabbed from category count / user request, per §1?
|
||||
- [ ] Is module chrome left to `EnterpriseDetailPageProvider` (no second breadcrumb/title/action bar)?
|
||||
- [ ] If tabbed: do identity / summary / stepper stay above the tab bar, per §9?
|
||||
- [ ] Is every category its own section card with title-left / action-right, per §4?
|
||||
- [ ] Are scalar fields using label-above grid on wide and label/value rows on narrow, per §5 / §13?
|
||||
- [ ] Are status/capability items using metric sub-blocks (§6), not mixed into a flat field grid?
|
||||
- [ ] Do related lists use header actions + table alignment rules, per §11?
|
||||
- [ ] Are global vs section vs row actions in the correct slots, per §14?
|
||||
- [ ] Does collapse preserve grouping and only change orientation/columns, per §13?
|
||||
|
||||
## Quick mapping to this codebase
|
||||
|
||||
```tsx
|
||||
// Stacked (few categories) — children of EnterpriseDetailPageProvider
|
||||
<>
|
||||
{/* optional identity */}
|
||||
<Paper>{/* section: SimpleGrid + FieldValue */}</Paper>
|
||||
<Paper>{/* section: status metrics or table */}</Paper>
|
||||
</>
|
||||
|
||||
// Tabbed (many categories / user asked for tabs)
|
||||
<>
|
||||
{/* optional identity + summary + stepper */}
|
||||
<Tabs defaultValue="basic">
|
||||
<Tabs.List>{/* category tabs */}</Tabs.List>
|
||||
<Tabs.Panel value="basic">{/* section cards */}</Tabs.Panel>
|
||||
<Tabs.Panel value="payments">{/* summary row + table */}</Tabs.Panel>
|
||||
</Tabs>
|
||||
</>
|
||||
```
|
||||
|
||||
Prefer existing primitives: `Paper` / section surfaces, `SimpleGrid`, `FieldValue`, `Tabs`, `StatusBadge`, table components from `@repo/ui` — this skill decides **where** they sit, not how they are themed.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
@@ -0,0 +1,221 @@
|
||||
# Eval Harness Skill
|
||||
|
||||
A formal evaluation framework for Claude Code sessions, implementing eval-driven development (EDD) principles.
|
||||
|
||||
## Philosophy
|
||||
|
||||
Eval-Driven Development treats evals as the "unit tests of AI development":
|
||||
- Define expected behavior BEFORE implementation
|
||||
- Run evals continuously during development
|
||||
- Track regressions with each change
|
||||
- Use pass@k metrics for reliability measurement
|
||||
|
||||
## Eval Types
|
||||
|
||||
### Capability Evals
|
||||
Test if Claude can do something it couldn't before:
|
||||
```markdown
|
||||
[CAPABILITY EVAL: feature-name]
|
||||
Task: Description of what Claude should accomplish
|
||||
Success Criteria:
|
||||
- [ ] Criterion 1
|
||||
- [ ] Criterion 2
|
||||
- [ ] Criterion 3
|
||||
Expected Output: Description of expected result
|
||||
```
|
||||
|
||||
### Regression Evals
|
||||
Ensure changes don't break existing functionality:
|
||||
```markdown
|
||||
[REGRESSION EVAL: feature-name]
|
||||
Baseline: SHA or checkpoint name
|
||||
Tests:
|
||||
- existing-test-1: PASS/FAIL
|
||||
- existing-test-2: PASS/FAIL
|
||||
- existing-test-3: PASS/FAIL
|
||||
Result: X/Y passed (previously Y/Y)
|
||||
```
|
||||
|
||||
## Grader Types
|
||||
|
||||
### 1. Code-Based Grader
|
||||
Deterministic checks using code:
|
||||
```bash
|
||||
# Check if file contains expected pattern
|
||||
grep -q "export function handleAuth" src/auth.ts && echo "PASS" || echo "FAIL"
|
||||
|
||||
# Check if tests pass
|
||||
npm test -- --testPathPattern="auth" && echo "PASS" || echo "FAIL"
|
||||
|
||||
# Check if build succeeds
|
||||
npm run build && echo "PASS" || echo "FAIL"
|
||||
```
|
||||
|
||||
### 2. Model-Based Grader
|
||||
Use Claude to evaluate open-ended outputs:
|
||||
```markdown
|
||||
[MODEL GRADER PROMPT]
|
||||
Evaluate the following code change:
|
||||
1. Does it solve the stated problem?
|
||||
2. Is it well-structured?
|
||||
3. Are edge cases handled?
|
||||
4. Is error handling appropriate?
|
||||
|
||||
Score: 1-5 (1=poor, 5=excellent)
|
||||
Reasoning: [explanation]
|
||||
```
|
||||
|
||||
### 3. Human Grader
|
||||
Flag for manual review:
|
||||
```markdown
|
||||
[HUMAN REVIEW REQUIRED]
|
||||
Change: Description of what changed
|
||||
Reason: Why human review is needed
|
||||
Risk Level: LOW/MEDIUM/HIGH
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
### pass@k
|
||||
"At least one success in k attempts"
|
||||
- pass@1: First attempt success rate
|
||||
- pass@3: Success within 3 attempts
|
||||
- Typical target: pass@3 > 90%
|
||||
|
||||
### pass^k
|
||||
"All k trials succeed"
|
||||
- Higher bar for reliability
|
||||
- pass^3: 3 consecutive successes
|
||||
- Use for critical paths
|
||||
|
||||
## Eval Workflow
|
||||
|
||||
### 1. Define (Before Coding)
|
||||
```markdown
|
||||
## EVAL DEFINITION: feature-xyz
|
||||
|
||||
### Capability Evals
|
||||
1. Can create new user account
|
||||
2. Can validate email format
|
||||
3. Can hash password securely
|
||||
|
||||
### Regression Evals
|
||||
1. Existing login still works
|
||||
2. Session management unchanged
|
||||
3. Logout flow intact
|
||||
|
||||
### Success Metrics
|
||||
- pass@3 > 90% for capability evals
|
||||
- pass^3 = 100% for regression evals
|
||||
```
|
||||
|
||||
### 2. Implement
|
||||
Write code to pass the defined evals.
|
||||
|
||||
### 3. Evaluate
|
||||
```bash
|
||||
# Run capability evals
|
||||
[Run each capability eval, record PASS/FAIL]
|
||||
|
||||
# Run regression evals
|
||||
npm test -- --testPathPattern="existing"
|
||||
|
||||
# Generate report
|
||||
```
|
||||
|
||||
### 4. Report
|
||||
```markdown
|
||||
EVAL REPORT: feature-xyz
|
||||
========================
|
||||
|
||||
Capability Evals:
|
||||
create-user: PASS (pass@1)
|
||||
validate-email: PASS (pass@2)
|
||||
hash-password: PASS (pass@1)
|
||||
Overall: 3/3 passed
|
||||
|
||||
Regression Evals:
|
||||
login-flow: PASS
|
||||
session-mgmt: PASS
|
||||
logout-flow: PASS
|
||||
Overall: 3/3 passed
|
||||
|
||||
Metrics:
|
||||
pass@1: 67% (2/3)
|
||||
pass@3: 100% (3/3)
|
||||
|
||||
Status: READY FOR REVIEW
|
||||
```
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### Pre-Implementation
|
||||
```
|
||||
/eval define feature-name
|
||||
```
|
||||
Creates eval definition file at `.cursor/evals/feature-name.md`
|
||||
|
||||
### During Implementation
|
||||
```
|
||||
/eval check feature-name
|
||||
```
|
||||
Runs current evals and reports status
|
||||
|
||||
### Post-Implementation
|
||||
```
|
||||
/eval report feature-name
|
||||
```
|
||||
Generates full eval report
|
||||
|
||||
## Eval Storage
|
||||
|
||||
Store evals in project:
|
||||
```
|
||||
.cursor/
|
||||
evals/
|
||||
feature-xyz.md # Eval definition
|
||||
feature-xyz.log # Eval run history
|
||||
baseline.json # Regression baselines
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Define evals BEFORE coding** - Forces clear thinking about success criteria
|
||||
2. **Run evals frequently** - Catch regressions early
|
||||
3. **Track pass@k over time** - Monitor reliability trends
|
||||
4. **Use code graders when possible** - Deterministic > probabilistic
|
||||
5. **Human review for security** - Never fully automate security checks
|
||||
6. **Keep evals fast** - Slow evals don't get run
|
||||
7. **Version evals with code** - Evals are first-class artifacts
|
||||
|
||||
## Example: Adding Authentication
|
||||
|
||||
```markdown
|
||||
## EVAL: add-authentication
|
||||
|
||||
### Phase 1: Define (10 min)
|
||||
Capability Evals:
|
||||
- [ ] User can register with email/password
|
||||
- [ ] User can login with valid credentials
|
||||
- [ ] Invalid credentials rejected with proper error
|
||||
- [ ] Sessions persist across page reloads
|
||||
- [ ] Logout clears session
|
||||
|
||||
Regression Evals:
|
||||
- [ ] Public routes still accessible
|
||||
- [ ] API responses unchanged
|
||||
- [ ] Database schema compatible
|
||||
|
||||
### Phase 2: Implement (varies)
|
||||
[Write code]
|
||||
|
||||
### Phase 3: Evaluate
|
||||
Run: /eval check add-authentication
|
||||
|
||||
### Phase 4: Report
|
||||
EVAL REPORT: add-authentication
|
||||
==============================
|
||||
Capability: 5/5 passed (pass@3: 100%)
|
||||
Regression: 3/3 passed (pass^3: 100%)
|
||||
Status: SHIP IT
|
||||
```
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
name: form-layout
|
||||
description: Use whenever building or editing a data-entry form in the ERP project (React/HTML forms, dialogs, wizards, settings pages, checkout-style forms, master-data screens, multi-step forms with line-item tables). Governs LAYOUT ONLY — field widths, grouping, column splits, vertical rhythm, label/input/helper placement, validation-state placement, checkbox/radio group layout, embedded data-table layout, wizard/stepper layout, and action-bar layout. Does not govern colors, fonts, border-radius, or other visual styling. Trigger this any time a new form, form section, form field, data table inside a form, or multi-step form flow is added or restructured, even if the user only says "add a field" or "build a form" without mentioning layout explicitly.
|
||||
---
|
||||
|
||||
# Form Layout
|
||||
|
||||
Layout rules for data-entry forms, derived from this project's reference forms (a checkout-style form and dense ERP entry forms — Journal Entry, Sales Invoice). These rules are about **structure and grid**, not visual style (color, weight, radius, shadows belong to the design system, not this skill).
|
||||
|
||||
Every field, group, section, table, and row decision should be made by walking the steps below, in order.
|
||||
|
||||
## 1. Pick the base grid for the form
|
||||
|
||||
Look at field count and density first — it decides the base grid for the whole form:
|
||||
|
||||
| Form type | Base grid |
|
||||
| ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Short, linear form (≤8–10 fields, e.g. checkout, a settings dialog) | Single column; multi-column rows only where §3 applies to a specific short-field group |
|
||||
| Dense ERP entry form (master data, journal entry, invoice — many fields grouped by section) | **Two-column grid by default.** Every field is placed into the left or right column of the current row. A field with no natural pair leaves the opposite column empty rather than stretching full width. |
|
||||
|
||||
Once a form picks a base grid, stay consistent — don't mix an ad-hoc single column with an ad-hoc two-column region without a section boundary between them.
|
||||
|
||||
Full-width elements (§5 section headers, §6 tables, §7 textareas, §9 compound fields) always break out of the two-column grid regardless of which base grid is active.
|
||||
|
||||
## 2. Vertical structure of one field
|
||||
|
||||
Every field is a fixed vertical stack, top to bottom, with no steps skipped or reordered:
|
||||
|
||||
1. **Label** — own line, directly above the input, tight gap, optionally suffixed with a required-marker (`*`) with no extra spacing added around it.
|
||||
2. **Input** — the control itself.
|
||||
3. **Status line** (optional, only one at a time) — sits directly under the input, same width as the input, in this priority order if multiple could apply: error message > helper/instructional text > success confirmation. Never stack more than one status line under a single field.
|
||||
|
||||
The label-to-input gap must be visibly smaller than the gap between one field's status line (or input, if no status line) and the next field's label — this is what makes fields read as self-contained units instead of a blurred list.
|
||||
|
||||
## 3. Multi-column field rows (row-level grouping)
|
||||
|
||||
Independent of the base grid (§1), some fields are grouped into one explicit row because the data itself is naturally short and multi-part:
|
||||
|
||||
- **Unequal column widths are correct when the data is unequal in length.** City/State/Zip is not three equal thirds; City is widest, State (a dropdown) is medium, Zip is narrowest. Date/Time/Date triplets (e.g. Date, Posting Time, Payment Due Date) can split evenly since each is a similarly-sized control.
|
||||
- Every field in the row keeps its own label directly above it (per §2) unless the row is a genuinely single concept sharing one collective label (e.g. "Full name" over First/Last).
|
||||
- All inputs in a row share the same height and top edge.
|
||||
- On a two-column base grid (§1), a 3+ field row spans across both grid columns as its own full-width row — don't try to cram a 3-column group into a single grid column.
|
||||
|
||||
## 4. Two-column grid mechanics (dense ERP forms)
|
||||
|
||||
When the base grid is two-column (§1):
|
||||
|
||||
- Fields are placed **in the order they'd be read**, filling left-then-right within each row, top to bottom — this is the same order screen readers and keyboard tab order should follow.
|
||||
- A field with a natural pair (e.g. Entry Type / From Template, Series / Company, Patient / Customer) sits with its pair in one row.
|
||||
- A field with no pair (e.g. a single Posting Date after Series/Company) still occupies the left column and leaves the right column of that row empty — do not stretch it to full width just to fill the space. Stretching to full width is reserved for the explicit full-width elements in §5–§9.
|
||||
- Both columns use identical widths and identical label/input/status structure (§2); only the content differs.
|
||||
- A section boundary (§5) can change the row's field pairing but the two-column mechanic continues underneath every section header.
|
||||
|
||||
## 5. Section headers
|
||||
|
||||
- A section header (e.g. "Accounting Entries", "Reference", "Printing Settings", "More Information", "Accounting Dimensions", "Customer PO Details", "Address and Contact") is bold text, full width — it spans both columns of a two-column grid, never sits inside a single column.
|
||||
- Gap above a section header uses the largest rhythm gap (§8), separating it from the previous section's last row.
|
||||
- Gap below a section header uses the label-to-input gap (§2), binding it tightly to the first row of fields it introduces.
|
||||
- A section header never has its own input — it is a pure divider/label for the group beneath it.
|
||||
|
||||
## 6. Embedded data tables (line items / entry grids)
|
||||
|
||||
Some ERP forms embed an editable table (e.g. "Accounting Entries" with Account/Party Type/Party/Debit/Credit rows). Layout rules:
|
||||
|
||||
- The table is a full-width element, breaking out of the two-column grid like a section header.
|
||||
- Column header row: short uppercase labels, left-aligned for text/identifier columns (NO., ACCOUNT, PARTY TYPE, PARTY), right-aligned for numeric columns (DEBIT, CREDIT) — numeric alignment must match the alignment of the values in the rows below it.
|
||||
- Each row: optional leading checkbox (row selection), then the data cells in the same alignment as their header, then a trailing per-row edit affordance in a fixed-width end column — the edit affordance column stays the same width on every row regardless of content length elsewhere.
|
||||
- Row-adding controls (e.g. "Add Multiple", "Add Row") sit directly below the table, left-aligned, as secondary-weight controls in their own row — not floated right, not mixed into the header row.
|
||||
- If the table has a totals/summary row (e.g. Total Debit / Total Credit), it sits in its own bounded row below the add-row controls, visually grouped with the table (same container), following the same left/right split as the action bar (§10): any secondary toggle (e.g. "Multi Currency" checkbox) on the left, the summary values on the right, right-aligned to match the numeric columns above.
|
||||
|
||||
## 7. Full-width text areas
|
||||
|
||||
- A multi-line text input (e.g. "User Remark") always spans the full form width — both columns of a two-column grid — never confined to one column's width, since its content length is unpredictable and benefits from the extra width.
|
||||
- Label sits above it per §2; no side-by-side pairing is ever applied to a textarea.
|
||||
|
||||
## 8. Vertical rhythm
|
||||
|
||||
Define three consistent gap sizes and use them the same way everywhere on the form:
|
||||
|
||||
1. **Label → input** (smallest gap): binds a label to its field.
|
||||
2. **Input → status line** (small, and reserved even when the status line is empty, so validation appearing/disappearing never shifts fields below it by more than this reserved height).
|
||||
3. **One field row/group → next field row/group, and section header → previous section** (largest gap): separates units of the form from each other.
|
||||
|
||||
This rhythm applies identically whether the base grid is single- or two-column (§1) — only the horizontal arrangement changes between the two, never the vertical spacing logic.
|
||||
|
||||
## 9. Compound fields (one logical field, many inputs)
|
||||
|
||||
Some "fields" are really one bounded control with several inputs inside it (e.g. a payment box with card number + expiry + CVV + zip all in one bordered container).
|
||||
|
||||
Use this pattern only when the sub-inputs are meaningless without each other and are always edited together:
|
||||
|
||||
- One outer container (not a row of separate fields), full width, breaking out of the two-column grid like §5–§7.
|
||||
- Sub-inputs sit in a single internal row, widths proportional to expected content — the primary value gets the majority of the width, auxiliary values get narrow fixed-width slots.
|
||||
- Status/helper text for the whole compound field goes below the container once, not below individual sub-inputs.
|
||||
- A **segmented toggle** (e.g. a Yes/No pair rendered as two adjacent buttons acting as one control, as opposed to a labeled dropdown) is a compound field of two options: it occupies one column slot in the two-column grid (paired with its own label above, per §2), same width as a normal single field in that grid position — don't let it stretch full width unless it has no pair per §4.
|
||||
|
||||
## 10. Option groups (checkboxes / radio buttons)
|
||||
|
||||
Two distinct layouts, chosen by what the options represent:
|
||||
|
||||
- **Short categorical tags/multi-select** (e.g. radio-technology checkboxes, a set of short mutually-relevant labels): lay out in a single horizontal row when there are ≤4–5 short options and the row fits the grid width; wrap to a multi-row grid if there are more. Equal, consistent spacing between options, tighter than the group-to-group gap (§8).
|
||||
- **Independent settings/preference toggles** (e.g. "Include Payment (POS)", "Is Return (Credit Note)", "Is Rate Adjustment Entry (Debit Note)"): stack vertically, one per row, each a fixed pair of control + label on one line. Use this layout whenever option labels are full phrases/sentences rather than short tags, or whenever an individual option may carry its own helper text below it (per §2's status-line pattern, scoped to that one option, indented to align under its label). Vertical stacking is also full-width, breaking out of the two-column grid.
|
||||
- In both layouts, each option is a fixed pair: control immediately followed by its label, never label-above-control.
|
||||
- A disabled option stays in its normal position (don't relocate or hide it) — position communicates "this exists but isn't available."
|
||||
|
||||
## 11. Multi-step / wizard forms
|
||||
|
||||
When a form is split into steps (e.g. Customer Details → Items & Pricing → Payments):
|
||||
|
||||
- A stepper header sits at the top of the form, showing all steps as numbered nodes connected by a line, in left-to-right sequence order. The current step is visually distinguished from completed and upcoming steps, but this skill governs only its position (top of form, spanning the width reserved for it) and order (sequence order, never reordered).
|
||||
- Only the current step's fields are shown in the body; the body underneath the stepper follows every other rule in this document (base grid, sections, tables, etc.) exactly as if it were a standalone form.
|
||||
- Step navigation controls (Back / Next, or Back / Save on the final step) sit in a footer action bar per §10-style split: Back (secondary) on the left, the forward/primary action on the right. This footer is pinned to the bottom of the form's visible area so it stays reachable regardless of how long the current step's field list scrolls.
|
||||
- Going back a step must restore that step's field values and scroll position — a layout requirement, not just a data one: don't rebuild the step from a blank layout.
|
||||
|
||||
## 12. Action bar (form footer, non-wizard)
|
||||
|
||||
- Split row: secondary/optional action (e.g. an opt-in checkbox) on one side, primary submit action on the other — don't stack them or center them together.
|
||||
- The primary action is the single visually dominant control in the row; any secondary control stays visually subordinate but does not shrink below a normal option-row size (§10).
|
||||
- This row gets the largest vertical gap (§8) above it, separating it clearly from the last field/section.
|
||||
|
||||
## 13. Validation and interaction states — placement, not color
|
||||
|
||||
State is communicated by _what's added to the layout_, not by recoloring alone:
|
||||
|
||||
- **Error**: status-icon inside the input, right-aligned, vertically centered; error message on the status line below (§2), left-aligned under the input.
|
||||
- **Success**: status-icon inside the input, right-aligned, vertically centered.
|
||||
- **Focus**: no layout change to surrounding elements — focusing a field must never shift neighboring fields, columns, or table rows.
|
||||
- **Disabled**: field/row/option stays in its original position and width; never collapsed, hidden, or resized because it's disabled.
|
||||
|
||||
## 14. Responsive collapse
|
||||
|
||||
- The two-column grid (§1, §4) collapses to a single stacked column below the defined breakpoint, left-column fields before right-column fields, in the same row order.
|
||||
- Multi-column field rows (§3) and compound fields (§9) collapse to a single stacked column, preserving left-to-right order top-to-bottom.
|
||||
- Embedded tables (§6) either scroll horizontally within their container or collapse each row into a stacked label/value list — pick one strategy per table and apply it consistently across the project, never mix per-table.
|
||||
- Option-group rows (§10) wrap to a multi-row grid before collapsing fully to one-per-line.
|
||||
- A stepper header (§11) may reduce to showing only the current step's label/number on narrow widths, but must preserve the sequence order and current-step position.
|
||||
- Never let collapse re-pair fields into different groupings than the base layout — grouping logic is fixed across breakpoints, only column count changes.
|
||||
|
||||
## Checklist before finalizing any form or new field
|
||||
|
||||
- [ ] Did you choose the base grid (single- vs two-column) from field density, per §1?
|
||||
- [ ] Does every field's width/position match its expected content and its pairing, per §1/§3/§4?
|
||||
- [ ] Are section headers, tables, textareas, and compound fields breaking out to full width, per §5–§7/§9?
|
||||
- [ ] Is every label-input-status stack using the three consistent gaps from §8?
|
||||
- [ ] Do embedded tables align numeric columns right and text columns left, with a fixed-width edit column?
|
||||
- [ ] Are table add-row controls below the table and any totals row split secondary-left/values-right?
|
||||
- [ ] Did you choose horizontal-tag vs vertical-toggle layout for each checkbox/radio group based on label length, per §10?
|
||||
- [ ] Does a wizard's stepper stay at the top, and its Back/Next footer stay pinned, per §11?
|
||||
- [ ] Do error/success states only add an icon + message, without moving neighboring fields?
|
||||
- [ ] Does the responsive layout preserve the same field groupings as the base layout, just fewer columns?
|
||||
@@ -0,0 +1,181 @@
|
||||
---
|
||||
name: project-guidelines-example
|
||||
description: Frontend monorepo guidelines for this pnpm + Turborepo React/Vite/Electron workspace. Use when scaffolding features, reviewing structure, or aligning code with this repo's conventions.
|
||||
---
|
||||
|
||||
# Project Guidelines
|
||||
|
||||
Project skill for this frontend monorepo. Architecture, file layout, patterns, testing, and scripts as they exist in the repo today.
|
||||
|
||||
## When to Use
|
||||
|
||||
Reference this skill when working on this project. It contains:
|
||||
|
||||
- Architecture overview
|
||||
- File structure
|
||||
- Code patterns
|
||||
- Testing requirements
|
||||
- Related skills
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
**Stack:**
|
||||
|
||||
- **Apps**: React 19 + Vite (`apps/web`, `apps/showcase`, `apps/landing`) + Electron (`apps/desktop`) + VitePress (`apps/docs-dev`)
|
||||
- **Packages**: `@repo/ui` (Mantine), `@repo/core-api`, `@repo/core-storage`, `@repo/core-i18n`, `@repo/core-events`, `@repo/utils`, `@repo/brand`, `packages/configs`
|
||||
- **Testing**: Vitest; Testing Library in `packages/ui` and `packages/core-events`
|
||||
- **Package manager**: pnpm 8.15.6 + Turbo
|
||||
|
||||
**Where to work:** product in `apps/web`; copy UI/API usage from `apps/showcase`; concepts from `apps/docs-dev`. Do not invent a parallel UI kit.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
.
|
||||
├── apps/
|
||||
│ ├── web/ # Product app
|
||||
│ ├── showcase/ # Living cookbook for @repo/*
|
||||
│ ├── docs-dev/ # VitePress
|
||||
│ ├── desktop/ # Electron wrapper of apps/web
|
||||
│ └── landing/ # Marketing SPA
|
||||
├── packages/
|
||||
│ ├── ui/ # @repo/ui — components, form, foundations
|
||||
│ ├── core-api/ # HTTP client + remote data services
|
||||
│ ├── core-storage/
|
||||
│ ├── core-i18n/
|
||||
│ ├── core-events/
|
||||
│ ├── utils/
|
||||
│ ├── brand/
|
||||
│ └── configs/
|
||||
└── package.json # Root scripts
|
||||
```
|
||||
|
||||
### Web module (copy `example/full-page`)
|
||||
|
||||
```
|
||||
apps/web/src/apps/main/modules/<group>/<feature>/
|
||||
data/ # *RemoteDataServices
|
||||
domain/
|
||||
constants/ # ModuleConfigEntity
|
||||
entities/
|
||||
factories/ # apiClient + service + transformer
|
||||
transformers/
|
||||
validators/ # Zod factories
|
||||
presentation/
|
||||
factory/ # registerModuleNamespace + EnterpriseModuleProvider + routes
|
||||
pages/ # index | form | detail
|
||||
components/
|
||||
store/ # optional zustand
|
||||
languages/{en,id}/
|
||||
```
|
||||
|
||||
Auth lives under `src/apps/auth/`. Shared-across-modules code lives in `src/core/`.
|
||||
|
||||
---
|
||||
|
||||
## Code Patterns
|
||||
|
||||
### Module config + factory
|
||||
|
||||
```typescript
|
||||
import { ModuleConfigEntity } from '@repo/ui/foundations'
|
||||
|
||||
export const fullPageModuleConfig: ModuleConfigEntity = {
|
||||
moduleKey: 'EXAMPLE_FULL_PAGE',
|
||||
translationNamespace: 'EXAMPLE_FULL_PAGE',
|
||||
apiUrl: '/full-page',
|
||||
webUrl: '/app/example/full-page',
|
||||
moduleCategory: 'FULL_PAGE',
|
||||
moduleType: 'MASTER_DATA',
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { EnterpriseModuleProvider } from '@repo/ui/foundations'
|
||||
import { registerModuleNamespace } from '@repo/core-i18n'
|
||||
import { apiClient } from '../../../../../../../core/lib/api-client'
|
||||
|
||||
registerModuleNamespace(fullPageModuleConfig.translationNamespace, { id, en })
|
||||
```
|
||||
|
||||
### Validators (Zod)
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
import { compose, required, rangeLength } from '@repo/ui/validators'
|
||||
|
||||
export const createFullPageSchema = (t: (key: string) => string) =>
|
||||
z.object({
|
||||
code: compose(z.string(), required(t('common:fields.code'))),
|
||||
name: compose(z.string(), required(t('common:fields.name')), rangeLength(3, 50, t('common:fields.name'))),
|
||||
})
|
||||
```
|
||||
|
||||
### Forms and HTTP
|
||||
|
||||
- Form fields: `FieldTextInput` and other `Field*` from `@repo/ui/form`
|
||||
- HTTP: `apiClient` from `src/core/lib/api-client` (built with `createHttpClient`). Never raw axios.
|
||||
- Env: `ENV` from `src/core/environment`. Files only in `apps/web/.env*`.
|
||||
|
||||
---
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
pnpm --filter web test
|
||||
pnpm --filter @repo/ui test
|
||||
pnpm typecheck:web
|
||||
pnpm check:all
|
||||
```
|
||||
|
||||
- Unit tests colocated as `*.test.ts(x)`
|
||||
- Component tests with Testing Library in packages that already have it
|
||||
- App journeys: browser-verify login and FULL_PAGE index / form / detail
|
||||
- Minimum 80% coverage; TDD (red → green → refactor)
|
||||
|
||||
---
|
||||
|
||||
## Scripts
|
||||
|
||||
```bash
|
||||
pnpm dev:web
|
||||
pnpm dev:showcase
|
||||
pnpm dev:docs-dev
|
||||
pnpm lint
|
||||
pnpm typecheck:web
|
||||
pnpm test
|
||||
pnpm check:all
|
||||
```
|
||||
|
||||
### Env (apps/web)
|
||||
|
||||
See `apps/web/.env.example`. Typical `VITE_*` keys: `VITE_APP_ENV`, `VITE_API_BASE_URL`, telemetry URLs. All `VITE_*` values are public to the client.
|
||||
|
||||
---
|
||||
|
||||
## Critical Rules
|
||||
|
||||
1. **No emojis** in code, comments, or documentation
|
||||
2. **Immutability** — never mutate objects or arrays
|
||||
3. **TDD** — tests before implementation
|
||||
4. **80% coverage** minimum
|
||||
5. **Many small files** — 200–400 lines typical, 800 max
|
||||
6. **No console.log** in production code
|
||||
7. **No raw Mantine/axios** — use `@repo/ui` and `apiClient`
|
||||
8. **Input validation** with Zod + `@repo/ui/validators`
|
||||
9. Copy `example/full-page`; do not invent a third layout
|
||||
|
||||
---
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `.agents/skills/coding-standards/` — TypeScript/React practices
|
||||
- `.agents/skills/form-layout/` — form layout
|
||||
- `.agents/skills/detail-layout/` — detail page layout
|
||||
- `.agents/skills/tdd-workflow/` — TDD
|
||||
- `.agents/skills/security-review/` — frontend/Electron security
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
name: security-review
|
||||
description: Use this skill when adding authentication, handling user input, working with secrets, or touching Electron IPC. Frontend/Electron security checklist for this SPA monorepo.
|
||||
---
|
||||
|
||||
# Security Review Skill
|
||||
|
||||
Client-side security for this React/Electron frontend. There is no NestJS API or SQL layer in this repo.
|
||||
|
||||
## When to Activate
|
||||
|
||||
- Auth or session handling
|
||||
- Forms and user input
|
||||
- Secrets / env vars
|
||||
- Electron preload / IPC
|
||||
- Rendering HTML from the server or users
|
||||
|
||||
## Checklist
|
||||
|
||||
### 1. Secrets
|
||||
|
||||
```typescript
|
||||
// NEVER
|
||||
const apiKey = "sk-proj-xxxxx"
|
||||
|
||||
// ALWAYS
|
||||
import { ENV } from '../environment'
|
||||
if (!ENV.API_BASE_URL) throw new Error('VITE_API_BASE_URL is not configured')
|
||||
```
|
||||
|
||||
- [ ] No hardcoded secrets
|
||||
- [ ] Env files only under `apps/*/.env*` (`apps/web/.env.example`)
|
||||
- [ ] Components use `ENV`, not scattered `import.meta.env`
|
||||
- [ ] Treat all `VITE_*` as public
|
||||
|
||||
### 2. Input validation
|
||||
|
||||
Zod + `@repo/ui/validators` (`compose`, `required`, `rangeLength`) on every form. File uploads: size, MIME, extension allow-lists.
|
||||
|
||||
### 3. XSS
|
||||
|
||||
- [ ] React text nodes by default
|
||||
- [ ] No unsanitized `dangerouslySetInnerHTML`
|
||||
- [ ] Sanitize if HTML is required (DOMPurify)
|
||||
|
||||
### 4. Auth
|
||||
|
||||
- [ ] HTTP only through `apiClient` (`src/core/lib/api-client`)
|
||||
- [ ] Session teardown via `terminateAuthSession`
|
||||
- [ ] Do not log tokens
|
||||
- [ ] Redirect query params encoded
|
||||
|
||||
Do not invent httpOnly-cookie APIs this SPA does not own. Token storage follows the existing `auth.helper` + storage adapters.
|
||||
|
||||
### 5. Electron (`apps/desktop`)
|
||||
|
||||
- [ ] `contextIsolation: true`
|
||||
- [ ] `nodeIntegration: false`
|
||||
- [ ] `sandbox: true`
|
||||
- [ ] No new Node APIs on `window` outside preload
|
||||
|
||||
### 6. Sensitive data
|
||||
|
||||
- [ ] No tokens or passwords in logs
|
||||
- [ ] Generic user-facing errors; details in telemetry only
|
||||
|
||||
### 7. Dependencies
|
||||
|
||||
```bash
|
||||
pnpm audit
|
||||
```
|
||||
|
||||
- [ ] Lockfile committed
|
||||
- [ ] No known high/critical issues without a documented exception
|
||||
|
||||
## Out of scope (backend)
|
||||
|
||||
Do not spend review time on SQL injection, Drizzle, CSRF-on-API-routes, or API rate limits. Flag them only if this client is clearly bypassing the API contract.
|
||||
|
||||
## Resources
|
||||
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [Electron security](https://www.electronjs.org/docs/latest/tutorial/security)
|
||||
|
||||
**Remember:** One XSS or leaked `VITE_` secret in the client is enough. Prefer the existing `apiClient` and `ENV` wrappers.
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
name: strategic-compact
|
||||
description: Suggests manual context compaction at logical intervals to preserve context through task phases rather than arbitrary auto-compaction.
|
||||
---
|
||||
|
||||
# Strategic Compact Skill
|
||||
|
||||
Suggests manual `/compact` at strategic points in your workflow rather than relying on arbitrary auto-compaction.
|
||||
|
||||
## Why Strategic Compaction?
|
||||
|
||||
Auto-compaction triggers at arbitrary points:
|
||||
- Often mid-task, losing important context
|
||||
- No awareness of logical task boundaries
|
||||
- Can interrupt complex multi-step operations
|
||||
|
||||
Strategic compaction at logical boundaries:
|
||||
- **After exploration, before execution** - Compact research context, keep implementation plan
|
||||
- **After completing a milestone** - Fresh start for next phase
|
||||
- **Before major context shifts** - Clear exploration context before different task
|
||||
|
||||
## How It Works
|
||||
|
||||
The `suggest-compact.sh` script runs on PreToolUse (Edit/Write) and:
|
||||
|
||||
1. **Tracks tool calls** - Counts tool invocations in session
|
||||
2. **Threshold detection** - Suggests at configurable threshold (default: 50 calls)
|
||||
3. **Periodic reminders** - Reminds every 25 calls after threshold
|
||||
|
||||
## Hook Setup
|
||||
|
||||
Already wired in `.cursor/hooks.json` as an `afterFileEdit` command:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"afterFileEdit": [
|
||||
{
|
||||
"command": "node .cursor/scripts/hooks/suggest-compact.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Environment variables:
|
||||
- `COMPACT_THRESHOLD` - Tool calls before first suggestion (default: 50)
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Compact after planning** - Once plan is finalized, compact to start fresh
|
||||
2. **Compact after debugging** - Clear error-resolution context before continuing
|
||||
3. **Don't compact mid-implementation** - Preserve context for related changes
|
||||
4. **Read the suggestion** - The hook tells you *when*, you decide *if*
|
||||
|
||||
## Related
|
||||
|
||||
- [The Longform Guide](https://x.com/affaanmustafa/status/2014040193557471352) - Token optimization section
|
||||
- Memory persistence hooks - For state that survives compaction
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# Strategic Compact Suggester
|
||||
# Runs on PreToolUse or periodically to suggest manual compaction at logical intervals
|
||||
#
|
||||
# Why manual over auto-compact:
|
||||
# - Auto-compact happens at arbitrary points, often mid-task
|
||||
# - Strategic compacting preserves context through logical phases
|
||||
# - Compact after exploration, before execution
|
||||
# - Compact after completing a milestone, before starting next
|
||||
#
|
||||
# Configured in .cursor/hooks.json:
|
||||
# afterFileEdit -> node .cursor/scripts/hooks/suggest-compact.js
|
||||
# This shell version is a fallback.
|
||||
#
|
||||
# Criteria for suggesting compact:
|
||||
# - Session has been running for extended period
|
||||
# - Large number of tool calls made
|
||||
# - Transitioning from research/exploration to implementation
|
||||
# - Plan has been finalized
|
||||
|
||||
# Track tool call count (increment in a temp file)
|
||||
COUNTER_FILE="/tmp/claude-tool-count-$$"
|
||||
THRESHOLD=${COMPACT_THRESHOLD:-50}
|
||||
|
||||
# Initialize or increment counter
|
||||
if [ -f "$COUNTER_FILE" ]; then
|
||||
count=$(cat "$COUNTER_FILE")
|
||||
count=$((count + 1))
|
||||
echo "$count" > "$COUNTER_FILE"
|
||||
else
|
||||
echo "1" > "$COUNTER_FILE"
|
||||
count=1
|
||||
fi
|
||||
|
||||
# Suggest compact after threshold tool calls
|
||||
if [ "$count" -eq "$THRESHOLD" ]; then
|
||||
echo "[StrategicCompact] $THRESHOLD tool calls reached - consider /compact if transitioning phases" >&2
|
||||
fi
|
||||
|
||||
# Suggest at regular intervals after threshold
|
||||
if [ "$count" -gt "$THRESHOLD" ] && [ $((count % 25)) -eq 0 ]; then
|
||||
echo "[StrategicCompact] $count tool calls - good checkpoint for /compact if context is stale" >&2
|
||||
fi
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
name: tdd-workflow
|
||||
description: Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage using Vitest, Testing Library, and browser journeys.
|
||||
---
|
||||
|
||||
# Test-Driven Development Workflow
|
||||
|
||||
TDD for this frontend monorepo (Vitest, not NestJS/Supertest).
|
||||
|
||||
## When to Activate
|
||||
|
||||
- New features or components
|
||||
- Bug fixes
|
||||
- Refactors
|
||||
- New validators, transformers, stores
|
||||
|
||||
## Core Principles
|
||||
|
||||
1. Tests BEFORE code
|
||||
2. 80% coverage (unit + component + critical journeys)
|
||||
3. Edge cases and error paths
|
||||
|
||||
### Test types
|
||||
|
||||
- **Unit** — validators, transformers, utils, stores (`*.test.ts`)
|
||||
- **Component** — Testing Library in `packages/ui` / `packages/core-events`
|
||||
- **Journeys** — login and FULL_PAGE index/form/detail; mock HTTP services; browser-verify layout
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Write the failing test (RED)
|
||||
2. `pnpm --filter web test` or `pnpm test` — must fail
|
||||
3. Minimal implementation (GREEN)
|
||||
4. Tests pass
|
||||
5. Refactor
|
||||
6. `pnpm check:all`
|
||||
|
||||
## Unit example
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { createFullPageSchema } from './full-page.validator'
|
||||
|
||||
describe('createFullPageSchema', () => {
|
||||
const t = (key: string) => key
|
||||
|
||||
it('rejects an empty code', () => {
|
||||
const result = createFullPageSchema(t).safeParse({ code: '', name: 'Widget' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## Component example
|
||||
|
||||
```tsx
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
|
||||
it('calls onClick', async () => {
|
||||
const onClick = vi.fn()
|
||||
render(<Button onClick={onClick}>Save</Button>)
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Save' }))
|
||||
expect(onClick).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
```
|
||||
|
||||
## Mocking
|
||||
|
||||
Mock `@repo/core-api` and `apiClient`, not a database.
|
||||
|
||||
```ts
|
||||
vi.mock('@repo/core-api/http-client', () => ({
|
||||
createHttpClient: () => ({ get: vi.fn(), post: vi.fn(), put: vi.fn(), delete: vi.fn() }),
|
||||
}))
|
||||
```
|
||||
|
||||
## File organization
|
||||
|
||||
Colocate `*.test.ts(x)` next to source. No `test/*.e2e-spec.ts` NestJS tree.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
pnpm --filter @repo/ui test
|
||||
pnpm --filter web test -- --watch
|
||||
pnpm lint
|
||||
```
|
||||
|
||||
## Mistakes to avoid
|
||||
|
||||
- Testing implementation details instead of behavior
|
||||
- Tests that depend on each other
|
||||
- CSS-class selectors instead of roles/labels
|
||||
- Hitting a real API in unit tests
|
||||
|
||||
## Success
|
||||
|
||||
- 80%+ coverage
|
||||
- All tests green
|
||||
- Critical FULL_PAGE flows covered or browser-verified
|
||||
@@ -0,0 +1,120 @@
|
||||
# Verification Loop Skill
|
||||
|
||||
A comprehensive verification system for Claude Code sessions.
|
||||
|
||||
## When to Use
|
||||
|
||||
Invoke this skill:
|
||||
- After completing a feature or significant code change
|
||||
- Before creating a PR
|
||||
- When you want to ensure quality gates pass
|
||||
- After refactoring
|
||||
|
||||
## Verification Phases
|
||||
|
||||
### Phase 1: Build Verification
|
||||
```bash
|
||||
# Check if project builds
|
||||
npm run build 2>&1 | tail -20
|
||||
# OR
|
||||
pnpm build 2>&1 | tail -20
|
||||
```
|
||||
|
||||
If build fails, STOP and fix before continuing.
|
||||
|
||||
### Phase 2: Type Check
|
||||
```bash
|
||||
# TypeScript projects
|
||||
npx tsc --noEmit 2>&1 | head -30
|
||||
|
||||
# Python projects
|
||||
pyright . 2>&1 | head -30
|
||||
```
|
||||
|
||||
Report all type errors. Fix critical ones before continuing.
|
||||
|
||||
### Phase 3: Lint Check
|
||||
```bash
|
||||
# JavaScript/TypeScript
|
||||
npm run lint 2>&1 | head -30
|
||||
|
||||
# Python
|
||||
ruff check . 2>&1 | head -30
|
||||
```
|
||||
|
||||
### Phase 4: Test Suite
|
||||
```bash
|
||||
# Run tests with coverage
|
||||
npm run test -- --coverage 2>&1 | tail -50
|
||||
|
||||
# Check coverage threshold
|
||||
# Target: 80% minimum
|
||||
```
|
||||
|
||||
Report:
|
||||
- Total tests: X
|
||||
- Passed: X
|
||||
- Failed: X
|
||||
- Coverage: X%
|
||||
|
||||
### Phase 5: Security Scan
|
||||
```bash
|
||||
# Check for secrets
|
||||
grep -rn "sk-" --include="*.ts" --include="*.js" . 2>/dev/null | head -10
|
||||
grep -rn "api_key" --include="*.ts" --include="*.js" . 2>/dev/null | head -10
|
||||
|
||||
# Check for console.log
|
||||
grep -rn "console.log" --include="*.ts" --include="*.tsx" src/ 2>/dev/null | head -10
|
||||
```
|
||||
|
||||
### Phase 6: Diff Review
|
||||
```bash
|
||||
# Show what changed
|
||||
git diff --stat
|
||||
git diff HEAD~1 --name-only
|
||||
```
|
||||
|
||||
Review each changed file for:
|
||||
- Unintended changes
|
||||
- Missing error handling
|
||||
- Potential edge cases
|
||||
|
||||
## Output Format
|
||||
|
||||
After running all phases, produce a verification report:
|
||||
|
||||
```
|
||||
VERIFICATION REPORT
|
||||
==================
|
||||
|
||||
Build: [PASS/FAIL]
|
||||
Types: [PASS/FAIL] (X errors)
|
||||
Lint: [PASS/FAIL] (X warnings)
|
||||
Tests: [PASS/FAIL] (X/Y passed, Z% coverage)
|
||||
Security: [PASS/FAIL] (X issues)
|
||||
Diff: [X files changed]
|
||||
|
||||
Overall: [READY/NOT READY] for PR
|
||||
|
||||
Issues to Fix:
|
||||
1. ...
|
||||
2. ...
|
||||
```
|
||||
|
||||
## Continuous Mode
|
||||
|
||||
For long sessions, run verification every 15 minutes or after major changes:
|
||||
|
||||
```markdown
|
||||
Set a mental checkpoint:
|
||||
- After completing each function
|
||||
- After finishing a component
|
||||
- Before moving to next task
|
||||
|
||||
Run: /verify
|
||||
```
|
||||
|
||||
## Integration with Hooks
|
||||
|
||||
This skill complements PostToolUse hooks but provides deeper verification.
|
||||
Hooks catch issues immediately; this skill provides comprehensive review.
|
||||
Reference in New Issue
Block a user