# AGENTS.md — Wallora Searcher > This file contains agent-focused context about the project: build steps, tests, conventions, and preferences that don't belong in the README. ## Project Overview Wallora Searcher is a Next.js 16 App Router project with three distinct surfaces: 1. **Public SEO website** — Landing pages for visitors 2. **Admin dashboard** — Authenticated admin interface for gallery/photo management 3. **Public API** — REST endpoints for external clients ## Tech Stack - **Framework**: Next.js 16.2.6 (App Router, Turbopack) - **Runtime**: React 19.2.4, React DOM 19.2.4 - **Language**: TypeScript 6.0.3 - **Styling**: Tailwind CSS v4, OKLCH color system - **UI System**: shadcn/ui (base-nova style, base primitives) - **Auth**: NextAuth.js v5 beta (Credentials provider) - **Database**: Supabase (PostgreSQL) - **Package Manager**: pnpm (monorepo with pnpm-workspace.yaml) - **Lint**: ESLint 9 + eslint-config-next + tailwind-canonical-classes - **Python Scripts**: Selenium + ChromeDriver for browser automation ## Directory Structure ``` app/ (admin)/ # Admin route group admin/ (protected)/ # Protected routes (requires auth) dashboard/ # Admin dashboard gallery/ # Gallery photo picker (瀑布流 masonry) login/ # Admin login page (site)/ # Public website route group api/ # API routes admin/ gallery-photos/ # GET — paginated gallery photos auth/[...nextauth]/ # NextAuth handlers cron/ gallery-photos/ # Cron job for sync components/ admin/gallery/ # Gallery-specific components ui/ # shadcn/ui components lib/ auth.ts # NextAuth configuration supabase/ service-role.ts # Supabase service role client utils.ts # cn() utility server/ admin/gallery-sync.ts # Gallery sync logic api/unsplash.ts # Unsplash API client scripts/ sync-gallery-photos.py # Python script: Selenium Chrome → Unsplash → Supabase requirements.txt # Python deps: selenium, webdriver-manager, supabase, python-dotenv .venv/ # Python virtual environment types/ admin/gallery.ts # GalleryPhoto, GalleryPagination types ``` ## Environment Variables Required in `.env.local`: ```bash # NextAuth AUTH_SECRET= # Supabase NEXT_PUBLIC_SUPABASE_URL=http://your-supabase-url NEXT_PUBLIC_SUPABASE_ANON_KEY= SUPABASE_SERVICE_ROLE_KEY= # Admin Credentials ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword # Cron (optional) CRON_SECRET= ``` ## Scripts ```bash # Development pnpm dev # Start dev server at localhost:3000 # Build & Lint pnpm build # Production build pnpm lint # ESLint check pnpm lint:fix # ESLint with auto-fix # Format pnpm format # Prettier format all pnpm format:check # Prettier check # Gallery Sync pnpm sync:gallery # Node.js sync script (legacy) # Python Sync python scripts/sync-gallery-photos.py --max-pages=10 --topic=wallpapers ``` ## Python Sync Script The Python script controls a real Chrome browser via Selenium to fetch Unsplash data: ```bash # Setup (first time) cd scripts python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt # Run python scripts/sync-gallery-photos.py --max-pages=5 --topic=wallpapers ``` **Features**: - `--max-pages`: Required. Pages to fetch (1..N) - `--topic`: Optional. Unsplash topic slug (e.g. `wallpapers`, `3d-renders`, `nature`) - `--per-page`: Optional. Default 20 - `--headless/--no-headless`: Default headless - `--delay`: Base delay between pages (default 3s, +0-2s random) ## Admin Authentication - Uses NextAuth.js v5 beta with Credentials provider - Login page: `/admin/login` - Protected routes: `/admin/(protected)/*` - Route protection via `proxy.ts` (Next.js 16 middleware convention) - Session stored as JWT ## Gallery Page Features - **Masonry Layout**: 4 independent columns with greedy shortest-column algorithm - **Infinite Scroll**: IntersectionObserver-based pagination - **Animations**: Entrance fade + translateY + scale, hover scale + shadow, lightbox transitions - **Lightbox**: Click to view full image with metadata overlay - **API**: `/api/admin/gallery-photos?page=N&per_page=24` ## Supabase Tables - `wg_gallery_photos` — Photo data from Unsplash - `wg_gallery_sync_state` — Sync state tracking ## Conventions ### Routing - Use App Router (`app/`). Never create `pages/` unless explicitly requested. - Route groups: `(admin)` for admin, `(site)` for public. - Protected routes nested under `(protected)`. ### Components - React Server Components by default. - Add `"use client"` only for interactivity (state, effects, browser APIs). - shadcn/ui as base. Use `npx shadcn@latest add ` to install. - Prefer Tailwind utility classes and CSS variables over custom CSS. ### API Design - Separate JWT auth (public API) and session auth (admin) as different trust boundaries. - Update `swagger.yaml` when API contracts change. ### Styling - Use semantic colors (`bg-primary`, `text-muted-foreground`). - No raw colors like `bg-blue-500`. - Use `size-*` for equal width/height. - Use `gap-*` instead of `space-x-*` / `space-y-*`. ### Python Scripts - All Python code lives in `scripts/`. - Use virtual environment at `scripts/.venv/`. - Keep `.env.local` parsing logic consistent with Node.js scripts. ## Known Issues / Gotchas 1. **Next.js 16 uses `proxy.ts` instead of `middleware.ts`** for route interception. 2. **shadcn/ui base-nova style** uses `@base-ui/react` primitives, not Radix. 3. **ESLint** has `react-hooks/set-state-in-effect` disabled (false positives with async data fetching). 4. **`.venv/` and `node_modules/`** should be ignored by ESLint (configured in `eslint.config.mjs`). 5. **GalleryGrid** uses `` not Next.js `` because external Unsplash URLs don't work well with the Image optimizer without domain configuration. ## Verification Checklist After making changes: - [ ] `pnpm lint` passes - [ ] `pnpm build` succeeds - [ ] For visual changes: verify at `http://localhost:3000` - [ ] For admin changes: verify login/logout flow - [ ] For API changes: test with curl or browser ## Contact - Admin: luoyw1106703846@gmail.com