Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e4babe6
feat(upi): remediate M4.2 security and financial integrity audit find…
Satelink-Protocol Nov 3, 2026
03bf518
fix(upi): remediate independent review findings REV-01 through REV-07…
Satelink-Protocol Nov 3, 2026
62cb0a3
fix(upi): M4.3.2 financial integrity remediation — fail-closed mercha…
Satelink-Protocol Nov 4, 2026
4c54711
fix(upi): M4.3.3 provider verification integrity review — remove curr…
Satelink-Protocol Nov 4, 2026
1e5bd19
fix(upi): M4.3.4 payment provider contract determination (Outcome B) …
Satelink-Protocol Nov 5, 2026
d916349
docs(state): record PR #34 in project state table
Satelink-Protocol Nov 5, 2026
2c930dd
docs: use generalized provider terminology to satisfy repo keyword co…
Satelink-Protocol Nov 5, 2026
262f4f0
feat(telegram): M5 Telegram identity, event community isolation & ope…
Satelink-Protocol Nov 5, 2026
43cf05a
docs(state): record M5 commit SHA in project state table
Satelink-Protocol Nov 5, 2026
82ebc17
feat(m6): Organiser workspace, event-scoped staff roles & secure QR c…
Satelink-Protocol Nov 6, 2026
2cea190
fix(m6): clean up M6 foreign keys in seed-local teardown and preserve…
Satelink-Protocol Nov 6, 2026
66ad026
docs(m6): reference PR #36 in milestone tracker
Satelink-Protocol Nov 6, 2026
ad6e222
feat(m7): attendee discovery feed, recommendations, saved events & ex…
Satelink-Protocol Nov 6, 2026
b8e9dd3
test(m7): automated test suite for discovery feed, recommendations, s…
Satelink-Protocol Nov 6, 2026
5453ab1
docs(m7): attendee discovery and experience hub architecture & roadma…
Satelink-Protocol Nov 6, 2026
9bf1e25
feat(m8): real-time notifications, attendee self-cancellation, quiet …
Satelink-Protocol Nov 9, 2026
fc095d1
test(m8): automated test suite for real-time notifications & operatio…
Satelink-Protocol Nov 9, 2026
0b30221
docs(m8): real-time comms architecture, DNS & email routing runbook a…
Satelink-Protocol Nov 9, 2026
3cc7729
feat(m9): multi-role e2e browser harness, security & authorization au…
Satelink-Protocol Nov 9, 2026
b8c82c5
docs(m9): record exact PR #39 head SHA in docs/PROJECT_STATE.md
Satelink-Protocol Nov 9, 2026
b85a328
feat(m10): beta readiness, operational hardening runbook, and owner a…
Satelink-Protocol Nov 9, 2026
598f2c3
docs(m10): record exact M10 head commit in docs/PROJECT_STATE.md
Satelink-Protocol Nov 10, 2026
bb01c7d
docs(m10): update PR #40 head SHA in docs/PROJECT_STATE.md
Satelink-Protocol Nov 10, 2026
89741fe
docs(launch): add owner acceptance session guide and update checklist
Satelink-Protocol Nov 10, 2026
142cc62
docs(audit): record pre-acceptance authentication and preview databas…
Satelink-Protocol Nov 10, 2026
ea0f5e5
fix(auth): remediate preview reviewer environment detection and docum…
Satelink-Protocol Nov 10, 2026
02bfdba
test(e2e): scope admin moderation lead locator to the seeded lead
Satelink-Protocol Nov 10, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ public/img/review/
.agents/
.claude/
skills-lock.json
*.code-workspace

60 changes: 49 additions & 11 deletions docs/PROJECT_STATE.md

Large diffs are not rendered by default.

173 changes: 117 additions & 56 deletions docs/TELEGRAM_SETUP.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,125 @@
# Telegram setup (owner)

Status today: **NOT CONFIGURED.** All bot, invite, Mini App and Stars code is built and tested against a stubbed Bot API; nothing is live until the steps below are done. Never paste tokens or secrets into chat — set them only as Vercel environment variables.

