From 1d4dc38d06966997c04c8888446ba7c1801af203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gjermund=20H=C3=B8s=C3=B8ien=20Wiggen?= Date: Tue, 9 Jun 2026 23:07:32 +0200 Subject: [PATCH] docs: update CLAUDE.md, redesign AGENTS.md, add design-system.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CLAUDE.md: updated API endpoints, dev workflow, current stack - web/AGENTS.md: replaced auto-generated text with Tessera design rules - docs/design-system.md: new — component patterns, typography scale, color tokens, anti-patterns to avoid Ensures design consistency across all future work. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 60 ++++++++++----------- docs/design-system.md | 118 ++++++++++++++++++++++++++++++++++++++++++ web/AGENTS.md | 52 +++++++++++++++++-- 3 files changed, 193 insertions(+), 37 deletions(-) create mode 100644 docs/design-system.md diff --git a/CLAUDE.md b/CLAUDE.md index b69713d..cf8c4db 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,8 +14,10 @@ tessera/ │ ├── models/ # TypeScript types + Zod schemas │ ├── scrip/ # Scrip engine (prepare/commit two-phase) │ └── lifecycle/ # State machine validator -├── web/ # Frontend: Next.js 15 + shadcn/ui -│ └── src/app/ # App Router pages +├── web/ # Frontend: Next.js 16 + shadcn/ui +│ ├── src/app/ # App Router pages +│ ├── src/components/ # Reusable components + widgets +│ └── src/lib/ # API client + types + utils ├── drizzle/ # SQL migration files └── docs/ # Architecture + design specs ``` @@ -24,9 +26,9 @@ tessera/ **Backend:** Bun runtime, Hono web framework, Drizzle ORM, PostgreSQL 17, Zod validation, Handlebars templates, nodemailer -**Frontend:** Next.js 15 App Router, shadcn/ui (Tailwind CSS), next-themes (light/dark), React Hook Form + Zod, TanStack Table, date-fns, lucide-react icons +**Frontend:** Next.js 16 App Router (Turbopack), shadcn/ui (Tailwind CSS), next-themes, date-fns, lucide-react icons -**Fonts:** Inter (variable, with cv01+ss03 OpenType features), JetBrains Mono +**Fonts:** Inter (variable), JetBrains Mono ## Running Locally @@ -39,45 +41,47 @@ tessera/ ### Start backend ```bash cd ~/projects/tessera -cp .env.example .env # Edit DATABASE_URL to point to postgres://tessera:***@127.0.0.1:5433/tessera +cp .env.example .env npm run dev:backend # Starts API on port 9876 ``` ### Run migrations ```bash npm run db:migrate -npm run db:seed # Optional demo data for UI review -npm run db:seed:reset # Reset local app data, then recreate demo data +npm run db:seed # Demo data +npm run db:seed:reset # Reset + re-seed ``` ### Start frontend ```bash cd web -npm install # Use npm, NOT bun (bun has compatibility issues with Next.js dev server) -npm run build # Production build -npm run start # Production server on 127.0.0.1:3100 +npm install # Use npm, NOT bun +bun run dev # Dev server on 127.0.0.1:3100 (HMR) ``` -**Note:** `bun run dev` (Turbopack) has WebSocket HMR issues in this environment. Use production mode only. - ## API Endpoints -All endpoints are served by the backend on port 9876. The frontend proxies `/api/*` to the backend via `next.config.ts`. +All endpoints on port 9876. Frontend proxies `/api/*` via `next.config.ts`. | Method | Path | Description | |--------|------|-------------| | GET | /health | Health check | -| GET | /tickets | List tickets (?queue_id=&status=) | +| GET | /tickets | List tickets (?queue_id=&status=&owner_id=&team_id=&q=&limit=&cf.*=) | | POST | /tickets | Create ticket | | GET | /tickets/:id | Get ticket with custom fields | -| PATCH | /tickets/:id | Update ticket (validates lifecycle, runs scrips) | +| PATCH | /tickets/:id | Update ticket (validates lifecycle, runs scrips, returns scrip_results) | | POST | /tickets/:id/preview | Dry-run scrips for status change | | POST | /tickets/:id/comment | Add comment to ticket | | GET | /tickets/:id/transactions | List ticket transactions | -| GET/POST | /queues | List/create queues | -| GET/POST/PATCH | /scrips | CRUD scrips | -| GET/POST | /custom-fields | List/create custom fields | -| GET/POST | /lifecycles | List/create lifecycles | +| GET/POST/PATCH | /queues | CRUD queues | +| GET/POST/PATCH/DELETE | /scrips | CRUD scrips | +| GET/POST/PATCH | /custom-fields | CRUD custom fields | +| GET/POST/PATCH | /lifecycles | CRUD lifecycles | +| GET/POST/PATCH/DELETE | /users | CRUD users | +| GET/POST/PATCH/DELETE | /templates | CRUD templates + POST /preview | +| GET/POST/PATCH/DELETE | /views | CRUD saved views | +| GET/POST/PATCH/DELETE | /teams | CRUD teams + POST/DELETE members | +| GET/POST/PATCH/DELETE | /dashboards | CRUD dashboards + widgets + widget data | ## Key Design Decisions @@ -85,32 +89,22 @@ All endpoints are served by the backend on port 9876. The frontend proxies `/api - **Transaction-centric:** Every state change creates a transaction record. The scrip engine runs on transactions. - **Two-phase scrip engine:** Prepare (no side effects) then Commit (execute actions). Supports dry-run mode. - **Lifecycle state machines:** Per-queue configurable status transitions with wildcard support. -- **Light mode is default.** Dark mode available via theme toggle (next-themes). +- **SQL-level filtering:** Ticket filters (status, queue, owner, team, custom fields) pushed to PostgreSQL via Drizzle WHERE clauses. - **No ORM for frontend:** Drizzle is only on the backend. Frontend uses a typed fetch wrapper (`web/src/lib/api.ts`). +- **Dev server over production:** Use `bun run dev` (port 3100) with HMR. Build+restart only when dev server has issues. +- **Design consistency:** See `docs/design-system.md` for the design rules applied across the app. ## Git Workflow Repo: `https://git.gjermund.xyz/gjermund/tessera` -Push via HTTPS with token auth (SSH port 2222 is not configured on Gitea): ```bash git remote set-url origin https://gjermund:TOKEN@git.gjermund.xyz/gjermund/tessera.git ``` -## Development Workflow - -All code is written by **OpenCode** (AI coding agent). Hermes writes specs, OpenCode writes code, Gjermund reviews. - -OpenCode server: `opencode serve --port 4096` (Gjermund attaches with `opencode --attach http://127.0.0.1:4096`) - -After OpenCode makes changes: -1. `cd web && npx next build` — verify zero errors -2. `npm run start` — restart production server on 127.0.0.1:3100 -3. `git push` — push to origin - ## Common Issues -- **Frontend shows skeleton/blank page:** The frontend dev server (Turbopack) has WebSocket HMR issues. Use production mode (`npx next build` + `npx next start`). +- **Frontend shows skeleton/blank page:** Dev server may have HMR issues. Kill port 3100, rebuild with `npm run build`, restart with `npm run start`. - **Backend not running on 9876:** Restart with `bun run src/index.ts`. Check port with `ss -tlnp | grep 9876`. - **Database connection refused:** Docker container may be stopped. `docker start tessera-db`. - **Build errors after migration:** Run `bun run src/db/migrate.ts` to apply new migrations. diff --git a/docs/design-system.md b/docs/design-system.md new file mode 100644 index 0000000..ee14834 --- /dev/null +++ b/docs/design-system.md @@ -0,0 +1,118 @@ +# Tessera Design System + +The app follows a clean, minimal aesthetic — no heavy borders, no unnecessary shadows, flat hierarchy. + +## Principles + +1. **Flat, not boxed.** Avoid bordered containers around every section. Use whitespace for separation. +2. **Soft borders.** Never full-opacity borders. Always `/50` or `/30`. +3. **No shadows.** Cards and sections don't need shadows. The sidebar has the only subtle shadow. +4. **Consistent typography.** Three font sizes: labels (10px), content (12-13px), headings (14-24px). +5. **Dimmed by default.** Icons, borders, and secondary text start dimmed. They brighten on hover/focus. + +## Component Patterns + +### Section Wrapper +```tsx +
+ ... +
+``` + +### Section Header / Title Bar +```tsx +
+

