The Pinterest of WoW Housing — a community gallery for World of Warcraft player housing builds.
Browse stunning builds, get decoration ideas, share your own creations, and connect with fellow builders.
Live at wowplots.com
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Runtime | Cloudflare Workers via @opennextjs/cloudflare |
| Database | Cloudflare D1 (SQLite) + Drizzle ORM |
| Storage | Cloudflare R2 (images) |
| Auth | Discord OAuth via arctic |
| Resend | |
| CSS | Tailwind CSS v4 |
| Testing | Playwright |
| Package Manager | pnpm |
- Node.js 20+
- pnpm (
npm install -g pnpm) - Cloudflare account with Workers, D1, and R2 enabled
- Discord Developer Application (for OAuth)
# Clone and install
git clone https://github.com/ottomansky/wowplots.git
cd wowplots
pnpm install
# Configure environment
cp .env.example .dev.vars
# Edit .dev.vars with your credentials (see Environment Variables below)
# Set up local D1 database
pnpm db:migrate # Apply Drizzle migrations to local D1
pnpm db:seed # Seed 25 sample builds
# Start dev server
pnpm dev # Next.js + Turbopack on http://localhost:3000Create .dev.vars for local development. In production, set via wrangler secret put.
| Variable | Description | Where to get it |
|---|---|---|
DISCORD_CLIENT_ID |
Discord OAuth app client ID | Discord Developer Portal |
DISCORD_CLIENT_SECRET |
Discord OAuth app client secret | Same as above |
RESEND_API_KEY |
Transactional email API key | resend.com |
SESSION_SECRET |
32-byte hex for signing session cookies | openssl rand -hex 32 |
ADMIN_DISCORD_IDS |
Comma-separated Discord user IDs for admin access | Your Discord user ID |
ENVIRONMENT |
development or production |
Set accordingly |
| Command | Description |
|---|---|
pnpm dev |
Start local dev server with Turbopack |
pnpm build |
Production Next.js build |
pnpm typecheck |
TypeScript strict check |
pnpm lint |
ESLint |
pnpm test:e2e |
Playwright test suite |
pnpm db:generate |
Generate Drizzle migration files |
pnpm db:migrate |
Apply migrations to local D1 |
pnpm db:migrate:prod |
Apply migrations to production D1 |
pnpm db:seed |
Seed local D1 with sample data |
pnpm db:seed:prod |
Seed production D1 |
pnpm cf:deploy |
Build with OpenNext + deploy to Workers |
Schema defined in src/db/schema.ts using Drizzle ORM:
users— Discord OAuth usersbuilds— Housing build entries with metadatabuild_images— Screenshots per build (R2 keys)tags/build_tags— Categorization systemlikes/bookmarks— User interactionscomments— Build commentswaitlist— Email signupsbuilds_fts— FTS5 full-text search index
Migrations in drizzle/, applied via wrangler d1 execute.
CI/CD via GitHub Actions (.github/workflows/deploy.yml):
- Push to
main→ install → typecheck → lint → OpenNext build → deploy - Requires
CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_IDGitHub secrets
Manual deploy: pnpm cf:deploy
src/
├── app/ # Next.js App Router pages + API routes
│ ├── api/ # REST API (auth, builds, comments, waitlist)
│ ├── gallery/ # Gallery browse + build detail pages
│ ├── blog/ # Article index + [slug] pages
│ ├── biomes/ # Biome category pages
│ ├── styles/ # Style category pages
│ ├── sizes/ # Size category pages
│ ├── admin/ # Admin panel (auth-gated)
│ ├── submit/ # Build submission form
│ ├── my-builds/ # User's submissions
│ ├── bookmarks/ # Saved builds
│ └── creators/ # Creator profiles
├── components/ # React components
│ ├── layout/ # Header, Footer
│ ├── gallery/ # BuildCard, ImageGallery, Filters, etc.
│ ├── blog/ # ArticleBody, TOC, RelatedArticles
│ └── auth/ # UserMenu
├── content/articles/ # MDX blog articles
├── db/ # Drizzle schema + database helper
├── lib/ # Utilities, auth, queries, constants
└── types/ # Global type definitions
Fan project. World of Warcraft is a trademark of Blizzard Entertainment, Inc.