Skip to content

Latest commit

 

History

History
311 lines (232 loc) · 13.1 KB

File metadata and controls

311 lines (232 loc) · 13.1 KB

Sinau LMS - Product Requirements Document

Version: 0.1.0-draft
Date: Jul 16, 2026
Author: CTO
Status: Planning
Repo: codecoradev/sinau-lms


1. Product Vision

Sinau LMS is a modern, lightweight, self-hostable open-source learning management system. Built with Rust (Axum) + SvelteKit 5 for optimal performance and developer experience.

Name: Sinau - Javanese (Krama) for "to learn".
Tagline: Learn without limits, platform without weight.

1.1 Target Users

Persona Description Core Needs
Content Creator Teacher, instructor, content writer Create courses, manage chapters, publish content
Student/Learner Online learner Access courses, track progress, self-paced learning
Admin Platform manager Manage users, orgs, analytics, configuration
Developer Integrator / headless consumer API access, webhooks, custom frontend

1.2 Problem Statement

LearnHouse is the most modern open-source LMS today, but uses Python (FastAPI) + Next.js (React). For an ecosystem already built on Rust + SvelteKit (Hompimpah), an LMS is needed that:

  • Consistent stack - Rust backend, SvelteKit frontend
  • Lightweight - runs on SQLite for development, PostgreSQL for production
  • Not over-engineered - without unused features (code execution, podcasts, trails)
  • Full control - custom domain logic, auth module, deployment patterns

2. Feature Specification

2.1 Tier 1 - Must Have (MVP)

F-001: User Management & Authentication

Field Specification
Registration OAuth-only (no email/password). Google, GitHub, Keycloak.
Login OAuth2 Authorization Code flow with CSRF protection (state token).
Session JWT (HS256), 7-day expiry, HttpOnly cookie.
Logout Clear session cookie.
Profile Email, name, avatar (from OAuth provider).
RBAC Roles , , . Admin = full access, Teacher = create/manage courses, Student = consume content.
Admin Emails ENV-based - emails matching auto-promoted to admin.

User Model:

F-002: Organization

Field Specification
Single-tenancy first One default org. Multi-org later.
Org Model slug, name, logo, config JSON
Membership User <-> Org via UserOrganization table

Organization Model:

F-003: Courses

Field Specification
CRUD Create, Read, Update, Delete courses
Published/Public = visible to authenticated users. = visible without auth.
Thumbnail Image upload, stored as file.
Clone Duplicate course with all chapters + activities.
Meta Endpoint GET single course with all chapters + activities (nested).
List Paginated, filterable by org.

Course Model:

F-004: Chapters

Field Specification
Hierarchical Chapter belongs to Course via join table.
Reorder POST /chapters/reorder with ordered IDs.
Activities Chapter has many activities (ordered).

Chapter Model:

F-005: Activities (Content)

Field Specification
Activity Types (TipTap JSON), ,
Content Storage TYPE_DYNAMIC -> column (TipTap JSON). Others -> .
Published Activity-level published flag.
Lock Type (free), , (future).

Activity Model:

F-006: Content Editor

Field Specification
Editor TipTap rich text editor (Svelte extension). See editor selection analysis below.
Block Types Heading (1-6), Paragraph, Bullet List, Ordered List, Code Block, Blockquote, HR, Image, Table
Inline Types Bold, Italic, Code, Link, Strikethrough
Storage Format TipTap/ProseMirror JSON (LearnHouse-compatible).
Image Upload Inline image upload within editor.

Editor Selection Analysis:

Why TipTap over alternatives? Full comparison below.

Editor Based On Svelte Support Bundle Size License Collaboration Verdict
TipTap ProseMirror Official extension Small (tree-shakable) MIT (core) Yjs + Tiptap Cloud + Liveblocks Selected
BlockNote TipTap + ProseMirror No (React-only) Larger MPL 2.0 Yjs + Liveblocks Not suitable (React-only)
Lexical Custom (Meta) Community/unofficial Larger core MIT Yjs + Liveblocks (buggy) Immature (< 1.0), collaboration issues
Slate Custom Community/unofficial Medium MIT Yjs (no official) No Svelte support, harder API
ProseMirror - No (Vanilla JS) Small MIT Yjs (manual) Too low-level, no Svelte bindings
Plate Slate No (React-only) Medium MIT Hocuspocus (Yjs) React-only

