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>
164 lines
4.6 KiB
Markdown
164 lines
4.6 KiB
Markdown
# 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
|
||
|
||
1. Develop on macOS locally
|
||
2. Push code to Gitea (`gitea.04080616.xyz/yiekheng/sunnymh-manga-site`)
|
||
3. On Proxmox Docker host: `git pull` → `docker build` → restart container
|
||
4. 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)
|
||
|
||
```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 `contains` query)
|
||
|
||
### SEO
|
||
- Next.js SSR/SSG for all public pages
|
||
- `generateMetadata()` per page (title, description)
|
||
- Auto-generated `/sitemap.xml` via `app/sitemap.ts`
|
||
- Submit sitemap to Google Search Console
|
||
|
||
### Search
|
||
- **Phase 1**: PostgreSQL `contains` with `insensitive` mode (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)
|
||
|
||
```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)
|
||
|
||
```nginx
|
||
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
|
||
|
||
1. Set up Prisma schema + connect to PostgreSQL
|
||
2. Build manga listing and reader pages (static UI first)
|
||
3. Wire up database queries via Prisma
|
||
4. Add R2 upload + image serving
|
||
5. Add search API
|
||
6. Add SEO metadata + sitemap
|
||
7. Dockerize and deploy to Proxmox via Gitea
|