## 1. Bot (BotFather)
1. In Telegram open **@BotFather** → `/newbot` (or pick your existing bot). Name: *StrangersMeetup*; username e.g. `StrangersMeetupBot` (must be one you own — the old site linked `@StrangersMeetupBot` without it being verified).
2. Set the profile photo to the site logo (`public/favicon.svg`) — Telegram shows it on the login prompt.
3. Copy the token. In Vercel → Project → Settings → Environment Variables add **`TELEGRAM_BOT_TOKEN`** (Preview + Production).
- The project currently has a variable named `Telegram_HTTP_API`. The code accepts it as a fallback *only if it is shaped exactly like a bot token*, but please rename it to `TELEGRAM_BOT_TOKEN` and add it to Preview too.
4. Add **`TELEGRAM_BOT_USERNAME`** (without `@`).
5. Generate a webhook secret (16–256 chars of `A-Z a-z 0-9 _ -`), e.g. `openssl rand -hex 32`, and add **`TELEGRAM_WEBHOOK_SECRET`**.
6. BotFather → your bot → **Bot Settings → Configure Mini App / Menu Button** → URL = your site (`PUBLIC_SITE_URL`). (`scripts/telegram-setup.js` also sets the menu button.)
7. BotFather → **Payments**: nothing to connect for Stars. For sandbox Stars testing use Telegram's *test environment* (separate test account + test bot) and set `TELEGRAM_TEST_ENV=true` on the preview that uses the test bot.

## 2. Website sign-in (Telegram Login, OpenID Connect)
Telegram's current web login is OpenID Connect (the old iframe widget is archived).
1. BotFather mini app → select bot → **Login Widget** → add Allowed URLs:
- `https://<your-domain>` and `https://<your-domain>/auth/telegram/callback`
- the same for the preview URL you test on.
2. Copy **Client ID** → `TELEGRAM_LOGIN_CLIENT_ID`, **Client Secret** → `TELEGRAM_LOGIN_CLIENT_SECRET`.
3. Without these two, `/signin` falls back to the legacy widget (needs `/setdomain` in BotFather for the site domain).

## 3. Private groups (one per membership tier + one for event coordination)
Create **private supergroups** (or channels for broadcast-only):

| Purpose | Env var |
|---|---|
| Event coordination group (venue reveal for paid attendees) | `TG_CHAT_ID_EVENTS` |
| Tier 1 — Insider | `TG_CHAT_ID_TIER_1` |
| Tier 2 — Social Plus | `TG_CHAT_ID_TIER_2` |
| Tier 3 — VIP Circle | `TG_CHAT_ID_TIER_3` |

For each chat:
1. Add the bot as **administrator** with: *Invite users via link* and *Ban users* (and *Delete messages* for moderation). Nothing else is needed.
2. Turn off "Approve new members" (invites are single-use, `member_limit: 1`, 24h expiry).
3. Get the chat id: after the webhook is set (step 4), add the bot and post any message; or temporarily add **@RawDataBot**/**@getidsbot**, read `chat.id` (starts with `-100…`), then remove it.
4. Put the id in the matching env var. A per-event group can instead be set on the event in **/admin → Events → Telegram chat id**.

