Skip to content
Merged
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
39 changes: 39 additions & 0 deletions .claude/rules/auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
description: Authentication rules
globs:
- 'src/lib/server/auth.ts'
- 'src/routes/(auth)/**'
- 'src/hooks.server.ts'
---

# Authentication

## Lucia v2

- Session validation in `src/hooks.server.ts`
- Session data attached to `event.locals.user`
- User properties: `id`, `name`, `role`, `atcoder_name`, `is_validated`

## Protected Routes

- Validate `event.locals.user` in `+page.server.ts` load functions
- Redirect unauthenticated users to `/login`
- Validate `role` for admin-only routes

## Form Validation

- Use Superforms + Zod for auth forms
- Server-side validation is authoritative
- Return structured error responses

## Key Files

- `src/lib/server/auth.ts`: Lucia configuration
- `src/hooks.server.ts`: Global request handler
- `prisma/schema.prisma`: User, Session, Key models

## Security

- Never expose session secrets in client code
- Use HTTPS in production
- Validate all user inputs server-side
40 changes: 40 additions & 0 deletions .claude/rules/prisma-db.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
description: Prisma and database rules
globs:
- 'prisma/**'
- 'src/lib/server/**'
- 'src/lib/services/**'
---

# Prisma & Database

## Schema Changes

1. Edit `prisma/schema.prisma`
2. Run `pnpm exec prisma migrate dev --name <description>` to create migration
3. Run `pnpm exec prisma generate` to update client (auto-runs after migrate)

## Naming

- Model names: `PascalCase` (e.g., `User`, `TaskAnswer`)
- Field names: `camelCase` (preferred) or `snake_case` (legacy)
- Relation fields: Descriptive names matching the relation

## Key Models

- `User`: User accounts with AtCoder validation status
- `Task`: Tasks with difficulty grades (Q11-D6)
- `TaskAnswer`: User submission status per task
- `WorkBook`: task collections
- `Tag` / `TaskTag`: task categorization

## Server-Only Code

- Import database client only in `src/lib/server/`
- Use `$lib/server/database` for Prisma client access
- Never import server code in client components

## Transactions

- Use `prisma.$transaction()` for multi-step operations
- Handle errors with try-catch and proper rollback
46 changes: 46 additions & 0 deletions .claude/rules/svelte-components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
description: Svelte component development rules
globs:
- 'src/**/*.svelte'
- 'src/lib/components/**'
- 'src/lib/stores/**/*.svelte.ts'
---

# Svelte Components

## Runes Mode (Required)

- Use `$props()` for component props
- Use `$state()` for reactive state
- Use `$derived()` for computed values
- Use `$effect()` for side effects

## Props Pattern

```svelte
<script lang="ts">
interface Props {
title: string;
count?: number;
}

let { title, count = 0 }: Props = $props();
</script>
```

## Stores

- Place store files in `src/lib/stores/` with `.svelte.ts` extension
- Use class-based stores with `$state()` for internal state
- Export singleton instances

## Flowbite Svelte

- Import components from `flowbite-svelte`
- Use Tailwind CSS v4 utility classes
- Dark mode: Use `dark:` prefix for dark mode variants

## File Naming

- Components: `PascalCase.svelte`
- Stores: `snake_case.svelte.ts`
54 changes: 54 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
description: Testing rules and patterns
globs:
- '**/*.test.ts'
- '**/*.spec.ts'
- 'tests/**'
- 'src/test/**'
---

# Testing

## Test Types

| Type | Tool | Location | Run Command |
| ----------- | ---------- | ----------------------- | ----------------------- |
| Unit | Vitest | `src/test/**/*.test.ts` | `pnpm test:unit` |
| Integration | Vitest | `src/test/` | `pnpm test:unit` |
| E2E | Playwright | `tests/*.test.ts` | `pnpm test:integration` |

## Unit Tests

- Place tests in `src/test/` mirroring `src/lib/` structure
- Use `@quramy/prisma-fabbrica` for test data factories
- Mock external APIs with Nock

## E2E Tests

- Place in `tests/` directory
- Use Playwright test utilities
- Test user flows, not implementation details

## Patterns

```typescript
import { describe, test, expect, vi } from 'vitest';

describe('functionName', () => {
test('expects to do something', () => {
// Arrange
// Act
// Assert
});
});
```

