docs: update CLAUDE.md, GEMINI.md, add README
- Add test-* and seed-demo Make targets to command reference - Document TT_TEST_MODE, /health route, test_reset route module - Expand admin subroutes list, add Testing and CI sections - Fix SQLx contradiction (runtime queries, no DATABASE_URL needed) - Rewrite GEMINI.md with full Claude parity - Add root README.md with quickstart, stack, and doc links
This commit is contained in:
30
CLAUDE.md
30
CLAUDE.md
@@ -15,13 +15,23 @@ make build # pnpm build, then cargo build --release
|
||||
make compose-up # docker compose build + start
|
||||
|
||||
# Backend
|
||||
cargo test # run all tests (uses sqlx::test macro — no DB setup needed)
|
||||
cargo test # run all backend unit tests
|
||||
cargo check # fast type check without linking
|
||||
|
||||
# Frontend
|
||||
pnpm check # TypeScript + Svelte type check
|
||||
pnpm check:watch # watch mode
|
||||
pnpm build # Vite build to dist/
|
||||
|
||||
# Demo data
|
||||
make seed-demo # wipe dev.db and reseed from backend/demo/demo_seed.sql
|
||||
|
||||
# E2E test pipeline (see docs/testing.md for full detail)
|
||||
make test-up # build test DB if missing, start backend on test port, wait for /health
|
||||
make test-down # stop the test backend
|
||||
make test-reset # fast DB reset via POST /__test__/reset (~10–50 ms)
|
||||
make test-rebuild # wipe and rebuild test DB from migrations + seed
|
||||
make test-e2e # test-up + pnpm test:e2e in one step
|
||||
```
|
||||
|
||||
## Architecture
|
||||
@@ -37,7 +47,11 @@ TutorTool is a **Rust + SvelteKit attendance tracker** for tutoring sessions.
|
||||
- **Migrations**: auto-run via `sqlx::migrate!` at startup from `backend/migrations/`
|
||||
- **`PRAGMA foreign_keys = ON`** is enforced on every connection in `db.rs`
|
||||
|
||||
Route handlers live in `backend/src/routes/` and are merged into the main router in `main.rs`. Each handler receives `State<SqlitePool>` and extracts `TutorClaims` from the JWT on protected routes.
|
||||
Route handlers live in `backend/src/routes/` and are merged in `routes/mod.rs`. Each handler receives `State<SqlitePool>` and extracts `TutorClaims` from the JWT on protected routes.
|
||||
|
||||
Route modules: `auth_routes`, `checkin`, `courses`, `rooms`, `sessions`, `attendance`, `notes`, `export`, `tutors`, and `test_reset` (mounted only when `TT_TEST_MODE=1`).
|
||||
|
||||
The `/health` route always returns `"ok"` and is used by the test pipeline to wait for startup.
|
||||
|
||||
### Frontend (`frontend/`)
|
||||
|
||||
@@ -49,6 +63,7 @@ Route handlers live in `backend/src/routes/` and are merged into the main router
|
||||
Routes:
|
||||
- `routes/admin/login/` — public login
|
||||
- `routes/admin/` — all tutor-facing pages (guarded by `+layout.svelte` auth check)
|
||||
- `attendance/`, `courses/`, `export/`, `live/`, `rooms/`, `sessions/`, `students/`, `tutors/`
|
||||
- `routes/s/[code]/` — public student check-in page
|
||||
|
||||
### Data Model (SQLite, 9 tables)
|
||||
@@ -62,14 +77,21 @@ rooms (layout_json) ←── slots.room_id
|
||||
|
||||
Key slot status transitions: `closed` → `open` → `locked`. The `code` field on slots is the public check-in token students use at `/s/[code]`.
|
||||
|
||||
### Container / K8s
|
||||
### Testing
|
||||
|
||||
E2E tests run Playwright against a dedicated test backend daemon. The test backend uses a separate DB and is started with `TT_TEST_MODE=1`, which enables `POST /__test__/reset` for fast state resets (~10–50 ms) without restarting the process. Each git worktree gets its own deterministic port and DB path (no collisions when testing across branches).
|
||||
|
||||
See `docs/testing.md` for the full guide including seed data, MCP-driven verification, and worktree isolation details.
|
||||
|
||||
### Container / K8s / CI
|
||||
|
||||
- `Dockerfile`: 3-stage build (Node 20 frontend → Rust 1.95 backend → Debian slim runtime)
|
||||
- `k8s/`: Deployment, Service, PVC for SQLite, CronJob for nightly vacuum + backup rotation
|
||||
- Live at `tutor.puchstein.dev` (tenant-5, ITSH Cloud)
|
||||
- CI: Gitea Actions at `.gitea/workflows/test.yml` — runs `cargo check`, `pnpm check`, `cargo test`, `pnpm build`, and `make test-e2e` on every push to `main` and on PRs
|
||||
|
||||
## Conventions
|
||||
|
||||
- SQLx compile-time queries require `DATABASE_URL` set to a valid SQLite file during `cargo build`/`cargo check`. Use `export DATABASE_URL=sqlite:./dev.db` if running outside `make dev`.
|
||||
- Rust toolchain is pinned to 1.95.0 via `rust-toolchain.toml`.
|
||||
- Frontend indentation: 2 spaces (Svelte/TS files). Backend: standard `rustfmt` defaults.
|
||||
- All SQLx queries are runtime (`sqlx::query_as::<_, T>()`); no compile-time macros are used, so `DATABASE_URL` is not required for `cargo build` or `cargo check`.
|
||||
|
||||
145
GEMINI.md
145
GEMINI.md
@@ -11,70 +11,113 @@ TutorTool is a full-stack web application for tracking student attendance in tut
|
||||
- **Tools**: `remember`, `recall`, `list`, `get_status`.
|
||||
<!-- SLM-END -->
|
||||
|
||||
## Project Overview
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Development
|
||||
make dev # start backend + frontend in parallel
|
||||
make dev-backend # cargo run (port 3000)
|
||||
make dev-frontend # pnpm dev (port 5173, /api proxied to :3000)
|
||||
|
||||
# Build
|
||||
make build # pnpm build, then cargo build --release
|
||||
make compose-up # docker compose build + start
|
||||
|
||||
# Backend
|
||||
cargo test # run all backend unit tests
|
||||
cargo check # fast type check without linking
|
||||
|
||||
# Frontend
|
||||
pnpm check # TypeScript + Svelte type check
|
||||
pnpm build # Vite build to dist/
|
||||
|
||||
# Demo data
|
||||
make seed-demo # wipe dev.db and reseed from backend/demo/demo_seed.sql
|
||||
|
||||
# E2E test pipeline (see docs/testing.md for full detail)
|
||||
make test-up # build test DB if missing, start backend on test port, wait for /health
|
||||
make test-down # stop the test backend
|
||||
make test-reset # fast DB reset via POST /__test__/reset (~10–50 ms)
|
||||
make test-rebuild # wipe and rebuild test DB from migrations + seed
|
||||
make test-e2e # test-up + pnpm test:e2e in one step
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
- **Architecture**: Standalone repo with a Rust backend (Axum) and a SvelteKit 5 frontend.
|
||||
- **Backend**:
|
||||
- **Framework**: Axum (async) on Tokio.
|
||||
- **Database**: SQLite via SQLx. Migrations are automatically run at startup.
|
||||
- **Auth**: JWT-based authentication (`jsonwebtoken` crate) with bcrypt for passwords.
|
||||
- **Static Serving**: Serves the compiled SvelteKit frontend as a Single-Page App (SPA).
|
||||
- **Framework**: Axum (async) on Tokio, port 3000.
|
||||
- **Database**: SQLite via SQLx. All queries use runtime `sqlx::query()` / `sqlx::query_as::<_, T>()` — no compile-time macros, so `DATABASE_URL` is not required for `cargo build` or `cargo check`. Migrations are automatically run at startup.
|
||||
- **Auth**: JWT-based authentication (`jsonwebtoken` crate, 7-day expiry) with bcrypt for passwords. The `TutorClaims` extractor in `auth.rs` enforces authentication on protected routes.
|
||||
- **Static Serving**: Serves the compiled SvelteKit frontend as a Single-Page App (SPA) via `tower_http::ServeDir`.
|
||||
- **`PRAGMA foreign_keys = ON`** is enforced on every connection in `db.rs`.
|
||||
- Route modules: `auth_routes`, `checkin`, `courses`, `rooms`, `sessions`, `attendance`, `notes`, `export`, `tutors`, and `test_reset` (mounted only when `TT_TEST_MODE=1`).
|
||||
- The `/health` route always returns `"ok"` — used by the test pipeline to wait for startup.
|
||||
- **Frontend**:
|
||||
- **Framework**: SvelteKit 5 using Svelte Runes (`$state`, `$derived`, etc.).
|
||||
- **Build Tool**: Vite.
|
||||
- **Build Tool**: Vite with `adapter-static` (SPA mode, `fallback: 'index.html'`).
|
||||
- **Package Manager**: pnpm (preferred over npm).
|
||||
- **Styling**: Vanilla CSS (based on design handoff).
|
||||
- **API**: Centralized fetch wrapper in `src/lib/api.ts`.
|
||||
- **API**: Centralized fetch wrapper in `src/lib/api.ts`; JWT injected from `src/lib/auth.ts`.
|
||||
- **Types**: `src/lib/types.ts` mirrors `backend/src/models.rs` — keep in sync when changing the API.
|
||||
|
||||
## Build and Run
|
||||
## Routes
|
||||
|
||||
### Prerequisites
|
||||
- Rust 1.95.0 (pinned via `rust-toolchain.toml`)
|
||||
- Node.js & pnpm
|
||||
- SQLite
|
||||
### Backend
|
||||
|
||||
### Demo Credentials
|
||||
Route handlers live in `backend/src/routes/` and are merged in `routes/mod.rs`.
|
||||
|
||||
### Frontend
|
||||
|
||||
- `src/routes/admin/login/` — public login page
|
||||
- `src/routes/admin/` — protected tutor-facing pages (guarded by `+layout.svelte` auth check)
|
||||
- `attendance/`, `courses/`, `export/`, `live/`, `rooms/`, `sessions/`, `students/`, `tutors/`
|
||||
- `src/routes/s/[code]/` — public student check-in page
|
||||
|
||||
## Data Model (SQLite, 9 tables)
|
||||
|
||||
```
|
||||
tutors ──< tutor_courses >── courses ──< students
|
||||
└──< sessions ──< slots ──< attendances
|
||||
└──< notes
|
||||
rooms (layout_json) ←── slots.room_id
|
||||
```
|
||||
|
||||
Key slot status transitions: `closed` → `open` → `locked`. The `code` field on slots is the public check-in token students use at `/s/[code]`.
|
||||
|
||||
## Testing
|
||||
|
||||
E2E tests run Playwright against a dedicated test backend daemon. The test backend uses a separate DB and is started with `TT_TEST_MODE=1`, which enables `POST /__test__/reset` for fast state resets (~10–50 ms) without restarting the process. Each git worktree gets its own deterministic port and DB path — no collisions when testing across branches.
|
||||
|
||||
See `docs/testing.md` for the full guide including seed data, MCP-driven verification, and worktree isolation details.
|
||||
|
||||
Demo / seed credentials:
|
||||
- **Admin**: `admin@tutortool.com` / `admin`
|
||||
|
||||
### Environment-specific Fixes
|
||||
- **btrfs pnpm fix**: Use `--package-import-method copy` when running pnpm.
|
||||
## CI
|
||||
|
||||
### Key Commands
|
||||
- `make dev`: Starts both backend and frontend in parallel (requires `JWT_SECRET` and `DATABASE_URL` in environment).
|
||||
- `make build`: Performs a full production build (frontend first, then backend).
|
||||
- `cargo test`: Runs all backend unit and integration tests (uses `sqlx::test`).
|
||||
- `pnpm check`: Performs TypeScript and Svelte type checking for the frontend.
|
||||
|
||||
### Environment Variables
|
||||
- `DATABASE_URL`: Path to the SQLite database (e.g., `sqlite:./dev.db`).
|
||||
- `JWT_SECRET`: Secret key for signing and verifying JWT tokens.
|
||||
- `STATIC_DIR`: Path to the compiled frontend (defaults to `../frontend/build`).
|
||||
|
||||
## Development Conventions
|
||||
|
||||
### Backend (Rust)
|
||||
- **Error Handling**: Uses a custom `AppError` enum (see `error.rs`) that implements `IntoResponse`.
|
||||
- **Database**: Queries use runtime `sqlx::query()` / `sqlx::query_as()`. **Note**: While CLAUDE.md mentions compile-time queries might need `DATABASE_URL`, the current implementation primarily uses runtime queries to simplify CI/CD.
|
||||
- **Routing**: Routes are modularized in `backend/src/routes/` and merged in `routes/mod.rs`.
|
||||
- **Auth**: Use the `TutorClaims` extractor in route handlers to enforce authentication and access the current user's ID and email.
|
||||
|
||||
### Frontend (SvelteKit)
|
||||
- **Runes**: Use Svelte 5 Runes for state management.
|
||||
- **Type Safety**: Ensure `frontend/src/lib/types.ts` is kept in sync with `backend/src/models.rs`.
|
||||
- **Layouts**:
|
||||
- `src/routes/admin/login/`: Public login page.
|
||||
- `src/routes/admin/`: Protected admin routes (tutor dashboard).
|
||||
- `src/routes/s/[code]/`: Public student check-in page.
|
||||
Gitea Actions at `.gitea/workflows/test.yml` runs on every push to `main` and on PRs:
|
||||
1. `cargo check` + `pnpm check` (type checks)
|
||||
2. `cargo test` (unit tests)
|
||||
3. `pnpm build` (frontend build)
|
||||
4. `make test-up` + `pnpm test:e2e` (E2E)
|
||||
|
||||
## Key Files
|
||||
- `backend/src/main.rs`: Entry point and server configuration.
|
||||
- `backend/src/db.rs`: Database initialization and migration logic.
|
||||
- `backend/src/auth.rs`: JWT encoding/decoding and Axum extractor.
|
||||
- `backend/src/models.rs`: Shared data models (DB rows and Request/Response DTOs).
|
||||
- `frontend/src/lib/api.ts`: API client for frontend-backend communication.
|
||||
- `frontend/src/lib/RoomCanvas.svelte`: Interactive SVG-based room layout component.
|
||||
- `conductor/attendance-tool.md`: Detailed implementation plan and project scope.
|
||||
|
||||
## Project History & Context
|
||||
- The project was migrated/continued from a feature branch as documented in `conductor/attendance-tool.md`.
|
||||
- Deployment is targeted at Kubernetes with a 3-stage Docker build.
|
||||
- `backend/src/main.rs` — entry point, `TT_TEST_MODE` flag, `/health` route
|
||||
- `backend/src/db.rs` — database initialization and migration logic
|
||||
- `backend/src/auth.rs` — JWT encoding/decoding and Axum extractor
|
||||
- `backend/src/models.rs` — shared data models (DB rows and Request/Response DTOs)
|
||||
- `backend/src/routes/mod.rs` — router assembly; test_reset mounted conditionally
|
||||
- `backend/src/routes/test_reset.rs` — `POST /__test__/reset` handler (test-mode only)
|
||||
- `backend/demo/demo_seed.sql` — demo/test seed data
|
||||
- `frontend/src/lib/api.ts` — API client for frontend-backend communication
|
||||
- `frontend/src/lib/RoomCanvas.svelte` — interactive SVG-based room layout component
|
||||
- `docs/testing.md` — E2E test pipeline guide
|
||||
|
||||
## Conventions
|
||||
|
||||
- Rust toolchain is pinned to 1.95.0 via `rust-toolchain.toml`.
|
||||
- Frontend indentation: 2 spaces (Svelte/TS files). Backend: standard `rustfmt` defaults.
|
||||
- All SQLx queries are runtime; `DATABASE_URL` is not required for `cargo build`/`cargo check`.
|
||||
- **btrfs pnpm fix**: Use `--package-import-method copy` when running pnpm on btrfs filesystems (e.g., `pnpm install --package-import-method copy`).
|
||||
|
||||
34
README.md
Normal file
34
README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# TutorTool
|
||||
|
||||
Attendance tracker for tutoring sessions. Tutors manage courses, rooms, and slots; students check in via a public QR code link. Live at [tutor.puchstein.dev](https://tutor.puchstein.dev).
|
||||
|
||||
## Quickstart
|
||||
|
||||
```bash
|
||||
make dev
|
||||
# Backend: http://localhost:3000
|
||||
# Frontend: http://localhost:5173
|
||||
```
|
||||
|
||||
Demo credentials: `admin@tutortool.com` / `admin`
|
||||
|
||||
## Stack
|
||||
|
||||
- **Backend**: Rust + Axum + SQLite (via SQLx), JWT auth
|
||||
- **Frontend**: SvelteKit 5 (Svelte runes), TypeScript, adapter-static (SPA)
|
||||
- **Build**: Vite + Cargo; 3-stage Docker build for production
|
||||
|
||||
## Documentation
|
||||
|
||||
| Doc | Contents |
|
||||
|---|---|
|
||||
| [`CLAUDE.md`](CLAUDE.md) | Agent guidance: commands, architecture, conventions |
|
||||
| [`GEMINI.md`](GEMINI.md) | Same, with Gemini-specific context |
|
||||
| [`docs/testing.md`](docs/testing.md) | E2E test pipeline (Playwright + test daemon) |
|
||||
| [`docs/specs/`](docs/specs/) | Feature specs |
|
||||
| [`docs/plans/`](docs/plans/) | Implementation plans |
|
||||
| [`docs/design_handoff/`](docs/design_handoff/) | UI design mocks |
|
||||
|
||||
## Deployment
|
||||
|
||||
Kubernetes via `k8s/` manifests on ITSH Cloud (tenant-5, Hetzner). CI via Gitea Actions at `.gitea/workflows/test.yml`.
|
||||
Reference in New Issue
Block a user