first commit
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user