An open API service indexing awesome lists of open source software.

https://github.com/andresjmorales/cognote

CogNote: Open Source Music Note Practice Tool 🎹
https://github.com/andresjmorales/cognote

flashcards key memorization musical notation quiz signature

Last synced: 3 months ago
JSON representation

CogNote: Open Source Music Note Practice Tool 🎹

Awesome Lists containing this project

README

          

# CogNote

**Music note memorization for piano students β€” quizzes, flashcards, and spaced repetition.**

CogNote is an open-source web app that helps piano teachers assign and track music exercises for their students. Teachers create customizable lesson plans β€” note identification drills, musical symbol quizzes, or both β€” share them via unique URLs, and monitor progress through an analytics dashboard. Students β€” primarily children ages 5–14 β€” open a link and immediately start practicing. No login, no signup.

---

## Features

### For Teachers
- **Student management** β€” Add students, track their practice history, and see per-note accuracy breakdowns
- **Customizable lesson plans** β€” Two plan types: note identification (clef, key signature, specific notes) and musical symbols & concepts (dynamics, tempo, articulation, note values, and more)
- **Reusable templates** β€” Create lesson plan templates and assign them to multiple students with one click
- **Share via URL** β€” Each student gets a unique practice link; copy it to clipboard and send to parents
- **Analytics dashboard** β€” See which notes students struggle with, session history, accuracy trends

### For Students
- **Quiz mode** β€” Multiple-choice note identification or symbol/concept questions with immediate feedback and score tracking
- **Free practice** β€” Unlimited questions with no pressure, practice at your own pace
- **Flashcard mode** β€” Spaced repetition (SM-2 algorithm) for both notes and symbols, with kid-friendly emoji ratings
- **Zero friction** β€” Open the link, tap "Start", begin practicing. No account needed
- **Kid-friendly UI** β€” Large buttons, friendly fonts, gentle feedback animations

