Aurrin Ventures Platform
The refined technical plan for Aurrin’s event and validation platform. Architecture decisions, data model, and phased delivery.
← Read the partnership overviewArchitecture overview
The platform is a full-stack Next.js application continuing Aurrin’s existing framework. The major architectural shift is moving from JSON files to a managed database with proper auth and role-based access.
- Application boundary: Next.js (App Router) for the web tier; business logic lives in domain services, not page components or route handlers.
- Database: PostgreSQL via Supabase for OLTP and source-of-truth transactional data
- Auth: Supabase Auth for identity; database-backed role assignments and RLS for authorization
- Async workflows: Durable job runner for webhooks, notifications, reports, social assets, mentor matching, and exports
- Storage: Object storage for pitch decks, generated PDFs, and social assets with signed URLs
- Payments: Stripe Billing + Checkout backed by a shared commerce model (products, orders, transactions, entitlements)
- Real-time: Supabase Realtime for subscriptions and live UI updates; Postgres remains the system of record
- Hosting: Vercel for the web tier; worker runtime can scale independently from the request/response path
- Email: Resend (replaces SendGrid—simpler, fewer integrations)
- Observability: Structured logs, audit events, metrics, error tracking, and restore-tested backups
- Social assets: Satori /
@vercel/ogfor dynamic image generation
System boundaries
Long-term maintainability depends on not letting Next.js routes become the architecture. The platform should be implemented as bounded contexts with thin web handlers and explicit domain services.
| Domain | Owns |
|---|---|
| Identity & Access | Supabase identity, user profiles, role assignments, permission checks, active session context, admin access changes. |
| Event Operations | Events, status windows, founder/judge assignments, rubric publication, sponsorship placements, live-event controls. |
| Judging & Rubrics | Rubric templates and versions, scoring drafts, scoring locks, judge comments, ranking calculations. |
| Audience Validation | QR entry points, public validation sessions, dedup rules, validation question sets, live aggregates. |
| Founder Outcomes | Founder portal, validation reports, public directory publishing, public profiles, shareable highlights. |
| Commerce & Entitlements | Products, prices, subscriptions, orders, transaction ledger, premium access gating, digital-product fulfillment. |
| Notifications & Media | Email/SMS orchestration, pitch deck uploads, generated PDFs, social cards, file retention, delivery tracking. |
| Ops & Compliance | Audit logs, exports, deletion workflows, metrics, alerts, backups, restore drills, incident visibility. |
Data model
The original brief listed entity names without relationships. The refined model defines source-of-truth records, scoping rules, and operational tables needed for auditable production workflows.
| Entity | Key Relationships |
|---|---|
| Users | External identity from Supabase Auth plus human profile fields. Authentication state lives here; authorization does not. |
| RoleAssignments | User-to-role mapping with optional scope (global, event, founder, subscriber). Source of truth for authorization, RLS, and admin audit history. |
| Events | Status lifecycle: Upcoming → Live → Archived. Owns judge assignments, founder pitches, validation config, sponsorship slots, and scoring/publishing windows. |
| Rubrics | Template plus version tables. Live events reference an immutable rubric_version. JSON is reserved for presentation metadata, not the core scoring model. |
| FounderApplications | Status: Pending → Accepted → Assigned (to event) or Declined. Acceptance creates a Founder account and sends confirmation email. |
| FounderPitches | Join record between Founder and Event. Owns pitch deck version, presentation order, score aggregates, validation summary, public directory highlights, and publish state. |
| JudgeScores | Per-judge, per-founder_pitch, per-rubric_version. Stores normalized question/category responses, calculated totals, draft/submitted state, and revision history for audit. |
| AudienceSessions | Server-issued public participation session with consent, rate-limit, dedup markers, and optional contact fields. |
| AudienceResponses | Per-audience_session, per-founder_pitch, per-question. Unique constraints enforce one submission per founder/question path; aggregate views are derived from these rows. |
| MentorMatches | Random pairing with repeat prevention (no same pair within configurable period). Both parties accept/decline. Intro email on mutual acceptance. |
| DigitalProducts | Admin-managed paid assets (maps, reports, downloads). Linked to Stripe prices, fulfillment files, and purchaser entitlements. |
| Subscriptions | Stripe-managed. Gates premium content. Status synced via webhooks. |
| Transactions | Append-only ledger of Stripe events (checkout, subscription, refund). Links users, subscriptions, and digital products for reconciliation and export. |
| Files | Metadata for pitch decks, generated reports, and social assets. Stores signed-url policy, retention rules, and content ownership. |
| OutboxJobs | Durable async workflow state for notifications, PDFs, social assets, exports, mentor matching, and webhook processing. |
| AuditLogs | Immutable actor/action/effect records for approvals, role changes, score locks, entitlement changes, and exports. |
| Sponsors | Placement per event or site-wide. Admin-managed. No self-serve. |
Role access matrix
The original brief mentioned role-based access everywhere but never defined who can see what. These are product decisions, not implementation details, and they need to be specified upfront.
| Data | Who Can See It |
|---|---|
| Individual judge scores | The judge who submitted them + Admin. Not other judges. Founders see them only after scoring is locked and results are published. |
| Aggregated judge scores | Founders see their own aggregate + breakdown after scoring is locked and published. Admin sees all. |
| Audience validation data | Founders see their own results after admin publish or automatic post-event release. Admin sees all. Public directory shows curated highlights only. |
| Founder applications | Admin only. Founders see their own application status. |
| Role assignments and access policies | Admin only. Every change is audited. Users never edit their own effective permissions directly. |
| Other founders’ profiles | Public directory shows approved public data. Founders cannot see each other’s scores or validation. |
| Mentor matching data | Admin sees all matches. Mentors see only their own pending or accepted matches. Founders see only their own mentor assignments and contact details after mutual acceptance. |
| Premium content and digital products | Subscribers see the premium content, downloads, and purchase history they are entitled to. Admin sees all orders and entitlements. Non-subscribers see previews only. |
| Event management | Admin only. Judges see their assigned events. Founders see events they are assigned to. |
| Revenue / transactions / entitlements | Admin only for full financial records. Subscribers see only their own subscriptions, orders, and entitlements. |
Architecture decision records
Context: The brief says “managed database such as PostgreSQL via Supabase or similar.”
Decision: Supabase.
Rationale: Includes auth, realtime, storage, and row-level security out of the box. Reduces the number of services to integrate. Aurrin’s team (non-technical operators) benefits from the Supabase dashboard for direct data inspection when needed.
Trade-offs: Vendor coupling to Supabase. Auth and realtime are good but not infinitely flexible. Acceptable for this scale.
Context: Six user roles with route-level and data-level access control, and some people may wear more than one hat at the same time.
Decision: Use Supabase Auth for authentication, but store role assignments and scopes in relational tables. JWT claims identify the user and can cache coarse context; RLS resolves effective permissions from the database.
Rationale: This supports concurrent roles, event-scoped permissions, auditable admin reassignment, and safer long-term evolution than treating auth metadata as the source of truth.
Trade-offs: More schema and policy complexity up front. Permission changes need careful cache invalidation / token refresh handling.
Context: The brief lists five revenue models: premium subscriptions, digital map purchases, sponsored placements, job board listings, and paid founder upgrades. Each needs its own Stripe logic, admin UI, and access control.
Decision: Build a shared commerce foundation (products, prices, orders, transactions, entitlements) from day one, but activate premium subscriptions first. Additional revenue models reuse the same ledger and entitlement model.
Rationale: This avoids rebuilding access control, reconciliation, exports, and admin tooling every time a new monetization path ships.
Trade-offs: More upfront schema than a subscription-only MVP. Worth it to avoid payment-model rework later.
Context: Admin needs to define scoring categories, weights, scales, and custom questions—cloneable across events. The system also needs analytics, exports, and auditability when rubrics change.
Decision: Store rubric definitions in versioned relational tables. Use JSON only for flexible presentation metadata. When an event goes Live, it binds to an immutable rubric_version. Scores are recorded as normalized responses with calculated aggregate snapshots.
Rationale: This is more analytics-friendly, migration-safe, and auditable than an opaque JSONB-only schema while still supporting dynamic rendering in the scoring UI.
Trade-offs: More tables and joins than a single schema column. Worth it for long-term reporting and change control.
Context: The brief mentions WebSockets for real-time scoring and audience validation. Live UX matters, but correctness cannot depend on a socket staying open.
Decision: All writes go through transactional database endpoints with optimistic concurrency and idempotency keys. Supabase Realtime broadcasts committed changes to subscribed clients. Polling is a fallback display strategy, not the correctness model.
Rationale: This gives the UI a real-time feel without making delivery dependent on ephemeral connection state. Correctness stays in Postgres.
Trade-offs: Slightly more plumbing than naive socket-first updates. Worth it because data integrity survives reconnects and transient outages.
Context: Audience members scan a QR code and submit validation feedback. The brief requires optional anonymous submissions and duplicate prevention.
Decision: Public /validate/[eventId] route. The server issues an audience_session and signed cookie/token on entry. Dedup is enforced with unique constraints plus optional email matching and rate limits. Fingerprinting, if used at all, is only secondary abuse detection.
Rationale: Server-controlled session identity is more reliable, more privacy-conscious, and easier to reason about under GDPR than browser fingerprinting as a primary control.
Trade-offs: Slightly more bootstrap complexity and device-cookie handling. Still the right trade-off for trustworthy validation data.
Context: Emails, PDFs, social assets, mentor matching, Stripe webhooks, and exports should not rely on the request/response lifecycle, especially on Vercel.
Decision: Persist domain events to an outbox table and process them with a dedicated worker/queue. All jobs are idempotent, retryable, and dead-lettered for operator intervention when necessary.
Rationale: Durable jobs survive retries, deploys, and live-event traffic spikes. They also give operators a single place to inspect side-effect failures.
Trade-offs: Introduces worker infrastructure and more operational surface area. Necessary for production-grade reliability.
Context: The brief lists both SendGrid for email and Twilio for SMS as required integrations.
Decision: Use Resend for email (simpler API, fewer integrations to manage). Defer SMS (Twilio) to post-Phase 1. Email covers all critical notifications.
Rationale: SMS adds cost per message and a separate integration to maintain. Every notification in the brief can be delivered via email. SMS can be layered in later for time-sensitive alerts (live event start) once the core platform is stable.
Trade-offs: No SMS for launch. Email delivery is subject to spam filters. Acceptable trade-off—reduces integration surface area for the initial build.
Context: Live events, approvals, score changes, and billing entitlements are the highest-risk moments. They need explicit resilience and audit rules.
Decision: Use optimistic local scoring drafts, idempotent submission APIs, explicit scoring lock/publish states, immutable audit logs for approvals and entitlement changes, and operator-visible failure states for jobs and integrations.
Rationale: A network blip should not lose scores, and a human operator should always be able to explain who changed what and when.
Trade-offs: More state machines, retry logic, and audit volume. Worth it for correctness under pressure.
Context: Founders need downloadable validation reports, and the platform also needs generated social assets and reusable exports.
Decision: Use @react-pdf/renderer and @vercel/og, but generate artifacts asynchronously in the worker tier, store them in object storage, and serve them via signed URLs. API routes request generation or fetch existing artifacts; they do not render heavy outputs inline.
Rationale: This avoids request timeouts and makes artifacts cacheable, retryable, and auditable.
Trade-offs: Eventual consistency: newly requested artifacts may take seconds to appear. Acceptable for reports and share assets.
Operational foundation
If this is the base of a skyscraper, these practices are not optional extras. They are part of the architecture.
- All schema changes ship through reviewed migrations. No production-only dashboard edits.
- Dev, staging, and prod stay isolated, with seeded fixtures for realistic test runs.
- Point-in-time recovery is enabled and restore drills are practiced on a schedule.
- Request IDs and job IDs flow through logs, metrics, and error tracking for traceability.
- Admin decisions, scoring locks, entitlement changes, and exports write immutable audit events.
- Stripe webhooks, validation responses, and scoring submissions use idempotency keys and replay-safe handlers.
- Uploads use signed URLs, file type/size limits, malware scanning, and retention rules.
- Risky features such as payments, live scoring, and directory publishing are rollout-controlled with feature flags.
Phased delivery
Each phase is delivered as a set of GitHub issues. The pipeline decomposes, implements, reviews, merges, and deploys each module independently.
- Database setup (Supabase, schema, RLS policies, migration pipeline)
- Authentication + authorization (Supabase Auth + scoped role assignments)
- Background job infrastructure (outbox + worker)
- Object storage and upload pipeline (decks, generated artifacts)
- Observability + audit logging
- Admin dashboard (event CRUD, rubric builder, founder management)
- Founder application intake (public form, approval workflow, auto-account creation)
- Judge scoring (dynamic rubric rendering, weighted totals, comments)
- Event management (status lifecycle, judge/founder assignment)
- Audience validation (public routes, QR codes, configurable questions, dedup)
- Founder portal (score breakdown, validation results, downloadable PDF/CSV)
- Public founder directory (search, filter, shareable profiles)
- Social asset generation (Satori for milestone images)
- Stripe integration (premium subscriptions first, with the commerce data model ready for digital products)
- Mentor matching engine (random pairing, repeat prevention, acceptance flow)
- Additional revenue models (digital products, sponsored placements, job board, paid founder upgrades)
- Advanced analytics (cross-event trends, cohort analysis)
- Ecosystem intelligence exports
What changed from the original brief
The brief was strong on vision and user experience. These refinements are about making it buildable and resilient:
- Data relationships defined—the brief listed entity names. This architecture defines the actual relationships: founders can pitch multiple events, rubrics freeze on go-live, scores reference frozen rubrics.
- Role access spelled out—who sees what is now a defined matrix, not an implicit assumption. Judges cannot see each other’s scores. Founders see aggregates only after the publish state allows it. Mentor and subscriber access is defined explicitly instead of being implied.
- Claims-only RBAC replaced with database-backed authorization—identity comes from Supabase Auth, but permissions live in relational role assignments that can be scoped and audited.
- Rubrics moved from opaque JSON toward a versioned domain model—dynamic rendering still works, but analytics, exports, and score locking now rest on normalized structures.
- Realtime is treated as delivery, not correctness—Supabase Realtime updates the UI, but committed database writes remain the source of truth.
- Audience dedup no longer depends on fingerprinting—public sessions, unique constraints, and rate limits are the primary controls.
- Background jobs are now first-class architecture—notifications, reports, assets, exports, and webhook handling run through durable async workflows instead of request-time side effects.
- Revenue delivery narrowed, not the revenue data model—premium subscriptions ship first, but digital products and transactions stay in the schema from day one to avoid payment-model rework.
- SMS deferred—email handles all notifications. Twilio/SMS is a Phase 3+ addition once the core is stable.
- SendGrid replaced with Resend—simpler API, fewer integrations.
- Public founder directory timing clarified—it ships with founder reporting in Phase 2, because public profiles, validation highlights, and shareable links ride on the same publishing pipeline.
- Failure handling added—the brief assumed 100% uptime. This architecture defines what happens when scoring, payments, uploads, or notification jobs go down.