Simple landing page for initial Portainer GitOps deployment. Includes Dockerfile, docker-compose.yml with pull_policy: build, and project documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.6 KiB
4.6 KiB
This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ before writing any code. Heed deprecation notices.
Manga Website Project Requirements
Tech Stack
| Layer | Technology |
|---|---|
| Frontend & Backend | Next.js (App Router, TypeScript, Tailwind CSS) |
| Database | PostgreSQL 16 |
| ORM | Prisma |
| Image Storage | Cloudflare R2 |
| Containerization | Docker + Docker Compose (managed via Portainer) |
| Reverse Proxy | Nginx via aaPanel |
| Domain | manga.04080616.xyz |
Infrastructure
- Server: Proxmox host, Docker VM/LXC running Portainer
- Reverse proxy: aaPanel Nginx routes
manga.04080616.xyz→http://127.0.0.1:3001 - SSL: Let's Encrypt via aaPanel
- DDNS already configured — no Cloudflare Tunnel needed
Port Allocation
| Port | Service |
|---|---|
| 3001 | Next.js app (host) → 3000 (container) |
| 5433 | PostgreSQL (host) → 5432 (container) |
Ports 3000, 8000–8002, 8005, 2283, 5432, 51820–51821, 9443 are already in use.
Deployment Workflow
- Develop on macOS locally
- Push code to Gitea (
gitea.04080616.xyz/yiekheng/sunnymh-manga-site) - On Proxmox Docker host:
git pull→docker build→ restart container - Portainer used for container management (GUI)
Image Storage (Cloudflare R2)
- Images stored in R2 (S3-compatible), not on the Proxmox host
- Upload flow: backend generates presigned URL → browser uploads directly to R2 → database records image path
- Format: WebP (25–35% smaller than JPEG)
- Multiple resolutions: thumbnail / reading / original
R2 Directory Structure
/manga/{manga_id}/{chapter_id}/{page_number}.webp
/thumbnails/{manga_id}/cover.webp
Database Schema (Prisma)
model Manga {
id Int @id @default(autoincrement())
title String
description String
coverUrl String
slug String @unique
status Status @default(PUBLISHED)
chapters Chapter[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Chapter {
id Int @id @default(autoincrement())
mangaId Int
number Int
title String
pages Page[]
manga Manga @relation(fields: [mangaId], references: [id])
}
model Page {
id Int @id @default(autoincrement())
chapterId Int
number Int
imageUrl String
chapter Chapter @relation(fields: [chapterId], references: [id])
}
enum Status {
PUBLISHED
DRAFT
}
Features
Core (build first)
- Manga listing page with cover images
- Manga detail page (title, description, chapter list)
- Chapter reader page (page-by-page image display)
- Internal search by manga title (PostgreSQL
containsquery)
SEO
- Next.js SSR/SSG for all public pages
generateMetadata()per page (title, description)- Auto-generated
/sitemap.xmlviaapp/sitemap.ts - Submit sitemap to Google Search Console
Search
- Phase 1: PostgreSQL
containswithinsensitivemode (sufficient for < 10k titles) - Phase 2 (future): Meilisearch for fuzzy/full-text search if needed
URL Structure
/ Homepage (manga grid)
/manga/[slug] Manga detail + chapter list
/manga/[slug]/[chapter] Chapter reader
/api/search?q= Search API endpoint
/api/manga Manga CRUD (admin)
/api/upload R2 presigned URL generation
Environment Variables (.env)
DATABASE_URL=postgresql://manga_user:yourpassword@localhost:5433/manga_db
R2_ACCOUNT_ID=your_cloudflare_account_id
R2_ACCESS_KEY=your_r2_access_key
R2_SECRET_KEY=your_r2_secret_key
R2_BUCKET=manga-images
R2_PUBLIC_URL=https://your-r2-public-url.r2.dev
Nginx Reverse Proxy Config (aaPanel)
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
Content Source
- Public domain / free manga only (no copyright issues)
- Sources: Comic Book Plus, Digital Comic Museum, Internet Archive
- Initial: manual download and upload
- Future: automated scraper (Node.js + cheerio) for allowed sources
Recommended Build Order
- Set up Prisma schema + connect to PostgreSQL
- Build manga listing and reader pages (static UI first)
- Wire up database queries via Prisma
- Add R2 upload + image serving
- Add search API
- Add SEO metadata + sitemap
- Dockerize and deploy to Proxmox via Gitea