Skip to content

Commit 6ba6d25

Browse files
committed
feat: add flashcard entities and migration
1 parent d45d472 commit 6ba6d25

5 files changed

Lines changed: 92 additions & 4 deletions

File tree

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {
2+
Column,
3+
CreateDateColumn,
4+
Entity,
5+
PrimaryGeneratedColumn,
6+
} from 'typeorm';
7+
8+
@Entity({ name: 'flashcards' })
9+
export class FlashcardEntity {
10+
@PrimaryGeneratedColumn('uuid')
11+
id!: string;
12+
13+
@Column({ type: 'text', unique: true })
14+
conceptKey!: string;
15+
16+
@Column({ type: 'text' })
17+
front!: string;
18+
19+
@Column({ type: 'text' })
20+
back!: string;
21+
22+
@Column({ type: 'text' })
23+
category!: string;
24+
25+
@Column({ type: 'int', default: 1 })
26+
difficulty!: number;
27+
28+
@CreateDateColumn({ type: 'timestamptz' })
29+
createdAt!: Date;
30+
}
31+
32+
@Entity({ name: 'flashcard_progress' })
33+
export class FlashcardProgressEntity {
34+
@PrimaryGeneratedColumn('uuid')
35+
id!: string;
36+
37+
@Column({ type: 'uuid' })
38+
userId!: string;
39+
40+
@Column({ type: 'uuid' })
41+
flashcardId!: string;
42+
43+
@Column({ type: 'boolean', default: false })
44+
known!: boolean;
45+
46+
@Column({ type: 'int', default: 0 })
47+
reviewCount!: number;
48+
49+
@CreateDateColumn({ type: 'timestamptz' })
50+
createdAt!: Date;
51+
52+
@Column({ type: 'timestamptz', nullable: true })
53+
lastReviewedAt!: Date | null;
54+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-- Migration: Create flashcards tables
2+
-- Created: 2024-02-11
3+
4+
-- Flashcards table: stores AWS concept flashcards
5+
CREATE TABLE IF NOT EXISTS flashcards (
6+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
7+
concept_key TEXT NOT NULL UNIQUE,
8+
front TEXT NOT NULL,
9+
back TEXT NOT NULL,
10+
category TEXT NOT NULL,
11+
difficulty INTEGER DEFAULT 1,
12+
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
13+
);
14+
15+
-- Index for concept key lookups
16+
CREATE INDEX IF NOT EXISTS idx_flashcards_concept_key ON flashcards(concept_key);
17+
CREATE INDEX IF NOT EXISTS idx_flashcards_category ON flashcards(category);
18+
19+
-- Flashcard progress table: tracks user learning progress
20+
CREATE TABLE IF NOT EXISTS flashcard_progress (
21+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
22+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
23+
flashcard_id UUID NOT NULL REFERENCES flashcards(id) ON DELETE CASCADE,
24+
known BOOLEAN DEFAULT FALSE,
25+
review_count INTEGER DEFAULT 0,
26+
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
27+
last_reviewed_at TIMESTAMPTZ,
28+
UNIQUE(user_id, flashcard_id)
29+
);
30+
31+
-- Indexes for performance
32+
CREATE INDEX IF NOT EXISTS idx_flashcard_progress_user_id ON flashcard_progress(user_id);
33+
CREATE INDEX IF NOT EXISTS idx_flashcard_progress_flashcard_id ON flashcard_progress(flashcard_id);

backend/src/infrastructure/db/typeorm.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DataSourceOptions } from 'typeorm';
22
import { requireEnv, envInt, env } from '../../config/env';
3-
import { QuestionEntity, UserEntity, AttemptEntity, ChapterEntity, UserChapterProgressEntity } from './typeorm.entities';
3+
import { QuestionEntity, UserEntity, AttemptEntity, ChapterEntity, UserChapterProgressEntity, FlashcardEntity, FlashcardProgressEntity } from './typeorm.entities';
44

55
// Parse DATABASE_URL if provided (Render style), otherwise use individual vars
66
function parseDatabaseUrl(): { host: string; port: number; username: string; password: string; database: string } | null {
@@ -45,7 +45,7 @@ export function makeTypeOrmOptions(): DataSourceOptions {
4545

4646
// Entities are the TypeORM representations of our DB tables.
4747
// They are NOT the same thing as Domain entities.
48-
entities: [QuestionEntity, UserEntity, AttemptEntity, ChapterEntity, UserChapterProgressEntity],
48+
entities: [QuestionEntity, UserEntity, AttemptEntity, ChapterEntity, UserChapterProgressEntity, FlashcardEntity, FlashcardProgressEntity],
4949

5050
// Migrations are generated as TypeScript during development.
5151
// When we build (`nest build`), they will be compiled to JS under dist/.

backend/src/infrastructure/db/typeorm.entities.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
export { UserEntity } from './user.entity';
1313
export { AttemptEntity } from './attempt.entity';
1414
export { ChapterEntity, UserChapterProgressEntity } from './chapter.entities';
15+
export { FlashcardEntity, FlashcardProgressEntity } from './flashcard.entities';
1516

1617
// Database entity for a question.
1718
//

backend/src/scripts/seed-flashcards.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { DataSource } from 'typeorm';
21
import { AppDataSource } from '../infrastructure/db/data-source';
2+
import { FlashcardEntity } from '../infrastructure/db/flashcard.entities';
33

44
const flashcards = [
55
{
@@ -221,7 +221,7 @@ async function seedFlashcards() {
221221
await AppDataSource.initialize();
222222
console.log('📊 Database connected');
223223

224-
const flashcardRepository = AppDataSource.getRepository('Flashcard');
224+
const flashcardRepository = AppDataSource.getRepository(FlashcardEntity);
225225

226226
// Check if flashcards already exist
227227
const count = await flashcardRepository.count();

0 commit comments

Comments
 (0)