Khurram Badar / Archive / Papers / Phase 2 — Post-Signing Autonomy Stack

Phase 2 — Post-Signing Autonomy Stack

briefing · 2026-04-22 · 1510 words · Khurram Badar

The goal in one sentence Stack (locked) Supabase schema Cron jobs (Vercel Cron).

ai · technology

Phase 2 — Post-Signing Autonomy Stack

Everything below turns the pitch demo into the living, self-running platform Dr. Rashid will eventually see as "his" practice online. Target: 3–5 build days after signing, no development team, built entirely from Claude Code in the terminal.

The goal in one sentence

**Dr. Rashid opens Zoom once a month. The platform does everything else.**

Every day at 06:00 GST the site generates its own Today's Reflection and Gulf Brief. Every month a new Majlis topic, landing page variant, and promotional email sequence are produced. Every reservation is processed, paid, rostered, and reminded without him touching it. Every Private Council request is triaged to his calendar. He only spends his time on the thing only he can do — being in the room.

Stack (locked)

| Layer | Service | Role |
|---|---|---|
| Hosting | **Vercel** | Static + serverless functions + cron |
| Framework | **Next.js 14 (App Router)** | Migration from static HTML — adds server components, route handlers, and proper form actions |
| Styling | **Tailwind CSS** | Port the current design tokens into a Tailwind config |
| Database | **Supabase** (Postgres + Auth + Storage) | Reservations, subscribers, content archive, user accounts |
| Email | **Resend** | Transactional + The Brief daily send |
| Payments | **Stripe** (cards) + **Tabby** (UAE BNPL) | Majlis $49 + Council $299 |
| AI | **Claude Haiku 4.5** via Anthropic API | Correspondence desk + daily content generation |
| Video | **Zoom API** | Auto-create per-session links and mint attendee joins |

Supabase schema

```sql
-- Users who have interacted with the platform
create table users (
id uuid primary key default gen_random_uuid(),
email text unique not null,
first_name text,
last_name text,
phone text,
company text,
role text,
locale text default 'en', -- 'en' | 'ar'
created_at timestamptz default now()
);

-- The monthly Majlis sessions
create table majlis_sessions (
id uuid primary key default gen_random_uuid(),
session_date timestamptz not null,
topic_title_en text not null,
topic_title_ar text not null,
topic_description_en text,
topic_description_ar text,
seats_cap int default 40,
zoom_url text,
zoom_meeting_id text,
status text default 'upcoming', -- upcoming | live | past | cancelled
created_at timestamptz default now()
);

-- Who reserved which seat
create table majlis_reservations (
id uuid primary key default gen_random_uuid(),
user_id uuid references users(id),
session_id uuid references majlis_sessions(id),
question text,
payment_method text, -- tabby | stripe | invoice
payment_intent_id text,
payment_status text default 'pending',
paid_at timestamptz,
attended boolean default false,
created_at timestamptz default now()
);

-- Private Council requests
create table council_requests (
id uuid primary key default gen_random_uuid(),
user_id uuid references users(id),
question text not null,
preferred_window text,
scheduled_at timestamptz,
zoom_url text,
payment_status text default 'pending',
summary_sent_at timestamptz,
status text default 'requested', -- requested | confirmed | completed | cancelled
created_at timestamptz default now()
);

-- Subscribers to The Brief
create table subscribers (
id uuid primary key default gen_random_uuid(),
user_id uuid references users(id),
email text not null,
locale text default 'en',
source text, -- brief | book | majlis_reminder
active boolean default true,
unsubscribe_token text unique,
created_at timestamptz default now()
);

-- Daily Brief archive — generated each morning
create table daily_briefs (
id uuid primary key default gen_random_uuid(),
publish_date date unique not null,
reflection_en text not null,
reflection_ar text not null,
item_1_tag text, item_1_title_en text, item_1_title_ar text,
item_1_body_en text, item_1_body_ar text,
item_1_take_en text, item_1_take_ar text,
item_2_tag text, item_2_title_en text, item_2_title_ar text,
item_2_body_en text, item_2_body_ar text,
item_2_take_en text, item_2_take_ar text,
item_3_tag text, item_3_title_en text, item_3_title_ar text,
item_3_body_en text, item_3_body_ar text,
item_3_take_en text, item_3_take_ar text,
sent_at timestamptz,
created_at timestamptz default now()
);

-- Correspondence log (transcript of Ask Dr. Rashid sessions)
create table correspondence (
id uuid primary key default gen_random_uuid(),
user_id uuid references users(id),
session_token text,
messages jsonb not null,
locale text default 'en',
created_at timestamptz default now()
);
```

Apply Row Level Security so only the service role (server functions) can write. Public-read is off. Everything goes through the serverless layer.

Cron jobs (Vercel Cron)

Add to `vercel.json`:

```json
{
"crons": [
{ "path": "/api/cron/daily-brief", "schedule": "0 2 * * *" },
{ "path": "/api/cron/majlis-reminders", "schedule": "0 */2 * * *" },
{ "path": "/api/cron/monthly-majlis-generate", "schedule": "0 6 1 * *" }
]
}
```

All times UTC; 02:00 UTC = 06:00 GST.

`/api/cron/daily-brief`

1. Call Claude Haiku with a prompt that takes yesterday's news (via web search), extracts 3 UAE/GCC business items relevant to Dr. Rashid's audience, generates a Mentor's Take for each, and writes Today's Reflection.
2. Write to `daily_briefs` table.
3. Render the email via Resend (React Email template) in both EN and AR.
4. Send to all active subscribers in batches of 100.
5. Update the homepage via on-demand revalidation so the site shows today's Brief.

`/api/cron/majlis-reminders`

Runs every 2 hours. For each upcoming session, send:
- T-7 days: "One week until The Majlis" with session prep
- T-3 days: "Your preparation note" with curated pre-read
- T-1 day: "Tomorrow at 19:00 GST" with Zoom link
- T-1 hour: "Starting soon" with Zoom link + test link
- T+24 hours: "Your Majlis notes" with private notes + recording link (expires T+7)

All bilingual based on `users.locale`.

`/api/cron/monthly-majlis-generate`

First of each month. Claude Haiku generates:
1. Next month's Majlis topic (from a rotation framework: starting/scaling, succession, capital, talent, GCC expansion, governance, resilience).
2. 90-minute session outline (private — for Dr. Rashid's reference only).
3. Three promotional variants for the landing page topic description.
4. Four-email promotional sequence to subscribers not yet reserved.

Inserts into `majlis_sessions`. Dr. Rashid receives a single email: "May's Majlis topic is ready for your approval. Reply YES to publish, or send edits."

Stripe + Tabby payment flow

Majlis reservation (`$49`)

1. User submits reservation form → `/api/reserve-majlis` creates a pending `majlis_reservations` row.
2. User chose:
- **Tabby**: server creates a Tabby checkout session, redirects user.
- **Stripe**: server creates a Stripe Checkout session, redirects user.
- **Invoice**: mark `pending_invoice`, email team and user; manual process.
3. Webhook (`/api/webhooks/stripe`, `/api/webhooks/tabby`) flips `payment_status = 'paid'`, triggers confirmation email with Zoom link.

Private Council ($299)

Same flow. After payment, a Zoom meeting is created via the Zoom API for the proposed date, and the user receives: (a) confirmation, (b) the brief template to complete, (c) a calendar invite.

Zoom API integration

Use OAuth Server-to-Server app in Zoom Marketplace registered under Dr. Rashid's account.

Resend email engine

Templates (in `/emails/` using React Email):

Each template has `<LocaleSwitch locale="ar">` and auto-renders the RTL Arabic version.

The correspondence desk upgraded

The `/api/ask` function already works. Phase 2:

1. Log every exchange to `correspondence` table.
2. Weekly digest to Dr. Rashid: "This week, 47 people wrote to your desk. Here are the 3 questions most worth your personal reply." Generated by Claude Haiku from the week's transcripts.
3. When a visitor's question repeatedly surfaces a topic Dr. Rashid has written about privately, the desk can reference his own prior notes (stored in a Supabase vector table for retrieval). Not word-for-word — voice-matched.

PWA layer (install as app)

Add `manifest.webmanifest`, service worker, and iOS splash assets. Target: visitor can "Add to Home Screen" on iPhone and launch the site as an app with the emerald splash. Good for Dr. Rashid's own daily use to check The Brief.

SEO / discoverability

Build sequence (post-signing)

**Day 1** — Migrate to Next.js; port styles to Tailwind; Supabase project + schema; auth flow if needed.

**Day 2** — Stripe + Tabby integration end-to-end; both reservation flows wired; Zoom meeting creation.

**Day 3** — Resend templates; confirmation + reminder sequences; welcome drip for Brief subscribers.

**Day 4** — Daily Brief cron + generation prompts tuned with Dr. Rashid over 2–3 iterations until he signs off on tone. Set up monthly Majlis topic cron.

**Day 5** — PWA layer, SEO, OG images, final QA on real devices. Domain cutover if not already done. Go live.

**Ongoing** — weekly check-in with Dr. Rashid: review that week's correspondence digest, approve next month's Majlis topic, adjust the Brief tone as needed.

The quiet promise behind all of this

Dr. Rashid has built twelve companies. He does not need another business to run. What he needs is a way to open his practice to a generation of Gulf founders without it becoming a second full-time job. The stack above is designed to honour that — a platform that looks like his office and runs like a publication, demanding from him only what only he can give: the ninety minutes, once a month.

← Createagent Runtime — Architecture DocumentMission →
Two years of working thought, indexed.
Ask me to present it in your conference room — WhatsApp +971 55 623 9111
Book Session →