Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
f4bbc2b
test(e2e): give the two axe-heavy admin tests a 90s timeout
Satelink-Protocol Oct 29, 2026
ac28795
feat(checkout): SuperProfile hosted checkout for tickets
Satelink-Protocol Oct 29, 2026
870e337
chore(payments): delete retired gateway adapters; scrub env example a…
Satelink-Protocol Oct 29, 2026
801b92d
feat(checkout): CI, reconciliation endpoint, e2e, ops doc, review fixes
Satelink-Protocol Oct 29, 2026
64cfe6f
test(e2e): wait for wizard controls to be visible before measuring (C…
Satelink-Protocol Oct 29, 2026
f5e7223
Merge pull request #7 from Jakuraa/feature/superprofile-checkout
Satelink-Protocol Oct 29, 2026
d4a9c73
fix: pin feed DNS at connect time, fail-closed session/checkout edges…
Satelink-Protocol Oct 29, 2026
a596c5c
test(feeds): TLS hostname + redirect regression tests; no auto-deploy…
Satelink-Protocol Oct 29, 2026
02d2e8d
docs(audit): record PR #8 and CI run 40949643679 results
Satelink-Protocol Oct 29, 2026
d238792
feat(safety): fail-closed preview DB write protection, hardened migra…
Satelink-Protocol Oct 29, 2026
4ad1705
docs(audit): record commit d238792 CI run 40958014582 results
Satelink-Protocol Oct 29, 2026
740e0a5
feat: prepare latest website UX and launch improvements
Satelink-Protocol Oct 30, 2026
4e7fd12
feat: add secure cloud-ready StrangersMeetup MCP service
Satelink-Protocol Oct 30, 2026
d74d199
chore: add Render deployment configuration
Satelink-Protocol Oct 30, 2026
4ed00db
fix(mcp): resolve PR #9 CI detached HEAD, Playwright runtime, secret …
Satelink-Protocol Oct 30, 2026
fb28579
fix(a11y): resolve .linkish contrast ratio on dark surfaces for WCAG AA
Satelink-Protocol Oct 30, 2026
607d708
Merge pull request #10 from Jakuraa/fix/cloud-deployment-pr9-blockers
Satelink-Protocol Oct 30, 2026
e6e427d
Merge pull request #9 from Jakuraa/feature/cloud-deployment-prep
Satelink-Protocol Oct 30, 2026
a6d6159
fix(deploy): align Render Docker runtime, Playwright base image, and …
Satelink-Protocol Oct 30, 2026
1777eef
Merge pull request #11 from Jakuraa/fix/render-docker-alignment
Satelink-Protocol Oct 30, 2026
b972f96
feat(ux): enhance event discovery search, card ergonomics, mobile nav…
Satelink-Protocol Oct 31, 2026
27597aa
fix(e2e): make screenshot directory portable for CI runner
Satelink-Protocol Oct 31, 2026
9ab424c
Merge pull request #12 from Jakuraa/feature/website-ux-enhancements
Satelink-Protocol Oct 31, 2026
f9a51fc
feat(attendee): synthetic preview seeding, free booking flow, mystery…
Satelink-Protocol Oct 31, 2026
14ebace
fix(ci): make E2E screenshot directory portable and add preview revie…
Satelink-Protocol Oct 31, 2026
4e6155a
Merge pull request #13 from Jakuraa/feature/attendee-discovery-booking
Satelink-Protocol Oct 31, 2026
9cbd15b
feat(organiser): polish host onboarding, event wizard and dashboard
Satelink-Protocol Oct 31, 2026
3b21b61
test(e2e): adjust assertion timeouts for mobile wizard publish in CI
Satelink-Protocol Oct 31, 2026
f77e437
fix(organiser): scope rate-limit keys for publish and image upload
Satelink-Protocol Oct 31, 2026
09e48de
Merge pull request #14 from Jakuraa/feature/organiser-onboarding-wizard
Satelink-Protocol Oct 31, 2026
1613b54
feat(marketplace): complete attendee booking pass, re-booking clarity…
Satelink-Protocol Oct 31, 2026
6ad0da0
test(e2e): allow optional query params when awaiting booking redirect
Satelink-Protocol Oct 31, 2026
8c40410
Merge pull request #15 from Jakuraa/feature/complete-marketplace-journey
Satelink-Protocol Oct 31, 2026
b4f7f73
feat(safety): website safety reporting, attendee blocking and moderat…
Satelink-Protocol Oct 31, 2026
bc074fb
Merge PR #16: Phase 3O Trust & Safety Remediation
Satelink-Protocol Nov 1, 2026
24798c3
docs(launch): Phase 4A production readiness and pre-flight audit report
Satelink-Protocol Nov 1, 2026
9294fcc
docs(launch): Phase 4B production provisioning and release dry-run re…
Satelink-Protocol Nov 1, 2026
619bc5f
docs(launch): Phase 4C production launch decisions and readiness vali…
Satelink-Protocol Nov 1, 2026
67371cb
docs(launch): Phase 4D independent production release review and Phas…
Satelink-Protocol Nov 1, 2026
8eafc30
Merge pull request #8 from Jakuraa/fix/preview-recovery-audit
Satelink-Protocol Nov 1, 2026
4e81eb8
docs: add first revenue event runbook for SuperProfile link-out
Satelink-Protocol Nov 1, 2026
4e9ff1e
fix(payments): gate paid checkout redirects on ENABLE_LIVE_PAYMENTS
Satelink-Protocol Nov 1, 2026
0a4340d
docs(launch): Phase 5.1 final production gate verification review
Satelink-Protocol Nov 1, 2026
2ac4a2e
docs(launch): Phase 5.2 PR #18 independent review and release alignme…
Satelink-Protocol Nov 1, 2026
db1f25c
test(e2e): set ENABLE_LIVE_PAYMENTS to true in serverEnv for browser …
Satelink-Protocol Nov 1, 2026
5507b2f
docs(launch): Phase 5.3 PR #18 E2E test environment remediation report
Satelink-Protocol Nov 1, 2026
f6f85c4
Merge PR #18: fix(payments): strictly gate SuperProfile checkout redi…
Satelink-Protocol Nov 1, 2026
2dd5eaa
Merge branch 'fix/preview-recovery-audit' into launch-mvp (include pa…
Satelink-Protocol Nov 1, 2026
75b3e82
feat(brand): customer-facing rebrand from StrangersMeetup to NIGHTLIFEZ
Satelink-Protocol Nov 2, 2026
c8d4d85
fix(brand): remediate residual customer-facing references and dynamic…
Satelink-Protocol Nov 2, 2026
070a7a8
docs(launch): P0 ground truth — refs, PRs, CI, branch table, env gate
Satelink-Protocol Nov 2, 2026
40a6f1e
Merge pull request #20 from Jakuraa/feature/p0-ground-truth
Satelink-Protocol Nov 2, 2026
8a91787
Merge pull request #19 from Jakuraa/feature/nightlifez-rebrand
Satelink-Protocol Nov 2, 2026
7198f53
feat(orgs): identities, organisations, scoped memberships and can() p…
Satelink-Protocol Nov 2, 2026
21f5a5d
Merge pull request #21 from Jakuraa/feature/p2-identity-orgs
Satelink-Protocol Nov 2, 2026
2a0e9ce
test(e2e): poll every wizard tap-target measurement
Satelink-Protocol Nov 2, 2026
9d48147
Merge pull request #22 from Jakuraa/fix/p2-wizard-e2e-flake
Satelink-Protocol Nov 2, 2026
15b923d
feat(location): P3 Location Intelligence V1, official LGD data, geosp…
Satelink-Protocol Nov 2, 2026
e9af6b4
docs(state): M1 repository truth — PROJECT_STATE.md and docs/history …
Satelink-Protocol Nov 2, 2026
cd40fcf
Merge pull request #24 from Jakuraa/feature/m1-project-state
Satelink-Protocol Nov 2, 2026
65705b0
chore(sync): merge origin/launch-mvp (PR #24) into feature/p3-locatio…
Satelink-Protocol Nov 3, 2026
d7836ff
feat(location): M2 location remediation — auto city resolution, rate …
Satelink-Protocol Nov 3, 2026
7c5079e
Merge pull request #23 from Jakuraa/feature/p3-location-intelligence
Satelink-Protocol Nov 3, 2026
7fc3726
feat(ops): implement owner addendum — dynamic prod DB block list, bra…
Satelink-Protocol Nov 3, 2026
83a30a7
Merge pull request #25 from Jakuraa/feature/m2-addendum-ops
Satelink-Protocol Nov 3, 2026
0fafdf8
feat(deploy): M3 Deployment & Database Migration Architecture
Satelink-Protocol Nov 3, 2026
f8398b3
docs(launch): remove prohibited legacy provider names from readiness doc
Satelink-Protocol Nov 3, 2026
46b85c1
Merge pull request #26 from Jakuraa/feature/m3-deployment-migration
Satelink-Protocol Nov 3, 2026
8282dab
feat(payments): M4 payment, booking and revenue readiness audit
Satelink-Protocol Nov 3, 2026
69cafae
Merge pull request #27 from Jakuraa/feature/m4-payment-booking-audit
Satelink-Protocol Nov 3, 2026
d354038
feat(payments): implement M4.1 UPI-first checkout, dynamic QR, and ve…
Satelink-Protocol Nov 3, 2026
133ffa2
fix(docs): replace legacy provider names with allowed aliases in UPI …
Satelink-Protocol Nov 3, 2026
c3b4e83
Merge pull request #28 from Jakuraa/feature/m4-1-upi-checkout
Satelink-Protocol Nov 3, 2026
c0ad01d
docs(project-state): record M4.1 PR #28 merge at c3b4e83 in milestone…
Satelink-Protocol Nov 3, 2026
b9b8199
docs(audit): independent security review and provider readiness asses…
Satelink-Protocol Nov 3, 2026
c71ec8d
Merge pull request #29 from Jakuraa/feature/m4-2-upi-security-audit
Satelink-Protocol Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Dependencies
node_modules/

# Version control and agent configuration
.git/
.github/
.claude/
.agents/
.remember/
.playwright-mcp/
skills-lock.json

# Environment and secrets
.env
.env*
.env.local

# Vercel deployment cache
.vercel/

# Local MCP runtime state, screenshots and audit logs
.mcp/

# Test output and reports
test-results/
playwright-report/
coverage/
*.log

# Operating system and temporary artifacts
.DS_Store
Thumbs.db
*.db
*.sqlite
data/
public/img/review/
research_notes/
reports/
26 changes: 15 additions & 11 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,13 @@ TG_CHAT_ID_TIER_2=
TG_CHAT_ID_TIER_3=
TG_CHAT_ID_EVENTS=

# Payments (tickets)
PAYMENT_PROVIDER=razorpay
RAZORPAY_KEY_ID=
RAZORPAY_KEY_SECRET=
RAZORPAY_WEBHOOK_SECRET=
CASHFREE_APP_ID=
CASHFREE_SECRET_KEY=
# Payments
# Tickets are bought on SuperProfile (no card gateway keys here). ENABLE_LIVE_PAYMENTS only labels
# Telegram Stars membership payments as test/live.
ENABLE_LIVE_PAYMENTS=false
# Organiser ticket tiers: paid checkout stays OFF unless explicitly set to true (and provider keys exist).
# Free tiers work without it. Leave unset until an approved payment provider is configured.
TICKET_CHECKOUT_ENABLED=

# Membership via SuperProfile (Zapier/Pabbly webhook shared secret, 24+ chars)
# SuperProfile notifications (tickets + memberships) via Zapier/Pabbly: shared secret sent as X-Webhook-Secret, 24+ chars
# Endpoint: POST /api/webhooks/superprofile
SUPERPROFILE_WEBHOOK_SECRET=

# Site
Expand All @@ -49,10 +43,20 @@ GRIEVANCE_EMAIL=
# Database operations
# Vercel builds migrate only in Production. Set true on Preview ONLY if Preview has its own database.
MIGRATE_ON_PREVIEW=
# Explicitly proves database isolation in Preview deployments. Required for preview migrations & writes.
ISOLATED_PREVIEW_DB=
# Dedicated Preview database connection URL (Preview scope only; never in Production).
PREVIEW_DATABASE_URL=
# Allow `npm run seed:demo` against a non-local database (a dedicated preview DB only; never production).
SEED_ALLOW_REMOTE=
PG_POOL_MAX=

# Preview isolation and test safeguards (Preview scope only; never in Production)
PREVIEW_TELEGRAM_BOT_TOKEN=
ALLOW_PREVIEW_TELEGRAM=
ALLOW_PREVIEW_PAID_CHECKOUT=
PREVIEW_PUBLIC_SITE_URL=

# Optional
DISABLE_WEB_ANALYTICS=

Expand Down
65 changes: 65 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: CI

# Runs on every PR and on pushes to the long-lived branches. Needs no secrets: tests use a throwaway
# Postgres service container and stubbed external APIs (no Telegram, SuperProfile or Vercel calls).
on:
pull_request:
push:
branches: [main, launch-mvp]

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: lint, unit, e2e
runs-on: ubuntu-latest
timeout-minutes: 25
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: sm_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
CI: 'true'
PGPASSWORD: postgres
TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/sm_test
E2E_DATABASE_URL: postgres://postgres:postgres@localhost:5432/sm_e2e
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- name: Lint
run: npm run lint
- name: Unit and integration tests (real Postgres)
run: npm test
- name: Create the e2e database
run: psql -h localhost -U postgres -c 'CREATE DATABASE sm_e2e'
- name: Install Chromium
run: npx playwright install --with-deps chromium
- name: Browser tests (Playwright + axe)
run: npm run test:e2e
- name: Upload Playwright report and screenshots
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-failure
path: |
playwright-report/
test-results/
retention-days: 7
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ research_notes/
reports/
test-results/
playwright-report/
.mcp/
public/img/review/
.agents/
.claude/
skills-lock.json

26 changes: 26 additions & 0 deletions Dockerfile.mcp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Dockerfile.mcp - Container runtime for StrangersMeetup Control MCP with Playwright Chromium support
# Base image includes all Linux dependencies for headless Chromium, Firefox and WebKit
FROM mcr.microsoft.com/playwright:v1.64.1-noble

WORKDIR /app

ENV NODE_ENV=production \
PORT=3333 \
MCP_PORT=3333 \
MCP_HOST=0.0.0.0 \
MCP_LOG_STDOUT=true

# Copy package manifests first for efficient layer caching
COPY package*.json ./

# Install production dependencies
RUN npm ci

# Copy project source files
COPY . .

# Expose MCP HTTP port
EXPOSE 3333

# Start the MCP server
CMD ["node", "mcp/server.js"]
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ Small hosted meetups, dinners, dating mixers and weekend trips for adults 21+ ac
- Zero-build Node 24. One Vercel function (`api/index.js` → `lib/router.js`) renders pages and serves the API; `public/` holds static CSS/JS/images.
- Postgres (`pg`), migrations in `migrations/NNN_*.sql`, tracked in `schema_migrations`.
- Telegram Bot API (webhook), Telegram Login (OIDC) + Mini App `initData`.
- Payments: Razorpay Payment Links for tickets; Telegram Stars subscriptions for membership. See `docs/PAYMENTS_DECISION.md`.
- Payments: SuperProfile hosted checkout for tickets (linked from the site, confirmed by SuperProfile notifications); Telegram Stars subscriptions for membership inside Telegram. See `docs/PAYMENTS_DECISION.md`.

## Layout
```
api/index.js single serverless entry
lib/router.js route table (pages + API)
lib/handlers/* HTTP handlers (pages, auth, bookings, payments, telegram, cron, admin, leads)
lib/services/* domain logic (events, bookings, membership, invites, notifications, refunds, users)
lib/payments/* PaymentProvider adapters (razorpay, cashfree)
lib/payments/* PaymentProvider (superprofile_link) + SuperProfile URL allowlist
lib/telegram/* Bot API client, auth validation, bot command routing
lib/views/* server-rendered HTML (auto-escaping `html` tag)
migrations/ Postgres migrations (legacy SQLite files kept in migrations/legacy-sqlite/)
Expand Down
2 changes: 1 addition & 1 deletion docs/AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Scope: live site `https://strangersmeetup-virid.vercel.app/`, repo `Jakuraa/Stra

### P0 — blocks the money loop
1. No persistent database in production (SQLite in `/tmp`). → Managed Postgres + migration runner.
2. No ticket payment path at all; "booking" is free and unverified. → `PaymentProvider` + Razorpay/Cashfree sandbox + webhook-driven confirmation.
2. No ticket payment path at all; "booking" is free and unverified. → `PaymentProvider` + SuperProfile hosted checkout + notification-driven confirmation.
3. Auth bypass when bot token missing (S1); no sessions. → Strict initData/Login Widget validation, signed httpOnly session.
4. IDOR on entitlements/invite links and cancel (S2, S3). → Session-scoped endpoints only.
5. Webhook processing non-transactional, non-retryable (S8); hardcoded fallback secret (S5).
Expand Down
85 changes: 85 additions & 0 deletions docs/FIRST_EVENT_RUNBOOK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# First Revenue Event Runbook: SuperProfile Link-Out

This runbook guides the platform owner through publishing and running the first revenue-generating event on **StrangersMeetup** using the zero-gateway-liability **SuperProfile link-out** mechanism.

---

## Architecture Summary

* **Payment Processing:** 100% handled externally on **SuperProfile**. StrangersMeetup handles zero card data, stores zero payment credentials, and incurs zero gateway compliance liability.
* **Redirection Gate in Production:**
In `lib/payments/availability.js`, the production redirect is enabled purely by:
`event.checkout_mode = 'superprofile'` and `Boolean(event.superprofile_url)`.
* `ENABLE_LIVE_PAYMENTS` is **NOT** required.
* No secret keys or payment API credentials are required in the app.
* **Venue & Group Delivery:** Handled immediately via SuperProfile's post-purchase confirmation screen and connected Telegram group.
* **Database Tracking (Optional):** When the webhook is active, sales are automatically logged in `orders`. Even without the webhook, Event 1 runs safely because SuperProfile manages ticket stock, attendee payment, and group delivery.

---

## Step-by-Step Owner Instructions

### Step 1: Create the Event Product on SuperProfile
1. Log in to your **SuperProfile** dashboard (https://superprofile.bio).
2. Create a new **Event / Ticket Product**:
- **Title:** Match your event title (e.g., *Friday Night Social Mixer*).
- **Price:** Set your ticket price in INR (e.g., ₹499).
- **Inventory / Capacity:** Set the maximum number of tickets available (e.g., 25).
- **Post-Purchase Delivery:** Connect your private Telegram group or enter the secret venue details to be revealed upon purchase.
3. **Publish** the product on SuperProfile.
4. Copy the public product link (e.g., `https://superprofile.bio/event/friday-night-mixer`).

---

### Step 2: Publish the Event on StrangersMeetup Admin Console
1. Navigate to `https://strangersmeetup-virid.vercel.app/admin` (or your custom domain).
2. Sign in with your bootstrapped `super_admin` Telegram account.
3. Go to **Events** → **New Event** (or edit an existing draft):
- **Title, City, Date & Time:** Enter details.
- **Category:** Choose Nightlife, Dinner, Social Mixer, etc.
- **Venue Privacy:** Set to **Secret Venue** (renders neighborhood teaser publicly; exact address remains hidden).
- **Checkout Mode:** Select **SuperProfile**.
- **SuperProfile Link:** Paste the link copied from Step 1 (`https://superprofile.bio/...`).
- **Status:** Set to **Published**.
4. Save the event.
5. Verify on `https://strangersmeetup-virid.vercel.app/events/<slug>`:
- The event displays the **Book Tickets** button.
- Clicking **Book Tickets** routes through `/checkout/<slug>` and redirects directly to your SuperProfile page with an attached `?ref=...` tracking code.

---

### Step 3: Test Purchase & Refund (Dry-Run)
1. Open the event page in an incognito window or on your mobile device.
2. Click **Book Tickets** and complete a test purchase on SuperProfile using a personal card or UPI.
3. Confirm that:
- SuperProfile displays the purchase confirmation.
- You receive the Telegram group invite / secret venue details.
4. In the SuperProfile dashboard, locate your test order and issue a **Refund**.

---

### Step 4: (Optional) Connect Automated Purchase Webhook
To sync SuperProfile purchases into StrangersMeetup's `/admin` Orders table automatically:
1. In Vercel, set a high-entropy secret:
```bash
vercel env add SUPERPROFILE_WEBHOOK_SECRET production
```
2. In Zapier, Pabbly, or SuperProfile Webhook settings, configure a webhook trigger for new purchases targeting:
```
POST https://strangersmeetup-virid.vercel.app/api/webhooks/superprofile
```
* Header: `X-SuperProfile-Signature: <hex HMAC-SHA256 of payload>`
* Payload format:
```json
{
"event": "payment.success",
"data": {
"order_id": "SP-123456",
"custom_fields": { "ref": "<ref from checkout URL>" },
"amount": 49900,
"currency": "INR",
"buyer_email": "attendee@example.com"
}
}
```
3. *Note:* If running Event 1 without the webhook, your event still runs smoothly: SuperProfile caps capacity and invites guests to the Telegram group, while you can view your guest list directly in the SuperProfile dashboard.
Loading
Loading