# Zodiac Compatibility A private astrology compatibility website for sharing your zodiac signs and compatibility report with friends — no accounts, no tracking, no data storage. **Deployed at:** [zodiac.psingletary.com](https://zodiac.psingletary.com) ## How it works 1. You share the link with someone (in person or via SMS). 2. They enter their birthday (and optionally their name) and instantly see: - Their **Western zodiac sign** (Sun sign + element, modality, ruling planet) - Their **Chinese zodiac sign** (animal + element + heavenly stem) - A **compatibility report** comparing them to a fixed admin profile 3. They tap "Text this chart to [admin]" which opens **their own phone's SMS app** — no server-side SMS, no Twilio cost. The visitor sends the message themselves. ## Privacy - **No birthdays are stored anywhere.** The report is computed client-side. - Share tokens are **encoded directly into the URL** (base64url). No server storage, no database. Tokens expire client-side after 48 hours. - No analytics. No cookies with PII. - The admin's birthday lives only in env vars — never in the client bundle. ## Tech Stack - **Framework:** Next.js 16 (App Router) + TypeScript - **Styling:** Tailwind CSS v4 - **Architecture:** **Fully static** — zero server routes, zero API endpoints. Deployable to any static host (Tangled, wisp, Vercel, S3, etc.) - **Astrology:** Pure TypeScript with baked-in Lunar New Year lookup table (no external library needed; 1900-2100 coverage) - **Share tokens:** Client-side encode/decode (base64url, embedded expiry). No server storage, no database. - **Testing:** Vitest (62 tests) ## Project Structure ``` src/ ├── app/ │ ├── r/page.tsx # Static page — decodes report from ?t= query param │ ├── layout.tsx # Root layout with metadata │ ├── page.tsx # Landing page with birthday form │ └── globals.css # Tailwind + base styles ├── components/ │ ├── BirthdayForm.tsx # Form with validation + computation │ ├── CompatibilityReport.tsx # Full report display + share section │ └── SmsLink.tsx # sms: URI builder + copy fallback ├── lib/ │ ├── astrology/ │ │ ├── western.ts # Western zodiac computation │ │ ├── chinese.ts # Chinese zodiac (Lunar New Year table) │ │ ├── index.ts # Barrel export │ │ └── __tests__/ # 47 tests │ ├── compatibility/ │ │ ├── data.ts # All sign profiles + compatibility ratings │ │ ├── engine.ts # Report builder │ │ └── __tests__/ # 8 tests │ ├── config/ │ │ └── admin.ts # Admin profile from env vars │ └── share/ │ ├── tokens.ts # Client-side token encode/decode │ └── __tests__/ # 7 tests └── .hermes/plans/ # Implementation plan ``` ## Getting Started ### Prerequisites - Node.js 20+ - npm ### Local Development ```bash # Install dependencies npm install # Copy and configure environment cp .env.example .env.local # Edit .env.local with your phone number and nickname: # ADMIN_PHONE="+1XXXXXXXXXX" # ADMIN_NICKNAME="YourName" # Run dev server npm run dev # Opens at http://localhost:3000 ``` ### Run Tests ```bash npm test # Single run (62 tests) npm run test:watch # Watch mode ``` ### Build ```bash npm run build # Production build npm start # Start production server ``` ## Environment Variables | Variable | Required | Default | Description | |---|---|---|---| | `ADMIN_PHONE` | Yes | — | E.164 phone number for SMS sharing | | `ADMIN_NICKNAME` | No | `"me"` | Display name for the share button | | `SHARE_TOKEN_TTL_SECONDS` | No | `172800` (48h) | How long share links stay valid | ## Admin Profile The admin (the person receiving the SMS) is **Fire Dragon Virgo** (Yang Fire / Bing). The admin's actual birthday is configured via `ADMIN_BIRTHDAY` env var (if present) and is **never exposed** to the client bundle. To change the admin's astrology profile, edit the compatibility data in `src/lib/compatibility/data.ts`. The current profile is: - **Western:** Virgo (Earth, Mutable, Mercury) - **Chinese:** Fire Dragon (Yang Fire, 丙 / Bing) - **Lucky numbers:** 1, 6, 7 - **Lucky colors:** Gold, Silver, Gray ## SMS Sharing The sharing mechanism uses the `sms:` URI scheme, not a server-side SMS provider: 1. Visitor views their report on the site 2. They tap "Text this chart to [admin]" which generates a share link 3. On mobile, the `sms:` URI opens their native SMS app pre-filled with the link 4. On desktop, a "Copy link" button + admin phone number is shown instead The `sms:` URI uses `&` separator for iOS and `?` for Android (auto-detected via user agent). ## Deployment **Fully static.** Deploy to any static host. See [DEPLOY.md](./DEPLOY.md) for detailed instructions (Tangled, wisp, Vercel, Netlify, S3, etc.). ## License Private project — all rights reserved.