Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
7899f11
docs: Create plan (#943)
KATO-Hiro Mar 1, 2026
e5e9ed7
docs: Add TDD to AGENTS.md (#943)
KATO-Hiro Mar 1, 2026
38e0006
docs: Update plan (#943)
KATO-Hiro Mar 1, 2026
5b5a4f8
refactor: Remove old mock (#943)
KATO-Hiro Mar 1, 2026
7879606
refactor: Extract calcWorkBookGradeModes to features/utils (#943)
KATO-Hiro Mar 1, 2026
57f6977
test: Add tests for calcWorkBookGradeModes (#943)
KATO-Hiro Mar 1, 2026
6521d6c
feat: Add WorkBookPlacement and SolutionCategory (#943)
KATO-Hiro Mar 1, 2026
35cbdd0
docs: Update plan (#943)
KATO-Hiro Mar 1, 2026
07d1d3c
docs: Add WorkBookPlacement (#943)
KATO-Hiro Mar 1, 2026
59712b6
feat: Add WorkBookPlacement and SolutionCategory (#943)
KATO-Hiro Mar 1, 2026
e6a84a7
docs: Add comment (#943)
KATO-Hiro Mar 1, 2026
e340b49
docs: Add dnd lib to CONTRIBUTING.md (#943)
KATO-Hiro Mar 1, 2026
1c0e1aa
build(deps): Use @dnd-kit for kanban board (#943)
KATO-Hiro Mar 1, 2026
456d86a
feat: Validate WorkBookPlacement using zod (#943)
KATO-Hiro Mar 1, 2026
3726fae
build: Update deps (#43)
KATO-Hiro Mar 2, 2026
a886711
docs: Add plan (#943)
KATO-Hiro Mar 2, 2026
fe59718
feat: Add DSL, GCL and NTL to AOJ courses (#943)
KATO-Hiro Mar 3, 2026
37c632c
feat: Add DSL, GCL and NTL to AOJ courses (#943)
KATO-Hiro Mar 3, 2026
90d1a92
feat: Add WorkBookPlacement ans related types (#943)
KATO-Hiro Mar 4, 2026
e9349a9
feat: [WIP] Enable sorting of workbook order in Kanban board (#943)
KATO-Hiro Mar 4, 2026
f6af23d
feat: Add seed data for Solution Categories (#943)
KATO-Hiro Mar 4, 2026
9cdf57d
docs: Add drafts for bugfix and refactor (#943)
KATO-Hiro Mar 4, 2026
3ce3942
docs: Create bug fix plan (#943)
KATO-Hiro Mar 4, 2026
6daf3a9
refactor: Replace form action with JSON API endpoint for placement up…
KATO-Hiro Mar 4, 2026
543efd8
docs: Add new bug and update plan (#943)
KATO-Hiro Mar 4, 2026
84c3b43
chore: Fix format (#943)
KATO-Hiro Mar 4, 2026
8d6c086
fix: Resolve cross-column drag assignment and improve E2E tests (#943)
KATO-Hiro Mar 4, 2026
7924f18
chore: Fix format (#943)
KATO-Hiro Mar 4, 2026
0fd3431
chore: Rename query params (#943)
KATO-Hiro Mar 4, 2026
36544d4
chore: Fix format (#943)
KATO-Hiro Mar 5, 2026
e19a0eb
Merge branch 'staging' of github.com:AtCoder-NoviSteps/AtCoderNoviSte…
KATO-Hiro Mar 8, 2026
5d78ce9
docs: Update plan (#943)
KATO-Hiro Mar 8, 2026
be06adb
docs: Update plan (#943)
KATO-Hiro Mar 8, 2026
6626fe9
docs: Revise refactor plan (#943)
KATO-Hiro Mar 8, 2026
73c2f1b
refactor: workbook order management with type-safe placements and Kan…
KATO-Hiro Mar 8, 2026
b61730e
chore: Fix format (#943)
KATO-Hiro Mar 8, 2026
374db64
refactor: simplify KanbanBoard with Record-based column state
KATO-Hiro Mar 8, 2026
f9cf7b7
chore: Fix format (#943)
KATO-Hiro Mar 8, 2026
c1a9783
refactor: extract validateAdminAccess and service helpers for placeme…
KATO-Hiro Mar 8, 2026
5a3136a
feat: improve Kanban UI — nav link, card link, and style tweaks
KATO-Hiro Mar 8, 2026
abb09b6
test: add unit tests for solutionCategory and fixture-based curriculu…
KATO-Hiro Mar 8, 2026
f13d97c
chore: Update plan (#943)
KATO-Hiro Mar 8, 2026
0e87e6d
docs: TODO list (#943)
KATO-Hiro Mar 8, 2026
332b1d9
chore: Fix typo (#943)
KATO-Hiro Mar 8, 2026
aef5236
chore: Add and update refactor plan v2 (#943)
KATO-Hiro Mar 8, 2026
e821536
refactor: Phase 7 — color tokens, type renames, BAD_REQUEST constant,…
KATO-Hiro Mar 9, 2026
1bb2960
refactor: Phase 8 — type extraction, WorkbookLink component, props sp…
KATO-Hiro Mar 9, 2026
04131c1
refactor: Phase 9 — layout width, snippet DRY, tab styling (#943)
KATO-Hiro Mar 9, 2026
def975d
refactor: Phase 10 — buildKanbanItems, calcPriorityUpdates, TabConfig…
KATO-Hiro Mar 9, 2026
e0d52a5
refactor: Phase 11 — service layer, KanbanTabBar extraction (#943)
KATO-Hiro Mar 9, 2026
01bd501
docs: update refactor.md to concise format (#943)
KATO-Hiro Mar 10, 2026
9e7ebef
chore: Add and update refactor plan (#943)
KATO-Hiro Mar 10, 2026
3058bc8
Merge branch 'staging' of github.com:AtCoder-NoviSteps/AtCoderNoviSte…
KATO-Hiro Mar 11, 2026
c967bc6
chore: Fix format (#943)
KATO-Hiro Mar 11, 2026
9f768ed
docs: Add todo v3 (#943)
KATO-Hiro Mar 11, 2026
25a8443
docs: Revise todo v3 (#943)
KATO-Hiro Mar 11, 2026
21647e5
docs: Revise todo v3 (#943)
KATO-Hiro Mar 11, 2026
0579b17
docs: Revise todo v3 (#943)
KATO-Hiro Mar 11, 2026
774d15d
refactor: Apply Phase 1-3 refactoring to workbook order feature
KATO-Hiro Mar 11, 2026
6f1b377
docs: Update project rules and architecture docs
KATO-Hiro Mar 11, 2026
ca4587a
refactor: Apply Phase 4-5 refactoring to workbook order feature
KATO-Hiro Mar 11, 2026
8dec79b
refactor: Apply Phase 6 service layer restructuring to workbook_place…
KATO-Hiro Mar 11, 2026
483cb83
refactor: Apply Phase 7 investigation and KanbanBoard cleanup
KATO-Hiro Mar 11, 2026
1841837
test: Apply Phase 8 test refactoring to workbook_placements
KATO-Hiro Mar 11, 2026
6550bf7
test: Expand kanban utils tests and extract fixtures
KATO-Hiro Mar 11, 2026
c08d42a
docs: Consolidate lessons learned into reusable rules and guides
KATO-Hiro Mar 11, 2026
1e1eeb1
docs: Rewrite refactor.md as reusable refactoring guide
KATO-Hiro Mar 11, 2026
33760fe
feat: Add /refactor-plan skill and consolidate Svelte component rules
KATO-Hiro Mar 11, 2026
332621b
docs: Add AI review (#943)
KATO-Hiro Mar 12, 2026
3d10cdb
Merge branch 'staging' of github.com:AtCoder-NoviSteps/AtCoderNoviSte…
KATO-Hiro Mar 13, 2026
d794c74
chore: Fix conflict (#943)
KATO-Hiro Mar 13, 2026
77e6d10
docs: Update AI review (#943)
KATO-Hiro Mar 13, 2026
f533f94
Merge branch 'staging' of github.com:AtCoder-NoviSteps/AtCoderNoviSte…
KATO-Hiro Mar 14, 2026
c0e7c5b
chore: Fix conflict (#943)
KATO-Hiro Mar 14, 2026
ff6d6ef
docs: Update review (#943)
KATO-Hiro Mar 14, 2026
16e05a8
chore: Fix format (#943)
KATO-Hiro Mar 14, 2026
b2864db
refactor: Apply fixes based on AI review feedback (#943)
KATO-Hiro Mar 14, 2026
6dc15e2
chore: Fix format (#943)
KATO-Hiro Mar 14, 2026
33344d2
docs: Consolidate dev-notes into plan.md and remove stale files (#943)
KATO-Hiro Mar 14, 2026
28cdf7c
chore: Fix format (#943)
KATO-Hiro Mar 14, 2026
3a8f320
docs: Resolve the TDD contradiction between workflow and conventions …
KATO-Hiro Mar 14, 2026
102f6d5
fix: Double-submit could throw an uncaught unique constraint violatio…
KATO-Hiro Mar 14, 2026
4b03a27
fix: typo (#943)
KATO-Hiro Mar 14, 2026
0565030
docs: Add rules from lessons (#943)
KATO-Hiro Mar 14, 2026
c5ecf36
docs: Update plan (#943)
KATO-Hiro Mar 14, 2026
bf4fca2
docs: Remove old tasks (#943)
KATO-Hiro Mar 14, 2026
fe12792
docs: Move important decisions to code (#943)
KATO-Hiro Mar 14, 2026
ab38501
chore: Update docs (#943)
KATO-Hiro Mar 14, 2026
b28badf
chore: Add and update rules (#943)
KATO-Hiro Mar 14, 2026
7916518
chore: Add and update rules (#943)
KATO-Hiro Mar 14, 2026
227dc35
docs: Add and update skills (#943)
KATO-Hiro Mar 14, 2026
20333d0
chore: Fix format (#943)
KATO-Hiro Mar 14, 2026
7009a63
chore: Rename (#943)
KATO-Hiro Mar 14, 2026
477dd33
chore: Add type (#943)
KATO-Hiro Mar 14, 2026
da0df19
chore: Use const and update descriptions (#943)
KATO-Hiro Mar 14, 2026
95d2010
chore: Use getter (#943)
KATO-Hiro Mar 14, 2026
60230e9
docs: Update plan (#943)
KATO-Hiro Mar 14, 2026
3db6e68
docs: Update plan (#943)
KATO-Hiro Mar 15, 2026
e0c65ce
chore: Fix type (#943)
KATO-Hiro Mar 15, 2026
e774963
chore: Use type (#943)
KATO-Hiro Mar 15, 2026
1b62f00
chore: Fix format (#943)
KATO-Hiro Mar 15, 2026
fb68371
refactor: Extract method (#943)
KATO-Hiro Mar 15, 2026
cd46c70
refactor (#943)
KATO-Hiro Mar 15, 2026
4fa7973
chore: Fix order (#943)
KATO-Hiro Mar 15, 2026
83cdf70
docs: Add note (#943)
KATO-Hiro Mar 15, 2026
aeecdcc
docs: Update rules and plan (#943)
KATO-Hiro Mar 15, 2026
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
7 changes: 6 additions & 1 deletion .claude/rules/auth.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
---
description: Authentication rules
globs:
paths:
- 'src/lib/server/auth.ts'
- 'src/routes/(auth)/**'
- 'src/routes/(admin)/_utils/auth.ts'
- 'src/routes/(admin)/**'
- 'src/hooks.server.ts'
---

Expand Down Expand Up @@ -30,6 +32,9 @@ globs:

- `src/lib/server/auth.ts`: Lucia configuration
- `src/hooks.server.ts`: Global request handler
- `src/routes/(admin)/_utils/auth.ts`:
- `validateAdminAccess(locals)` — for page routes; redirects to `/login` for both unauthenticated and non-admin users (do not use in `+server.ts`)
- `validateAdminAccessForApi(locals)` — for API routes (`+server.ts`); throws `error(401)` if unauthenticated, `error(403)` if not admin
- `prisma/schema.prisma`: User, Session, Key models

## Security
Expand Down
38 changes: 38 additions & 0 deletions .claude/rules/coding-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Coding Style

## Naming

- **Abbreviations**: avoid non-standard abbreviations (`res` → `response`, `btn` → `button`). When in doubt, spell it out.
- **Lambda parameters**: no single-character names (e.g., use `placement`, `workbook`). Iterator index `i` is the only exception.
- **`upsert`**: only use when the implementation performs both insert and update. For insert-only, use `initialize`, `seed`, or another accurate verb.
- **`any`**: before using `any`, check the value's origin — adding a missing `@types/*` or `devDependency` often provides the correct type.
- **UI labels**: if a label does not match actual behavior, update it or add an inline comment explaining the intentional mismatch.

## Syntax

- **Braces**: always use braces for single-statement `if` blocks. Never `if () return;` — write `if () { return; }`.
- **Plural type aliases**: define `type Placements = Placement[]` instead of using `Placement[]` directly in signatures and variables.

## Markdown Code Blocks

Always specify a language identifier on every fenced code block. Never write bare ` ``` `.

Common identifiers: `typescript`, `svelte`, `sql`, `bash`, `mermaid`, `json`, `prisma`, `html`, `css`.

## SvelteKit: Routes vs API Endpoints

- Page routes (`+page.server.ts`): use `redirect()` to navigate
- API routes (`+server.ts`): use `error()` — throwing `redirect()` causes `fetch` clients to receive HTML instead of a JSON error

## Async Rollback: Capture State Before `await`

Capture `$state` values before the first `await` for safe rollback. A concurrent update can overwrite the variable while awaiting:

```typescript
const previous = items; // capture before await
try {
await saveToServer(items);
} catch {
items = previous;
}
```
65 changes: 47 additions & 18 deletions .claude/rules/prisma-db.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,69 @@
---
description: Prisma and database rules
globs:
paths:
- 'prisma/**'
- 'src/lib/server/**'
- 'src/lib/services/**'
- 'src/features/**/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)
2. Run `pnpm exec prisma migrate dev --name <snake_case_description>`

## 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
- Models: `PascalCase` | Fields: `camelCase` (preferred) or `snake_case` (legacy)

## Server-Only Code

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

## Service Layer

- All CRUD through the service layer (`src/lib/services/` or `src/features/**/services/`)
- Route handlers call service methods — no direct Prisma in `+server.ts` / `+page.server.ts`
- Service functions return pure values (`{ error: string } | null`), never `Response` / `json()`

## Transactions

- Use `prisma.$transaction()` for multi-step operations
- Handle errors with try-catch and proper rollback
Use `prisma.$transaction()` for multi-step operations.

## N+1 Queries

Replace per-item DB calls in loops with a bulk fetch + `Map`:

```typescript
const records = await prisma.foo.findMany({ where: { id: { in: ids } } });
const map = new Map(records.map((r) => [r.id, r]));
```

## Enum Types

Prisma-generated enums and app-defined enums are distinct TypeScript types even with identical members. Keep explicit casts at the boundary — do not remove them as "redundant".

## Idempotent Writes

Prefer `createMany({ skipDuplicates: true })` over catching P2002 for expected unique violations (e.g., double-submit). Maps to `INSERT ... ON CONFLICT DO NOTHING`. Top-level only (not nested); PostgreSQL/CockroachDB/SQLite only.

## Zod Schema for Int Fields

`z.number().positive()` passes decimals. For Prisma `Int` fields use `z.number().int().positive()`.

## Validate Constraints

Prisma does not support `@@check`. To add one:

1. `pnpm exec prisma migrate dev --create-only --name <description>` — generate migration without applying
2. Edit the generated `migration.sql` to add the CHECK constraint manually
3. `pnpm exec prisma migrate dev` — apply

Document the constraint in `prisma/ERD.md` (the only place it's visible):

```mermaid
%% XOR constraint: workbookplacement_xor_grade_category — exactly one of taskGrade or solutionCategory must be non-null
```
81 changes: 63 additions & 18 deletions .claude/rules/svelte-components.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Svelte component development rules
globs:
paths:
- 'src/**/*.svelte'
- 'src/lib/components/**'
- 'src/lib/stores/**/*.svelte.ts'
Expand All @@ -10,37 +10,82 @@ globs:

## 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
Use `$props()`, `$state()`, `$derived()`, `$effect()` in all components. Props pattern:

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

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

## Stores
## File Naming

- Place store files in `src/lib/stores/` with `.svelte.ts` extension
- Use class-based stores with `$state()` for internal state
- Export singleton instances
- Components: `PascalCase.svelte`
- Stores: `snake_case.svelte.ts` in `src/lib/stores/`, class-based with `$state()`, export singleton

## Flowbite Svelte

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

## File Naming
## `$state()` Initialization with `$props()`

- Components: `PascalCase.svelte`
- Stores: `snake_case.svelte.ts`
Referencing `$props()` inside `$state()` initializer triggers "This reference only captures the initial value". Wrap with `untrack` if intentional:

```svelte
let count = $state(untrack(() => initialCount)); // intentional: prop is initial seed only
```

## `{#snippet}` Placement

Define snippets at the **top level**, outside component tags. Inside a tag = named slot = type error:

```svelte
<!-- Good -->
{#snippet footer()}...{/snippet}
<Dialog {footer} />

<!-- Bad: named slot, not a snippet prop -->
<Dialog>{#snippet footer()}...{/snippet}</Dialog>
```

## Snippet vs Component

Prefer `{#snippet}` when: (1) needs direct `$state` access, (2) pure display only, (3) same-file DRY.
Promote to component when: independent state/lifecycle needed, exceeds ~30 lines, or reused across files.

## Keep Components Thin

Business logic and pure utilities belong in `_types/` and `_utils/`, not in `<script>` blocks:

- Static config → `_utils/` constants
- Pure computation → `_utils/` functions with adjacent tests

## Pure Functions and Side Effect Separation

Extract business logic as pure functions to `_utils/`; keep side effects in the caller:

```typescript
// Before: untestable
function updateUrl() { replaceState(new URL($page.url).searchParams.set('tab', activeTab)); }

// After: pure function in _utils/, side effect in caller
export function buildUpdatedUrl(url: URL, activeTab: ActiveTab): URL { ... }
// Caller: replaceState(buildUpdatedUrl($page.url, activeTab), {})
```

## Eliminate Branching with Records

Replace `if`/ternary chains with `Record<EnumType, T>`:

```typescript
const TAB_CONFIGS: Record<ActiveTab, TabConfig> = {
curriculum: { label: 'Curriculum', ... },
solution: { label: 'Solution', ... },
};
```

Use the enum type as the key type, not `string`.
67 changes: 41 additions & 26 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Testing rules and patterns
globs:
paths:
- '**/*.test.ts'
- '**/*.spec.ts'
- 'tests/**'
Expand All @@ -11,44 +11,59 @@ globs:

## 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` |
| Type | Tool | Location | Run Command |
| ---- | ---------- | ----------------------------------------------------------------- | ----------------------- |
| Unit | Vitest | `src/test/` (mirrors `src/lib/`) or co-located in `src/features/` | `pnpm test:unit` |
| E2E | Playwright | `tests/` | `pnpm test:integration` |

## Unit Tests
## Assertions

- Place tests in `src/test/` mirroring `src/lib/` structure
- Use `@quramy/prisma-fabbrica` for test data factories
- Mock external APIs with Nock
- Use `toBe(true)` / `toBe(false)` over `toBeTruthy()` / `toBeFalsy()`
- For DB query tests, assert `orderBy`, `include`, and other significant parameters with `expect.objectContaining` — not just `where`
- Enum membership: `in` traverses the prototype chain; use `Object.hasOwn(Enum, value)` instead

## E2E Tests
## Cleanup in Tests

- Place in `tests/` directory
- Use Playwright test utilities
- Test user flows, not implementation details
Wrap DB-mutating cleanup in `try/finally` — a failing assertion skips cleanup and contaminates later tests:

## Patterns
```typescript
try {
await doSomething();
expect(result).toBe(expected);
} finally {
await restoreState();
}
```

## Test Data

- Use realistic fixture values (real task IDs, grade names) instead of placeholders like `'t1'`
- Extract shared data into fixture files; inline is fine for single-use cases
- After `.filter()` on fixtures, verify actual contents — same ID may refer to a different entity after fixture updates

## Mock Helpers

Extract repeated mock patterns into a helper in the test file:

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

describe('functionName', () => {
test('expects to do something', () => {
// Arrange
// Act
// Assert
});
});
function mockFindMany(value: WorkBookPlacements) {
vi.mocked(prisma.workBookPlacement.findMany).mockResolvedValue(
value as unknown as Awaited<ReturnType<typeof prisma.workBookPlacement.findMany>>,
);
}
```

## Testing Extracted Utilities

- Add tests at extraction time, not later
- For URL manipulation: assert the original URL is not mutated
- For multi-column operations (e.g., DnD): assert both source and destination columns

## 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
Use Nock for external HTTP calls. See `src/test/lib/clients/` for examples.
13 changes: 13 additions & 0 deletions .claude/skills/refactor-plan/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: refactor-plan
description: Analyze a GitHub issue or file path and produce a phased refactoring plan. Outputs a TODO list only — does not make code changes.
disable-model-invocation: true
argument-hint: '[issue-number | file-path]'
---

Produce a refactoring plan for: $ARGUMENTS

1. **Gather context** — number: `gh issue view $ARGUMENTS --comments` (if `gh` unavailable, fetch the issue via WebFetch); path: read source files under that path
2. **Investigate** — read relevant source files; apply the checklist in [instructions.md](instructions.md)
3. **Plan** — group findings into phases (lowest → highest risk); each phase is a `- [ ]` checklist; note inter-phase dependencies
4. **Stop — output the plan only. Do not implement any changes.**
Loading
Loading