| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 1 | 38 | 0% |
| Commands | 0 | 0 | 39 | 0% |
| Section tags | 1 | 0 | 15 | 6% |
What each file covers
Sections
0 shared · 1 only in A · 38 only in B- − No Direct GraphQL Calls in Example Applications
- + CLAUDE.md
- + Project Overview
- + Architecture
- + Essential Commands
- + Initial setup
- + Development
- + Documentation
- + Testing
- + Code Quality
- + Building
- + Docker Services
- + Cleanup
- + Other
- + Development Workflow
- + Key Design Principles
- + Code Placement Guidelines
- + Published Packages
- + Package Decision Tree
- + packages/backend (Python - Published to PyPI)
- + ✅ Good - Generic board creation logic
- + ❌ Bad - Application-specific business rule
- + packages/frontend (React/TypeScript - Published to npm)
- + apps/baseboards (Next.js - Published via Docker)
- + packages/cli-launcher (Node.js - Published to npm)
- + Auth Packages (Published to npm)
- + Database Configuration
- + Code Quality Rules
- + Type Checking and Testing
- + Logging
- + SQLAlchemy Object Creation
- + Database Migrations: `updated_at` Triggers
- + GraphQL Schema Changes
- + 1. Remove from backend GraphQL type
- + 2. Search frontend for references
- + 3. Update all found references
- + 4. Run typecheck to catch any missed TypeScript references
- + Git Commit Policy
- + Task Management
Commands
0 shared · 0 only in A · 39 only in B- + make install
- + make docker-up
- + make dev
- + make dev-backend
- + make dev-worker
- + make dev-worker-watch
- + make dev-frontend
- + pnpm turbo dev
- + make docs
- + make dev-docs
- + make build-docs
- + make serve-docs
- + make test
- + make test-backend
- + make test-frontend
- + pnpm turbo test
- + uv run pytest tests/
- + make lint
- + make lint-backend
- + make lint-frontend
- + make typecheck
- + make typecheck-backend
- + make typecheck-frontend
- + pnpm turbo lint
- + pnpm turbo typecheck
- + make build
- + make build-backend
- + make build-frontend
- + pnpm turbo build
- + make docker-down
- + make docker-logs
- + make clean
- + make clean-backend
- + make clean-frontend
- + make help
- + turbo.json
- + git add
- + git commit
- + git push
Section tags
1 shared · 0 only in A · 15 only in B- + setup
- + build
- + test
- + lint-format
- + architecture
- + types
- + git-pr
- + security
- + dependencies
- + database
- + ui
- + monorepo
- + do-not
- + agent-behaviour
- + docs
- api
Line diff
weirdfingers/boards · .cursor/rules/no-graphql-in-examples.mdc
@@ −1 @@
1---
2globs: apps/example-*/**
3---
4
5# No Direct GraphQL Calls in Example Applications
6
7Do not make direct GraphQL calls from example applications. GraphQL usage and urql should be transparent to the example applications. Abstract away GraphQL interactions so that examples do not depend on specific client implementations like urql.
8
weirdfingers/boards · CLAUDE.md
@@ +1 @@
1# CLAUDE.md
2
3This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
5## Project Overview
6
7Boards is an open-source creative toolkit for AI-generated content (images, video, audio, text) built as a monorepo with both Python and TypeScript/JavaScript components.
8
9## Architecture
10
11**Monorepo Structure:**
12
13- `/packages/` - Shared libraries (Python backend, React frontend)
14- `/apps/` - Applications (Next.js example app, Docusaurus docs)
15- `/design/` - Architecture and design documents
16
17**Tech Stack:**
18
19- **Backend**: Python 3.12 with SQLAlchemy + Supabase (storage and optional auth)
20- **Frontend**: React + Next.js with TypeScript
21- **Job System**: Framework-agnostic queue (RQ or Dramatiq) with workers
22- **API**: GraphQL (Strawberry) with urql client; SSE for job progress
23- **Infrastructure**: PostgreSQL, Redis (via Docker Compose)
24- **Package Management**: pnpm (Node) and uv (Python)
25- **Build System**: Turborepo for orchestrating builds
26
27## Essential Commands
28
29```bash
30# Initial setup
31make install # Install all dependencies (Python and Node)
32make docker-up # Start PostgreSQL and Redis
33
34# Development
35make dev # Start all development servers (backend + frontend)
36make dev-backend # Start backend development server only
37make dev-worker # Start background worker (development)
38make dev-worker-watch # Start background worker with auto-reload (requires entr)
39make dev-frontend # Start frontend development servers only
40pnpm turbo dev # Alternative: start dev servers via Turbo
41
42# Documentation
43make docs # Start documentation development server
44make dev-docs # Start documentation development server (same as above)
45make build-docs # Build documentation for production
46make serve-docs # Serve built documentation
47
48# Testing
49make test # Run all tests (Python pytest + Node tests)
50make test-backend # Run backend (Python) tests only
51make test-frontend # Run frontend (Node) tests only
52pnpm turbo test # Run Node tests only via Turbo
53uv run pytest tests/ # Run Python tests in a specific package
54
55# Code Quality
56make lint # Run all linters (ruff, pyright for Python; ESLint for JS)
57make lint-backend # Lint backend (Python) only
58make lint-frontend # Lint frontend (Node) only
59make typecheck # Run all type checking (Python and TypeScript)
60make typecheck-backend # Typecheck backend (Python) only
61make typecheck-frontend # Typecheck frontend (TypeScript) only
62pnpm turbo lint # Run Node linters only via Turbo
63pnpm turbo typecheck # Run TypeScript checking only via Turbo
64
65# Building
66make build # Build all packages (Python and Node)
67make build-backend # Build backend (Python) only
68make build-frontend # Build frontend (Node) only
69pnpm turbo build # Build Node packages only via Turbo
70
71# Docker Services
72make docker-up # Start PostgreSQL and Redis
73make docker-down # Stop services
74make docker-logs # View service logs
75
76# Cleanup
77make clean # Remove all build artifacts and dependencies
78make clean-backend # Clean backend (Python) artifacts only
79make clean-frontend # Clean frontend (Node) artifacts only
80
81# Other
82make help # Show all available Makefile commands
83```
84
85## Development Workflow
86
871. **Python packages**: Located in `/packages/*/` with `pyproject.toml` or `setup.py`. Installed in editable mode during setup using uv.
882. **Node packages**: Managed via pnpm workspaces. Internal packages referenced as `workspace:*`.
893. **Turbo pipeline**: Configured in `turbo.json` with build dependencies and caching.
90
91## Key Design Principles
92
93- **Hooks-first frontend design**: The toolkit ships React hooks, not mandatory UI components
94- **Pluggable auth**: Support for multiple auth providers via adapters (Supabase, Clerk, Auth0, custom JWT/OIDC)
95- **Observability**: Structured logs, job metrics, audit trail on credit transactions
96- **GraphQL abstraction**: Example applications MUST NOT directly import from `urql` or GraphQL operations (e.g., `@weirdfingers/boards/graphql/operations`). All GraphQL usage must be abstracted behind hooks from `@weirdfingers/boards` (e.g., `useBoards`, `useBoard`, `useGenerators`). When adding new GraphQL functionality, create a hook in `/packages/frontend/src/hooks/` first, then use that hook in example applications.
97
98## Code Placement Guidelines
99
100**CRITICAL**: Boards is a toolkit of reusable packages, not just an application. Most code should go into published packages (`packages/`), not the application (`apps/baseboards`).
101
102### Published Packages
103
104The following packages are published to public registries:
105
106- **`packages/backend`** → PyPI (Python package for backends)
107- **`packages/frontend`** → npm as `@weirdfingers/boards` (React hooks)
108- **`packages/cli-launcher`** → npm (CLI tool for scaffolding/deployment)
109- **Auth packages** → npm as `@weirdfingers/boards-auth-*` (separate packages per provider)
110
111### Package Decision Tree
112
113**When adding new code, ask:**
114
1151. **Is this specific to the Baseboards application UI/UX?**
116
117 - YES → `apps/baseboards`
118 - NO → Continue to question 2
119
1202. **Is this reusable toolkit functionality?**
121
122 - NO → Reconsider the design
123 - YES → Continue to question 3
124
1253. **Is this backend/server-side logic?**
126
127 - YES → `packages/backend`
128 - NO → Continue to question 4
129
1304. **Is this React/frontend logic?**
131 - YES → `packages/frontend`
132 - NO → Determine appropriate package (CLI, auth, etc.)
133
134### packages/backend (Python - Published to PyPI)
135
136**SHOULD contain:**
137
138- GraphQL schema definitions (Strawberry types and resolvers)
139- SQLAlchemy models and database logic
140- Business logic and service layer
141- FastAPI/Starlette routes and middleware
142- Auth plugins/adapters (backend auth logic)
143- Job queue integration (RQ/Dramatiq workers)
144- Database migrations
145- Reusable utilities for backend development
146
147**SHOULD NOT contain:**
148
149- Application-specific business rules
150- Hardcoded configuration for specific deployments
151- Frontend-specific logic
152
153**Example:**
154
155```python
156# ✅ Good - Generic board creation logic
157@strawberry.mutation
158def create_board(self, info: Info, input: CreateBoardInput) -> Board:
159 """Create a new board - reusable across any Boards deployment"""
160 board = Boards()
161 board.title = input.title
162 board.description = input.description
163 # ... generic board creation logic
164 return board
165
166# ❌ Bad - Application-specific business rule
167@strawberry.mutation
168def create_board(self, info: Info, input: CreateBoardInput) -> Board:
169 """Create board with hardcoded Baseboards-specific limits"""
170 if user.boards_count > 10: # Hardcoded limit specific to Baseboards app
171 raise Exception("Maximum 10 boards")
172 # ...
173```
174
175### packages/frontend (React/TypeScript - Published to npm)
176
177**SHOULD contain:**
178
179- React hooks for all Boards functionality
180- GraphQL operations and fragments
181- urql client configuration and exchanges
182- TypeScript type definitions for GraphQL responses
183- Generic, unstyled React components (sparingly - favor hooks)
184- Frontend auth adapters (Supabase, Clerk integration)
185- SSE/WebSocket utilities
186- Reusable state management utilities
187
188**MUST be framework-agnostic:**
189
190- React only (no Next.js-specific code)
191- Should work with Remix, Vite, Create React App, etc.
192- No `next/router`, `next/navigation`, `next/image`, etc.
193
194**Components policy:**
195
196- Favor hooks over components
197- If shipping components, they MUST support:
198 - Arbitrary theming (no hardcoded styles)
199 - Accessibility (a11y)
200 - Internationalization (i18n)
201- When in doubt, ship a hook and let apps build their own UI
202
203**SHOULD NOT contain:**
204
205- Next.js-specific code
206- Styled/opinionated components
207- Application business logic
208- Direct imports that bypass hooks (apps importing from `/graphql/operations` directly)
209
210**Example:**
211
212```typescript
213// ✅ Good - Generic hook for any React app
214export function useBoards() {
215 const [result] = useQuery({ query: BoardsQuery });
216 return {
217 boards: result.data?.boards ?? [],
218 loading: result.fetching,
219 error: result.error,
220 };
221}
222
223// ✅ Good - Unstyled, accessible component
224export function BoardCard({ board, className, onSelect }: BoardCardProps) {
225 return (
226 <article
227 className={className}
228 role="button"
229 aria-label={board.title}
230 onClick={() => onSelect?.(board)}
231 >
232 {/* Minimal, unstyled structure */}
233 </article>
234 );
235}
236
237// ❌ Bad - Next.js-specific code
238import { useRouter } from "next/navigation";
239export function useBoards() {
240 const router = useRouter(); // Not framework-agnostic!
241 // ...
242}
243
244// ❌ Bad - Styled, opinionated component
245export function BoardCard({ board }: BoardCardProps) {
246 return (
247 <div className="bg-blue-500 rounded-lg p-4 shadow-xl">
248 {/* Hardcoded Tailwind styles - should be in app */}
249 </div>
250 );
251}
252```
253
254### apps/baseboards (Next.js - Published via Docker)
255
256**Purpose:** Baseboards serves dual roles:
257
2581. **Reference implementation** - demonstrates best practices for using the packages
2592. **Standalone application** - production-ready Boards instance deployable via Docker
260
261**SHOULD contain:**
262
263- Next.js pages, layouts, and routing
264- UI components with styling (Tailwind, Radix UI, etc.)
265- Application-specific configuration (environment variables, themes)
266- Sensible defaults that users can deploy as-is
267- Example flows demonstrating package usage
268- Generic application logic (not overly opinionated)
269
270**SHOULD import:**
271
272- Hooks from `@weirdfingers/boards`
273- Types from `@weirdfingers/boards`
274
275**SHOULD NOT import:**
276
277- Direct urql client usage (use hooks instead)
278- GraphQL operations from `@weirdfingers/boards/graphql/operations`
279- Anything that bypasses the hooks abstraction
280
281**SHOULD NOT contain:**
282
283- Reusable business logic (move to `packages/frontend` or `packages/backend`)
284- Hardcoded business rules that make it too opinionated
285- Backend logic (keep in `packages/backend`)
286
287**Philosophy:** Baseboards should be both:
288
289- Generic enough to deploy unchanged for most use cases
290- Well-structured enough to serve as a customization starting point
291
292**Example:**
293
294```typescript
295// ✅ Good - Uses hooks from the package
296import { useBoards, useCreateBoard } from "@weirdfingers/boards";
297
298export function BoardsPage() {
299 const { boards, loading } = useBoards();
300 const createBoard = useCreateBoard();
301
302 return (
303 <div className="container mx-auto">
304 {/* Baseboards-specific styled UI */}
305 {boards.map((board) => (
306 <StyledBoardCard key={board.id} board={board} />
307 ))}
308 </div>
309 );
310}
311
312// ❌ Bad - Bypasses hooks, imports GraphQL directly
313import { useQuery } from "urql";
314import { BoardsQuery } from "@weirdfingers/boards/graphql/operations";
315
316export function BoardsPage() {
317 const [result] = useQuery({ query: BoardsQuery }); // Should use useBoards() hook
318 // ...
319}
320
321// ❌ Bad - Reusable logic that should be in packages/frontend
322export function useBoardValidation() {
323 // This is generic logic that other apps would need - move to packages/frontend!
324 return { validateTitle, validateDescription };
325}
326```
327
328### packages/cli-launcher (Node.js - Published to npm)
329
330**SHOULD contain:**
331
332- CLI commands for project scaffolding
333- Docker deployment utilities
334- Development environment setup
335
336**SHOULD NOT contain:**
337
338- Application business logic
339- Backend/frontend code (import from published packages instead)
340
341### Auth Packages (Published to npm)
342
343**Available packages:**
344
345- `@weirdfingers/boards-auth-supabase` - Supabase authentication provider
346- `@weirdfingers/boards-auth-clerk` - Clerk authentication provider
347- `@weirdfingers/boards-auth-jwt` - JWT authentication provider
348- `@weirdfingers/boards-auth-auth0` (placeholder) - Auth0 authentication provider
349
350Each contains frontend auth adapter implementations for their respective providers.
351
352## Database Configuration
353
354Local development uses Docker Compose with:
355
356- PostgreSQL 15 on port 5433 (user: boards, password: boards_dev, database: boards_dev)
357- Redis 7 on port 6380
358
359## Code Quality Rules
360
361### Type Checking and Testing
362
363- To typecheck the backend and frontend, run `make typecheck` at the root of the project
364- To run tests for the backend and frontend, run `make test` at the root of the project
365
366### Logging
367
368- For backend logging, always use `@packages/backend/src/boards/logging.py` which is based on `structlog`
369- Use keyword arguments for log data, avoid f-strings
370- Never use `exc_info=True` in log statements
371
372### SQLAlchemy Object Creation
373
374**IMPORTANT**: When creating SQLAlchemy model instances, DO NOT pass properties as kwargs to the constructor. Instead, set properties explicitly after instantiation. This allows the type checker (pyright) to catch incorrect property names.
375
376**Bad** (kwargs bypass type checking):
377
378```python
379new_board = Boards(
380 tenant_id=tenant_uuid,
381 owner_id=auth_context.user_id,
382 title=input.title,
383 descritpion=input.description, # Typo won't be caught!
384)
385```
386
387**Good** (explicit assignment catches typos):
388
389```python
390new_board = Boards()
391new_board.tenant_id = tenant_uuid
392new_board.owner_id = auth_context.user_id
393new_board.title = input.title
394new_board.descritpion = input.description # Type checker will error!
395```
396
397### Database Migrations: `updated_at` Triggers
398
399All tables with an `updated_at` column have a `BEFORE UPDATE` trigger that automatically sets `updated_at = CURRENT_TIMESTAMP`. When adding a new table with an `updated_at` column, you **must** also add a trigger for it in a migration:
400
401```python
402op.execute("""
403 CREATE TRIGGER trg_<table_name>_updated_at
404 BEFORE UPDATE ON boards.<table_name>
405 FOR EACH ROW
406 EXECUTE FUNCTION boards.update_updated_at_column();
407""")
408```
409
410The shared trigger function `boards.update_updated_at_column()` already exists. Do **not** manually set `updated_at` in application code -- the trigger handles it.
411
412### GraphQL Schema Changes
413
414**CRITICAL**: When modifying GraphQL types in the backend, you MUST update the frontend in the same commit:
415
4161. **Backend changes** in `/packages/backend/src/boards/graphql/types/`:
417
418 - Update the Strawberry GraphQL type definition
419 - If removing/renaming fields, grep the frontend codebase first
420
4212. **Frontend changes** that MUST be synchronized:
422
423 - Update GraphQL fragments in `/packages/frontend/src/graphql/operations.ts`
424 - Update TypeScript interfaces in `/packages/frontend/src/hooks/`
425 - Search for any component usage in example applications
426
4273. **Validation**: GraphQL queries that reference non-existent fields will fail at schema validation (before resolver execution), returning errors like "Cannot query field 'fieldName' on type 'TypeName'". This prevents resolvers from being called.
428
429**Example workflow when removing a field**:
430
431```bash
432# 1. Remove from backend GraphQL type
433# 2. Search frontend for references
434grep -r "fieldName" packages/frontend apps/
435# 3. Update all found references
436# 4. Run typecheck to catch any missed TypeScript references
437make typecheck
438```
439
440### Git Commit Policy
441
442**IMPORTANT**: Claude Code must NEVER commit changes to git without being explicitly instructed to do so by the user.
443
444Claude Code should:
445
446- Make code changes as requested
447- Run tests and verify changes
448- Show git status and explain what files have been modified
449- Suggest commit messages if helpful
450
451But Claude Code must NOT:
452
453- Run `git add` commands
454- Run `git commit` commands
455- Run `git push` commands
456
457Unless the user explicitly asks for commits to be made.
458
459**CRITICAL**: Claude Code must NEVER push to remote repositories unless explicitly instructed to commit changes, always ask the user to push manually. This prevents accidental pushes to production or shared branches.
460
461## Task Management
462This project uses a CLI ticket system for task management. Run `tk help` when you need to use it.
463
@@ −1 +1 @@
1−---
2−globs: apps/example-*/**
3−---
1+# CLAUDE.md
42
5−# No Direct GraphQL Calls in Example Applications
3+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
64
7−Do not make direct GraphQL calls from example applications. GraphQL usage and urql should be transparent to the example applications. Abstract away GraphQL interactions so that examples do not depend on specific client implementations like urql.
5+## Project Overview
6+
7+Boards is an open-source creative toolkit for AI-generated content (images, video, audio, text) built as a monorepo with both Python and TypeScript/JavaScript components.
8+
9+## Architecture
10+
11+**Monorepo Structure:**
12+
13+- `/packages/` - Shared libraries (Python backend, React frontend)
14+- `/apps/` - Applications (Next.js example app, Docusaurus docs)
15+- `/design/` - Architecture and design documents
16+
17+**Tech Stack:**
18+
19+- **Backend**: Python 3.12 with SQLAlchemy + Supabase (storage and optional auth)
20+- **Frontend**: React + Next.js with TypeScript
21+- **Job System**: Framework-agnostic queue (RQ or Dramatiq) with workers
22+- **API**: GraphQL (Strawberry) with urql client; SSE for job progress
23+- **Infrastructure**: PostgreSQL, Redis (via Docker Compose)
24+- **Package Management**: pnpm (Node) and uv (Python)
25+- **Build System**: Turborepo for orchestrating builds
26+
27+## Essential Commands
28+
29+```bash
30+# Initial setup
31+make install # Install all dependencies (Python and Node)
32+make docker-up # Start PostgreSQL and Redis
33+
34+# Development
35+make dev # Start all development servers (backend + frontend)
36+make dev-backend # Start backend development server only
37+make dev-worker # Start background worker (development)
38+make dev-worker-watch # Start background worker with auto-reload (requires entr)
39+make dev-frontend # Start frontend development servers only
40+pnpm turbo dev # Alternative: start dev servers via Turbo
41+
42+# Documentation
43+make docs # Start documentation development server
44+make dev-docs # Start documentation development server (same as above)
45+make build-docs # Build documentation for production
46+make serve-docs # Serve built documentation
47+
48+# Testing
49+make test # Run all tests (Python pytest + Node tests)
50+make test-backend # Run backend (Python) tests only
51+make test-frontend # Run frontend (Node) tests only
52+pnpm turbo test # Run Node tests only via Turbo
53+uv run pytest tests/ # Run Python tests in a specific package
54+
55+# Code Quality
56+make lint # Run all linters (ruff, pyright for Python; ESLint for JS)
57+make lint-backend # Lint backend (Python) only
58+make lint-frontend # Lint frontend (Node) only
59+make typecheck # Run all type checking (Python and TypeScript)
60+make typecheck-backend # Typecheck backend (Python) only
61+make typecheck-frontend # Typecheck frontend (TypeScript) only
62+pnpm turbo lint # Run Node linters only via Turbo
63+pnpm turbo typecheck # Run TypeScript checking only via Turbo
64+
65+# Building
66+make build # Build all packages (Python and Node)
67+make build-backend # Build backend (Python) only
68+make build-frontend # Build frontend (Node) only
69+pnpm turbo build # Build Node packages only via Turbo
70+
71+# Docker Services
72+make docker-up # Start PostgreSQL and Redis
73+make docker-down # Stop services
74+make docker-logs # View service logs
75+
76+# Cleanup
77+make clean # Remove all build artifacts and dependencies
78+make clean-backend # Clean backend (Python) artifacts only
79+make clean-frontend # Clean frontend (Node) artifacts only
80+
81+# Other
82+make help # Show all available Makefile commands
83+```
84+
85+## Development Workflow
86+
87+1. **Python packages**: Located in `/packages/*/` with `pyproject.toml` or `setup.py`. Installed in editable mode during setup using uv.
88+2. **Node packages**: Managed via pnpm workspaces. Internal packages referenced as `workspace:*`.
89+3. **Turbo pipeline**: Configured in `turbo.json` with build dependencies and caching.
90+
91+## Key Design Principles
92+
93+- **Hooks-first frontend design**: The toolkit ships React hooks, not mandatory UI components
94+- **Pluggable auth**: Support for multiple auth providers via adapters (Supabase, Clerk, Auth0, custom JWT/OIDC)
95+- **Observability**: Structured logs, job metrics, audit trail on credit transactions
96+- **GraphQL abstraction**: Example applications MUST NOT directly import from `urql` or GraphQL operations (e.g., `@weirdfingers/boards/graphql/operations`). All GraphQL usage must be abstracted behind hooks from `@weirdfingers/boards` (e.g., `useBoards`, `useBoard`, `useGenerators`). When adding new GraphQL functionality, create a hook in `/packages/frontend/src/hooks/` first, then use that hook in example applications.
97+
98+## Code Placement Guidelines
99+
100+**CRITICAL**: Boards is a toolkit of reusable packages, not just an application. Most code should go into published packages (`packages/`), not the application (`apps/baseboards`).
101+
102+### Published Packages
103+
104+The following packages are published to public registries:
105+
106+- **`packages/backend`** → PyPI (Python package for backends)
107+- **`packages/frontend`** → npm as `@weirdfingers/boards` (React hooks)
108+- **`packages/cli-launcher`** → npm (CLI tool for scaffolding/deployment)
109+- **Auth packages** → npm as `@weirdfingers/boards-auth-*` (separate packages per provider)
110+
111+### Package Decision Tree
112+
113+**When adding new code, ask:**
114+
115+1. **Is this specific to the Baseboards application UI/UX?**
116+
117+ - YES → `apps/baseboards`
118+ - NO → Continue to question 2
119+
120+2. **Is this reusable toolkit functionality?**
121+
122+ - NO → Reconsider the design
123+ - YES → Continue to question 3
124+
125+3. **Is this backend/server-side logic?**
126+
127+ - YES → `packages/backend`
128+ - NO → Continue to question 4
129+
130+4. **Is this React/frontend logic?**
131+ - YES → `packages/frontend`
132+ - NO → Determine appropriate package (CLI, auth, etc.)
133+
134+### packages/backend (Python - Published to PyPI)
135+
136+**SHOULD contain:**
137+
138+- GraphQL schema definitions (Strawberry types and resolvers)
139+- SQLAlchemy models and database logic
140+- Business logic and service layer
141+- FastAPI/Starlette routes and middleware
142+- Auth plugins/adapters (backend auth logic)
143+- Job queue integration (RQ/Dramatiq workers)
144+- Database migrations
145+- Reusable utilities for backend development
146+
147+**SHOULD NOT contain:**
148+
149+- Application-specific business rules
150+- Hardcoded configuration for specific deployments
151+- Frontend-specific logic
152+
153+**Example:**
154+
155+```python
156+# ✅ Good - Generic board creation logic
157+@strawberry.mutation
158+def create_board(self, info: Info, input: CreateBoardInput) -> Board:
159+ """Create a new board - reusable across any Boards deployment"""
160+ board = Boards()
161+ board.title = input.title
162+ board.description = input.description
163+ # ... generic board creation logic
164+ return board
165+
166+# ❌ Bad - Application-specific business rule
167+@strawberry.mutation
168+def create_board(self, info: Info, input: CreateBoardInput) -> Board:
169+ """Create board with hardcoded Baseboards-specific limits"""
170+ if user.boards_count > 10: # Hardcoded limit specific to Baseboards app
171+ raise Exception("Maximum 10 boards")
172+ # ...
173+```
174+
175+### packages/frontend (React/TypeScript - Published to npm)
176+
177+**SHOULD contain:**
178+
179+- React hooks for all Boards functionality
180+- GraphQL operations and fragments
181+- urql client configuration and exchanges
182+- TypeScript type definitions for GraphQL responses
183+- Generic, unstyled React components (sparingly - favor hooks)
184+- Frontend auth adapters (Supabase, Clerk integration)
185+- SSE/WebSocket utilities
186+- Reusable state management utilities
187+
188+**MUST be framework-agnostic:**
189+
190+- React only (no Next.js-specific code)
191+- Should work with Remix, Vite, Create React App, etc.
192+- No `next/router`, `next/navigation`, `next/image`, etc.
193+
194+**Components policy:**
195+
196+- Favor hooks over components
197+- If shipping components, they MUST support:
198+ - Arbitrary theming (no hardcoded styles)
199+ - Accessibility (a11y)
200+ - Internationalization (i18n)
201+- When in doubt, ship a hook and let apps build their own UI
202+
203+**SHOULD NOT contain:**
204+
205+- Next.js-specific code
206+- Styled/opinionated components
207+- Application business logic
208+- Direct imports that bypass hooks (apps importing from `/graphql/operations` directly)
209+
210+**Example:**
211+
212+```typescript
213+// ✅ Good - Generic hook for any React app
214+export function useBoards() {
215+ const [result] = useQuery({ query: BoardsQuery });
216+ return {
217+ boards: result.data?.boards ?? [],
218+ loading: result.fetching,
219+ error: result.error,
220+ };
221+}
222+
223+// ✅ Good - Unstyled, accessible component
224+export function BoardCard({ board, className, onSelect }: BoardCardProps) {
225+ return (
226+ <article
227+ className={className}
228+ role="button"
229+ aria-label={board.title}
230+ onClick={() => onSelect?.(board)}
231+ >
232+ {/* Minimal, unstyled structure */}
233+ </article>
234+ );
235+}
236+
237+// ❌ Bad - Next.js-specific code
238+import { useRouter } from "next/navigation";
239+export function useBoards() {
240+ const router = useRouter(); // Not framework-agnostic!
241+ // ...
242+}
243+
244+// ❌ Bad - Styled, opinionated component
245+export function BoardCard({ board }: BoardCardProps) {
246+ return (
247+ <div className="bg-blue-500 rounded-lg p-4 shadow-xl">
248+ {/* Hardcoded Tailwind styles - should be in app */}
249+ </div>
250+ );
251+}
252+```
253+
254+### apps/baseboards (Next.js - Published via Docker)
255+
256+**Purpose:** Baseboards serves dual roles:
257+
258+1. **Reference implementation** - demonstrates best practices for using the packages
259+2. **Standalone application** - production-ready Boards instance deployable via Docker
260+
261+**SHOULD contain:**
262+
263+- Next.js pages, layouts, and routing
264+- UI components with styling (Tailwind, Radix UI, etc.)
265+- Application-specific configuration (environment variables, themes)
266+- Sensible defaults that users can deploy as-is
267+- Example flows demonstrating package usage
268+- Generic application logic (not overly opinionated)
269+
270+**SHOULD import:**
271+
272+- Hooks from `@weirdfingers/boards`
273+- Types from `@weirdfingers/boards`
274+
275+**SHOULD NOT import:**
276+
277+- Direct urql client usage (use hooks instead)
278+- GraphQL operations from `@weirdfingers/boards/graphql/operations`
279+- Anything that bypasses the hooks abstraction
280+
281+**SHOULD NOT contain:**
282+
283+- Reusable business logic (move to `packages/frontend` or `packages/backend`)
284+- Hardcoded business rules that make it too opinionated
285+- Backend logic (keep in `packages/backend`)
286+
287+**Philosophy:** Baseboards should be both:
288+
289+- Generic enough to deploy unchanged for most use cases
290+- Well-structured enough to serve as a customization starting point
291+
292+**Example:**
293+
294+```typescript
295+// ✅ Good - Uses hooks from the package
296+import { useBoards, useCreateBoard } from "@weirdfingers/boards";
297+
298+export function BoardsPage() {
299+ const { boards, loading } = useBoards();
300+ const createBoard = useCreateBoard();
301+
302+ return (
303+ <div className="container mx-auto">
304+ {/* Baseboards-specific styled UI */}
305+ {boards.map((board) => (
306+ <StyledBoardCard key={board.id} board={board} />
307+ ))}
308+ </div>
309+ );
310+}
311+
312+// ❌ Bad - Bypasses hooks, imports GraphQL directly
313+import { useQuery } from "urql";
314+import { BoardsQuery } from "@weirdfingers/boards/graphql/operations";
315+
316+export function BoardsPage() {
317+ const [result] = useQuery({ query: BoardsQuery }); // Should use useBoards() hook
318+ // ...
319+}
320+
321+// ❌ Bad - Reusable logic that should be in packages/frontend
322+export function useBoardValidation() {
323+ // This is generic logic that other apps would need - move to packages/frontend!
324+ return { validateTitle, validateDescription };
325+}
326+```
327+
328+### packages/cli-launcher (Node.js - Published to npm)
329+
330+**SHOULD contain:**
331+
332+- CLI commands for project scaffolding
333+- Docker deployment utilities
334+- Development environment setup
335+
336+**SHOULD NOT contain:**
337+
338+- Application business logic
339+- Backend/frontend code (import from published packages instead)
340+
341+### Auth Packages (Published to npm)
342+
343+**Available packages:**
344+
345+- `@weirdfingers/boards-auth-supabase` - Supabase authentication provider
346+- `@weirdfingers/boards-auth-clerk` - Clerk authentication provider
347+- `@weirdfingers/boards-auth-jwt` - JWT authentication provider
348+- `@weirdfingers/boards-auth-auth0` (placeholder) - Auth0 authentication provider
349+
350+Each contains frontend auth adapter implementations for their respective providers.
351+
352+## Database Configuration
353+
354+Local development uses Docker Compose with:
355+
356+- PostgreSQL 15 on port 5433 (user: boards, password: boards_dev, database: boards_dev)
357+- Redis 7 on port 6380
358+
359+## Code Quality Rules
360+
361+### Type Checking and Testing
362+
363+- To typecheck the backend and frontend, run `make typecheck` at the root of the project
364+- To run tests for the backend and frontend, run `make test` at the root of the project
365+
366+### Logging
367+
368+- For backend logging, always use `@packages/backend/src/boards/logging.py` which is based on `structlog`
369+- Use keyword arguments for log data, avoid f-strings
370+- Never use `exc_info=True` in log statements
371+
372+### SQLAlchemy Object Creation
373+
374+**IMPORTANT**: When creating SQLAlchemy model instances, DO NOT pass properties as kwargs to the constructor. Instead, set properties explicitly after instantiation. This allows the type checker (pyright) to catch incorrect property names.
375+
376+**Bad** (kwargs bypass type checking):
377+
378+```python
379+new_board = Boards(
380+ tenant_id=tenant_uuid,
381+ owner_id=auth_context.user_id,
382+ title=input.title,
383+ descritpion=input.description, # Typo won't be caught!
384+)
385+```
386+
387+**Good** (explicit assignment catches typos):
388+
389+```python
390+new_board = Boards()
391+new_board.tenant_id = tenant_uuid
392+new_board.owner_id = auth_context.user_id
393+new_board.title = input.title
394+new_board.descritpion = input.description # Type checker will error!
395+```
396+
397+### Database Migrations: `updated_at` Triggers
398+
399+All tables with an `updated_at` column have a `BEFORE UPDATE` trigger that automatically sets `updated_at = CURRENT_TIMESTAMP`. When adding a new table with an `updated_at` column, you **must** also add a trigger for it in a migration:
400+
401+```python
402+op.execute("""
403+ CREATE TRIGGER trg_<table_name>_updated_at
404+ BEFORE UPDATE ON boards.<table_name>
405+ FOR EACH ROW
406+ EXECUTE FUNCTION boards.update_updated_at_column();
407+""")
408+```
409+
410+The shared trigger function `boards.update_updated_at_column()` already exists. Do **not** manually set `updated_at` in application code -- the trigger handles it.
411+
412+### GraphQL Schema Changes
413+
414+**CRITICAL**: When modifying GraphQL types in the backend, you MUST update the frontend in the same commit:
415+
416+1. **Backend changes** in `/packages/backend/src/boards/graphql/types/`:
417+
418+ - Update the Strawberry GraphQL type definition
419+ - If removing/renaming fields, grep the frontend codebase first
420+
421+2. **Frontend changes** that MUST be synchronized:
422+
423+ - Update GraphQL fragments in `/packages/frontend/src/graphql/operations.ts`
424+ - Update TypeScript interfaces in `/packages/frontend/src/hooks/`
425+ - Search for any component usage in example applications
426+
427+3. **Validation**: GraphQL queries that reference non-existent fields will fail at schema validation (before resolver execution), returning errors like "Cannot query field 'fieldName' on type 'TypeName'". This prevents resolvers from being called.
428+
429+**Example workflow when removing a field**:
430+
431+```bash
432+# 1. Remove from backend GraphQL type
433+# 2. Search frontend for references
434+grep -r "fieldName" packages/frontend apps/
435+# 3. Update all found references
436+# 4. Run typecheck to catch any missed TypeScript references
437+make typecheck
438+```
439+
440+### Git Commit Policy
441+
442+**IMPORTANT**: Claude Code must NEVER commit changes to git without being explicitly instructed to do so by the user.
443+
444+Claude Code should:
445+
446+- Make code changes as requested
447+- Run tests and verify changes
448+- Show git status and explain what files have been modified
449+- Suggest commit messages if helpful
450+
451+But Claude Code must NOT:
452+
453+- Run `git add` commands
454+- Run `git commit` commands
455+- Run `git push` commands
456+
457+Unless the user explicitly asks for commits to be made.
458+
459+**CRITICAL**: Claude Code must NEVER push to remote repositories unless explicitly instructed to commit changes, always ask the user to push manually. This prevents accidental pushes to production or shared branches.
460+
461+## Task Management
462+This project uses a CLI ticket system for task management. Run `tk help` when you need to use it.
8463
