Skip to content

Repository files navigation

Dreambook — Next.js + TailwindCSS

A multi-book, hands-on learning platform. Each book becomes its own course with lessons, quizzes, exercises/clinical cases, assignments, and flashcards. Progress is saved in the browser (localStorage).

Three courses ship in the box:

  • The Well-Grounded Rubyist (16 chapters) — a code book with a live in-browser Ruby playground and auto-checked coding exercises, powered by ruby.wasm loaded from a CDN at runtime.
  • Harrison's Principles of Internal Medicine (14 modules, first ~500 pages) — a reflect book with clinical-vignette quizzes and self-assessed cases.
  • Newman and Carranza's Clinical Periodontology (14 modules, 14th ed.) — a reflect book covering the periodontium, biofilm, pathogenesis, the 2017 staging/grading, diagnosis, surgery, and implantology, with vignette quizzes and clinical cases.

Accounts & database

Each person has their own account, and progress (lesson completion, quiz scores, exercise/case status, assignment checklists, notes) is stored per user in Postgres and synced across devices. Auth is intentionally lightweight — no third-party auth service:

  • Passwords are hashed with Node's built-in scrypt (random per-user salt).
  • Sessions are opaque tokens stored in the sessions table and carried in an httpOnly, Secure, SameSite=Lax cookie (revocable server-side).
  • middleware.ts gates every non-public route; unauthenticated visitors are sent to /login.
  • Tables (users, sessions, user_progress) are created automatically on first request (ensureSchema()), so there's no migration step to run.

Required environment variables

Copy .env.example to .env and fill in:

Variable Required Purpose
DATABASE_URL yes* Postgres connection string (SSL auto-enabled for non-localhost hosts).
POSTGRES_URL yes* Alternative name — auto-set by Vercel Postgres/Neon. Either one works.
SIGNUP_CODE no If set, new sign-ups must enter this exact code (invite gate for a small group).

* Provide exactly one of DATABASE_URL / POSTGRES_URL. Use the pooled connection string on serverless (Vercel).

On Vercel: add these under Project → Settings → Environment Variables (the .env file is git-ignored and never deployed). Setting SIGNUP_CODE is recommended so only people you share the code with can register.

Getting started

npm install
cp .env.example .env    # then set DATABASE_URL
npm run dev             # http://localhost:3000  → redirects to /login

Build for production:

npm run build
npm start

The Ruby playground fetches the ruby.wasm runtime (~25 MB) from jsDelivr the first time you run code, so that feature needs an internet connection. Every other part of the site works fully offline.

Project structure

middleware.ts                  Auth gate — redirects unauthenticated users to /login
app/
  page.tsx                     Library (bookshelf)
  login/ , register/           Auth pages
  api/
    register, login, logout    Auth endpoints (set/clear session cookie)
    me                         Current-user lookup
    progress                   GET/PUT per-user progress (Postgres)
  [bookId]/
    layout.tsx                 Sidebar shell + per-book accent theme
    page.tsx                   Book dashboard
    playground/page.tsx        Ruby playground (code books only)
    flashcards/page.tsx        Full flashcard deck
    [chapterId]/page.tsx       Chapter with Lesson/Quiz/Exercises/Assignment/Cards tabs
components/                    Reusable UI (CodeRunner, Quiz, SessionProvider, UserMenu, …)
lib/
  types.ts                     Shared TypeScript types
  books.ts                     Book registry
  ruby.ts / harrison.ts / perio.ts   Course content (data)
  rubyvm.ts                    ruby.wasm loader + runner
  db.ts                        Postgres pool + schema bootstrap
  auth.ts                      Password hashing (scrypt) + sessions
  progress.ts                  Server-synced per-user progress store (useSyncExternalStore)

Adding another book

  1. Add a chapter-data module in lib/ (an array of Chapter objects).
  2. Register the book in lib/books.ts with practice: "code" (gives a code runner) or practice: "reflect" (gives self-assessed cases).

The routes, sidebar, dashboard, and progress tracking pick it up automatically.

Styling

TailwindCSS (v3) provides layout and utility classes; the shared design-system components (cards, code runner, quiz options, flashcards, etc.) are defined as component classes in app/globals.css using CSS variables, so the per-book accent color can be swapped at runtime.

About

Turn books into hands-on courses

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages