Notes

# Rajat Agarwal, Startup Coach: single-page website

Live: https://rajat-agarwal-startup-coach.pages.dev (free Cloudflare Pages + Pages Functions + one free D1 database for the payment ledger; no paid add-ons).

## How payment works (same route as Corporate Tambola)
1. `POST /api/checkout` (functions/api/checkout.js): validates name, startup, e-mail, mobile, number of startups; the PRICE IS SET HERE (Rs 19,999 per startup, max 5); creates a Razorpay Order on the IT Services by Rajat Agarwal account. The booking is written to this site's own ledger (C) first, with its `txn_id` (`COA-<payment id>`); the same `txn_id` and the buyer's details travel in the Razorpay order notes.
2. The browser opens Razorpay's window inside `https://itservices-rajat-agarwal.pages.dev/payframe/` (the website registered with Razorpay). That page lists this site in `ALLOWED` (payframe/pay.js) and in `frame-ancestors` (_headers); both are generated by `C:\ct\itservices-site\build.py`.
3. `POST /api/verify` (functions/api/verify.js): checks Razorpay's HMAC signature, asks Razorpay for the order and payment, checks amount/status (captures if only authorized), then e-mails the buyer and rajatsiroffice@gmail.com through Resend.

Pages secrets (production): RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET, RAZORPAY_WEBHOOK_SECRET, RESEND_API_KEY, OWNER_EMAIL, ACCESS_SECRET, PAY_SERVICE_KEY, OWNER_LEDGER_KEY (the owner's key for the ledger view; kept only in the git-ignored `config/live-secrets.txt`). D1 binding `DB` = `rajat-startup-coach-ledger`. The Razorpay keys are LIVE keys.

## Payment ledger C (A = Razorpay, B = central ledger of IT Services, C = this site)
Spec: `PAYMENT_LEDGER_ABC_SPEC_2026-10-13.md` in the compliance-tracker repo. Code: `functions/api/_ledgerc.js` (header comment explains ids, zero-duplication rules and how C differs from B); schema: `migrations/0001_ledger_c.sql` (run once on the D1 database; safe to repeat).
- `txn_id` = `COA-` + the site's own payment id, made when the buyer starts paying; in the Razorpay order notes, in C and in B.
- `/api/verify` and `POST /api/webhook` (Razorpay's webhook, signature checked with `RAZORPAY_WEBHOOK_SECRET`, repeated deliveries ignored) keep every attempt (authorized / captured / failed with Razorpay's reason), fee, tax, bank reference and refunds; a status never moves backwards.
- `GET /api/owner/ledger?month=YYYY-MM[&format=csv]` with `Authorization: Bearer <OWNER_LEDGER_KEY>`; anybody else gets 404. No payer name, e-mail or phone in it.
- The month (and the previous one) is sent to the central `POST /api/pay/site-summary` at most every 30 minutes after a payment change.
- A booking is only confirmed to the buyer (e-mails, private link) by `/api/verify`; the webhook records money but sends nothing.

## Build / test / deploy
    set NODE_PATH=C:\ct\ct\node_modules;C:\ct\ppt-work\node_modules   (react, react-dom, react-icons)
    node build.cjs                       # writes dist/ (needs python on the path: it applies the uniform footer, tools/ufooter.py)
    node tools/check-site.mjs dist --its C:\ct\itservices-site\dist   # pages, links, SEO, sitemap, manifest, no very dark colours
    bun test                             # payment, consent and ledger tests; Razorpay, the central service and Resend replaced by a stand-in
    node C:\ct\tools\wrangler3\node_modules\wrangler\bin\wrangler.js pages deploy dist --project-name rajat-agarwal-startup-coach --branch main --commit-dirty=true
(wrangler needs CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN from the user environment.)

## Contact details used
Phone (+91) 96503 97480, e-mail rajatsiroffice@gmail.com (the same as on the IT Services site).

## Look, install and footer (14 Oct 2026)
- Bright palette only (saffron, teal, sky blue, cream); `tools/check-site.mjs` fails the build on a very dark background.
- Installable app: `static/` holds the manifest, icons (192, 512, maskable), `og.png` (1200x630), `sw.js` (offline page + pages already opened) and `pwa.js`; made by `games-ops/sitegfx.py`.
- Every page ends with the same footer block (`tools/ufooter.py COA dist`, run at the end of `build.cjs`); its Pricing link is `/pricing.html` (built from `legal/pricing.frag.html`), its "Test a payment (Rs 1)" button opens the central page with `?from=COA`.