Files
reader-api/README.md
T
virtus 1b1217ace2
Build and Push Reader API Image / docker (push) Successful in 26s
feat(storage): add delete_href method to remove files and clean up empty directories
chore(docker): remove MongoDB service and related configurations from local setup

feat(migrations): create ChapterMeta table and add search_name, size_bytes, mtime_epoch, lastScannedAt, review_status, and review_payload columns to SourceAsset

chore(dependencies): remove motor and pymongo from project dependencies
2026-05-03 20:57:29 +07:00

227 lines
5.4 KiB
Markdown

# 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 (structured data)
## API Base URL
- Local dev: http://localhost:8000
- Healthcheck: GET /api/health
## Environment
Create `.env` from `.env.example`.
Required keys:
```env
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
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
2. Sync dependencies
```bash
uv sync
```
3. Run API in dev mode
```bash
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```
4. Verify health
```bash
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)
```bash
docker compose up -d --build api web
```
Required env for web OAuth in `.env`:
```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)
```bash
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):
```env
NAS_CONTENT_ROOT=/data/content
EPUB_SOURCE_ROOT=/data/epub-source
```
If you want to bind to host folders for local testing:
```yaml
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:
```yaml
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
- 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}
- GET /api/import/assets/search
- GET /api/import/assets/{assetId}/preview-metadata
- POST /api/import/assets/{assetId}/ai-suggest
- POST /api/import/assets/{assetId}/review
- POST /api/import/assets/{assetId}/parse-preview
- POST /api/import/assets/{assetId}/start-import
- GET /api/import/sessions/{sessionId}
## Simple EPUB Import Flow (Review-first)
MOD/ADMIN flow on new import wizard:
1. Search source EPUB by name (DB index): `GET /api/import/assets/search`
2. Review/edit metadata: `GET /api/import/assets/{id}/preview-metadata` + `POST /api/import/assets/{id}/review`
3. Preview chapter split (TOC or regex-start): `POST /api/import/assets/{id}/parse-preview`
4. Start import and poll progress:
- `POST /api/import/assets/{id}/start-import`
- `GET /api/import/sessions/{sessionId}`
AI assist in step 2:
- `POST /api/import/assets/{id}/ai-suggest`
- Returns up to 6 genres + 1 short description.
- New genres are allowed and created immediately on apply.
## 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:
```bash
python scripts/backfill_chapter_content_refs.py --limit 1000 --dry-run
```
Then execute:
```bash
python scripts/backfill_chapter_content_refs.py --limit 1000
```
You can run multiple batches by increasing/changing `--limit`.
Checkpoint/resume mode:
```bash
python scripts/backfill_chapter_content_refs.py --limit 1000 --state-file .backfill_state.json
```
Or continue from a known ObjectId:
```bash
python scripts/backfill_chapter_content_refs.py --limit 1000 --after-id 680f7f3a2f0d53f4f2b7a123
```
## Chapter Read Cutover Flag
Set in `.env`:
```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.