Discover, organize, and rate manhwa/webtoons.
Public monorepo containing:
- rankhwa-frontend – React + Vite app
- rankhwa-backend – Spring Boot API (PostgreSQL, JWT)
- tools/seed – Python scripts to seed the database from AniList
TL;DR: Run Postgres, start the Spring Boot API, start the React app, optionally seed titles from AniList. Secrets are not documented here and must be provided via your own environment configuration.
- 🔎 Search & filter (rating, year, genres; sort by rating/date/title)
- 🧾 Title details: description, covers, and alternate titles (English/Romaji/Native)
- ⭐ 1–10 user ratings with cached averages and vote counts
- 📚 User lists (Reading, Completed, Plan to Read, Favorites) + custom lists
- 🔐 JWT-based authentication (email/password, BCrypt hashing)
- 🌐 CORS for local dev & production hosts
- 🧪 DB health/ping endpoint
Frontend: React, Vite, TypeScript, Tailwind, lucide-react
Backend: Java, Spring Boot (Web, Security, Data JPA), JJWT
Database: PostgreSQL 16+ (JSONB for genres & titles)
Tools: Python (requests, psycopg, python-dotenv) for AniList seeding
.
├── rankhwa-frontend/ # React app (Vite)
├── rankhwa-backend/ # Spring Boot API
│ └── src/main/java/com/rankhwa/backend/{config,controller,dto,model,repository,security,service}
└── tools/
└── seed/
├── anilist_seed.py # AniList → PostgreSQL seeder
└── requirements.txt # Python deps for seeding
This repository does not include secrets or example
.envfiles. Configure your own environment variables and secrets per your setup (local or cloud). Do not commit secrets.
- Node ≥ 20.19
- Java 17+ (21 recommended)
- PostgreSQL 16+
- Python 3.10+ (for optional seeding)
docker run --name rankhwa-db -p 5432:5432 -e POSTGRES_DB=rankhwa -e POSTGRES_USER=rankhwa -e POSTGRES_PASSWORD=rankhwa -d postgres:16cd rankhwa-backend
mvn spring-boot:run
# API: http://localhost:8080cd rankhwa-frontend
npm install
npm run dev
# App: http://localhost:5173Seeding is optional and requires you to configure your own database connection and any thresholds locally or in your runtime environment.
cd tools/seed
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt || pip install psycopg requests python-dotenv
python anilist_seed.pyBase: http://localhost:8080 (or your deployed API base)
GET /health/sanity-check→{ "status": "UP" }
POST /auth/register→ body:{ email, password, displayName }POST /auth/login→ body:{ email, password }→{ token }
GET /users/{id}→ public profileGET /users/me→ current user (requiresAuthorization: Bearer <JWT>)PATCH /users/me→ updatedisplayName
GET /manhwa– query & filter (params:query,min_rating,min_votes,year,genrescsv,sortinrating|date|title,page,size)GET /manhwa/{id}– detailGET /manhwa/{id}/rating– current user’s rating (auth)POST /manhwa/{id}/rating– body:{ "score": 1..10 }(auth)
GET /lists– all lists for userPOST /lists– body:{ "name": "Custom" }GET /lists/{listId}– detail (IDs only)PATCH /lists/{listId}– rename (default lists cannot be renamed)DELETE /lists/{listId}– delete (default lists cannot be deleted)POST /lists/{listId}/items– body:{ "manhwaId": 123 }DELETE /lists/{listId}/items/{manhwaId}
Security (summary): unauthenticated access for /auth/**, /health/**, /users/*, /manhwa/**; authenticated access for /users/me/**, /manhwa/*/rating, /lists/**. JWT is processed via a stateless filter.
# Register (local dev)
curl -X POST http://localhost:8080/auth/register -H 'Content-Type: application/json' -d '{"email":"you@example.com","password":"<your-password>","displayName":"You"}'
# Login (local dev)
curl -X POST http://localhost:8080/auth/login -H 'Content-Type: application/json' -d '{"email":"you@example.com","password":"<your-password>"}'
# → {"token":"<JWT>"}
# Authenticated request
curl http://localhost:8080/users/me -H "Authorization: Bearer <JWT>"
# Search
curl "http://localhost:8080/manhwa?query=solo&min_rating=6&genres=Action,Fantasy&sort=rating&page=0&size=20"- Provide all configuration through your own environment setup (CI/CD, container runtime, or platform variables). Do not bake secrets into the repo or images.
- Ensure backend CORS allows your production frontend origins.
- Prefer managed Postgres for production deployments and use SSL where appropriate.
- Use proper schema migrations (e.g., Flyway/Liquibase) for production instead of auto-DDL.
PRs welcome. Keep commits focused. For entity or schema changes, include appropriate migration scripts for production environments.
MIT.
- Data seeding powered by the AniList GraphQL API.
- Icons via lucide-react.