# Web Development Guidelines > Astro 6 + React 19 + Tailwind CSS 4 + shadcn/ui --- ## Tech Stack | Layer | Technology | Version | |-------|-----------|---------| | Framework | Astro | 6.x | | Interactive UI | React | 19.x (client-only, no RSC) | | Styling | Tailwind CSS | 4.x (via `@tailwindcss/vite`) | | Component Library | shadcn/ui | latest | | Language | TypeScript | 5.x (strict) | | i18n | Built-in (type-safe object in `src/i18n/utils.ts`) | - | | Markdown Rendering | `marked` | latest | | Auth | Supabase Auth JS SDK | - | ### Architecture Decision - **Astro SSG** for marketing/public pages (SEO-critical) - **React client islands** for interactive parts (Login, Dashboard, Notifications) - **No React Server Components** — CVE-2025-55182 risk eliminated - **No Next.js** — multiple critical CVEs (CVE-2025-55182, CVE-2025-29927, CVE-2025-66478) ### Actual Dependencies ``` astro, @astrojs/react, react, react-dom, @tailwindcss/vite, tailwindcss, marked ``` --- ## Pre-Development Checklist Before writing web code, read: - [ ] This index - [ ] Design file: `web/design/eryao.pen` - [ ] Backend API contracts: `docs/protocols/` - [ ] Error code mapping: `docs/protocols/common/http-error-codes.md` - [ ] Mobile i18n files (for translation sync): `apps/lib/l10n/app_*.arb` --- ## Project Structure ``` web/ ├── design/ # Pencil design files (.pen) │ ├── eryao.pen │ └── assets/ # Shared assets (images, legal) │ ├── images/ │ └── legal/{zh,zh_Hant,en}/ ├── public/ │ ├── images -> ../design/assets/images # symlink, no duplication │ ├── legal -> ../design/assets/legal # symlink, no duplication │ ├── favicon.ico │ └── favicon.svg ├── src/ │ ├── components/ │ │ ├── Navbar.astro # Marketing nav (responsive, lang switcher) │ │ ├── Footer.astro # Marketing footer (responsive) │ │ ├── Hero.astro # Landing hero section │ │ ├── Showcase.astro # Landing showcase section │ │ ├── Testimonials.astro # Landing testimonials section │ │ ├── CtaSection.astro # Landing CTA section │ │ ├── FeaturesPage.astro # Features grid page │ │ ├── PricingPage.astro # Pricing cards page │ │ ├── AboutPage.astro # About + company info page │ │ └── LegalPage.astro # Markdown legal page (generic) │ ├── layouts/ │ │ └── Marketing.astro # Nav + content + footer + scroll animations │ ├── pages/ │ │ ├── index.astro # Root redirect -> /zh/ │ │ ├── {zh,zh_Hant,en}/ │ │ │ ├── index.astro # Landing │ │ │ ├── features.astro │ │ │ ├── pricing.astro │ │ │ ├── about.astro │ │ │ ├── privacy.astro │ │ │ └── terms.astro │ ├── i18n/ │ │ └── utils.ts # Type-safe translations (all inline) │ └── styles/ │ ├── global.css # Tailwind entry │ └── animations.css # Scroll reveal animations ├── astro.config.mjs ├── tsconfig.json └── package.json ``` --- ## Responsive Layout **All pages must be fully responsive: full-width sections, no fixed pixel widths.** ### Layout Principles 1. **Full-width sections** — Each section spans `w-full`, content is centered with `max-w-7xl mx-auto` 2. **No fixed pixel widths** — Use `w-full`, `max-w-*`, and `flex/grid` for all layouts 3. **Mobile-first** — Base styles target mobile, `md:` breakpoint for desktop 4. **Viewport-filling sections** — Hero and CTA use `min-h-screen` or generous padding to fill viewport 5. **Smooth scroll transitions** — Each section flows into the next with gradients or color changes ### Breakpoints | Breakpoint | Target | |-----------|--------| | Base (< 768px) | Mobile phones | | `md:` (>= 768px) | Tablets and desktop | ### Section Patterns ``` Hero: w-full, min-h-screen, bg-gradient, centered content Showcase: w-full, flex-col md:flex-row, gap, centered max-w Testimonials: w-full, bg-slate-900, grid cols-1 md:cols-3 CTA: w-full, bg-violet-600, centered Footer: w-full, bg-slate-950, responsive flex ``` --- ## Design Tokens All colors from design map directly to Tailwind defaults: | Token | Tailwind | Hex | |-------|----------|-----| | Primary | `violet-600` | #7C3AED | | Primary light | `violet-100` | — | | Background | `white` | #FFFFFF | | Surface | `slate-50` | #F8FAFC | | Dark bg | `slate-900` | #0F172A | | Footer bg | `slate-950` | #020617 | | Border | `slate-200` | #E2E8F0 | | Warning bg | `amber-50` | #FFFBEB | | Gradient top | `white` -> `violet-50` | — | --- ## Scroll Animations Defined in `src/styles/animations.css`, triggered by `IntersectionObserver` in `Marketing.astro`. | Class | Effect | Use Case | |-------|--------|----------| | `.reveal` | Fade up (translateY 24px) | Default for most elements | | `.reveal-left` | Slide from left | Showcase left column | | `.reveal-right` | Slide from right | Showcase right column | | `.reveal-scale` | Scale in (0.95 -> 1) | CTA section | | `.stagger-1` to `.stagger-4` | Delay 0.1s-0.4s | Grouped elements (cards, grid items) | - All animations: `0.6-0.7s`, `cubic-bezier(0.22, 1, 0.36, 1)` (ease-out-quint) - `prefers-reduced-motion: reduce` disables all animations - Observer `rootMargin: 0px 0px -60px 0px` for pre-trigger - Elements are `opacity: 0` until `.visible` class is added, then `animation-fill-mode: forwards` --- ## i18n (CRITICAL) **Every user-visible text must use i18n keys. No hardcoded strings.** ### Supported Locales | Code | Language | Brand Name | |------|----------|------------| | `zh` | 简体中文 | 觅爻签问 | | `zh_Hant` | 繁體中文 | 覓爻簽問 | | `en` | English | MeiYao Divination | ### Implementation - All translations are in `src/i18n/utils.ts` as a typed `Record` object - Access via `t(locale, 'section')` which returns the section object (e.g., `t(locale, 'nav').features`) - URL strategy: `/{locale}/path` prefix (e.g., `/zh/`, `/en/`) - Default locale: `zh`, root `/` redirects to `/zh/` - Config in `astro.config.mjs` with `prefixDefaultLocale: true` ### Rules 1. **All text must come from `t()`** — never inline strings 2. **Brand name** is always from `footer.brandName` (consistent across Navbar/Footer) 3. **Check Flutter i18n first** (`apps/lib/l10n/app_*.arb`) before inventing translations 4. **Legal content** loaded from `public/legal/{locale}/` markdown files --- ## Assets - Shared assets live in `web/design/assets/` (used by Pencil) - `web/public/images` and `web/public/legal` are **symlinks** to `../design/assets/*` - **Never duplicate** assets — always use symlinks or references --- ## Cross-Layer Contracts ### API Integration - Backend: FastAPI REST endpoints (see `docs/protocols/`) - Auth: Supabase Auth JS SDK (client-side) - Error format: RFC 7807 `ApiProblem` (same as mobile) ### Brand Consistency (Flutter app) - App title: "觅爻签问" / "MeiYao Divination" (NOT "MiYao") - Company: 洵觅科技(深圳)有限公司 / Xunmee Technology (Shenzhen) Co., Ltd. - Contact: xuyunlong@xunmee.com - ICP: 粤ICP备2025428416号-1A --- ## Quality Rules ### Forbidden - Do not use React Server Components (RSC) - Do not import server-only modules in client islands - Do not hardcode colors outside Tailwind tokens - Do not use fixed pixel widths for layout (use responsive utilities) - Do not use `any` in TypeScript - Do not use third-party shadcn registries (official only) - Do not duplicate assets — use symlinks ### Required - All pages must be fully responsive (mobile + desktop) - All sections must be full-width with centered content - All pages must pass Lighthouse SEO >= 95 (marketing pages) - All interactive components must be accessible (ARIA) - `npm audit` must be clean before merge - TypeScript strict mode enabled - `prefers-reduced-motion` must disable animations