This project uses bun instead of node/npm:
- Location:
~/.bun/bin/bun(also in PATH via.claude/settings.json) - Package manager:
bun install,bun add,bun remove - Script runner:
bun run <script> - Test runner:
bun test
This project uses tofu instead of terraform:
- Location:
/opt/homebrew/bin/tofu - All terraform commands should use
tofuinstead
Run these commands in order and fix all issues before committing:
bun run test:all- All tests must pass (backend + frontend)bun format- Format code with Biomebun check:fix- Lint and auto-fix issues with Biomebun typecheck- Fix all TypeScript type errors and warningsbun run check:boundaries- Verify architecture boundaries
Repeat until all checks pass without errors.
Note: You can run tests separately during development:
bun testfor backend/integration tests onlybun run test:componentsfor frontend component tests in watch mode
bun run check:boundaries- Verify no forbidden cross-layer imports- See AGENTS.md "Architecture Boundaries" section for full dependency rules
- Domain must never have runtime imports from infrastructure, api, or app
- Transaction ownership belongs to API handlers, not domain services
Same workflow as above - test, format, lint, typecheck.
Development:
bun run dev:api- Start API server with hot reloadbun run dev:app- Start Vite dev server for frontendbun install- Install dependencies
Testing & Quality:
bun test- Run backend/integration tests with shuffle (uses PGlite for database tests)bun test <path/to/test.ts>- Run specific backend test filebun run test:components- Run frontend component tests in watch mode (Vitest)bun run test:components:run- Run frontend component tests once (CI mode)bun run test:all- Run all tests (backend + frontend)bun typecheck- TypeScript type checkingbun check- Biome lint check (read-only)bun check:fix- Biome lint with auto-fixbun format- Format code with Biomebun run check:boundaries- Check architecture boundary violations
Building:
bun run build:app- Build frontend with Vitebun run build:docker- Build Docker image
Docker:
bun run docker:dev- Start development Docker Composebun run docker:dev:build- Rebuild and start dev Dockerbun run docker:down- Stop Docker servicesbun run docker:logs- View Docker logs
Database:
bun run db:generate- Generate Drizzle migrationsbun run db:migrate- Run migrationsbun run db:reset- Reset databasebun run db:seed- Seed database with test databun run db:seed:dry-run- Preview seed data without applying
Management Scripts:
bun run users:create- Create userbun run users:list- List all usersbun run seasons:create- Create seasonbun run contests:create- Create contestbun run divisions:create- Create divisionbun run brackets:create- Create bracket
If database schemas are modified:
- Run
bun run db:generateto create migration files - Update any related scripts in
scripts/db/if needed - Test migrations with
bun run db:migrate
- Use
buncommands (PATH is configured via.claude/settings.json) - Use
tofuinstead ofterraform - If a command is not found, use explicit paths:
~/.bun/bin/bun/opt/homebrew/bin/tofu
The following tools are pre-approved in .claude/settings.json:
- All
buncommands (both short form and full path) - All
gitoperations - File operations (
Read,Write,Edit) - Docker commands
- Common utilities (
ls,find,curl,cut) - Superpowers skills
- No commits without passing all checks - Always run test, format, check:fix, typecheck
- Fix type errors immediately - TypeScript strict mode is enabled
- Maintain test coverage - Write tests for new features
- Follow project patterns - Check existing code before implementing new patterns
src/- Source codeapp/- SolidJS frontend applicationdomain/- Domain logic and business rulesapi/- API routes and handlersdb/- Database schema and migrations
__tests__/- Test filescomponents/- Frontend component tests (Vitest + Solid Testing Library)api/,domain/, etc. - Backend/integration tests (Bun Test + PGlite)test-db.ts- PGlite test database utilities
scripts/- Management and utility scriptsdocs/- Documentation and design documents.claude/- Claude Code configurationvitest.config.ts- Vitest configuration for component tests
Integration tests use PGlite (WASM-based in-memory PostgreSQL) for complete test isolation:
- ✅ Zero side effects - Tests never touch the development database
- ✅ Complete isolation - Each test file gets its own isolated database instance
- ✅ Faster execution - In-memory database with no network overhead
- ✅ No dependencies - Tests run without requiring PostgreSQL to be running
- ✅ Full compatibility - PGlite implements PostgreSQL 16 with complete schema support
Backend/Integration Tests (Bun Test):
bun test # Run backend/integration tests with shuffle
bun test <path> # Run specific backend test file
bun test --shuffle # Run with randomized order (default)Frontend Component Tests (Vitest):
bun run test:components # Run in watch mode (for development)
bun run test:components:run # Run once (for CI)All Tests:
bun run test:all # Run both backend and frontend testsFor tests that need database access, use the test database utilities:
import { setupTestDb, teardownTestDb, clearTestData } from "../test-db.js";
describe("My Test Suite", () => {
// Setup isolated PGlite database for this test file
beforeAll(async () => {
await setupTestDb();
});
// Cleanup PGlite database after all tests
afterAll(async () => {
await teardownTestDb();
});
// Clear data between tests
beforeEach(async () => {
await clearTestData();
// Insert test data
const db = await getDb();
await db.insert(someTable).values({...});
});
it("should test something", async () => {
// Your test code - uses PGlite automatically via getDb()
});
});Key Points:
- Each test file gets its own isolated PGlite instance (set up in
beforeAll) - Data is cleared between tests (call
clearTestData()inbeforeEach) - No existence checks needed - database starts empty after
clearTestData() - Use
getDb()normally - it automatically returns the test database - Tests are completely isolated from development database
Frontend component tests use Vitest and Solid Testing Library:
import { render, screen, waitFor } from "@solidjs/testing-library";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import MyComponent from "../../src/app/components/MyComponent";
describe("MyComponent", () => {
it("should render and handle user interaction", async () => {
const user = userEvent.setup();
const onSubmit = vi.fn();
render(() => (
<MyComponent onSubmit={onSubmit} />
));
// Query elements
expect(screen.getByText("Submit")).toBeInTheDocument();
// Simulate user interaction
const button = screen.getByRole("button", { name: /submit/i });
await user.click(button);
// Verify behavior
expect(onSubmit).toHaveBeenCalled();
});
});Key Points:
- Component tests live in
__tests__/components/directory - Use
render()with a function that returns JSX (SolidJS requirement) - Use
userEventfor realistic user interactions (notfireEvent) - Query by role/label/text (not test IDs or class names) for accessibility
- Use
waitFor()for async updates - Mock functions with
vi.fn()from Vitest
When to Write Component Tests:
- Complex UI logic (modals, forms with validation, multi-step flows)
- User interactions (clicks, keyboard navigation, form inputs)
- Conditional rendering based on props or state
- Accessibility concerns (keyboard navigation, ARIA attributes)
When NOT to Write Component Tests:
- Simple presentational components (just display props)
- Components that are better tested via integration/E2E tests
- Styling/layout (use visual regression testing instead)