## Coverage

- Run `pnpm coverage` for coverage report
- Target: 80% lines, 70% branches

## HTTP Mocking

- Use Nock for mocking external HTTP calls
- See `src/test/lib/clients/` for examples
15 changes: 13 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"workspaceFolder": "/usr/src/app",
// Use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"dockerComposeFile": ["../compose.yaml"],
"mounts": ["source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,type=bind,consistency=cached"],
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,type=bind,consistency=cached",
"source=${localEnv:HOME}/.claude,target=/home/node/.claude,type=bind,consistency=cached"
],
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
//
Expand All @@ -18,8 +21,11 @@
],
// "shutdownAction": "none",
//
// Use 'initializeCommand' to run commands before the container is created.
"initializeCommand": "mkdir -p ~/.claude",
//
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
"postCreateCommand": "npm install -g @anthropic-ai/claude-code && pnpm install",
//
// Configure tool-specific properties.
"customizations": {
Expand Down Expand Up @@ -72,6 +78,7 @@
"svelte.enable-ts-plugin": true
},
"extensions": [
"anthropic.claude-code",
"bradlc.vscode-tailwindcss",
"christian-kohler.path-intellisense",
"csstools.postcss",
Expand All @@ -85,6 +92,10 @@
"vscode-icons-team.vscode-icons"
]
}
},
"containerEnv": {
"NODE_OPTIONS": "--max-old-space-size=4096 --dns-result-order=ipv4first",
"CLAUDE_CONFIG_DIR": "/home/node/.claude"
}
//
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
Expand Down
59 changes: 59 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# AtCoder NoviSteps

A web service for tracking submissions on AtCoder and other competitive programming sites, which are graded by difficulty (Q11-D6).

## Tech Stack

SvelteKit 2 + Svelte 5 (Runes) + TypeScript | PostgreSQL + Prisma | Flowbite Svelte + Tailwind 4 | Vitest + Playwright

## Commands

```bash
pnpm dev # Start dev server (localhost:5174)
pnpm build # Build for production
pnpm test # Run all tests
pnpm test:unit # Vitest unit tests
pnpm test:integration # Playwright E2E tests
pnpm coverage # Report test coverage
pnpm lint # ESLint check
pnpm format # Prettier format
pnpm check # Svelte type check
pnpm exec prisma generate # Generate Prisma client
pnpm exec prisma migrate dev --name # Create migration (with description)
pnpm db:seed # Seed database
```

## Project Structure

```md
src/routes/ # SvelteKit file-based routing
src/lib/
├── actions/ # SvelteKit actions
├── clients/ # External API clients (AtCoder Problems, AOJ)
├── components/ # Svelte components
├── constants/
├── server/ # Server-only (auth.ts, database.ts)
├── services/ # Business logic
├── stores/ # Svelte stores (.svelte.ts with Runes)
├── types/ # TypeScript types
├── utils/ # Pure utility functions
└── zod/ # Validation schemas
src/test/ # Unit tests (mirrors src/lib/)
tests/ # E2E tests (Playwright)
prisma/schema.prisma # Database schema
```

## Key Conventions

- **Svelte 5 Runes**: Use `$props()`, `$state()`, `$derived()` in all new components
- **Server data**: `+page.server.ts` → `+page.svelte` via `data` prop
- **Forms**: Superforms + Zod validation
- **Tests**: Factories via `@quramy/prisma-fabbrica`, HTTP mocking via Nock
- **Naming**: `camelCase` variables, `PascalCase` types/components, `snake_case` files/routes, `kebab-case` directories
- **Pre-commit**: Lefthook runs Prettier + ESLint (bypass: `LEFTHOOK=0 git commit`)

## References

- See `package.json` for versions and scripts
- See `prisma/schema.prisma` for database models
- See `docs/guides/` for detailed documentation
9 changes: 9 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# CLAUDE.md

@AGENTS.md

## Claude Code Specific

- Path-specific rules are in `.claude/rules/`
- Run `pnpm format` before committing
- When uncertain about project conventions, see existing code in `src/lib/`
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ RUN apt-get update \
ENV NODE_PATH=/node_modules
ENV PATH=$PATH:/node_modules/.bin

RUN pnpm install --frozen-lockfile
RUN pnpm install

CMD ["pnpm", "dev"]
Loading
Loading