A production-ready multi-user flashcard system with spaced repetition using the SM-2 algorithm.
- ✅ User authentication (JWT-based)
- ✅ Create and manage flashcard decks
- ✅ Create and manage flashcards
- ✅ SM-2 spaced repetition algorithm
- ✅ Study sessions with intelligent scheduling
- ✅ Progress tracking and statistics
- ✅ RESTful API design
- ✅ TypeScript for type safety
- ✅ SQLite database (easy to migrate to PostgreSQL)
- Runtime: Node.js 18+
- Language: TypeScript
- Framework: Express.js
- Database: SQLite (via Prisma ORM)
- Auth: JWT + bcrypt
- Validation: Zod
npm installcp .env.example .envEdit .env and set your JWT_SECRET:
DATABASE_URL="file:./dev.db"
JWT_SECRET="your-super-secret-jwt-key-at-least-32-characters-long"
JWT_EXPIRES_IN="7d"
PORT=3000
NODE_ENV="development"npx prisma generate
npx prisma migrate dev --name initnpm run devThe API will be running at http://localhost:3000
POST /api/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"username": "john_doe",
"password": "secure_password123"
}POST /api/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "secure_password123"
}Response:
{
"user": {
"id": "uuid",
"email": "user@example.com",
"username": "john_doe"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}GET /api/auth/me
Authorization: Bearer <token>GET /api/decks
Authorization: Bearer <token>POST /api/decks
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "Spanish Vocabulary",
"description": "Common Spanish words and phrases"
}GET /api/decks/:deckId
Authorization: Bearer <token>PATCH /api/decks/:deckId
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "Updated Deck Name"
}DELETE /api/decks/:deckId
Authorization: Bearer <token>GET /api/cards/deck/:deckId
Authorization: Bearer <token>POST /api/cards
Authorization: Bearer <token>
Content-Type: application/json
{
"deckId": "deck-uuid",
"front": "Hola",
"back": "Hello"
}GET /api/cards/:cardId
Authorization: Bearer <token>PATCH /api/cards/:cardId
Authorization: Bearer <token>
Content-Type: application/json
{
"front": "Updated front",
"back": "Updated back"
}DELETE /api/cards/:cardId
Authorization: Bearer <token>GET /api/study/deck/:deckId/due
Authorization: Bearer <token>Response:
{
"card": {
"id": "uuid",
"front": "Hola",
"back": "Hello",
"dueDate": "2024-01-15T10:00:00Z",
"easeFactor": 2.5,
"interval": 0,
"repetitions": 0
}
}GET /api/study/due
Authorization: Bearer <token>POST /api/study/answer
Authorization: Bearer <token>
Content-Type: application/json
{
"cardId": "card-uuid",
"quality": 4
}Quality Scale (SM-2):
5- Perfect response4- Correct response after hesitation3- Correct response with difficulty2- Incorrect; correct answer seemed easy to recall1- Incorrect; correct answer remembered0- Complete blackout
GET /api/study/stats
Authorization: Bearer <token>Response:
{
"totalCards": 150,
"dueCards": 12,
"reviewsToday": 25,
"totalDecks": 5
}User {
id, email, username, password
decks[]
reviews[]
}
Deck {
id, name, description
userId
cards[]
}
Card {
id, front, back
deckId
easeFactor, interval, repetitions, dueDate
reviews[]
}
Review {
id, cardId, userId, quality, createdAt
}The system uses the SuperMemo SM-2 spaced repetition algorithm:
- Quality < 3: Card is reset (review again tomorrow)
- Quality ≥ 3: Card progresses through intervals:
- First review: 1 day
- Second review: 6 days
- Subsequent: interval × easeFactor
The ease factor adjusts based on how difficult you find each card.
npm run devnpm run build
npm start# Open Prisma Studio (GUI)
npm run prisma:studio
# Create migration
npx prisma migrate dev --name your_migration_name
# Reset database
npx prisma migrate resetnpm testflashcard-backend/
├── prisma/
│ └── schema.prisma # Database schema
├── src/
│ ├── algorithms/
│ │ └── sm2.ts # SM-2 spaced repetition
│ ├── config/
│ │ ├── database.ts # Prisma client
│ │ └── env.ts # Environment validation
│ ├── middleware/
│ │ └── auth.middleware.ts # JWT authentication
│ ├── routes/
│ │ ├── auth.routes.ts # Auth endpoints
│ │ ├── decks.routes.ts # Deck management
│ │ ├── cards.routes.ts # Card management
│ │ └── study.routes.ts # Study sessions
│ ├── utils/
│ │ └── auth.ts # Auth helpers
│ └── index.ts # App entry point
├── .env.example
├── package.json
├── tsconfig.json
└── README.md
DATABASE_URL="file:./prod.db" # Or PostgreSQL connection string
JWT_SECRET="very-long-secure-random-string"
JWT_EXPIRES_IN="7d"
PORT=3000
NODE_ENV="production"- Update
prisma/schema.prisma:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}- Update
.env:
DATABASE_URL="postgresql://user:password@localhost:5432/flashcards"- Run migrations:
npx prisma migrate dev- Image/audio support for cards
- Deck sharing and public decks
- Export/import decks (.csv, .json)
- Mobile apps (React Native)
- Gamification (streaks, achievements)
- FSRS algorithm option (newer than SM-2)
- Cloze deletion cards
- Tag system for cards
MIT