virtus bddd592146
Build and Push Reader API Image / docker (push) Successful in 14s
feat(auth, epub): enhance Google token verification and EPUB chapter extraction
- Added Google token verification logic to improve security and ensure valid tokens are processed.
- Introduced functions for extracting chapters from EPUB files based on HTML tags, including support for chapter markers.
- Updated `.env.example` to include configuration for an OpenAI-compatible router.
- Refactored existing functions for better readability and maintainability.
2026-05-19 00:15:20 +07:00

reader-api (FastAPI + UV)

Shared backend API for both:

  • Web app: reader
  • Mobile app: reader-app

This project is Python-first (FastAPI), with production-focused Docker setup and healthcheck.

Stack

  • Python 3.11+
  • FastAPI
  • UV (package manager / runner)
  • PostgreSQL (metadata, user data, chapter refs; chapter text stored via NAS/files — see NAS_CONTENT_ROOT / storage layer)

API Base URL

Environment

Create .env from .env.example.

Required keys:

DATABASE_URL=postgresql://reader:reader@localhost:5432/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

Dev Setup (UV)

  1. Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
  1. Sync dependencies
uv sync
  1. Run API in dev mode
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
  1. Verify health
curl http://localhost:8000/api/health

Docker Compose

Current docker-compose.yml supports a unified deployment for both web + API.

Web + API (use external DBs)

docker compose up -d --build api web

Required env for web OAuth in .env:

WEB_GOOGLE_CLIENT_ID=web-client-id.apps.googleusercontent.com
WEB_GOOGLE_CLIENT_SECRET=replace-with-web-google-client-secret

Full local stack (API local + Postgres)

docker compose --profile localdb up -d --build api-local postgres

Notes:

  • api listens on port 8000 and is intended for external DB deployments.
  • api-local listens on port 8001 and automatically points to postgres container.
  • web listens on port 3000 and calls API internally through http://api:8000.

NAS mount points (chapter content + EPUB source)

API containers now reserve two mount folders:

  • /data/content: converted chapter files (txt + raw_html)
  • /data/epub-source: source EPUB library

Default env mapping (already wired in compose):

NAS_CONTENT_ROOT=/data/content
EPUB_SOURCE_ROOT=/data/epub-source

If you want to bind to host folders for local testing:

services:
  api:
    volumes:
      - /absolute/local/path/content:/data/content
      - /absolute/local/path/epub-source:/data/epub-source

If you want to use NFS-backed docker volumes, define them under volumes:. Example:

volumes:
  nas_chapter_content:
    driver: local
    driver_opts:
      type: nfs
      o: addr=100.93.79.10,nolock,soft,rw
      device: ":/volume2/apps/reader-content"

  nas_epub_source:
    driver: local
    driver_opts:
      type: nfs
      o: addr=100.93.79.10,nolock,soft,rw
      device: ":/volume2/apps/reader-epub"

For your EPUB structure (folder per novel, multiple .epub parts inside), mount the parent folder to /data/epub-source.

Implemented Endpoints (snapshot)

Public / user

  • GET /api/health
  • GET /api/genres, GET /api/genres/{slug}
  • GET /api/novels/browse, GET /api/novels/{idOrSlug}
  • GET /api/truyen (query slug), GET /api/truyen/{novel_id}/chapters, GET /api/truyen/{novel_id}/chapters/by-number/{n}
  • GET /api/chapters/{chapter_id}
  • GET /api/truyen/suggest
  • GET/POST /api/truyen/{novel_id}/comments, POST /api/truyen/{novel_id}/rate

Auth

  • POST /api/auth/mobile-login (JWT cho mobile)
  • GET /api/auth/session (session bridge cho web — xem handler trong main.py)

User (login)

  • GET /api/user/profile
  • GET/POST /api/user/bookmarks, DELETE /api/user/bookmarks/{novel_id}
  • POST /api/user/reading-progress
  • GET/POST /api/user/settings
  • GET/POST/DELETE /api/user/recommendations

MOD / ADMIN — prefix /api/mod/* (thể loại, truyện, chương, overview, đề cử, upload bìa, EPUB…). Liệt kê đầy đủ trong app/main.py.

Import (MOD — web)

  • POST /api/import/uploads/preview — upload EPUB multipart để lấy preview metadata/cover gợi ý.
  • POST /api/mod/epub, POST /api/mod/epub/ai-suggest — luồng import EPUB chính.
  • GET/POST/PUT/DELETE /api/mod/the-loai — quản lý thể loại trong wizard.

Luồng SourceAsset / /api/import/assets/* và job pipeline cũ đã gỡ khỏi codebase (không còn endpoint).

NAS Migration Ops

1) Apply SQL migration manually

Run SQL in migrations/2026_04_nas_content_storage.sql against PostgreSQL.

2) Backfill existing chapter content to NAS + ChapterContentRef

Dry-run first:

python scripts/backfill_chapter_content_refs.py --limit 1000 --dry-run

Then execute:

python scripts/backfill_chapter_content_refs.py --limit 1000

You can run multiple batches by increasing/changing --limit.

Checkpoint/resume mode:

python scripts/backfill_chapter_content_refs.py --limit 1000 --state-file .backfill_state.json

Chapter Read Cutover Flag

Set in .env:

CHAPTER_CONTENT_MODE=nas_first

Values:

  • nas_first (default): read NAS ref first.

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.
S
Description
Shared backend API for reader web and reader-app mobile clients
Readme 1 MiB
Languages
Python 99%
JavaScript 0.8%
Dockerfile 0.2%