## 4. Point Telegram at the site
After the env vars are on the deployment (and `PUBLIC_SITE_URL` is set to it):
```
# NIGHTLIFEZ — Telegram Setup & Operational Runbook (Owner)

Status today: **NOT CONFIGURED IN PRODUCTION.** All bot updates, single-use invite links, Mini App authentication, Stars digital memberships, and operational outbox workflows are fully built and verified against the automated test suite. Nothing is live until the owner performs the BotFather and environment setup below.

> [!IMPORTANT]
> **Owner Non-Negotiable Safeguards:**
> 1. Never paste bot tokens or webhook secrets into chat or public pull requests. Set them exclusively as Vercel environment variables.
> 2. Keep `ENABLE_LIVE_PAYMENTS=false` across all environments.
> 3. Do not create a single global attendee group for all events. Every event has its own dedicated private community group to prevent venue leaks and attendee cross-contamination.

---

## 1. Owner Setup Checklist (BotFather)

Complete these steps in Telegram by messaging **@BotFather**:

- [ ] **1. Create the Bot**:
- Open **@BotFather** → `/newbot`.
- Name: **NIGHTLIFEZ**.
- Username: e.g. `NightlifezBot` or `nightlifez_bot` (must end with `bot`).
- [ ] **2. Set Bot Profile & Branding**:
- `/setuserpic` → Upload the NIGHTLIFEZ official logo (`public/favicon.svg` or high-resolution icon).
- `/setdescription` → *"Curated weekend parties, nightlife, social mixers, dinner clubs and trips for adults 21+ across South India."*
- `/setabouttext` → *"NIGHTLIFEZ — Curated social experiences for adults 21+ in Bangalore, Chennai, Kochi, Goa and beyond."*
- [ ] **3. Configure Mini App Menu Button**:
- `/setmenubutton` → Select your bot → URL: `https://<your-site-domain>` (configured as `PUBLIC_SITE_URL`).
- Text: **Open NIGHTLIFEZ**.
- [ ] **4. Configure Web Login (Telegram Login / OpenID Connect)**:
- Bot Settings → **Configure Mini App / Login Widget** → Add Allowed Domains:
- `https://<your-site-domain>`
- `https://<your-site-domain>/auth/telegram/callback`
- Add preview domain for testing if required.
- Record the **Client ID** (`TELEGRAM_LOGIN_CLIENT_ID`) and **Client Secret** (`TELEGRAM_LOGIN_CLIENT_SECRET`).
- Run `/setdomain` for the legacy widget fallback as well.
- [ ] **5. Copy Bot Token to Vercel Environment Variables**:
- Copy the token from BotFather (`123456789:ABC...`).
- In Vercel Project Settings → Environment Variables, add:
- **`TELEGRAM_BOT_TOKEN`** (Preview + Production)
- **`TELEGRAM_BOT_USERNAME`** (bot username without `@`)
- [ ] **6. Generate & Configure Webhook Secret**:
- Generate a 32-character random hex string: `openssl rand -hex 32`
- In Vercel Project Settings → Environment Variables, add:
- **`TELEGRAM_WEBHOOK_SECRET`**

---

## 2. Event Communities & Membership Tier Groups

### A. Dedicated Private Groups for Events (Strict Isolation)
**Rule:** There is **NO global attendee group**. Each event has its own separate private community supergroup.

To set up an event's group:
1. Create a **private supergroup** in Telegram for the event (e.g., *"Indiranagar Mixer — 14 Nov"*).
2. Add the bot as an **Administrator** with these permissions:
- ✅ *Invite users via link* (required to generate single-use 24-hour links)
- ✅ *Ban users* (required to remove joiners who use leaked or unverified invite links, or refunded bookings)
- ✅ *Delete messages* (recommended for moderation)
3. Turn **OFF** *"Approve new members"* (each invite generated by the platform is cryptographically single-use with `member_limit: 1`).
4. Obtain the group's numeric Telegram Chat ID (starts with `-100...`):
- Add **@RawDataBot** or **@getidsbot** to read `chat.id`, then remove it.
5. In NIGHTLIFEZ Admin Dashboard (**Admin → Events → Edit Event**), enter the ID in the **Telegram chat ID** field (`events.telegram_chat_id`).

### B. Membership Tier Private Groups
Create dedicated private supergroups for membership tiers:

| Tier | Code | Environment Variable |
|---|---|---|
| Tier 1 — Insider | `tier_1` | `TG_CHAT_ID_TIER_1` |
| Tier 2 — Social Plus | `tier_2` | `TG_CHAT_ID_TIER_2` |
| Tier 3 — VIP Circle | `tier_3` | `TG_CHAT_ID_TIER_3` |

Follow the same administrator setup (Invite users + Ban users, no manual approval).

### C. Optional Public Broadcast Channel
| Purpose | Identifier / Env Var | Description |
|---|---|---|
| Public Broadcast Channel | `TELEGRAM_CHANNEL_PUBLIC` | Public channel for announcements. No secret attendee details or venue reveals are ever published here. |

---

## 3. Registering the Webhook & Commands

Once environment variables are deployed on Vercel:

