Một môi trường học tập từ vựng thông minh dựa trên kỹ thuật Spaced Repetition
-
Hơn 3000 từ vựng được chia thành các sổ tay theo chủ đề để dễ học thuộc
-
Kỹ thuật Spaced Repetion dựa trên Đường cong lãng quên (Forgetting Curve) của Hermann Ebbinghaus sẽ giúp nhắc bạn ôn tập từ ngay khi bạn sắp quên, giúp ghi nhớ từ vựng hiệu quả.
-
Thống kê các từ vựng bạn đã học, đang ôn tập, và cần ôn tập.
- React 18 + Vite
- React Router
- Tailwind CSS
- Recharts / ApexCharts (biểu đồ tiến độ)
- Node.js
- Express.js
- PostgreSQL
- JWT Authentication
- bcrypt password hashing
- Docker + Docker Compose
- Render Blueprint (
render.yaml)
client/ React + Vite
server/ Express API, migrations, seed, other-tools/
docker/ Dockerfile, docker-compose.yml, docker-entrypoint.sh
nginx/ cấu hình reverse proxy (tùy chọn, không dùng khi chạy Docker)
docs/ ROADMAP.md, PHASES.md
backups/ dump database ở máy bạn — không commit
render.yaml Render Blueprint — Render mặc định tìm ở thư mục gốc
Có 3 cách chạy dự án. Docker là cách nhanh nhất — không cần cài Postgres, không cần tạo database, không cần import dữ liệu bằng tay.
git clone https://github.com/CodingchallengeJS/NeuroLex.git
cd EnVocabLearnerYêu cầu: Docker Desktop (đã bao gồm Docker Compose).
cd docker
docker compose up --buildHoặc chạy thẳng từ thư mục gốc, không cần cd:
docker compose -f docker/docker-compose.yml up --buildXong. Mở http://localhost:8000.
Lần đầu chạy, container sẽ tự động:
- Dựng Postgres 16 trong một container riêng (dữ liệu lưu ở volume
pgdata) - Chạy migration → tạo toàn bộ bảng + hàm
add_vocab_to_review - Chạy seed → nạp 45 sổ tay / ~2800 từ từ
server/assets/ - Khởi động Express, vừa phục vụ API vừa phục vụ bản build React
Bước 2 và 3 mất vài phút ở lần đầu. Những lần sau chúng tự bỏ qua (migration đã
ghi trong bảng schema_migrations, seed thấy đã có sổ tay thì không chạy lại).
Chạy trong thư mục docker/:
docker compose up --build # build và chạy
docker compose up -d # chạy nền
docker compose logs -f app # xem log
docker compose down # dừng (vẫn giữ dữ liệu)
docker compose down -v # dừng và XOÁ SẠCH databaseMặc định dùng được ngay, nhưng bạn nên đặt secret thật. Tạo file docker/.env
(cùng cấp với docker-compose.yml — Compose đọc .env cạnh chính nó):
POSTGRES_DB=neurolex
POSTGRES_USER=neurolex
POSTGRES_PASSWORD=doi-mat-khau-nay
AUTH_PEPPER=chuoi-ngau-nhien-1
JWT_SECRET=chuoi-ngau-nhien-2
APP_HOST_PORT=8000 # đổi nếu 8000 đang bị chiếm
DB_HOST_PORT=5432 # đổi nếu 5432 đang bị chiếmCác biến điều khiển quá trình khởi động:
| Biến | Mặc định | Ý nghĩa |
|---|---|---|
RUN_MIGRATIONS |
true |
Chạy migration khi khởi động |
RUN_SEED |
true |
Nạp từ vựng khi khởi động (tự bỏ qua nếu đã có sổ tay) |
FORCE_SEED |
false |
Ép chạy lại toàn bộ importer dù đã có dữ liệu |
Dùng cách này khi bạn muốn sửa code và có hot reload.
cp server/.env.example server/.envRồi sửa server/.env cho khớp với Postgres trên máy bạn. File này đã nằm trong
.gitignore — đừng bao giờ commit nó, và đừng viết thẳng mật khẩu vào code.
Tự tạo một database trống trong Postgres trước (ví dụ createdb envocab), sau đó:
cd server
npm install
npm run db:setup # = npm run migrate && npm run seednpm run migrate— tạo bảng theoserver/migrations/. An toàn khi chạy lại, và không xoá gì cả. Chạy được cả trên database đã có dữ liệu từ trước.npm run seed— nạp toàn bộ từ vựng. Tự bỏ qua nếu đã có sổ tay.
⚠️ server/reset-dev-db.sqlkhông còn là cách dựng DB nữa. Nó mở đầu bằngDROP SCHEMA public CASCADE— chỉ dùng khi bạn cố tình muốn xoá sạch và làm lại từ đầu. Dùngnpm run migratecho mọi trường hợp bình thường.
Muốn nạp lẻ từng bộ dữ liệu thì xem
server/other-tools/README.md.
cd server
npm run dev # http://localhost:8000Mở terminal thứ hai:
cd client
npm install
npm run dev # http://localhost:5173Frontend gọi API qua đường dẫn tương đối /api; Vite tự proxy sang backend ở
http://localhost:8000. Nếu backend chạy cổng khác, đặt VITE_DEV_API_TARGET.
Truy cập từ máy khác (LAN, Tailscale...) thì thêm hostname vào client/.env:
VITE_ALLOWED_HOSTS=laptop-cua-ban.dtth.tsQuan trọng: tạo một Web Service trên Render sẽ không tự tạo database. Phải
dùng Blueprint thì Render mới dựng cả web service lẫn Postgres cùng lúc. Repo này
đã có sẵn file render.yaml làm việc đó.
- Push code lên GitHub.
- Trên Render: New → Blueprint → chọn repo này.
- Render đọc
render.yamlvà tạo:- Postgres
neurolex-db - Web service
neurolex(build từdocker/Dockerfile) AUTH_PEPPERvàJWT_SECRETđược sinh ngẫu nhiên
- Postgres
- Dán
DATABASE_URLkhi Render hỏi: Internal Database URL củaneurolex-db(trang database → Connect), hoặc connection string của Neon. Biến này đểsync: falsenên các lần auto-deploy sau không ghi đè lại. (Trước đây nó dùngfromDatabase, khiến mỗi lần deploy app bị trỏ ngược về DB của Render.) - Đặt
ADMIN_EMAIL= email của bạn khi Render hỏi. Tài khoản đăng ký bằng email này sẽ có quyền sửa từ vựng dùng chung. Bỏ trống thì không ai có quyền đó (và bạn cấp sau bằngnpm run admin -- email@cua-ban). - Bấm Apply.
- Đăng ký tài khoản trên web bằng đúng email ở bước 5.
Lần deploy đầu tiên, container tự chạy migration rồi seed, nên schema và toàn bộ
sổ tay tự có sẵn, không cần chạy psql tay. Các lần deploy sau seed tự bỏ qua.
Kiểm tra bằng https://<tên-app>.onrender.com/api/health — trả về {"ok":true}.
- Web service ngủ sau 15 phút không có request → lần truy cập sau đó chậm ~30-60s.
- Postgres free hết hạn sau 90 ngày. Nhớ
pg_dumpđịnh kỳ nếu có dữ liệu thật. - Build Docker trên gói free khá chậm (vài phút).
npm run seed:topics imports both server/assets/vocabularies.json and
server/assets/va-c1c2-500-2023-2026.csv. The CSV is added as the notebook
SAT C1-C2 500 (2023-2026) and fills the detailed fields
english_meaning, vietnamese_meaning, and synonyms. Its CSV id
column is used as the notebook order, from highest frequency to lowest.