Title

+ +
+``` + +### List Item (clickable) +```tsx + +``` + +### Property Row (key-value) +```tsx +
+ Label + Value +
+``` + +### Sidebar Nav Item +```tsx + + + {label} + +``` + +### Section Label (small caps) +```tsx +
+ LABEL +
+``` + +### Form Input +```tsx + +``` + +### Form Select +```tsx + +``` + +## Typography Scale + +| Size | Weight | Use | +|------|--------|-----| +| `text-[10px]` | `font-medium` | Section labels, form labels | +| `text-[11px]` | `font-medium` | Meta, timestamps, badges | +| `text-[13px]` | `font-normal` | Nav items, list items | +| `text-sm` | `font-normal` | Body, property values | +| `text-sm` | `font-semibold` | Card titles, list item names | +| `text-base` | `font-semibold` | Section headings | +| `text-lg` | `font-semibold` | Form titles | +| `text-xl` | `font-semibold` | Page headings | + +## Color Tokens + +| Token | Use | +|-------|-----| +| `border-border/50` | Section borders, card borders | +| `border-border/30` | Subtle dividers, list separators | +| `border-border/50` | Sidebar border | +| `bg-muted/20` | Section header background | +| `bg-muted/40` | Tab bar background | +| `bg-sidebar-accent` | Active nav item | +| `text-sidebar-foreground/55` | Inactive nav item | +| `text-muted-foreground/60` | Section labels | +| `text-foreground/90` | Slightly muted body text | + +## What to Avoid + +- ❌ `rounded-md` — use `rounded-lg` for cards, `rounded-md` for small elements +- ❌ `shadow-sm` or `shadow-md` on any card or section +- ❌ `bg-card/82` — use solid `bg-card` or `bg-transparent` +- ❌ `border-border` (full opacity) — always `/50` or `/30` +- ❌ `backdrop-blur` on headers +- ❌ `
`/`
`/`
` grids for property lists — use flex rows +- ❌ `text-[11px] font-semibold uppercase` — use the section label pattern +- ❌ Heavy icon usage in section headers — keep icons small (`h-3 w-3`) diff --git a/web/AGENTS.md b/web/AGENTS.md index 8bd0e39..1a886d4 100644 --- a/web/AGENTS.md +++ b/web/AGENTS.md @@ -1,5 +1,49 @@ - -# This is NOT the Next.js you know +# Tessera Design Rules -This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. - +Follow these rules when writing any frontend code. The design is clean, modern, and minimal — avoid the "2015 admin panel" look. + +## Borders +- **Never** use `border-border` (full opacity). Always `border-border/50` or `border-border/30`. +- Section dividers: `border-b border-border/50` +- Subtle item separators: `border-b border-border/30` +- Card borders: `border border-border/50` + +## Shadows +- **Never** use `shadow-sm` or `shadow-md` on cards, sections, or tabs. +- The sidebar is the only element with a shadow (subtle). +- No `bg-card/82`, no `bg-background/55` — use `bg-card` or `bg-transparent`. + +## Section wrappers +- `rounded-lg border border-border/50` — NOT `rounded-md border border-border bg-card shadow-sm` + +## List items +- `rounded-lg border border-border/50 p-3`, hover: `hover:border-primary/30 hover:bg-accent/30` +- Active: `border-primary/50 bg-primary/5` + +## Nav items (sidebar) +- Default: `text-sidebar-foreground/55`, icons at 50% opacity +- Hover: `text-sidebar-foreground hover:bg-sidebar-accent/50`, icons at 70% +- Active: `bg-sidebar-accent text-sidebar-foreground font-medium`, icons at 90% +- No inset shadow on active items + +## Typography +- Section headers: `text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60` +- No `text-[11px] font-semibold uppercase` anywhere — use the above pattern +- Body text: `text-sm` for main, `text-xs` for secondary +- Keep font sizes consistent: 10px (labels), 12-13px (content), 14px (headings) + +## Icons +- Section headers: `h-3 w-3` (not `h-4 w-4`) +- In nav items: `w-4 h-4` +- Always dimmed when inactive (opacity-50), bright when active + +## Forms +- Inputs/selects: `h-8 rounded-md border border-input bg-transparent px-2.5 text-sm` +- No `bg-card` on inputs unless inside a card +- Labels: `text-[10px] font-medium text-muted-foreground` + +## General +- No `backdrop-blur` on headers or sections +- No `bg-card/82` or `bg-background/55` — use solid colors or `bg-transparent` +- Content areas: `bg-background/80` for the main page background +- Avoid `
`/`
`/`
` grids for properties — use simple `flex justify-between` rows