Files
worldmonitor/convex/schema.ts
Elie Habib dfc175023a feat(pro): Pro waitlist landing page with referral system (#1140)
* fix(desktop): settings UI redesign, IPC security hardening, release profile

Settings window:
- Add titlebar drag region (macOS traffic light clearance)
- Move Export/Import from Overview to Debug & Logs section
- Category cards grid changed to 3-column layout

Security (IPC trust boundary):
- Add require_trusted_window() to get_desktop_runtime_info, open_url,
  open_live_channels_window_command, open_youtube_login
- Validate base_url in open_live_channels_window_command (localhost-only http)

Performance:
- Add [profile.release] with fat LTO, codegen-units=1, strip, panic=abort
- Reuse reqwest::Client via app state with connection pooling
- Debounce window resize handler (150ms) in EventHandlerManager

* feat(pro): add Pro waitlist landing page with referral system

- React 19 + Vite 6 + Tailwind v4 landing page at /pro
- Cloudflare Turnstile + honeypot bot protection
- Resend transactional confirmation emails with branded template
- Viral referral system: unique codes, position tracking, social share
- Convex schema: referralCode, referredBy, referralCount fields + counters table
- O(1) position counter pattern instead of O(n) collection scan
- SEO: structured data, sitemap, scrolling source marquee
- Vercel routing: /pro rewrite + cache headers + SPA exclusion
- XSS-safe DOM rendering (no innerHTML with user data)
2026-03-06 23:50:24 +04:00

22 lines
661 B
TypeScript

import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
registrations: defineTable({
email: v.string(),
normalizedEmail: v.string(),
registeredAt: v.number(),
source: v.optional(v.string()),
appVersion: v.optional(v.string()),
referralCode: v.optional(v.string()),
referredBy: v.optional(v.string()),
referralCount: v.optional(v.number()),
})
.index("by_normalized_email", ["normalizedEmail"])
.index("by_referral_code", ["referralCode"]),
counters: defineTable({
name: v.string(),
value: v.number(),
}).index("by_name", ["name"]),
});