Why TipTap:

  1. ProseMirror foundation - Battle-tested, proven at scale (used by GitBook, New York Times).
  2. Framework-agnostic - Official Svelte extension exists. Same core works across frameworks.
  3. Headless - Full control over UI. Build custom toolbars, menus, slash commands.
  4. Extension system - Add nodes, marks, plugins without forking. Override behavior of existing extensions.
  5. JSON storage - ProseMirror JSON format. Compatible with LearnHouse content. Easy to parse/validate server-side.
  6. Collaboration-ready - Yjs support built-in. Can add real-time co-editing later (Phase 2+) without switching editor.
  7. MIT license (core) - Open-source core is genuinely free. Pro features (AI, comments, etc.) are paid but not needed for MVP.
  8. Tree-shakable - Only ship extensions you use. Core bundle is smaller than Lexical, Slate, and Quill.

Alternatives considered and rejected:

  • BlockNote - Great for Notion-like block editing, but React-only. No Svelte support. Deal-breaker.
  • Lexical - Backed by Meta, active development. But: no pure decorations (DOM workarounds needed), collaboration has hardcoded root node (can't have multiple editors per doc), no official Svelte support, still pre-1.0.
  • Slate - Powerful but React-only ecosystem. Steep learning curve. No Svelte bindings.
  • ProseMirror - Too low-level. No Svelte bindings. Would need to build TipTap-equivalent on top of it anyway.

Editor Selection Analysis:

Why TipTap over alternatives?

Editor Based On Svelte Support Bundle Size License Collaboration Verdict
TipTap ProseMirror Official extension Small (tree-shakable) MIT (core) Yjs + Tiptap Cloud + Liveblocks Selected
BlockNote TipTap + ProseMirror No (React-only) Larger MPL 2.0 Yjs + Liveblocks Rejected (React-only)
Lexical Custom (Meta) Community/unofficial Larger core MIT Yjs + Liveblocks (buggy) Rejected (pre-1.0, collab issues)
Slate Custom Community/unofficial Medium MIT Yjs (no official) Rejected (no Svelte, harder API)
ProseMirror - No (Vanilla JS) Small MIT Yjs (manual) Rejected (too low-level)
Plate Slate No (React-only) Medium MIT Hocuspocus (Yjs) Rejected (React-only)

Why TipTap:

  1. ProseMirror foundation - Battle-tested at scale (GitBook, New York Times).
  2. Framework-agnostic - Official Svelte extension. Same core across frameworks.
  3. Headless - Full UI control. Custom toolbars, menus, slash commands.
  4. Extension system - Add/override nodes, marks, plugins without forking.
  5. JSON storage - ProseMirror JSON. LearnHouse-compatible. Server-side parseable.
  6. Collaboration-ready - Yjs support built-in. Real-time co-editing can be added later without switching.
  7. MIT license (core) - Genuinely free core. Pro features (AI, comments) are paid but not needed for MVP.
  8. Tree-shakable - Ship only extensions you use. Core smaller than Lexical, Slate, Quill.

Alternatives rejected:

  • BlockNote - Great Notion-like editing but React-only. No Svelte = deal-breaker.
  • Lexical - Meta-backed, active dev. But: no pure decorations, collab hardcodes root node (one editor per doc), no official Svelte support, pre-1.0.
  • Slate - Powerful but React-only ecosystem. Steep learning curve.
  • ProseMirror - Too low-level. No Svelte bindings. Would rebuild TipTap on top anyway.

F-007: Media Upload

Field Specification
Endpoint POST /media/upload (multipart).
Storage Pluggable: local filesystem OR S3-compatible (MinIO, AWS S3, Cloudflare R2). Toggle via env.
Supported Types Image (png, jpg, webp, gif, svg), Document (pdf, doc), Video (mp4, webm).
Max Size 10MB default (ENV configurable).

Media Model:

F-008: API Tokens

Field Specification
Purpose Headless API access (without OAuth/JWT session).
Generation Admin/Teacher can create tokens.
Format prefix + random 32 chars.
Auth header.

ApiToken Model:

F-009: Webhooks

Field Specification
Purpose Notify external systems on events.
Events , , , , ,
Delivery POST to configured URL with signed payload (HMAC-SHA256).
Retry 3 retries with exponential backoff.

Webhook Model:


2.2 Tier 2 - Important (Phase 2)

ID Feature Brief Spec
F-010 Search Full-text search via SQLite FTS5 / Postgres tsvector.
F-011 Analytics User progress per course, time spent, enrollment count.
F-012 Folders Group courses into named folders.
F-013 User Groups Named groups of users. Control access.
F-014 Communities Threaded discussion per course. Posts, replies, likes.
F-015 Assignments Tasks with due date, submission, grading.
F-016 Certificates Auto-generated PDF on course completion.
F-017 Boards Collaborative whiteboard per course.

2.3 Tier 3 - Later (Phase 3+)

ID Feature Brief Spec
F-018 AI Features RAG tutoring, embeddings. Requires pgvector.
F-019 Payments Stripe integration. Sell courses.
F-020 SSO SAML/OIDC via WorkOS or Keycloak advanced.
F-021 Custom Domains Per-org custom domain routing.
F-022 Billing Usage tracking, subscription plans.

3. Non-Functional Requirements

3.1 Performance

Metric Target
API response (read) < 50ms p95 (single entity)
API response (list) < 200ms p95 (20 items)
Page load (SSR) < 500ms TTFB
Concurrent users 100+ (SQLite), 1000+ (Postgres)

3.2 Security

Requirement Implementation
Authentication JWT (HS256) HttpOnly cookie + CSRF state token
Authorization RBAC per-route via Axum middleware
Input validation sqlx compile-time checked SQL
File upload Type whitelist, size limit, no executable files
CORS Configurable origins (ENV)

3.3 Reliability

Requirement Implementation
Database backups sqlite3 backup / pg_dump via cron
Error handling Unified error type, structured JSON errors
Logging tracing crate, structured JSON logs
Health check GET /api/health - DB connectivity status

4. API Design Principles

  1. RESTful - Standard HTTP methods (GET, POST, PUT, DELETE)
  2. JSON - All request/response bodies in JSON
  3. Consistent errors -
  4. Pagination - pattern
  5. Auth - Cookie-based (JWT) OR Bearer token (API tokens)
  6. Prefix - All API routes under
  7. No trailing slash - Consistent

5. Tech Stack

Layer Technology Version
Runtime Bun latest
Frontend SvelteKit 5.x
UI Framework Svelte 5 (runes) 5.x
Styling Tailwind CSS 4.x
UI Components shadcn-svelte latest
Editor TipTap 2.x
Backend Rust (Axum) 0.8.x
DB Access sqlx 0.8.x
Database SQLite (dev) / PostgreSQL (prod) 16+
Migration sqlx-cli 0.8.x
Auth JWT (jsonwebtoken) latest
HTTP Client reqwest latest
Logging tracing latest
Serialization serde + serde_json latest

6. Milestones

Milestone Scope Target Status
M1 - Planning PRD, ERD, Roadmap, Repo setup Jul 16, 2026 In Progress
M2 - Foundation API Skeleton, config, DB, auth, users, orgs, courses Week 1-3 Pending
M3 - Content API Media upload, content CRUD, course clone Week 3-5 Pending
M4 - Access Control API RBAC, orgs, API tokens, webhooks, folders, groups Week 5-7 Pending
M5 - Engagement API Search, analytics, discussions, assignments, certs Week 7-9 Pending
M6 - Frontend SvelteKit dashboard, editor, public view, settings Week 9-12 Pending
M7 - Production Docker, deploy, CI, docs, release Week 12-13 Pending