# Wallora Searcher Architecture Reference ## Surfaces And Roles The project has three user-facing surfaces: - Public API: available to external users. Use JWT login/authorization for protected API access. Keep contracts documented in `swagger.yaml`. - Admin: available only after account/password login. Use NextAuth-backed sessions to persist admin login state and gate admin features. - Public website: available to anyone on the public internet. Optimize pages for SEO, metadata, crawlability, and public performance. Keep these surfaces separate in routing, middleware, authorization helpers, and mental model. ## Route Boundaries Prefer clear route groups as the app grows: - Public website: `app/(site)/...` - Admin UI: `app/(admin)/admin/...` - Protected admin UI: `app/(admin)/admin/(protected)/...` - Public API: `app/api/...` - Auth endpoints: `app/api/auth/...` for NextAuth If the existing tree does not yet use route groups, introduce them only when it makes the current change clearer. ## Authentication And Authorization - Public API authorization: validate JWTs explicitly for protected API routes. Define who issues the token before implementing token verification. - Current app-user JWTs are issued by `/api/v1/auth/login` and `/api/v1/auth/register`, signed with `APP_JWT_SECRET` or `AUTH_SECRET`, and validated by server-only helpers before accessing `/api/v1/users/me/...`. - Disabled app users should not be able to log in or use existing Bearer tokens because token validation reloads current `wg_app_users.status`. - Admin authorization: use NextAuth account/password login and session checks. Do not rely on public API JWT logic as the admin session source. - Only `/admin/login` is public under the admin surface. All other `/admin` pages need middleware/proxy protection and server-side `auth()` checks, preferably via a protected route-group layout. - Server code must keep secrets server-only. Never expose service-role Supabase keys, Aliyun OSS secrets, NextAuth secrets, or JWT signing secrets in `NEXT_PUBLIC_*`. - Keep authorization decisions close to the server boundary: route handlers, server actions, middleware, or server-only helpers. ## Data Storage Use Supabase for application data. - Prefix project-owned tables, indexes, triggers, and helper functions with `wg_` when practical. - Enable and design RLS for tables exposed through Supabase APIs. - Do not use user-editable metadata claims for authorization decisions. - Model admin roles and API consumer permissions in trusted tables or trusted auth metadata. - Verify Supabase behavior against current documentation before implementing schema, RLS, or auth-sensitive behavior. - Use service role credentials only in server-only code, one-shot scripts, cron workers, or protected internal route handlers. - Treat raw gallery rows as admin data. Public photo APIs should return picked rows only. - App-facing gallery list/detail endpoints may accept an optional Bearer app-user JWT to add user-specific fields such as `isFavorited`; anonymous responses must still work. - Keep picked state and OSS mirror metadata on `wg_gallery_photos`; use collections tables to group picked photos into public sets. - Admin collection writes should validate that every collection item references a picked photo. - Public collection APIs should filter on `is_published = true` and keep collection photo pagination compatible with infinite scroll. - App user favorites should accept picked photos only, and preferences/download preferences should be stored as JSON in `wg_user_settings`. - Keep phone and WeChat identity support as additive fields on `wg_app_users`; do not split them into separate user tables unless provider-specific complexity requires it later. ## Image Storage Use Aliyun OSS for image files. - Store files in OSS buckets; store metadata such as object key, URL, owner, MIME type, size, visibility, and related entity in Supabase. - Prefer server-side signed upload or server-mediated upload for private/admin flows. - Avoid placing OSS access keys in browser-exposed code. - Existing OSS env support accepts `OSS_REGION`, `OSS_ACCESS_KEY_ID`, `OSS_ACCESS_KEY_SECRET`, `OSS_BUCKET`, and either `OSS_PUBLIC_URL` or `OSS_PUBLIC_BASE_URL`. - Decide whether each image class is public, signed, or private before generating URLs. ## UI System Use shadcn/ui as the base UI layer. - Initialize and inspect shadcn project config before adding components. - Use the project package runner: `pnpm dlx shadcn@latest ...`. - Prefer existing shadcn components before writing custom controls. - Use semantic tokens and component variants instead of raw color overrides. - Compose forms, tables, dialogs, sheets, empty states, loading states, and feedback with shadcn primitives where available. ## SEO Website Pages For public website pages: - Use server-rendered pages by default. - Keep page-level metadata accurate with Next.js metadata APIs. - Use semantic HTML, crawlable content, canonical URLs where needed, and fast-loading assets. - Avoid hiding important public content behind client-only rendering. ## API Documentation Maintain `swagger.yaml` for public API contracts. - Update it whenever API endpoints, auth requirements, request schemas, response schemas, status codes, or error formats change. - Keep operation IDs stable and descriptive. - Document JWT requirements per route instead of assuming all routes share the same auth behavior. - Treat generated examples as contract examples, not placeholders. ## Scheduled Jobs - Do not assume Vercel Cron. This project is not planned for Vercel. - Prefer a one-shot script that can be called by crontab, PM2, Docker, or another scheduler. - Keep scheduled routes protected with a secret when an HTTP trigger is useful. - Never rely on `setInterval` inside a Next.js request/serverless process for durable jobs.