### Music Notation
- Real staff rendering with [VexFlow](https://www.vexflow.com/) β€” treble and bass clefs, key signatures, accidentals, ledger lines
- Clean, large notation sized for tablet screens
- **Standalone symbol SVGs** β€” Clefs, notes, rests, dynamics, articulations, and more are rendered from pre-extracted Bravura (SMuFL) vector paths in `public/symbols/`. No runtime font loading; consistent on all devices including iOS (no β€œtofu” from missing Unicode music fonts).
- Built-in library of 40+ musical symbols and concepts across 7 categories

---

## Spaced Repetition

The flashcard mode uses the **SM-2 algorithm** (same as Anki) and works for both note identification and symbol/concept plans. Students rate each card with kid-friendly labels:

| Button | SM-2 Rating | Effect |
|--------|------------|--------|
| πŸ˜• No clue | 1 (Again) | Card resets, shown again this session |
| πŸ€” Tricky | 2 (Hard) | Card resets, shown again this session |
| πŸ‘ Got it! | 4 (Good) | Card graduates, next review in 1–N days |
| ⭐ Too easy! | 5 (Easy) | Card graduates, interval grows faster |

See [notes/spaced-repetition.md](notes/spaced-repetition.md) for full algorithm documentation.

---

## Tech Stack

| Layer | Technology |
|-------|-----------|
| Framework | [Next.js 16](https://nextjs.org/) (App Router, Turbopack) |
| Language | TypeScript |
| Styling | Tailwind CSS 4 |
| Music Notation | VexFlow 5 |
| Database | [Supabase](https://supabase.com/) (PostgreSQL + Auth + Row Level Security) |
| Hosting | Vercel (recommended) |

---

## Getting Started

### Prerequisites

- **Node.js 18+**
- **Docker Desktop** β€” required by the Supabase CLI to run PostgreSQL, Auth, and the REST API locally

### Setup

```bash
# Clone the repo
git clone https://github.com/youruser/cognote.git
cd cognote

# Install dependencies
npm install

# Start local Supabase (pulls Docker images on first run β€” takes a few minutes)
npx supabase start

# Apply database migrations and seed with test data
npx supabase db reset

# Create your environment file
cp .env.example .env.local
```

After `npx supabase start`, you'll see output with your local credentials. Update `.env.local` with the **Publishable** key (as `NEXT_PUBLIC_SUPABASE_ANON_KEY`) and the **Secret** key (as `SUPABASE_SERVICE_ROLE_KEY`). Generate a token encryption key:

```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

Your `.env.local` should look like:

```
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
TOKEN_ENCRYPTION_KEY=<64-char hex string you generated>
```

Then start the dev server:

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000).

### Seed Data (Local Development Only)

Running `npx supabase db reset` loads `supabase/seed.sql` with a test teacher account, sample students, lesson plans, and practice history so you can explore the full dashboard immediately. See `seed.sql` for credentials β€” these are for **local development only** and should never be used in production.

### Clearing students and plans (e.g. production reset)

To wipe all students and lesson plans (and their assignments, sessions, and progress) while keeping teachers and auth intact, run `supabase/clear-data.sql` in the [Supabase SQL Editor](https://supabase.com/dashboard) or via:

```bash
psql $DATABASE_URL -f supabase/clear-data.sql
```

After clearing, **production** is ready for a fresh start. For **local dev**, run `npx supabase db reset` to reapply migrations and seed sample data.

### Local Dev Tools

| Tool | URL |
|------|-----|
| App | [http://localhost:3000](http://localhost:3000) |
| Supabase Studio | [http://127.0.0.1:54323](http://127.0.0.1:54323) |
| Mailpit (email) | [http://127.0.0.1:54324](http://127.0.0.1:54324) |

---

## Project Structure

```
cognote/
β”œβ”€β”€ app/
β”‚ β”œβ”€β”€ (teacher)/ # Teacher pages (auth required)
β”‚ β”‚ β”œβ”€β”€ dashboard/ # Overview with stats and recent activity
β”‚ β”‚ β”œβ”€β”€ students/ # Student list + detail views
β”‚ β”‚ β”‚ └── [id]/ # Per-student analytics
β”‚ β”‚ └── plans/ # Lesson plan list, editor, detail views
β”‚ β”‚ β”œβ”€β”€ [id]/
β”‚ β”‚ └── new/
β”‚ β”œβ”€β”€ (student)/ # Student pages (no auth)
β”‚ β”‚ └── practice/
β”‚ β”‚ └── [token]/ # Quiz, free practice, flashcard modes
β”‚ β”œβ”€β”€ api/ # API routes
β”‚ β”‚ β”œβ”€β”€ auth/ # Teacher account setup
β”‚ β”‚ β”œβ”€β”€ dashboard/ # Dashboard summary
β”‚ β”‚ β”œβ”€β”€ plans/ # Lesson plan CRUD + assignment
β”‚ β”‚ β”œβ”€β”€ practice/ # Student session + attempt tracking
β”‚ β”‚ └── students/ # Student CRUD + analytics
β”‚ β”œβ”€β”€ login/ # Teacher login/signup
β”‚ └── page.tsx # Landing page
β”œβ”€β”€ components/
β”‚ β”œβ”€β”€ music/ # VexFlow renderer, quiz engine, flashcards
β”‚ β”œβ”€β”€ teacher/ # Teacher-specific components
β”‚ └── ui/ # Shared primitives (Button, Card, etc.)
β”œβ”€β”€ lib/
β”‚ β”œβ”€β”€ supabase/ # Client, server, and middleware helpers
β”‚ β”œβ”€β”€ music.ts # Note utilities, answer generation, presets
β”‚ β”œβ”€β”€ symbol-paths.ts # Auto-generated: Bravura SVG path data (do not edit)
β”‚ β”œβ”€β”€ symbols.ts # Musical symbols & concepts library
β”‚ β”œβ”€β”€ srs.ts # SM-2 spaced repetition algorithm
β”‚ └── token.ts # AES-256-GCM token encryption
β”œβ”€β”€ public/
β”‚ └── symbols/ # Standalone SVG files (Bravura glyphs)
β”œβ”€β”€ scripts/
β”‚ └── extract-bravura-glyphs.js # One-time: extract Bravura β†’ SVG + lib/symbol-paths.ts
β”œβ”€β”€ supabase/
β”‚ β”œβ”€β”€ migrations/ # SQL schema migrations
β”‚ β”œβ”€β”€ seed.sql # Test data for local development
β”‚ └── clear-data.sql # Wipe students & plans (prod-safe; teachers unchanged)
└── notes/ # Design docs and specs
```

---

## Database Schema

```
teachers
β”œβ”€β”€ students (one-to-many)
β”œβ”€β”€ plans (one-to-many)
└── student_plans (students ↔ plans, many-to-many)
└── practice_sessions (one-to-many)
β”‚ └── note_attempts (one-to-many)
└── flashcard_progress (one-to-many, per note or symbol)
```

All teacher data is protected by **Row Level Security** β€” a teacher can only see their own students, lesson plans, and analytics. Student practice endpoints use token-based access with no authentication.

Migrations live in `supabase/migrations/` and are applied with `npx supabase db reset` (local) or `npx supabase db push` (remote).

**Local:** To apply new migrations (e.g. after pulling changes that add columns), run `npx supabase db reset`. This reapplies all migrations and refreshes the schema cache; it also re-runs the seed, so you’ll get fresh test data. If you see errors like β€œCould not find column X in the schema cache”, the DB is out of date β€” run `npx supabase db reset` (with Docker and `npx supabase start` running).

---

## API Routes

### Teacher-side (authenticated)

| Method | Route | Purpose |
|--------|-------|---------|
| GET | `/api/students` | List teacher's students |
| POST | `/api/students` | Create student |
| PUT | `/api/students/[id]` | Update student |
| DELETE | `/api/students/[id]` | Remove student |
| GET | `/api/students/[id]/analytics` | Student analytics |
| GET | `/api/plans` | List teacher's lesson plans |
| POST | `/api/plans` | Create lesson plan |
| PUT | `/api/plans/[id]` | Update lesson plan |
| DELETE | `/api/plans/[id]` | Remove lesson plan |
| POST | `/api/plans/[id]/assign` | Assign lesson plan to student, get practice URL |
| GET | `/api/dashboard/summary` | Dashboard metrics |

### Student-side (token-based, no auth)

| Method | Route | Purpose |
|--------|-------|---------|
| GET | `/api/practice/[token]` | Resolve token β†’ student name + plan config |
| POST | `/api/practice/[token]/session` | Start a practice session |
| POST | `/api/practice/[token]/session/[id]/attempt` | Record a note attempt |
| PUT | `/api/practice/[token]/session/[id]/complete` | Mark session complete |
| GET | `/api/practice/[token]/flashcards` | Get flashcard state (notes or symbols) |
| PUT | `/api/practice/[token]/flashcards` | Update flashcard after review (notes or symbols) |

---

## Deploying to Production

### 1. Create a Supabase project

Sign up at [supabase.com](https://supabase.com) (free tier is sufficient) and create a new project.

### 2. Push the schema

```bash
npx supabase login
npx supabase link --project-ref
npx supabase db push
```

`db push` applies migrations only β€” it does **not** run `seed.sql`. Your production database will have the schema but no test data.

### 3. Configure Supabase Auth redirects

If you use email confirmation, Supabase must know where to redirect users after they click the confirmation link:

1. Go to [Supabase Dashboard](https://supabase.com/dashboard) β†’ your project β†’ **Authentication** β†’ **URL Configuration**
2. Set **Site URL** to your production URL (e.g. `https://your-app.vercel.app`)
3. Add your production URL to **Redirect URLs** (e.g. `https://your-app.vercel.app/**`)
4. To support both local and production, add both: `http://localhost:3000/**` and `https://your-app.vercel.app/**`

Without this, confirmation links will redirect to localhost.

### 4. Deploy to Vercel

Connect your GitHub repo to [Vercel](https://vercel.com) and set these environment variables:

| Variable | Where to get it |
|----------|-----------------|
| `NEXT_PUBLIC_SUPABASE_URL` | Supabase Dashboard β†’ Settings β†’ API β†’ Project URL |
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase Dashboard β†’ Settings β†’ API β†’ anon (public) key |
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase Dashboard β†’ Settings β†’ API β†’ service_role key (click Reveal) |
| `TOKEN_ENCRYPTION_KEY` | Generate with `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` |

**Important:** Use the keys from your **cloud** Supabase project, not from `.env.local` (which has local Docker keys). Only `TOKEN_ENCRYPTION_KEY` can be copied from local β€” or generate a new one for production.

Variables without the `NEXT_PUBLIC_` prefix (like `SUPABASE_SERVICE_ROLE_KEY`) are server-only and never exposed to the browser.

### 5. Try a Lesson

The landing page "Try a Lesson" button links to `/try`, a standalone practice page that works without any seed data or database records. Visitors pick a note set and get the same experience students see β€” Start Lesson, Free Practice, and Flashcards.

---

## Contributing

1. Fork and clone the repo
2. Run `npx supabase start` (requires Docker)
3. Run `npx supabase db reset` to apply migrations and seed data
4. Copy `.env.example` to `.env.local` and fill in the local credentials
5. Run `npm run dev`
6. Full stack is running locally β€” no cloud accounts needed

### Adding a new migration

```bash
npx supabase migration new
# Edit the generated SQL file in supabase/migrations/
npx supabase db reset # Apply it
```

### Regenerating musical symbol SVGs

Symbols (clefs, notes, dynamics, articulations, etc.) are rendered from Bravura glyphs extracted into `public/symbols/` and `lib/symbol-paths.ts`. To add or update symbols:

```bash
npm install --save-dev opentype.js wawoff2
node scripts/extract-bravura-glyphs.js
```

Edit the `GLYPHS` map in `scripts/extract-bravura-glyphs.js` to add SMuFL code points (see [SMuFL](https://w3c.github.io/smufl/gitbook/)), then run the script. It reads Bravura from the VexFlow package, writes SVGs to `public/symbols/`, and regenerates `lib/symbol-paths.ts`. You can then remove the dev deps if desired.

---

## License

[MIT](LICENSE)