mirror of
https://github.com/ngthanhvu/kr-phim.git
synced 2026-08-10 14:07:47 +00:00
feat: add authentication modal component and user authentication logic
- Implemented AuthModal.vue for user login and registration with form handling. - Created useAuth composable for managing user state and authentication requests. - Added admin route middleware to protect admin routes. - Developed admin login page with authentication checks. - Implemented API endpoints for user management (login, logout, fetch user, register). - Created database migrations for users table and updated movies table. - Added utility functions for password hashing and JWT token management.
This commit is contained in:
@@ -1,137 +1,305 @@
|
||||
# CineK
|
||||
|
||||
CineK is a Korean movie streaming web app built with Nuxt and Tailwind CSS. It uses NguonC movie data, normalizes the responses on the server, and presents the content with a blue Netflix-inspired interface.
|
||||
CineK là website xem phim Hàn Quốc online với giao diện dark theme, hệ thống admin quản lý phim, đăng ký/đăng nhập thành viên, và đồng bộ dữ liệu từ nhiều nguồn API.
|
||||
|
||||
## Features
|
||||
## Tính năng
|
||||
|
||||
- Korean-only movie catalogue from NguonC.
|
||||
- Netflix-style home page with a large hero carousel.
|
||||
- Floating movie preview cards on home page hover.
|
||||
- Browse page with search, type filters, and pagination.
|
||||
- Movie detail page with embedded player and episode selector.
|
||||
- Shared responsive header with centered navigation and global search.
|
||||
- Shared footer and scroll-to-top button.
|
||||
- Tailwind CSS styling with the `Be Vietnam Pro` font.
|
||||
- Lucide icons for UI actions.
|
||||
### Người dùng
|
||||
- Trang chủ với hero carousel phim Hàn Quốc
|
||||
- Duyệt phim theo loại (phim bộ, phim lẻ), tìm kiếm, phân trang
|
||||
- Trang chi tiết phim với trình phát HLS + Nhúng
|
||||
- Đăng ký / Đăng nhập tài khoản thành viên (popup modal)
|
||||
- Lịch sử xem, danh sách phim yêu thích (lưu localStorage)
|
||||
|
||||
### Admin (`/admin`)
|
||||
- Dashboard tổng quan (tổng phim, đang hiển thị, chưa hiển thị)
|
||||
- Đồng bộ phim từ API (chọn nguồn: OPhim, NguonC, KKPhim)
|
||||
- Bật/tắt hiển thị từng phim
|
||||
- Chỉnh sửa phim: mô tả, poster, thumbnail, tập phim tuỳ chỉnh
|
||||
- Quản lý thành viên: đổi role, bật/tắt, xoá tài khoản
|
||||
- Xoá toàn bộ phim
|
||||
- Phân quyền: chỉ role `admin` mới truy cập được
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- Nuxt 4
|
||||
- Vue 3
|
||||
- Tailwind CSS 4
|
||||
- `@tailwindcss/vite`
|
||||
- `lucide-vue-next`
|
||||
- **Framework:** Nuxt 4 (Vue 3)
|
||||
- **Styling:** Tailwind CSS 4
|
||||
- **Database:** MySQL 8.0 + Drizzle ORM
|
||||
- **Cache:** Redis 7
|
||||
- **Auth:** JWT (bcryptjs + jsonwebtoken)
|
||||
- **Icons:** Lucide Vue Next
|
||||
- **Player:** HLS.js
|
||||
- **Container:** Docker + Docker Compose
|
||||
|
||||
## Project Structure
|
||||
## Cấu trúc thư mục
|
||||
|
||||
```text
|
||||
app/
|
||||
assets/css/main.css Global Tailwind and theme styles
|
||||
components/ Shared UI components
|
||||
pages/index.vue Home page
|
||||
pages/phim/index.vue Browse, search, filter, and pagination page
|
||||
pages/phim/[slug].vue Movie detail and player page
|
||||
components/ Components dùng chung (AppHeader, AppLogo, AuthModal, AdminToggle...)
|
||||
composables/ Composables (useAuth, useMovieLibrary, useWatchHistory)
|
||||
layouts/
|
||||
admin.vue Layout cho trang admin (sidebar + header)
|
||||
middleware/
|
||||
admin.global.ts Middleware chặn route /admin/* nếu chưa đăng nhập admin
|
||||
pages/
|
||||
index.vue Trang chủ
|
||||
phim/ Trang chi tiết phim
|
||||
xem/[slug].vue Trang xem phim (player)
|
||||
thanh-vien.vue Trang cá nhân thành viên
|
||||
yeu-thich.vue Phim yêu thích
|
||||
lich-su.vue Lịch sử xem
|
||||
dang-nhap.vue Đăng nhập
|
||||
dang-ky.vue Đăng ký
|
||||
admin/
|
||||
login.vue Trang đăng nhập admin
|
||||
index.vue Dashboard admin
|
||||
phim/index.vue Quản lý phim
|
||||
phim/[id].vue Chỉnh sửa phim
|
||||
thanh-vien.vue Quản lý thành viên
|
||||
cai-dat.vue Cài đặt hệ thống
|
||||
|
||||
server/
|
||||
api/movies.get.ts Movie list API endpoint
|
||||
api/movies/[slug].get.ts Movie detail API endpoint
|
||||
utils/movies.ts API adapters and normalization helpers
|
||||
API_nguonc.md NguonC API notes
|
||||
api/
|
||||
movies.get.ts API danh sách phim công khai (chỉ phim active)
|
||||
movies/[slug].get.ts API chi tiết phim công khai
|
||||
auth/ API xác thực (register, login, logout, me)
|
||||
admin/ API admin (sync, movies, thanh-vien, stats)
|
||||
database/
|
||||
schema.ts Schema Drizzle (bảng users, movies)
|
||||
migrations/ File migration SQL
|
||||
middleware/
|
||||
auth.ts Middleware chặn /api/admin/* nếu chưa đăng nhập admin
|
||||
utils/
|
||||
auth.ts Tiện ích auth (hash password, JWT sign/verify)
|
||||
db.ts Kết nối MySQL
|
||||
redis.ts Kết nối Redis
|
||||
movies.ts Adapter API phim + chuẩn hoá dữ liệu
|
||||
```
|
||||
|
||||
## Setup
|
||||
## Setup & Chạy dự án
|
||||
|
||||
Install dependencies:
|
||||
### Yêu cầu
|
||||
|
||||
- Docker & Docker Compose
|
||||
- Node.js 22+ (nếu chạy ngoài Docker)
|
||||
|
||||
### 1. Clone & cài dependencies
|
||||
|
||||
```bash
|
||||
git clone <repo-url>
|
||||
cd kr-phim
|
||||
npm install
|
||||
```
|
||||
|
||||
## Development
|
||||
### 2. Cấu hình biến môi trường
|
||||
|
||||
Start the development server:
|
||||
Tạo file `.env`:
|
||||
|
||||
```env
|
||||
DATABASE_URL=mysql://cinek:cinekpassword@localhost:3306/cinek
|
||||
REDIS_URL=redis://localhost:6379
|
||||
JWT_SECRET=your-secret-key-change-this
|
||||
```
|
||||
|
||||
### 3. Chạy MySQL & Redis
|
||||
|
||||
```bash
|
||||
# Chỉ bật MySQL và Redis
|
||||
docker compose up -d mysql redis
|
||||
```
|
||||
|
||||
Hoặc chạy tất cả (app + mysql + redis):
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
#### Thông tin kết nối mặc định
|
||||
|
||||
| Service | Host | Port | User | Password | Database |
|
||||
|----------|-----------|------|---------|----------------|----------|
|
||||
| MySQL | localhost | 3306 | cinek | cinekpassword | cinek |
|
||||
| MySQL | localhost | 3306 | root | rootpassword | - |
|
||||
| Redis | localhost | 6379 | - | - | - |
|
||||
| App | localhost | 3002 | - | - | - |
|
||||
|
||||
### 4. Tạo bảng database (migration)
|
||||
|
||||
```bash
|
||||
# Tạo file migration từ schema
|
||||
npx drizzle-kit generate
|
||||
|
||||
# Áp dụng migration vào MySQL
|
||||
npx drizzle-kit migrate
|
||||
```
|
||||
|
||||
### 5. Chạy dev server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The app will usually be available at:
|
||||
App chạy tại `http://localhost:3002`. Hot reload tự động khi sửa code.
|
||||
|
||||
```text
|
||||
http://localhost:3002
|
||||
```
|
||||
### 6. Tạo tài khoản admin đầu tiên
|
||||
|
||||
## Production Build
|
||||
Truy cập `http://localhost:3002` → bấm **Đăng nhập** → chuyển sang tab **Đăng ký**.
|
||||
|
||||
Build the app for production:
|
||||
Tài khoản đầu tiên đăng ký sẽ tự động được gán role **admin**.
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
Sau đó truy cập `http://localhost:3002/admin` để vào trang quản trị.
|
||||
|
||||
Preview the production build locally:
|
||||
### 7. Đồng bộ phim
|
||||
|
||||
```bash
|
||||
npm run preview
|
||||
```
|
||||
Vào **Admin → Dashboard** hoặc **Admin → Phim** → bấm **Đồng bộ từ API**.
|
||||
|
||||
Run the production server after building:
|
||||
Chọn nguồn muốn đồng bộ (OPhim, NguonC, KKPhim) → bấm **Đồng bộ**.
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
|
||||
The production server listens on port `3002` by default.
|
||||
Mặc định phim mới đồng bộ sẽ ở trạng thái **Ẩn**. Bật từng phim để hiển thị ra trang công khai.
|
||||
|
||||
## Docker
|
||||
|
||||
Build and run with Docker Compose:
|
||||
### Dev mode (có hot reload)
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The container exposes the app at:
|
||||
File code được mount vào container qua volume, sửa file tự reload.
|
||||
|
||||
```text
|
||||
http://localhost:3002
|
||||
```
|
||||
|
||||
Stop the container:
|
||||
### Production build
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
# Build image production
|
||||
docker build -t cinek .
|
||||
|
||||
# Chạy
|
||||
docker run -p 3002:3002 \
|
||||
-e DATABASE_URL=mysql://cinek:cinekpassword@host.docker.internal:3306/cinek \
|
||||
-e REDIS_URL=redis://host.docker.internal:6379 \
|
||||
cinek
|
||||
```
|
||||
|
||||
The Compose service is named `cinek` and maps host port `3002` to container port `3002`.
|
||||
### Dừng & xoá containers
|
||||
|
||||
## Available Routes
|
||||
```bash
|
||||
docker compose down # Dừng containers
|
||||
docker compose down -v # Dừng + xoá volumes (mất dữ liệu MySQL/Redis)
|
||||
```
|
||||
|
||||
- `/` - Home page with hero carousel and movie rows.
|
||||
- `/phim` - Browse page with search, filters, and pagination.
|
||||
- `/phim?type=series` - Browse Korean series.
|
||||
- `/phim?type=single` - Browse Korean movies.
|
||||
- `/phim?q=keyword` - Search Korean movies.
|
||||
- `/phim/[slug]` - Movie detail page from NguonC.
|
||||
## Database
|
||||
|
||||
## API Notes
|
||||
### Schema
|
||||
|
||||
The app does not call external movie APIs directly from the browser. Instead, Nuxt server endpoints request and normalize movie data:
|
||||
**Bảng `users`:**
|
||||
|
||||
- NguonC list/detail data is handled in `server/utils/movies.ts`.
|
||||
- Only Korean movies are kept in the normalized result.
|
||||
| Cột | Kiểu | Mô tả |
|
||||
|-----------|---------------|---------------------------|
|
||||
| id | INT (PK) | Tự tăng |
|
||||
| name | VARCHAR(200) | Tên hiển thị |
|
||||
| email | VARCHAR(255) | Email (unique) |
|
||||
| password | VARCHAR(255) | Mật khẩu (bcrypt hash) |
|
||||
| role | VARCHAR(50) | admin / moderator / user |
|
||||
| avatar | TEXT | URL ảnh đại diện |
|
||||
| active | BOOLEAN | Trạng thái tài khoản |
|
||||
| created_at| TIMESTAMP | Ngày tạo |
|
||||
| updated_at| TIMESTAMP | Ngày cập nhật |
|
||||
|
||||
The public server endpoints use NguonC as the single movie API source.
|
||||
**Bảng `movies`:**
|
||||
|
||||
| Cột | Kiểu | Mô tả |
|
||||
|----------------|---------------|----------------------------------|
|
||||
| id | INT (PK) | Tự tăng |
|
||||
| source | VARCHAR(50) | Nguồn (ophim/nguonc/kkphim) |
|
||||
| slug | VARCHAR(500) | Slug phim trên nguồn |
|
||||
| name | VARCHAR(500) | Tên phim |
|
||||
| origin_name | VARCHAR(500) | Tên gốc |
|
||||
| thumb/poster | TEXT | URL ảnh |
|
||||
| year | INT | Năm sản xuất |
|
||||
| active | BOOLEAN | Hiển thị trên web công khai |
|
||||
| custom_poster | TEXT | Poster admin tuỳ chỉnh |
|
||||
| custom_thumb | TEXT | Thumbnail admin tuỳ chỉnh |
|
||||
| custom_content | TEXT | Mô tả admin tuỳ chỉnh |
|
||||
| custom_episodes| JSON | Tập phim admin tuỳ chỉnh |
|
||||
| api_updated_at | TIMESTAMP | Thời gian API nguồn cập nhật |
|
||||
| synced_at | TIMESTAMP | Thời gian đồng bộ vào DB |
|
||||
|
||||
### Migration
|
||||
|
||||
```bash
|
||||
# Tạo migration mới (sau khi sửa schema.ts)
|
||||
npx drizzle-kit generate
|
||||
|
||||
# Áp dụng migration
|
||||
npx drizzle-kit migrate
|
||||
```
|
||||
|
||||
### Kết nối MySQL trực tiếp
|
||||
|
||||
```bash
|
||||
# Qua Docker
|
||||
docker exec -it cinek-mysql mysql -ucinek -pcinekpassword cinek
|
||||
|
||||
# Hoặc từ host
|
||||
mysql -h 127.0.0.1 -P 3306 -ucinek -pcinekpassword cinek
|
||||
```
|
||||
|
||||
### Kết nối Redis trực tiếp
|
||||
|
||||
```bash
|
||||
docker exec -it cinek-redis redis-cli
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Công khai
|
||||
|
||||
| Method | Endpoint | Mô tả |
|
||||
|--------|-----------------------|---------------------------------|
|
||||
| GET | /api/movies | Danh sách phim active (có cache)|
|
||||
| GET | /api/movies/[slug] | Chi tiết phim active |
|
||||
|
||||
### Xác thực
|
||||
|
||||
| Method | Endpoint | Mô tả |
|
||||
|--------|-----------------------|---------------------------------|
|
||||
| POST | /api/auth/register | Đăng ký (tài khoản đầu = admin) |
|
||||
| POST | /api/auth/login | Đăng nhập (trả JWT + cookie) |
|
||||
| POST | /api/auth/logout | Đăng xuất (xoá cookie) |
|
||||
| GET | /api/auth/me | Thông tin user hiện tại |
|
||||
|
||||
### Admin (cần role admin)
|
||||
|
||||
| Method | Endpoint | Mô tả |
|
||||
|--------|-----------------------------|-------------------------------|
|
||||
| GET | /api/admin/stats | Thống kê tổng phim |
|
||||
| POST | /api/admin/sync | Đồng bộ phim từ API nguồn |
|
||||
| GET | /api/admin/movies | Danh sách tất cả phim |
|
||||
| GET | /api/admin/movies/:id | Chi tiết 1 phim |
|
||||
| PATCH | /api/admin/movies/:id | Bật/tắt phim |
|
||||
| PUT | /api/admin/movies/:id | Cập nhật custom (poster, tập) |
|
||||
| DELETE | /api/admin/movies | Xoá tất cả phim |
|
||||
| GET | /api/admin/thanh-vien | Danh sách thành viên |
|
||||
| PATCH | /api/admin/thanh-vien/:id | Đổi role / bật/tắt |
|
||||
| DELETE | /api/admin/thanh-vien/:id | Xoá thành viên |
|
||||
|
||||
## Scripts
|
||||
|
||||
```bash
|
||||
npm run dev # Start Nuxt development server
|
||||
npm run build # Build for production
|
||||
npm run preview # Preview the production build
|
||||
npm run start # Start the built Nitro server
|
||||
npm run generate # Generate a static build when supported
|
||||
npm run dev # Dev server (hot reload)
|
||||
npm run build # Build production
|
||||
npm run preview # Preview production build
|
||||
npm run start # Chạy production server
|
||||
npm run db:generate # Tạo migration từ schema
|
||||
npm run db:migrate # Áp dụng migration
|
||||
```
|
||||
|
||||
## Notes
|
||||
## Nguồn phim
|
||||
|
||||
This project is intended as a movie browsing and streaming UI experiment using public movie API sources. Availability of movie metadata, images, and episode embeds depends on the upstream APIs.
|
||||
Dữ liệu phim được lấy từ 3 API nguồn:
|
||||
|
||||
- **OPhim** - `https://ophim1.com`
|
||||
- **NguonC** - `https://phim.nguonc.com`
|
||||
- **KKPhim** - `https://phimapi.com`
|
||||
|
||||
Chỉ lấy phim quốc gia Hàn Quốc. Dữ liệu bao gồm: tên phim, ảnh, thể loại, tập phim, link embed, link HLS.
|
||||
|
||||
Reference in New Issue
Block a user