2026-05-09 16:00:29 +08:00
|
|
|
# Web Spec
|
2026-05-09 12:11:10 +08:00
|
|
|
|
2026-05-09 16:00:29 +08:00
|
|
|
## Scope
|
2026-05-09 12:11:10 +08:00
|
|
|
|
2026-05-09 16:00:29 +08:00
|
|
|
This spec applies to `web/**`.
|
2026-05-09 12:11:10 +08:00
|
|
|
|
2026-05-09 16:00:29 +08:00
|
|
|
Read this file before changing the Astro site, React app islands, authenticated app routes, API clients, i18n, or responsive layout.
|
2026-05-09 12:11:10 +08:00
|
|
|
|
2026-05-09 16:00:29 +08:00
|
|
|
## Current Stack
|
2026-05-09 12:11:10 +08:00
|
|
|
|
2026-05-09 16:00:29 +08:00
|
|
|
- Astro 6 for static public pages and route files.
|
|
|
|
|
- React 19 for interactive client UI.
|
|
|
|
|
- React Router DOM for the authenticated business app shell.
|
|
|
|
|
- Tailwind CSS 4 through `@tailwindcss/vite`.
|
|
|
|
|
- TypeScript strict mode.
|
|
|
|
|
- Local i18n from `web/src/i18n/utils.ts`.
|
|
|
|
|
- Backend API base for production: `https://api.meeyao.com`.
|
|
|
|
|
- Local development API access uses the Vite `/api` proxy in `web/astro.config.mjs`.
|
2026-05-09 12:11:10 +08:00
|
|
|
|
2026-05-09 16:00:29 +08:00
|
|
|
Do not introduce a second frontend framework, a second router, or scattered API URL construction for web code.
|
|
|
|
|
|
|
|
|
|
## Route Architecture
|
|
|
|
|
|
|
|
|
|
Public pages are Astro pages under `web/src/pages/{locale}/` and use `Marketing.astro`.
|
|
|
|
|
|
|
|
|
|
Authenticated pages are Astro route shells that all render `DashboardAppPage.astro`. The actual logged-in application is a single React Router app:
|
|
|
|
|
|
|
|
|
|
- `DashboardApp.tsx` owns React Router routes for dashboard, store, history, notifications, profile, settings, and divination pages.
|
|
|
|
|
- `AppShell.tsx` owns the persistent sidebar, mobile drawer, route guard, and authenticated layout.
|
|
|
|
|
- Business page components render only their page body. They must not wrap themselves in `AppShell`.
|
|
|
|
|
- Sidebar navigation must use React Router navigation so the shell remains mounted and only the right-side content changes.
|
|
|
|
|
- Direct browser refresh on each existing business route must still render the app shell through Astro.
|
|
|
|
|
|
|
|
|
|
Login and public marketing/legal pages are not part of the authenticated app shell.
|
|
|
|
|
|
|
|
|
|
## Auth Rules
|
|
|
|
|
|
|
|
|
|
- Login and registration are the same email-code flow. The backend auto-registers new email accounts.
|
|
|
|
|
- Test credentials for local verification: `test@example.com` with code `123456`.
|
|
|
|
|
- Auth state is stored by `web/src/lib/auth.ts` under one local storage key.
|
|
|
|
|
- Every authenticated route must recover or refresh the session before showing business content.
|
|
|
|
|
- Missing, expired, invalid, or refresh-failed tokens must clear local auth and redirect to `/{locale}/login`.
|
|
|
|
|
- Do not add silent success paths for auth failures.
|
|
|
|
|
|
|
|
|
|
## API Rules
|
|
|
|
|
|
|
|
|
|
- All API paths live in `web/src/lib/api-routes.ts`.
|
|
|
|
|
- Shared request behavior lives in `web/src/lib/api-client.ts`.
|
|
|
|
|
- Auth/session behavior lives in `web/src/lib/auth.ts`.
|
|
|
|
|
- Business API functions live in `web/src/lib/api.ts`.
|
|
|
|
|
- Components must call typed API helper functions, not inline `fetch('/api/...')`.
|
|
|
|
|
- Dashboard-visible user, points, notification, and history data must come from the backend. Do not hardcode those values.
|
|
|
|
|
- Production API host is `https://api.meeyao.com`; local dev should use same-origin `/api` and the Vite proxy.
|
|
|
|
|
|
|
|
|
|
## Layout Rules
|
|
|
|
|
|
|
|
|
|
- Build mobile-first, then add `sm:`, `md:`, `lg:`, and `xl:` refinements.
|
|
|
|
|
- Business pages must not require horizontal scrolling at common phone widths such as `390x844`.
|
|
|
|
|
- Use responsive stacks for fixed-width desktop columns: `flex-col lg:flex-row`, `w-full lg:w-[...]`.
|
|
|
|
|
- Keep the authenticated shell as `h-screen` with the main content scrollable.
|
|
|
|
|
- Mobile sidebar must be reachable through the menu button and must not hide the page content permanently.
|
|
|
|
|
- Public header mobile navigation must expose feature, pricing, about, login, and language switching.
|
|
|
|
|
|
|
|
|
|
## i18n Rules
|
|
|
|
|
|
|
|
|
|
- Supported locales: `zh`, `zh_Hant`, `en`.
|
|
|
|
|
- Routes are prefixed by locale, including the default locale.
|
|
|
|
|
- User-visible text should come from `web/src/i18n/utils.ts` or locale-specific content assets.
|
|
|
|
|
- Do not add user-facing strings in only one locale.
|
|
|
|
|
|
|
|
|
|
## Design Source
|
|
|
|
|
|
|
|
|
|
- Pencil design files under `web/design/` are the visual source for login and public page design.
|
|
|
|
|
- If UI implementation diverges from Pencil, inspect the design first and keep the code aligned unless the user explicitly asks to change the design.
|
|
|
|
|
- Assets in `web/public/images` and `web/public/legal` are symlinks to `web/design/assets`; do not duplicate them.
|
|
|
|
|
|
|
|
|
|
## Verification
|
|
|
|
|
|
|
|
|
|
Before finishing meaningful web changes:
|
|
|
|
|
|
|
|
|
|
- Run `npm run build` in `web/`.
|
|
|
|
|
- Use Chrome DevTools on `http://localhost:4322/` for at least one desktop and one phone viewport when layout or routing changed.
|
|
|
|
|
- For authenticated changes, verify the test account can log in and lands on `/{locale}/dashboard`.
|
|
|
|
|
- Verify direct unauthenticated access to a business route redirects to login.
|
|
|
|
|
- Verify sidebar navigation changes content without a full document reload.
|
|
|
|
|
|
|
|
|
|
## Forbidden
|
|
|
|
|
|
|
|
|
|
- Do not hardcode API URLs or endpoint paths in components.
|
|
|
|
|
- Do not add `.env` as a required file for normal local development.
|
|
|
|
|
- Do not reintroduce page-refresh sidebar navigation inside the authenticated app.
|
|
|
|
|
- Do not wrap business page components in nested cards or duplicate `AppShell`.
|
|
|
|
|
- Do not add fallback/mock success behavior for failed API calls.
|