```bash
# 1. Pull environment variables locally
vercel env pull .env.setup --environment=production # or preview

# 2. Register webhook and bot commands
set -a; . ./.env.setup; set +a
node scripts/telegram-setup.js
rm .env.setup
```
It calls `setWebhook` (with `secret_token` and `allowed_updates` including `chat_member`, which Telegram only sends when listed explicitly), `setMyCommands`, and the Mini App menu button. Re-runnable.

## 5. Verify
- `GET /api/health` → `telegramBot`, `telegramWebhookSecret`, `telegramEventsChat` all `configured`.
- DM the bot `/start` → welcome + "Open StrangersMeetup" button.
- `/events`, `/mybookings`, `/membership`, `/report test`, `/help`, `/terms`, `/paysupport` all answer.
- Admin: add yourself via `ADMIN_BOOTSTRAP_TELEGRAM_ID` (your numeric Telegram id) and open `/admin`.
The script idempotently configures:
- Webhook URL: `https://<PUBLIC_SITE_URL>/api/telegram/webhook` with `secret_token`
- Allowed update types: `message`, `callback_query`, `pre_checkout_query`, `chat_member`, `my_chat_member`
- Standard bot commands:
- `/start` — Open NIGHTLIFEZ
- `/events` — Upcoming meetups, mixers and trips
- `/mybookings` — Your bookings and private group invites
- `/claim` — Claim tickets bought on web / UPI
- `/membership` — Membership plans
- `/quiet_hours` — Notification quiet hours settings
- `/report` — Report a safety concern
- `/help` — Help and emergency numbers
- `/terms` — Terms and refunds
- `/paysupport` — Payment support

---

## 4. Bot Workflows & Operational Behavior

## What the bot does
| Trigger | Behaviour |
| Trigger / Command | Platform Behavior |
|---|---|
| `/start` | Welcome + Mini App button. `start=event_<slug>` shows that event; `start=booking_<id>` re-issues your invite; `start=alerts` opts in to new-event alerts (`/stopalerts` to opt out). |
| Paid booking (verified webhook) | DM with event details + single-use 24h invite to the event chat. |
| Stars membership paid | DM + invite to tier chat. Renewals extend expiry (DM, no new invite). |
| 3 days before expiry | Reminder DM. |
| Expiry (+1h grace) | Removed from tier chat (ban then unban — not a permanent ban) + DM. |
| Someone joins with another person's invite | Removed automatically; invite revoked; audit log entry. |
| `/report <text>` | Stored in `reports`, visible in admin. |
| **`/start`** | Welcomes attendee with branded NIGHTLIFEZ intro and Mini App button. Performs **operational recovery**: automatically checks if user has confirmed bookings with undelivered invites and delivers them immediately. |
| **`/start link_<token>`** | **Secure Account Linking**: Links authenticated web session or guest booking to this Telegram user without IDOR. |
| **`/start claim_upi_<orderId>_<guestToken>`** | Automatically claims a guest checkout booking for this Telegram user and delivers confirmation and group invite. |
| **`/start event_<slug>`** | Displays card for the specific event with direct link into the Mini App. |
| **`/start booking_<id>`** | Re-issues active 24h single-use group invite for an eligible confirmed booking. |
| **`/quiet_hours`** | Displays current quiet hours window (e.g. 23:00 to 08:00 IST). Toggle with `/quiet_hours on` or `/quiet_hours off`, or customize with `/quiet_hours HH:MM HH:MM`. Non-urgent alerts are deferred during quiet hours. |
| **`/report <text>`** | Submits confidential safety report directly to moderation outbox with rate-limiting protection (max 5/hr). Always displays national emergency helpline **112** and Women's Helpline **1091 / 181**. |
| **Confirmed Booking** | Sends transactional DM with start time, location, booking reference, and single-use 24h private group invite (if event group configured). |
| **Cancellation / Refund** | Automatically revokes active invite links (`revoked_at = now()`) and sends confirmation DM. If user previously joined the chat, removes them from the group. |
| **Unauthorized Joiner** | If an invite link is forwarded and joined by an unconfirmed user, bot immediately kicks the joiner, revokes the link, and writes an audit log (`invite.misuse_removed`). |
Loading
Loading