Study/AGENTS.md
Elijah 061d13f421
All checks were successful
Automated Container Build / build-and-push (push) Successful in 59s
Update AGENTS.md
2026-07-11 19:29:45 -07:00

350 lines
No EOL
13 KiB
Markdown

# Study Desk - AI Contributor Guide
This file is the operating guide for AI agents and human contributors working in this repository.
## Project summary
Study Desk is a self-hosted, single-user study application built with Next.js, React, TypeScript, Prisma, and SQLite.
Core capabilities:
- Flashcard decks with Markdown content, self-grading, shuffle persistence, resume state, and card management
- Practice quizzes with multiple-choice and SATA questions, partial-credit scoring, rationales, category breakdowns, retakes, and attempt history
- JSON import, repair, validation, and generation workflows
- Material groups for organizing decks and quizzes
- Password-protected private pages
- Public, read-only share links for decks, quizzes, and groups
- Responsive light and dark themes
This is intentionally a single-user container, not a multi-tenant SaaS application. There is no `User` model. Content ownership is implicit in the local installation.
When documentation conflicts with implementation, prefer:
1. Current source code
2. `prisma/schema.prisma`
3. Applied migrations
4. This file
5. Older planning documents and the stock README
## Mandatory working rules
- Inspect `git status --short` before editing.
- Preserve unrelated user changes.
- Keep changes scoped to the requested behavior.
- Do not use destructive commands such as `git reset --hard` or `git checkout --` unless explicitly requested.
- Prefer narrow, patch-based edits over rewriting entire files.
- Do not commit secrets, `.env` files, database contents, generated credentials, or private study material.
- Do not manually edit generated Prisma files under `src/generated/prisma/`.
- Do not modify an already-applied migration. Change `prisma/schema.prisma`, then create a new migration.
- Prefer TypeScript types over `any`.
- Add dependencies only when the existing stack cannot reasonably solve the problem.
- When dependencies change, update `package-lock.json` and verify the build.
- Separate UI, route handling, services, and low-level utilities by responsibility.
- Ask a clarifying question only when missing information would materially change the implementation or create a risky assumption.
## Stack and source of truth
Confirm exact versions in `package.json`. The project currently uses:
- Next.js 16 App Router
- React 19
- TypeScript in strict mode
- Tailwind CSS v4
- Prisma 7 with SQLite and `@prisma/adapter-better-sqlite3`
- `iron-session` for encrypted session cookies
- Argon2 password hashing
- Zod validation
- `react-markdown` with `remark-gfm`
- `@dnd-kit` for sortable UI
- Node 22 in Docker
Important files:
- `package.json` - scripts and dependency versions
- `prisma/schema.prisma` - database source of truth
- `src/lib/db.ts` - shared Prisma client
- `src/lib/auth.ts` - session helpers
- `src/services/` - business logic and database access
- `src/app/api/` - route handlers
- `src/app/globals.css` - design tokens and global styling
- `src/config/studyModes.ts` - shared study-mode navigation
- `SKILL.md` - project workflow for adding API routes
- `study-app-implementation-plan.md` - historical architectural context only
- `README.md` - currently not authoritative
For framework-sensitive changes involving routing, layouts, dynamic params, middleware, server/client boundaries, or framework APIs, follow nearby repository patterns and consult version-matched Next.js documentation. Do not perform unrelated framework migrations.
## Local development
For a clean checkout:
```bash
npm ci
npx prisma generate
npm run dev
```
On Windows PowerShell, use `npm.cmd` and `npx.cmd` if script execution policy blocks the default shims.
Useful scripts:
```bash
npm run dev
npm run build
npm run start
npm run lint
```
There is currently no configured test runner. Use focused manual verification plus `npm run build`. Run lint as well, but distinguish pre-existing failures from failures introduced by the current change.
## Environment and authentication
Common environment variables:
- `DATABASE_URL` - SQLite URL
- `SESSION_SECRET` - `iron-session` secret, at least 32 characters outside throwaway local development
- `SECURE_COOKIES` - marks the session cookie secure when set to `true`
- `ADMIN_PASSWORD_HASH` - present in `.env.example`, but currently not used by the login flow
Current password behavior:
1. On first login, the submitted password is Argon2-hashed.
2. The hash is stored in the `Setting` row `admin_password_hash`.
3. Later logins verify against that stored hash.
Do not change password provisioning casually. Any change must update login, setup-status behavior, deployment documentation, and security handling together.
Authentication state is stored in the `study-app-session` cookie.
Public paths include:
- `/login`
- `/api/auth/*`
- `/shared/*`
- Static assets and Next internals
Everything else requires authentication unless explicitly designed and reviewed as public.
Do not log passwords, secrets, full share tokens, or private study content.
## Database and migration safety
The local `dev.db` may contain real study data.
- Do not delete, reset, replace, or recreate it during normal work.
- Back up the database before destructive migration work.
- Use the shared Prisma client from `@/lib/db`.
- Do not create additional `PrismaClient` instances in request handlers or components.
- Use transactions when partial writes would leave inconsistent state.
- Return 404 responses for missing records instead of exposing raw Prisma errors.
After changing the Prisma schema:
```bash
npx prisma generate
npx prisma migrate dev --name describe_the_change
```
Use `npx prisma migrate deploy` for deployed environments.
## Architecture conventions
### Server and client components
- Use Server Components by default.
- Add `"use client"` only when state, effects, event handlers, browser APIs, drag and drop, or client-side fetching are required.
- Keep database and authentication modules out of client import graphs.
- Do not access `window`, `localStorage`, `navigator`, or clipboard APIs from Server Components.
- Prefer `Link` for ordinary internal navigation.
- Use `useRouter` when navigation follows an action or must be imperative.
- Follow nearby Next.js 16 patterns for dynamic params and route context types.
### API routes and services
Preferred route-handler flow:
1. Parse and validate external input.
2. Delegate business logic to focused service or utility functions.
3. Return a useful status and JSON response.
Business logic and Prisma calls normally belong in `src/services/` or a focused `src/lib/` module. Reuse existing services before creating new abstractions.
Some older routes still contain direct Prisma calls or loose input handling. Improve the requested path without turning a small task into a broad refactor.
### Validation
- Reuse existing Zod schemas where available.
- Never rely only on client-side validation.
- Validate IDs, required strings, enums, arrays, and import payloads at the API boundary.
- Keep stored JSON parseable.
- Use `jsonRepair.ts` only for user- or LLM-generated import text, not to hide malformed database state.
## UI and accessibility
Use the existing design system in `src/app/globals.css`.
Common tokens include:
- `bg-bg-base`
- `bg-bg-surface`
- `bg-bg-surface-alt`
- `text-text-heading`
- `text-text-secondary`
- `text-text-muted`
- `primary`
- `primary-hover`
- `border`
- `border-light`
- `success`
- `error`
Preserve:
- Light and dark themes
- Responsive mobile layouts
- Existing card, modal, shadow, and rounded-corner language
- `editorial-title` for major serif headings
- Manrope for interface text
- Existing Markdown rendering through `ReactMarkdown`, `remarkGfm`, and `.markdown-content`
- Existing `@dnd-kit` patterns for sortable content
Accessibility requirements:
- Use semantic buttons and links.
- Preserve visible keyboard focus states.
- Give icon-only controls an accessible name with visible text or `aria-label`.
- Keep interactive controls keyboard accessible.
- Avoid horizontal overflow on study pages, library cards, modals, and action rows.
- Do not attach drag listeners to nested action buttons.
## Domain invariants
### Flashcards
- A deck contains ordered `Flashcard` rows with `front` and `back`.
- Study progress stores order and results as JSON.
- Study mode may be sequential or shuffled.
- Saved progress may contain stale card IDs after deletion. Resume helpers must filter and clamp stale IDs safely.
- Preserve both study and manage views.
- Preserve existing sharing entry points when adding new ones.
### Quizzes
- A quiz contains ordered questions with ordered answer options.
- `MULTIPLE_CHOICE` questions must have exactly one correct option.
- `SATA` questions may have multiple correct options.
- SATA uses partial-credit scoring in `src/lib/scoring.ts`.
- Partial retakes score only questions present in the submitted answer set.
- Attempts persist score, maximum score, submitted answers, retake state, and completion time.
- In-progress answers and position persist through `/api/progress`.
### Imports and generation
Flashcard import shape:
```json
{
"type": "flashcards",
"deckName": "Deck name",
"description": "Optional description",
"cards": [{ "front": "...", "back": "..." }]
}
```
Quiz import shape:
```json
{
"type": "quiz",
"quizName": "Quiz name",
"description": "Optional description",
"questions": [
{
"type": "multiple_choice",
"prompt": "...",
"category": "topic",
"options": [{ "text": "...", "correct": true }],
"rationale": "..."
}
]
}
```
The app does not call an LLM directly. The Generate UI prepares instructions and accepts generated JSON from the user.
Preserve Markdown inside JSON string values and render it through existing Markdown components.
Keep the current separation between `ImportModal`, `CreateTab`, `ImportTab`, and `GenerateTab`.
### Sharing
- `ShareLink` may target a `DECK`, `QUIZ`, or `GROUP`.
- Reuse `src/components/ui/ShareMenu.tsx`.
- Public routes are `/shared/<classSlug>/<type>/<token>`.
- Public viewers are read-only.
- Public viewers must not write authenticated progress.
- Validate that token, type, and class slug agree before returning shared content.
- A deck or quiz may appear publicly shared through its group. Preserve inherited group-share behavior and `?itemId=...` handling.
## Verification checklist
Before editing:
- Read `git status --short`.
- Inspect the target component, route, service, and schema paths relevant to the requested behavior.
- Check whether the change affects authentication, public sharing, migrations, generated Prisma output, or real study data.
During implementation:
- Keep route, service, utility, and component responsibilities clear.
- Add validation for new external input.
- Reuse existing design tokens, components, and services.
- Consider loading, error, empty, mobile, keyboard, light-theme, and dark-theme states.
- Avoid unrelated cleanup.
After editing:
```bash
npm run lint
npm run build
```
If lint already fails, report baseline failures separately.
For UI work, manually verify:
1. The affected authenticated route
2. The corresponding public/shared route when applicable
3. Loading, error, and empty states
4. Study resume and restart behavior when relevant
5. Drag and drop when relevant
6. Light and dark themes
7. A narrow mobile viewport
8. No horizontal overflow
9. Keyboard access for changed controls
## Known repository conditions
- `README.md` is still mostly stock create-next-app documentation.
- `study-app-implementation-plan.md` contains useful historical context but may be stale.
- `task.md` records completed implementation phases.
- `SKILL.md` describes the expected workflow for new API routes.
- The current lint baseline includes existing errors such as `any` usage and React effect-rule violations.
- A successful `next build` is the primary repository-wide compile and type check.
- The current middleware convention produces a known deprecation warning.
- `docker-compose.yml` may publish port `3000`, while the production Docker image uses port `3726`. Verify the mapping before relying on production Compose.
- Do not silently fix known baseline issues as unrelated cleanup.
## Extending the application
For a genuinely new study mode:
1. Add or update the Prisma model and migration when persistence is required.
2. Add a focused service in `src/services/`.
3. Add API routes under `src/app/api/`.
4. Add page routes and client components.
5. Add the mode to `src/config/studyModes.ts` when it belongs in shared navigation.
6. Extend progress, import, scoring, or sharing only when required.
7. Verify authentication, public/private boundaries, mobile layout, and both themes.
Do not add a new mode by placing unrelated logic into `deckService.ts`, `quizService.ts`, or a large page component.