A minimal, self-hostable LMS built with React 19 + TypeScript + Vite and Firebase (anonymous auth + Firestore). Designed to be cloned, customized, and deployed without touching backend infrastructure.
Demo mode lets you run the app locally with zero Firebase setup — just
npm install && npm run dev.
| Light mode | Dark mode |
|---|---|
![]() |
![]() |
The app has two views, switchable at the top of the page:
| View | Purpose |
|---|---|
| Workshop | Accordion-style interactive session — quick-wins gallery, custom sections, knowledge check quiz. |
| My Learning | Per-user learning path with module cards, hands-on tasks, progress tracking, and a curriculum map. Requires Firebase. |
Content for both views is defined in plain JSON files and seeded into Firestore. There is no CMS, no backend functions, and no accounts — visitors sign in anonymously.
git clone https://github.com/lbohn12/workshop-lms-starter.git
cd workshop-lms-starter
cp .env.example .env.local # VITE_DEMO_MODE=true is already set
npm install
npm run devOpen http://localhost:5173. The Workshop tab loads immediately. The My Learning tab is hidden in demo mode (there's no backing store).
See docs/setup-firebase.md for a step-by-step walkthrough. The short version:
- Create a Firebase project, enable Anonymous Authentication and Firestore.
- Copy the web SDK config into
.env.localand setVITE_DEMO_MODE=false. - Place a service account key at
scripts/service-account-key.jsonand runnpm run seed. firebase deploy --only firestore:rules,firestore:indexes,hosting
.
├── App.tsx # auth + view switcher
├── firebase.ts # env-driven init, DEMO_MODE flag
├── types.ts # shared TypeScript interfaces
├── firestore.rules # security rules
├── firestore.indexes.json # composite indexes
│
├── seed-data/ # your content lives here
│ ├── example-modules.json
│ ├── example-tasks.json
│ └── example-workshop-sections.json
│
├── components/
│ ├── workshop/ # Workshop view + accordion sections
│ ├── lms/ # Learning Path, progress dashboard, curriculum map
│ ├── modules/ # Module and Task cards
│ └── shared/ # Small shared primitives
│
├── hooks/
│ ├── useTheme.ts # dark/light toggle
│ ├── useAchievements.ts
│ └── useActiveTimeTracking.ts
│
├── utils/
│ ├── analytics.ts # no-op stubs — bring your own
│ └── timeTracking.ts
│
└── scripts/
├── seed-all.js # seeds seed-data/*.json → Firestore
└── backup-firestore-to-local.js
| Doc | What it covers |
|---|---|
| docs/setup-firebase.md | Create a Firebase project, enable auth + Firestore, fill env vars, seed, deploy |
| docs/configuration.md | All VITE_* env vars, demo mode, what happens when vars are missing |
| docs/authoring-content.md | JSON schema for modules, tasks, and workshop sections; how to add your own content |
| docs/architecture.md | How the two views fit together, auth flow, Firestore data model |
| docs/deployment.md | Firebase Hosting walkthrough; Netlify/Vercel alternatives |
| docs/customization.md | Rename, rebrand, swap colors, add/remove sections |
| docs/achievements.md | Badges, streaks, activity calendar — how it works and how to extend it |
- React 19 + TypeScript + Vite
- Firebase v12 — anonymous auth + Firestore (free tier sufficient for small groups)
- Tailwind CSS for styling
- lucide-react for icons
- reactflow for the curriculum map
MIT — see LICENSE.


