Private manga reader built as a pnpm monorepo with:
- a Vue 3 + Vite frontend
- a NestJS + Fastify backend
- PostgreSQL via Prisma
- S3-compatible image storage via MinIO
Public instance: https://manga-reader.tuturu.io
apps/
backend/ NestJS API
frontend/ Vue SPA
packages/
db/ Prisma + shared client
scripts/ admin/import scripts
- JWT authentication
- manga listing
- chapter and page listing
- reading resume and read-chapter tracking
- manga import
- page storage in MinIO / S3
- Prometheus endpoint at
/api/metrics
- Node.js 24 recommended
pnpm10- Docker + Docker Compose
The project expects a root .env file for local development.
Notes:
- the backend exposes the API under the
/apiprefix - in development, Vite proxies
/apitohttp://localhost:${BACKEND_PORT} VITE_COOKIE_TOKEN_DURATIONis read by the frontend and validated by the backend
- Install dependencies:
pnpm install- Start PostgreSQL and MinIO:
docker compose up -d- Generate and prepare the database:
pnpm db:generate
pnpm db:migrate- Start the application:
pnpm devUseful local URLs:
- frontend : http://localhost:5173
- backend : http://localhost:3000/api
- MinIO API : http://localhost:9000
- MinIO Console : http://localhost:9001
pnpm dev
pnpm lint
pnpm db:generate
pnpm db:build
pnpm db:migrate
pnpm db:deploy
pnpm db:reset
pnpm create:user -- <email> <password>
pnpm list:users
pnpm list:mangas
pnpm delete:manga -- <manga-name>
pnpm upload:manga-dir -- <directory>The pnpm upload:manga-dir -- <directory> script expects a directory structure like this:
My Manga/
Chapter 1/
001.jpg
002.jpg
Chapter 2/
001.jpg
002.png
Current constraints:
- the root folder name becomes the manga name
- each chapter must be a directory
- each chapter name must contain a number
- only
.jpg,.jpeg, and.pngfiles are supported - chapter directories must not contain nested subdirectories
The production Docker stack is defined in docker-compose.prod.yml:
postgresminiodbto prepare Prismabackendexposed locally on127.0.0.1:4030frontendexposed locally on127.0.0.1:3030
The frontend image does not reverse proxy /api. In production, an external reverse proxy must sit in front of the containers and route:
/to the frontend/apito the backend
This is the expected setup for manga-reader.tuturu.io.
The .env.docker file must provide at least the variables used by PostgreSQL, the backend, and MinIO, especially:
PG_MANGA_READER_DBPG_MANGA_READER_USERPG_MANGA_READER_PASSWORDPG_URLJWT_SECRETCOOKIE_SIGNATUREVITE_COOKIE_TOKEN_DURATIONS3_ENDPOINTS3_PORTS3_USE_SSLS3_ACCESS_KEYS3_SECRET_KEYS3_BUCKETPORT
Useful routes:
POST /api/auth/loginGET /api/mangasGET /api/mangas/:namePOST /api/mangas/importDELETE /api/mangas/:nameGET /api/chapters/:mangaName/:chapterNumberGET /api/pages/:idGET /api/pages/:id/minifiedGET /api/chapters-readPOST /api/chapters-readDELETE /api/chapters-read/:idGET /api/userGET /api/user/listGET /api/metrics