Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 59 additions & 18 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,40 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This file provides guidance to Claude Code (claude.ai/code) when working with
code in this repository.

## Project Overview

Mad CSS is a TanStack Start application for "The Ultimate CSS Tournament" - an event website featuring 16 developers battling for CSS glory. Built with React 19, TanStack Router, and deploys to Cloudflare Workers.
Mad CSS is a TanStack Start application for "The Ultimate CSS Tournament" - an
event website featuring 16 developers battling for CSS glory. Built with React
19, TanStack Router, and deploys to Cloudflare Workers.

## Commands

**Package manager: pnpm**

```bash
# Development
npm run dev # Start dev server on port 3000
pnpm dev # Start dev server on port 3000

# Build & Deploy
npm run build # Build for production
npm run deploy # Build and deploy to Cloudflare Workers
pnpm build # Build for production
pnpm deploy # Build and deploy to Cloudflare Workers

# Code Quality
npm run check # Run Biome linter and formatter checks
npm run lint # Lint only
npm run format # Format only
pnpm check # Run Biome linter and formatter checks
pnpm lint # Lint only
pnpm format # Format only

# Testing
npm run test # Run Vitest tests
pnpm test # Run Vitest tests

# Database
npm run db:generate # Generate Drizzle migrations from schema
npm run db:migrate:local # Apply migrations to local D1
npm run db:migrate:prod # Apply migrations to production D1
npm run db:studio # Open Drizzle Studio
npm run db:setup # Generate + migrate local (full setup)
pnpm db:generate # Generate Drizzle migrations from schema
pnpm db:migrate:local # Apply migrations to local D1
pnpm db:migrate:prod # Apply migrations to production D1
pnpm db:studio # Open Drizzle Studio
pnpm db:setup # Generate + migrate local (full setup)
```

## Database Setup
Expand Down Expand Up @@ -66,6 +71,20 @@ BETTER_AUTH_SECRET=your_random_secret
BETTER_AUTH_URL=http://localhost:3000
```

### GitHub OAuth Setup

1. Go to GitHub Settings > Developer settings > OAuth Apps > New OAuth App
2. Fill in:
- **Application name:** Mad CSS (Local) or similar
- **Homepage URL:** `http://localhost:3000/test`
- **Authorization callback URL:**
`http://localhost:3000/api/auth/callback/github`
3. Click "Register application"
4. Copy the **Client ID** to `GITHUB_CLIENT_ID` in `.dev.vars`
5. Generate a new **Client Secret** and copy to `GITHUB_CLIENT_SECRET`

The login flow redirects to `/test` after authentication.

### Production Deployment

1. Set secrets in Cloudflare dashboard (Workers > Settings > Variables):
Expand All @@ -82,21 +101,43 @@ BETTER_AUTH_URL=http://localhost:3000

**Stack:** TanStack Start (SSR framework) + React 19 + Vite + Cloudflare Workers

**File-based routing:** Routes live in `src/routes/`. TanStack Router auto-generates `src/routeTree.gen.ts` - don't edit this file manually.
**File-based routing:** Routes live in `src/routes/`. TanStack Router
auto-generates `src/routeTree.gen.ts` - don't edit this file manually.

**Key directories:**

- `src/routes/` - Page components and API routes
- `src/routes/__root.tsx` - Root layout, includes Header and devtools
- `src/components/` - Reusable components (Header, Ticket, Roster)
- `src/components/` - Reusable components (Header, Ticket, LoginSection,
bracket/, roster/, footer/, rules/)
- `src/lib/` - Auth setup (better-auth) and utilities (cfImage.ts for Cloudflare
Images)
- `src/data/` - Player data (players.ts with 16 contestants)
- `src/styles/` - CSS files imported directly into components
- `public/` - Static assets (logos, images)
- `public/` - Static assets (logos, images, card artwork)

**Path alias:** `@/*` maps to `./src/*`

**Styling:** Plain CSS with CSS custom properties defined in `src/styles/styles.css`. Uses custom fonts (Kaltjer, CollegiateBlackFLF, Inter) and texture backgrounds.
**Styling:** Plain CSS with CSS custom properties defined in
`src/styles/styles.css`. Uses custom fonts (Kaltjer, CollegiateBlackFLF, Inter)
and texture backgrounds.

## Code Style

- Biome for linting/formatting (tabs, double quotes)
- TypeScript strict mode
- XY Flow library for tournament bracket visualization

## Comment Policy

### Unacceptable Comments

- Comments that repeat what code does
- Commented-out code (delete it)
- Obvious comments ("increment counter")
- Comments instead of good naming

### Principle

Code should be self-documenting. If you need a comment to explain WHAT the code
does, consider refactoring to make it clearer.
23 changes: 23 additions & 0 deletions drizzle/0001_wooden_nomad.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CREATE TABLE `user_bracket_status` (
`id` text PRIMARY KEY NOT NULL,
`user_id` text NOT NULL,
`is_locked` integer DEFAULT false NOT NULL,
`locked_at` integer,
`created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE UNIQUE INDEX `user_bracket_status_user_id_unique` ON `user_bracket_status` (`user_id`);--> statement-breakpoint
CREATE INDEX `user_bracket_status_userId_idx` ON `user_bracket_status` (`user_id`);--> statement-breakpoint
CREATE TABLE `user_prediction` (
`id` text PRIMARY KEY NOT NULL,
`user_id` text NOT NULL,
`game_id` text NOT NULL,
`predicted_winner_id` text NOT NULL,
`created_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL,
`updated_at` integer DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)) NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE INDEX `user_prediction_userId_idx` ON `user_prediction` (`user_id`);--> statement-breakpoint
CREATE INDEX `user_prediction_userId_gameId_idx` ON `user_prediction` (`user_id`,`game_id`);
Loading