diff options
| -rw-r--r-- | LICENSE | 9 | ||||
| -rw-r--r-- | README.md | 91 | ||||
| -rw-r--r-- | docs/dev/architecture.md | 256 | ||||
| -rw-r--r-- | docs/dev/roadmap.md | 132 |
4 files changed, 488 insertions, 0 deletions
@@ -0,0 +1,9 @@ +MIT License + +Copyright 2025 nsfisis + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6c7ad13 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +# Kioku + +A spaced repetition learning application (Anki clone) with PWA offline support and cloud sync. + +## Features + +- Spaced Repetition: FSRS algorithm for optimal learning scheduling +- Offline Support: Full PWA with IndexedDB local storage +- Cloud Sync: Automatic sync when online with conflict resolution +- Anki Import: Import existing .apkg decks from Anki + +## Tech Stack + +| Layer | Technology | +|-------|------------| +| Frontend | SvelteKit | +| Backend | Hono + TypeScript | +| Database | PostgreSQL | +| ORM | Drizzle | +| Client DB | Dexie.js (IndexedDB) | +| PWA | @vite-pwa/sveltekit | +| Algorithm | FSRS (ts-fsrs) | +| Auth | Username/password + JWT | +| Test | Vitest | +| Monorepo | pnpm workspace | + +## Project Structure + +``` +kioku/ +├── apps/ +│ ├── web/ # SvelteKit frontend (PWA) +│ └── server/ # Hono backend API +└── packages/ + └── shared/ # Shared types and schemas +``` + +## Getting Started + +### Prerequisites + +- Node.js 22+ +- pnpm 9+ +- PostgreSQL 15+ +- Docker (optional) + +### Development + +```bash +# Install dependencies +pnpm install + +# Start PostgreSQL (with Docker) +docker compose up -d postgres + +# Run database migrations +pnpm --filter server db:migrate + +# Start development servers +pnpm dev +``` + +### Environment Variables + +Create `.env` files in each app directory: + +```apps/server/.env +DATABASE_URL=postgresql://user:password@localhost:5432/kioku +JWT_SECRET=your-secret-key +``` + +```apps/web/.env +PUBLIC_API_URL=http://localhost:3000 +``` + +## Scripts + +```bash +pnpm dev # Start all apps in development +pnpm build # Build all apps +pnpm test # Run tests +pnpm lint # Lint code +``` + +## Documentation + +See [docs/dev/architecture.md](docs/dev/architecture.md) for detailed architecture documentation. + +## License + +MIT diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md new file mode 100644 index 0000000..9c3749b --- /dev/null +++ b/docs/dev/architecture.md @@ -0,0 +1,256 @@ +# Kioku Architecture + +## Overview + +Kioku is a spaced repetition learning application (Anki clone) with PWA offline support and cloud sync. + +## Tech Stack + +| Layer | Technology | +|-------|------------| +| Frontend | SvelteKit | +| Backend | Hono + TypeScript | +| Database | PostgreSQL | +| ORM | Drizzle | +| Client DB | Dexie.js (IndexedDB) | +| PWA | @vite-pwa/sveltekit | +| Algorithm | FSRS (ts-fsrs) | +| Auth | username/password + JWT | +| Test | Vitest | +| Monorepo | pnpm workspace | +| Deploy | Docker + VPS | + +## Architecture Diagram + +``` ++--------------------------------------------------+ +| Client (PWA) | +| +-------------+ +------------+ +------------+ | +| | SvelteKit | | Dexie.js | | Service | | +| | UI |<>| (IndexedDB)|<>| Worker | | +| +-------------+ +------------+ +------------+ | +| | | | +| +-------+-------+ | +| | | +| +------v------+ | +| | Sync Engine | | +| +-------------+ | ++--------------------------------------------------+ + | + v HTTPS (REST API) ++--------------------------------------------------+ +| Server | +| +----------------------------------------------+| +| | Hono (TypeScript) || +| | +--------+ +--------+ +--------+ +--------+ || +| | | Auth | | FSRS | | Sync | | Import | || +| | +--------+ +--------+ +--------+ +--------+ || +| +----------------------------------------------+| +| | | +| v | +| +----------------------------------------------+| +| | PostgreSQL (Drizzle) || +| +----------------------------------------------+| ++--------------------------------------------------+ +``` + +## Project Structure + +``` +kioku/ +├── package.json # Workspace root +├── pnpm-workspace.yaml +├── docker-compose.yml +├── apps/ +│ ├── web/ # SvelteKit frontend +│ │ ├── src/ +│ │ │ ├── lib/ +│ │ │ │ ├── components/ +│ │ │ │ ├── stores/ +│ │ │ │ ├── db/ # Dexie IndexedDB +│ │ │ │ ├── sync/ # Sync engine +│ │ │ │ └── api/ +│ │ │ └── routes/ +│ │ └── static/ +│ └── server/ # Hono backend +│ └── src/ +│ ├── routes/ +│ ├── services/ +│ ├── db/ # Drizzle schema +│ ├── middleware/ +│ └── lib/ +│ └── apkg/ # Anki import +└── packages/ + └── shared/ # Shared types + └── src/ + ├── types/ + └── schemas/ # Zod validation +``` + +## Data Models + +### User + +```typescript +interface User { + id: string; // UUID + username: string; // unique + password_hash: string; + created_at: Date; + updated_at: Date; +} +``` + +### Deck + +```typescript +interface Deck { + id: string; + user_id: string; + name: string; + description: string | null; + new_cards_per_day: number; + created_at: Date; + updated_at: Date; + deleted_at: Date | null; // Soft delete + sync_version: number; +} +``` + +### Card (FSRS) + +```typescript +enum CardState { + New = 0, + Learning = 1, + Review = 2, + Relearning = 3, +} + +interface Card { + id: string; + deck_id: string; + front: string; // Plain text + back: string; // Plain text + + // FSRS fields + state: CardState; + due: Date; + stability: number; + difficulty: number; + elapsed_days: number; + scheduled_days: number; + reps: number; + lapses: number; + last_review: Date | null; + + created_at: Date; + updated_at: Date; + deleted_at: Date | null; + sync_version: number; +} +``` + +### ReviewLog + +```typescript +enum Rating { + Again = 1, + Hard = 2, + Good = 3, + Easy = 4, +} + +interface ReviewLog { + id: string; + card_id: string; + user_id: string; + rating: Rating; + state: CardState; + scheduled_days: number; + elapsed_days: number; + reviewed_at: Date; + duration_ms: number | null; + sync_version: number; +} +``` + +## API Design + +### Authentication + +``` +POST /api/auth/register - User registration +POST /api/auth/login - Login (returns JWT) +POST /api/auth/refresh - Refresh token +POST /api/auth/logout - Logout +``` + +### Decks + +``` +GET /api/decks - List decks +POST /api/decks - Create deck +GET /api/decks/:id - Get deck +PUT /api/decks/:id - Update deck +DELETE /api/decks/:id - Delete deck (soft) +``` + +### Cards + +``` +GET /api/decks/:deckId/cards - List cards +POST /api/decks/:deckId/cards - Create card +PUT /api/decks/:deckId/cards/:id - Update card +DELETE /api/decks/:deckId/cards/:id - Delete card +``` + +### Study + +``` +GET /api/decks/:deckId/study - Get cards to study +POST /api/decks/:deckId/study/:cardId - Submit review +``` + +### Sync + +``` +POST /api/sync/push - Push local changes to server +GET /api/sync/pull - Pull server changes +``` + +### Import + +``` +POST /api/import/apkg - Import Anki deck +``` + +## Offline Sync Strategy + +### Approach + +- **Method**: Last-Write-Wins with timestamps +- **Client**: Store in IndexedDB with `_synced` flag +- **Conflict Resolution**: Compare `updated_at`, newer wins +- **ReviewLog**: Append-only (no conflicts) + +### Sync Flow + +1. Local changes saved with `_synced = false` +2. On sync, push pending changes to server +3. Server resolves conflicts by timestamp +4. Client pulls server changes +5. Mark synced items with `_synced = true` + +## Authentication + +- **Hash**: Argon2 for password hashing +- **Access Token**: JWT, 15min expiry +- **Refresh Token**: JWT, 7 days, stored in DB + +## References + +- [ts-fsrs](https://github.com/open-spaced-repetition/ts-fsrs) +- [Anki APKG Format](https://eikowagenknecht.de/posts/understanding-the-anki-apkg-format/) +- [Vite PWA for SvelteKit](https://vite-pwa-org.netlify.app/frameworks/sveltekit.html) +- [Dexie.js](https://dexie.org/) diff --git a/docs/dev/roadmap.md b/docs/dev/roadmap.md new file mode 100644 index 0000000..32af8c7 --- /dev/null +++ b/docs/dev/roadmap.md @@ -0,0 +1,132 @@ +# Kioku Development Roadmap + +## Phase 1: Foundation + +### Project Setup +- [x] Create docs/dev/architecture.md +- [x] Create docs/dev/roadmap.md +- [ ] Initialize pnpm workspace +- [ ] Configure TypeScript +- [ ] Configure Biome +- [ ] Setup Vitest + +### Database +- [ ] Docker Compose with PostgreSQL +- [ ] Drizzle ORM setup +- [ ] Database migrations + +### Shared Package +- [ ] Create packages/shared +- [ ] Define types (User, Deck, Card, ReviewLog) +- [ ] Zod validation schemas + +### Server Foundation +- [ ] Initialize Hono app +- [ ] Error handling middleware +- [ ] Logger middleware + +### Authentication +- [ ] User registration endpoint +- [ ] Login endpoint (JWT) +- [ ] Refresh token endpoint +- [ ] Auth middleware + +## Phase 2: Core Features + +### Server API +- [ ] Deck CRUD endpoints +- [ ] Card CRUD endpoints +- [ ] ts-fsrs integration +- [ ] Study endpoints (get cards, submit review) + +### Frontend Foundation +- [ ] Initialize SvelteKit +- [ ] Setup routing +- [ ] API client + +### Auth UI +- [ ] Login page +- [ ] Register page +- [ ] Auth store + +### Deck Management UI +- [ ] Deck list page +- [ ] Deck detail page +- [ ] Create/edit deck + +### Card Management UI +- [ ] Card list view +- [ ] Create/edit card + +### Study UI +- [ ] Study session page +- [ ] Card flip interaction +- [ ] Rating buttons (Again, Hard, Good, Easy) +- [ ] Progress display + +## Phase 3: Offline Support + +### IndexedDB +- [ ] Dexie.js setup +- [ ] Local schema (with sync flags) +- [ ] Local CRUD operations + +### PWA +- [ ] @vite-pwa/sveltekit configuration +- [ ] Web manifest +- [ ] Service Worker +- [ ] Offline fallback + +### Sync Engine +- [ ] Sync queue management +- [ ] Push implementation +- [ ] Pull implementation +- [ ] Conflict resolution +- [ ] Auto-sync on reconnect + +### Sync API +- [ ] POST /api/sync/push +- [ ] GET /api/sync/pull + +### Sync UI +- [ ] Sync status indicator +- [ ] Manual sync button +- [ ] Offline mode indicator + +## Phase 4: Anki Import + +### Parser +- [ ] ZIP extraction +- [ ] SQLite database reading +- [ ] Note/Card mapping + +### Import API +- [ ] POST /api/import/apkg +- [ ] Progress tracking + +### Import UI +- [ ] File upload +- [ ] Import progress +- [ ] Import results + +## Phase 5: Deployment + +### Docker +- [ ] Dockerfile for server +- [ ] Dockerfile for web (static build) +- [ ] compose.yml (full stack) + +### Production +- [ ] Environment configuration +- [ ] Backup strategy + +### Documentation +- [ ] README.md + +## Future Considerations + +- Statistics and analytics +- Export functionality +- Multiple card types +- Tags and search +- Keyboard shortcuts |
