Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -1,180 +1,101 @@
|
||||
# reader-api
|
||||
# reader-api (FastAPI + UV)
|
||||
|
||||
Đây là backend API dùng chung cho cả web app `reader` và mobile app `reader-app`.
|
||||
Shared backend API for both:
|
||||
- Web app: reader
|
||||
- Mobile app: reader-app
|
||||
|
||||
## 🚀 Tính năng nổi bật
|
||||
This project is Python-first (FastAPI), with production-focused Docker setup and healthcheck.
|
||||
|
||||
- **Xác thực & Phân quyền**: Đăng nhập bằng Google Authentication (NextAuth). Hỗ trợ phân quyền người dùng (USER, MOD, ADMIN).
|
||||
- **Quản lý nội dung (Dành cho MOD/ADMIN)**: Dashboard quản lý truyện, tải lên chương mới, quản lý trạng thái truyện (Đang ra, Hoàn thành, Tạm ngưng).
|
||||
- **Trải nghiệm đọc**: Khám phá truyện theo thể loại, tìm kiếm truyện, đọc chương truyện với hiệu suất cao (nội dung lưu ở MongoDB).
|
||||
- **Tương tác người dùng**: Tính năng tủ sách (bookmark) giúp lưu lại tiến độ đọc, hỗ trợ bình luận ở truyện và từng chương.
|
||||
## Stack
|
||||
|
||||
## 🛠 Tech Stack
|
||||
- Python 3.11+
|
||||
- FastAPI
|
||||
- UV (package manager / runner)
|
||||
- PostgreSQL (structured data)
|
||||
- MongoDB (chapter content + user recommendations)
|
||||
|
||||
- **Framework**: [Next.js](https://nextjs.org/) (App Router), React 19
|
||||
- **Styling**: [TailwindCSS v4](https://tailwindcss.com/) & [Radix UI](https://www.radix-ui.com/) (shadcn/ui)
|
||||
- **Database Hybrid**:
|
||||
- **PostgreSQL**: Lưu trữ dữ liệu cấu trúc (Tài khoản, Truyện, Thể loại, Bình luận, Tủ sách) thông qua **Prisma ORM**.
|
||||
- **MongoDB**: Lưu trữ nội dung lớn (Chương truyện) thông qua **Mongoose**.
|
||||
- **Auth**: [NextAuth.js](https://next-auth.js.org/)
|
||||
## API Base URL
|
||||
|
||||
---
|
||||
- Local dev: http://localhost:8000
|
||||
- Healthcheck: GET /api/health
|
||||
|
||||
## 💻 Hướng dẫn chạy Local (Phát triển)
|
||||
## Environment
|
||||
|
||||
### 1. Yêu cầu cài đặt
|
||||
- [Node.js](https://nodejs.org/) (Khuyến nghị bản LTS)
|
||||
- [pnpm](https://pnpm.io/) (Tool quản lý package)
|
||||
- Database: PostgreSQL và MongoDB đang chạy cục bộ hoặc trên máy chủ.
|
||||
Create `.env` from `.env.example`.
|
||||
|
||||
### 2. Cấu hình môi trường
|
||||
Tạo file `.env` ở thư mục gốc dựa trên `.env.example` (nếu có) hoặc điền các thông tin sau:
|
||||
Required keys:
|
||||
|
||||
```env
|
||||
# URL kết nối PostgreSQL
|
||||
DATABASE_URL="postgresql://user:password@localhost:5432/reader?schema=public"
|
||||
|
||||
# URL kết nối MongoDB
|
||||
MONGODB_URI="mongodb://user:password@localhost:27017/reader?authSource=admin"
|
||||
|
||||
# Cấu hình NextAuth
|
||||
NEXTAUTH_SECRET="your-super-secret-key"
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
|
||||
# Cấu hình Google Login
|
||||
GOOGLE_CLIENT_ID="your_google_client_id"
|
||||
GOOGLE_CLIENT_SECRET="your_google_client_secret"
|
||||
|
||||
# AI Tool cho MOD (LLM + web search)
|
||||
OPENAI_API_KEY="your_openai_api_key"
|
||||
# Tùy chọn, mặc định: gpt-4o-mini-search-preview
|
||||
OPENAI_WEB_MODEL="gpt-4o-mini-search-preview"
|
||||
|
||||
# Cloudflare R2 (lưu ảnh bìa)
|
||||
R2_ACCOUNT_ID="your_cloudflare_account_id"
|
||||
R2_ACCESS_KEY_ID="your_r2_access_key_id"
|
||||
R2_SECRET_ACCESS_KEY="your_r2_secret_access_key"
|
||||
R2_BUCKET_NAME="your_r2_bucket_name"
|
||||
R2_PUBLIC_BASE_URL="https://your-public-r2-domain"
|
||||
DATABASE_URL=postgresql://reader:reader@localhost:5432/reader
|
||||
MONGODB_URI=mongodb://localhost:27017/reader
|
||||
NEXTAUTH_SECRET=replace-with-strong-secret
|
||||
MOBILE_JWT_SECRET=replace-with-strong-secret
|
||||
# Comma-separated allowed Google OAuth client IDs
|
||||
GOOGLE_CLIENT_ID=web-client-id.apps.googleusercontent.com,android-client-id.apps.googleusercontent.com
|
||||
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
|
||||
APP_ENV=development
|
||||
```
|
||||
|
||||
### 3. Cài đặt dependencies và khởi tạo DB
|
||||
## Dev Setup (UV)
|
||||
|
||||
1. Install UV
|
||||
|
||||
```bash
|
||||
# Cài đặt các gói thư viện
|
||||
pnpm install
|
||||
|
||||
# Đồng bộ schema xuống PostgreSQL và generate Prisma client
|
||||
npx prisma db push
|
||||
# hoặc (nếu muốn dùng migrate)
|
||||
# npx prisma migrate dev
|
||||
|
||||
# Generate thư viện Prisma
|
||||
npx prisma generate
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
### 4. Chạy môi trường phát triển
|
||||
2. Sync dependencies
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
uv sync
|
||||
```
|
||||
API chạy mặc định ở [http://localhost:3001](http://localhost:3001).
|
||||
Ví dụ endpoint: [http://localhost:3001/api/novels/browse](http://localhost:3001/api/novels/browse).
|
||||
|
||||
---
|
||||
|
||||
## 🏗 Hướng dẫn Build
|
||||
|
||||
Để build project cho môi trường production:
|
||||
3. Run API in dev mode
|
||||
|
||||
```bash
|
||||
# Đảm bảo Prisma Client đã được generate
|
||||
npx prisma generate
|
||||
|
||||
# Chạy lệnh build của Next.js
|
||||
pnpm build
|
||||
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
Sau khi build xong, bạn có thể khởi chạy server production bằng:
|
||||
```bash
|
||||
pnpm start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Triển khai dưới dạng Docker
|
||||
|
||||
Bạn có thể dễ dàng triển khai ứng dụng bằng nền tảng Docker. Dưới đây là cách đóng gói và chạy thông qua `docker-compose`.
|
||||
|
||||
### 1. Tạo file `Dockerfile`
|
||||
Tạo file `Dockerfile` ở thư mục gốc của dự án với cấu hình multi-stage build để tối ưu dung lượng:
|
||||
|
||||
```dockerfile
|
||||
# Stage 1: Dependencies
|
||||
FROM node:22-alpine AS deps
|
||||
WORKDIR /app
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN corepack enable pnpm && pnpm install --frozen-lockfile
|
||||
|
||||
# Stage 2: Builder
|
||||
FROM node:22-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
# Tạo prisma client
|
||||
RUN npx prisma generate
|
||||
# Chạy build
|
||||
RUN corepack enable pnpm && pnpm build
|
||||
|
||||
# Stage 3: Runner
|
||||
FROM node:22-alpine AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
|
||||
EXPOSE 3000
|
||||
ENV PORT=3000
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
*(Lưu ý: Để build mục `standalone` hoạt động, bạn cần bổ sung `output: 'standalone'` trong file `next.config.mjs`)*
|
||||
|
||||
### 2. Tạo file `docker-compose.yml`
|
||||
Sử dụng Docker Compose để chạy ứng dụng (giả sử Database của bạn được host riêng hoặc bạn có thể thêm service DB vào file này):
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: reader-web:latest
|
||||
container_name: reader-app
|
||||
ports:
|
||||
- "3000:3000"
|
||||
env_file:
|
||||
- .env
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### 3. Khởi chạy bằng Docker
|
||||
Chạy lệnh sau để build image và start container:
|
||||
4. Verify health
|
||||
|
||||
```bash
|
||||
# Build và chạy ngầm (detached mode)
|
||||
docker-compose up -d --build
|
||||
curl http://localhost:8000/api/health
|
||||
```
|
||||
|
||||
Để xem log của container:
|
||||
## Docker Compose
|
||||
|
||||
### Production-style API only (external DBs)
|
||||
|
||||
```bash
|
||||
docker-compose logs -f web
|
||||
docker compose up -d --build api
|
||||
```
|
||||
Dừng và xóa container:
|
||||
|
||||
### Full local stack (API + Postgres + Mongo)
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
docker compose --profile localdb up -d --build
|
||||
```
|
||||
|
||||
## Implemented Endpoints
|
||||
|
||||
- GET /api/health
|
||||
- POST /api/auth/mobile-login
|
||||
- GET /api/user/profile
|
||||
- GET/POST /api/user/bookmarks
|
||||
- DELETE /api/user/bookmarks/{novelId}
|
||||
- POST /api/user/reading-progress
|
||||
- GET/POST /api/user/settings
|
||||
- GET/POST/DELETE /api/user/recommendations
|
||||
- GET /api/genres
|
||||
- GET /api/novels/browse
|
||||
- GET /api/novels/{idOrSlug}
|
||||
- GET /api/truyen/{id}/chapters
|
||||
- GET/POST /api/truyen/{id}/comments
|
||||
- POST /api/truyen/{id}/rate
|
||||
- GET /api/truyen/suggest
|
||||
- GET /api/chapters/{chapterId}
|
||||
|
||||
## Notes
|
||||
|
||||
- Web session auth is supported via NextAuth session cookies (next-auth.session-token and secure variants).
|
||||
- Mobile auth is supported via Bearer JWT from /api/auth/mobile-login.
|
||||
|
||||
Reference in New Issue
Block a user