diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..5cb71ef --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/supabase/create/flash_card.sql b/supabase/create/flash_card.sql new file mode 100644 index 0000000..34bc5af --- /dev/null +++ b/supabase/create/flash_card.sql @@ -0,0 +1,101 @@ +-- ============================================ +-- FLASHCARD SYSTEM +-- ============================================ + +CREATE TABLE flashcard_list ( + id SERIAL PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description TEXT, + total_words INT DEFAULT 0, + created_by INT REFERENCES users(id) ON DELETE SET NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE flashcard_term ( + id SERIAL PRIMARY KEY, + list_id INT NOT NULL REFERENCES flashcard_list(id) ON DELETE CASCADE, + word VARCHAR(255) NOT NULL, + part_of_speech VARCHAR(50), -- "adjective", "noun", "verb"... + phonetic VARCHAR(100), -- "/kəˈmɜːʃəl/" + definition TEXT, -- nghĩa tiếng Việt + example TEXT, -- câu ví dụ (EN + VI) + image_url VARCHAR(500), + audio_tts_text VARCHAR(255), -- text để TTS (thường = word) + audio_lang VARCHAR(10) DEFAULT 'en-US', + display_order INT DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE user_flashcard_list ( + user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + list_id INT NOT NULL REFERENCES flashcard_list(id) ON DELETE CASCADE, + enrolled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (user_id, list_id) +); + +CREATE TABLE user_flashcard_progress ( + id SERIAL PRIMARY KEY, + user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + term_id INT NOT NULL REFERENCES flashcard_term(id) ON DELETE CASCADE, + list_id INT NOT NULL REFERENCES flashcard_list(id) ON DELETE CASCADE, + + -- SRS fields + status VARCHAR(20) NOT NULL DEFAULT 'new', + -- 'new' | 'learning' | 'known' | 'ignored' + ease_factor DECIMAL(4,2) DEFAULT 1.0, + -- 1.0=Dễ | 0.65=Trung bình | 0.1=Khó | -1=Đã biết/bỏ qua + review_count INT DEFAULT 0, + last_reviewed_at TIMESTAMP, + next_review_at TIMESTAMP, -- SRS scheduling + + UNIQUE (user_id, term_id, list_id) +); + +CREATE TABLE user_flashcard_session ( + id SERIAL PRIMARY KEY, + user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + list_id INT NOT NULL REFERENCES flashcard_list(id) ON DELETE CASCADE, + started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + ended_at TIMESTAMP, + terms_reviewed INT DEFAULT 0, + terms_new INT DEFAULT 0 +); + +CREATE TABLE user_flashcard_review_log ( + id SERIAL PRIMARY KEY, + session_id INT NOT NULL REFERENCES user_flashcard_session(id) ON DELETE CASCADE, + term_id INT NOT NULL REFERENCES flashcard_term(id) ON DELETE CASCADE, + user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + action_value DECIMAL(4,2) NOT NULL, -- 1 | 0.65 | 0.1 | -1 + reviewed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- ============================================ +-- INDEXES +-- ============================================ + +CREATE INDEX idx_term_list_id ON flashcard_term(list_id); +CREATE INDEX idx_term_display_order ON flashcard_term(list_id, display_order); +CREATE INDEX idx_progress_user ON user_flashcard_progress(user_id); +CREATE INDEX idx_progress_next_review ON user_flashcard_progress(user_id, next_review_at); +CREATE INDEX idx_progress_status ON user_flashcard_progress(user_id, list_id, status); +CREATE INDEX idx_review_log_session ON user_flashcard_review_log(session_id); +CREATE INDEX idx_enrolled_user ON user_flashcard_list(user_id); + +-- 1. Cài đặt chế độ review — trên trang có nút "Cài đặt chế độ review". +-- Cần lưu preferences của user như số từ mới mỗi ngày, thứ tự hiển thị (ngẫu nhiên hay tuần tự), hiển thị mặt trước là EN hay VI. Cần thêm table: + +CREATE TABLE user_flashcard_settings ( + user_id INT REFERENCES users(id), + list_id INT REFERENCES flashcard_list(id), + daily_new_limit INT DEFAULT 20, + shuffle BOOLEAN DEFAULT TRUE, + front_side VARCHAR(10) DEFAULT 'word', -- 'word' | 'definition' + show_all_terms BOOLEAN DEFAULT FALSE, + -- Khi TRUE: hiển thị tất cả từ kể cả ignored + -- Khi FALSE: từ ignored sẽ bị bỏ qua cho đến khi hết từ cần ôn + PRIMARY KEY (user_id, list_id) +); + +-- cho user tạo list riêng +ALTER TABLE flashcard_list ADD COLUMN is_public BOOLEAN DEFAULT TRUE; diff --git a/supabase/create/test.sql b/supabase/create/test.sql new file mode 100644 index 0000000..fbbb45c --- /dev/null +++ b/supabase/create/test.sql @@ -0,0 +1,54 @@ +CREATE TABLE test ( + id SERIAL PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description TEXT, + total_questions INT DEFAULT 0, + duration_minutes INT DEFAULT 120, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE part ( + id SERIAL PRIMARY KEY, + test_id INT NOT NULL REFERENCES test(id) ON DELETE CASCADE, + part_number INT NOT NULL, + title VARCHAR(100) NOT NULL, + question_count INT DEFAULT 0, + display_order INT DEFAULT 0, + UNIQUE (test_id, part_number) +); + +CREATE TABLE tag ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL UNIQUE +); + +CREATE TABLE part_tag ( + part_id INT NOT NULL REFERENCES part(id) ON DELETE CASCADE, + tag_id INT NOT NULL REFERENCES tag(id) ON DELETE CASCADE, + PRIMARY KEY (part_id, tag_id) +); + +CREATE TABLE question_group ( + id SERIAL PRIMARY KEY, + part_id INT NOT NULL REFERENCES part(id) ON DELETE CASCADE, + audio_url VARCHAR(500), + image_url VARCHAR(500), + passage_text TEXT, + display_order INT DEFAULT 0 +); + +CREATE TABLE question ( + id SERIAL PRIMARY KEY, + group_id INT NOT NULL REFERENCES question_group(id) ON DELETE CASCADE, + question_number INT NOT NULL, + question_text TEXT, + display_order INT DEFAULT 0 +); + +CREATE TABLE answer_choice ( + id SERIAL PRIMARY KEY, + question_id INT NOT NULL REFERENCES question(id) ON DELETE CASCADE, + value CHAR(1) NOT NULL CHECK (value IN ('A', 'B', 'C', 'D')), + label_text TEXT, + is_correct BOOLEAN NOT NULL DEFAULT FALSE +); \ No newline at end of file diff --git a/supabase/create/update.sql b/supabase/create/update.sql new file mode 100644 index 0000000..e69de29 diff --git a/supabase/create/user_test_history.sql b/supabase/create/user_test_history.sql new file mode 100644 index 0000000..b101ebe --- /dev/null +++ b/supabase/create/user_test_history.sql @@ -0,0 +1,30 @@ +CREATE TABLE user_test_attempt ( + id SERIAL PRIMARY KEY, + user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + test_id INT NOT NULL REFERENCES test(id) ON DELETE CASCADE, + + -- các part được chọn để luyện tập (có thể chọn 1 hoặc nhiều part) + selected_parts INT[], -- hoặc dùng junction table + + -- thời gian + time_limit_minutes INT, -- user chọn từ dropdown (NULL = không giới hạn) + started_at TIMESTAMP, + submitted_at TIMESTAMP, + time_spent_seconds INT, -- thời gian thực tế đã dùng + + -- kết quả + total_correct INT DEFAULT 0, + total_questions INT DEFAULT 0, + score DECIMAL(5,2), -- scaled score nếu full test + + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE user_answer ( + id SERIAL PRIMARY KEY, + attempt_id INT NOT NULL REFERENCES user_test_attempt(id) ON DELETE CASCADE, + question_id INT NOT NULL REFERENCES question(id), + selected_value CHAR(1), -- A / B / C / D (NULL nếu bỏ qua) + is_correct BOOLEAN, + UNIQUE (attempt_id, question_id) +); \ No newline at end of file