ExposedGays: map, shop, auth, Supabase schema, Coolify Dockerfile
This commit is contained in:
163
README.md
Normal file
163
README.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# ExposedGays
|
||||
|
||||
100% free gay cruising map + chat + spots directory + sex shop. No subscriptions ever.
|
||||
|
||||
**Domain:** exposedgays.com
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
npm install
|
||||
cp .env.example .env.local
|
||||
# Edit .env.local with your Supabase keys (optional for local demo — mock data works offline)
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000)
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | Status |
|
||||
|---------|--------|
|
||||
| Real-time cruising map (Leaflet + OSM) | ✅ Mock data + Supabase-ready |
|
||||
| User clustering + position badges | ✅ |
|
||||
| Map filters (age, position, kinks, PrEP) | ✅ |
|
||||
| Cruiser Cards + Profile popup | ✅ |
|
||||
| Instant chat + city chat + DMs + groups | ✅ Mock + Supabase schema |
|
||||
| Cruising spot directory | ✅ |
|
||||
| **Shop** (affiliate links, local cart) | ✅ |
|
||||
| Age verification gate (Florida-compliant) | ✅ |
|
||||
| Vanilla mode blur toggle | ✅ |
|
||||
| Dark mode, mobile-first, PWA manifest | ✅ |
|
||||
| Anonymous browsing + optional profile | ✅ |
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Next.js 15** App Router + TypeScript
|
||||
- **Tailwind CSS** + shadcn/ui components
|
||||
- **React-Leaflet** + OpenStreetMap tiles
|
||||
- **Supabase** — Auth, Postgres + PostGIS, Realtime, Storage
|
||||
- **Zustand** — localStorage cart
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
exposedgays/
|
||||
├── public/
|
||||
│ └── manifest.json # PWA manifest
|
||||
├── src/
|
||||
│ ├── app/
|
||||
│ │ ├── layout.tsx # Root layout + nav
|
||||
│ │ ├── page.tsx # Map (home)
|
||||
│ │ ├── shop/page.tsx # Sex shop
|
||||
│ │ ├── chat/page.tsx # City chat + DMs
|
||||
│ │ ├── spots/page.tsx # Spot directory
|
||||
│ │ └── profile/page.tsx # User profile editor
|
||||
│ ├── components/
|
||||
│ │ ├── AgeGate.tsx # 18+ DOB verification
|
||||
│ │ ├── Map.tsx # Interactive cruising map
|
||||
│ │ ├── Shop.tsx # Product grid + cart
|
||||
│ │ ├── Nav.tsx # Top/bottom nav with Shop link
|
||||
│ │ ├── ChatPanel.tsx # Real-time chat UI
|
||||
│ │ ├── CruiserCard.tsx # Squirt-style cruiser cards
|
||||
│ │ ├── ProfilePopup.tsx # Tap icon → profile modal
|
||||
│ │ ├── SpotDirectory.tsx # Spot listings + search
|
||||
│ │ └── ui/ # shadcn components
|
||||
│ ├── lib/
|
||||
│ │ ├── products.ts # Dummy shop inventory
|
||||
│ │ ├── cart.ts # Zustand localStorage cart
|
||||
│ │ ├── mock-data.ts # Demo cruisers + spots
|
||||
│ │ └── supabase/ # Supabase client helpers
|
||||
│ └── types/index.ts
|
||||
├── supabase/
|
||||
│ └── schema.sql # Full Postgres + PostGIS + RLS
|
||||
├── .env.example
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Supabase Setup
|
||||
|
||||
### 1. Create project
|
||||
|
||||
Go to [supabase.com](https://supabase.com) → New Project (free tier).
|
||||
|
||||
### 2. Run schema
|
||||
|
||||
SQL Editor → paste contents of `supabase/schema.sql` → Run.
|
||||
|
||||
### 3. Enable Realtime
|
||||
|
||||
Dashboard → Database → Replication → enable `chat_messages` and `profiles`.
|
||||
|
||||
### 4. Create Storage bucket
|
||||
|
||||
```sql
|
||||
INSERT INTO storage.buckets (id, name, public) VALUES ('gallery', 'gallery', true);
|
||||
INSERT INTO storage.buckets (id, name, public) VALUES ('shop', 'shop', true);
|
||||
```
|
||||
|
||||
### 5. Copy keys to `.env.local`
|
||||
|
||||
```
|
||||
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
|
||||
SUPABASE_SERVICE_ROLE_KEY=eyJ...
|
||||
```
|
||||
|
||||
### CLI alternative
|
||||
|
||||
```bash
|
||||
npx supabase init
|
||||
npx supabase link --project-ref YOUR_PROJECT_REF
|
||||
npx supabase db push
|
||||
```
|
||||
|
||||
## 5-Minute Deployment (Vercel + Supabase + DNS)
|
||||
|
||||
### Step 1 — Push to GitHub (1 min)
|
||||
|
||||
```bash
|
||||
git init
|
||||
git add .
|
||||
git commit -m "ExposedGays starter"
|
||||
gh repo create exposedgays --private --push
|
||||
```
|
||||
|
||||
### Step 2 — Vercel deploy (2 min)
|
||||
|
||||
1. [vercel.com](https://vercel.com) → Import Git repo
|
||||
2. Framework: **Next.js** (auto-detected)
|
||||
3. Add environment variables from `.env.example`
|
||||
4. Deploy → get `exposedgays.vercel.app`
|
||||
|
||||
### Step 3 — Custom domain (1 min)
|
||||
|
||||
1. Vercel → Project → Settings → Domains → Add `exposedgays.com` + `www.exposedgays.com`
|
||||
2. Vercel shows required DNS records
|
||||
|
||||
### Step 4 — DNS at registrar (1 min)
|
||||
|
||||
| Type | Name | Value |
|
||||
|------|------|-------|
|
||||
| A | @ | `76.76.21.21` |
|
||||
| CNAME | www | `cname.vercel-dns.com` |
|
||||
|
||||
(Or use Cloudflare CNAME flattening if proxied.)
|
||||
|
||||
### Step 5 — Verify
|
||||
|
||||
- Visit `https://exposedgays.com` — age gate appears
|
||||
- Map loads with cruiser icons
|
||||
- Shop nav works with affiliate buttons
|
||||
- PWA installable on mobile
|
||||
|
||||
## Shop Affiliate Notes
|
||||
|
||||
- Cart is **localStorage only** — no checkout on-site
|
||||
- "Buy Now" opens affiliate URLs in new tab (`rel="sponsored"`)
|
||||
- Replace placeholder URLs with real Amazon Associates / AdamMale affiliate links
|
||||
- Products defined in `src/lib/products.ts` (static) or `shop_products` table (DB)
|
||||
|
||||
## License
|
||||
|
||||
Private — exposedgays.com © 2026
|
||||
Reference in New Issue
Block a user