How gaurangrshah/plura works
1. Overall shape
- This is a Next.js 14 App Router monorepo-style application organized around three user-facing surfaces: a public marketing site, a multi-tenant authenticated dashboard, and public domain-based pages for funnels/content.
- The app is heavily componentized, with most business features implemented in route-local components under app/ and shared UI/forms under components/.
2. Route partitioning is the top-level boundary
- app/site contains the public marketing site.
- app/(main) contains the authenticated product UI.
- app/[domain]/[path] is a runtime-resolved public route for tenant-owned pages, likely used for funnel pages or branded content on custom domains/subdomains.
- This route split is important for architecture diagrams because it separates public web traffic, logged-in dashboard traffic, and tenant-hosted public pages.
3. Multi-tenant domain model
- The dashboard is split into two major tenant scopes:
- app/(main)/agency/[agencyId] for agency-level administration
- app/(main)/subaccount/[subaccountId] for client/sub-account operations
- The agency layer manages higher-order concerns like team, billing, subaccounts, launchpad, and settings.
- The subaccount layer manages operational features like contacts, pipelines, funnels, media, workflows, and settings.
- This is the core business boundary: agency owns and administers multiple subaccounts.
4. Authentication and access control
- The repo uses Clerk for auth, with routes for sign-in/sign-up under app/(main)/agency/(auth).
- middleware.ts indicates request-time protection and route gating, which is a key runtime boundary.
- There is a dedicated unauthorized screen at app/(main)/agency/unauthorized and a shared unauthorized component in components/unauthorized.
- For a diagram, auth should be shown as an edge/request gate in front of protected dashboard routes.
5. Data layer and persistence
- Data access is centered in lib/db.ts, lib/queries.ts, lib/constants.ts, and lib/types.ts.
- Persistence uses Prisma with prisma/schema.prisma, and the README states the backend uses SQLite locally and Turso/libsql in production.
- This means the architecture has a single database boundary serving all core product domains: agencies, subaccounts, funnels, workflows, pipelines, contacts, billing metadata, and media records.
6. Payments and billing subsystem
- Billing is isolated under app/(main)/agency/[agencyId]/billing.
- Stripe integration is split between:
- client/server helpers in lib/stripe/*
- API routes in app/api/stripe/*
- billing UI components such as pricing-card.tsx and subscription-helper.tsx
- Data flow here is: billing UI → Stripe action/API route → Stripe service → webhook → database update.
- This is a distinct external-service boundary and should be shown separately from the main app database flow.
7. File uploads and media subsystem
- UploadThing is exposed through app/api/uploadthing/* and configured in lib/uploadthing.ts.
- The user-facing media area lives at app/(main)/subaccount/[subaccountId]/media, with shared media components in components/media.
- This is another external boundary: dashboard UI → UploadThing API → stored assets → media library UI.
8. Funnel builder is a major product subsystem
- Funnel management lives under app/(main)/subaccount/[subaccountId]/funnels.
- The funnel editor is nested deeply under funnels/[funnelId]/editor/[funnelPageId] and is composed of:
- a central editor canvas
- a sidebar with tabs for components/layers/media/settings
- recursive render components for page elements
- The funnel editor supports element types like container, two-column layout, text, link, video, checkout, and contact form, indicating a block-based page builder.
- This subsystem should be diagrammed as a structured content editor backed by the database.
9. Workflow automation subsystem
- Workflows live under app/(main)/subaccount/[subaccountId]/workflows.
- The editor uses provider-based state and dedicated UI pieces:
- canvas
- sidebar
- toolbar
- node settings
- workflow nodes
- There is a small action layer in workflows/_actions/workflow-actions.ts, suggesting server-side mutations for workflow creation/update.
- This is a separate builder from funnels: funnels are for page composition, workflows are for automation logic.
10. Pipeline / CRM subsystem
- Pipelines are implemented under app/(main)/subaccount/[subaccountId]/pipelines.
- The feature uses lane/ticket/view/settings components, which implies a kanban-style deal or lead pipeline.
- Contacts live separately under contacts, and there are forms for tickets and contacts, so the likely flow is contacts and leads feed pipeline tickets.
- In a diagram, pipelines should be shown as the operational CRM layer connected to subaccount data.
11. Agency administration features
- Agency-level pages cover team, billing, all-subaccounts, launchpad, and settings.
- Shared forms such as invitation, agency details, subaccount details, and subscription forms support these admin flows.
- This layer is where an agency manages tenants, users, and paid plan state rather than end-customer operations.
12. Shared UI and composition model
- components/ui is a large shadcn/ui-style base layer used across the app.
- Feature-specific shared components live in components/forms, components/global, components/sidebar, components/media, and components/site.
- The repo uses reusable provider wrappers in providers/ for theme, modals, workflow editor state, and editor actions.
- This indicates a design where route pages are thin shells and most interactive behavior is delegated to shared component systems.
13. Runtime and deployment concerns
- The app runs on Next.js/Vercel, with vercel.json controlling the build command and Sentry configs present for client/edge/server error reporting.
- instrumentation.ts suggests app-level runtime instrumentation is enabled.
- Because auth middleware and public-domain routing are part of the request path, edge/runtime behavior matters to the system architecture.
14. What to show in an architecture diagram
- The most important boxes are:
- public site
- auth gate/middleware
- agency dashboard
- subaccount dashboard
- public domain page renderer
- Prisma/Turso database
- Stripe
- UploadThing
- funnel editor
- workflow editor
- pipeline/contacts CRM
- The key arrows are:
- browser/request → middleware → route group
- route group → server components/actions/queries → database
- billing UI → Stripe → webhook → database
- media UI → UploadThing → stored assets
- editors → provider state + database-backed persistence
Main entry points: [subaccountId]/page.tsx Subaccount hub · queries.ts Queries · layout.tsx App shell · [agencyId]/page.tsx Agency hub
Components 21
Public web
Marketing site and tenant-facing public pages
- Marketing site · Public site surface for marketing and acquisition
app/site/page.tsx - Tenant pages · Runtime-resolved public pages by domain and path
app/[domain]/[path]/page.tsx
Authenticated app
Protected agency and subaccount dashboard surfaces
- Sign in · Authentication entry for protected dashboard access
app/(main)/agency/(auth)/sign-in/[[...sign-in]]/page.tsx - Agency hub · Top-level agency administration landing area
app/(main)/agency/[agencyId]/page.tsx - Team · Agency team management and invitations
app/(main)/agency/[agencyId]/team/page.tsx - Billing · Agency subscription and plan management
app/(main)/agency/[agencyId]/billing/page.tsx - Subaccount hub · Primary subaccount workspace landing area
app/(main)/subaccount/[subaccountId]/page.tsx - Contacts · Contact management and lead records
app/(main)/subaccount/[subaccountId]/contacts/page.tsx - Pipelines · Deal and lead pipeline operations
app/(main)/subaccount/[subaccountId]/pipelines/page.tsx - Funnels · Funnel management and page composition entry
app/(main)/subaccount/[subaccountId]/funnels/page.tsx - Funnel editor · Structured funnel page editor and canvas
app/(main)/subaccount/[subaccountId]/funnels/[funnelId]/editor/[funnelPageId]/page.tsx - Workflows · Workflow automation management and editor entry
app/(main)/subaccount/[subaccountId]/workflows/editor/[workflowId]/page.tsx - Media library · Subaccount media browsing and uploads
app/(main)/subaccount/[subaccountId]/media/page.tsx
Platform core
Shared data access, auth gating, and runtime infrastructure
- App shell · Global app layout and shared shell
app/layout.tsx - Auth gate · Request-time protection and route gating
middleware.ts - Queries · Shared server-side query and mutation layer
lib/queries.ts - Database · Primary persistence for agencies, subaccounts, funnels, workflows, CRM, and media metadata
prisma/schema.prisma
External integrations
Payment and media service boundaries
- Stripe · Billing actions and subscription orchestration
lib/stripe/actions.ts - Stripe webhook · Stripe event ingestion and persistence updates
app/api/stripe/webhook/route.ts - UploadThing · Upload configuration and request handling for assets
lib/uploadthing.ts - Upload API · UploadThing API endpoint for media transfers
app/api/uploadthing/route.ts
Connections 33
- App shell → Marketing site: serves · Root shell renders the public marketing surface
- App shell → Sign in: wraps · App shell hosts the sign-in flow
- App shell → Agency hub: wraps · App shell hosts the protected agency dashboard
- App shell → Subaccount hub: wraps · App shell hosts the protected subaccount workspace
- App shell → Tenant pages: serves · App shell also serves runtime-resolved public pages
- Auth gate → Sign in: gates · Middleware protects access to authenticated routes
- Auth gate → Agency hub: gates · Middleware gates agency areas
- Auth gate → Subaccount hub: gates · Middleware gates subaccount areas
- Auth gate → Tenant pages: allows · Public tenant pages are resolved at request time
- Sign in → Agency hub: enters · Successful auth leads into the agency workspace
- Agency hub → Team: navigates · Agency admin surface links to team management
- Agency hub → Billing: navigates · Agency admin surface links to billing
- Billing → Stripe: charges · Billing UI delegates checkout and subscription actions
- Stripe → Stripe webhook: syncs · Stripe events are received through the webhook route
- Stripe webhook → Database: updates · Webhook state is persisted to the database
- Team → Queries: reads/writes · Team admin uses shared server-side data access
- Queries → Database: persists · Queries layer reads and writes the primary database
- Subaccount hub → Contacts: navigates · Subaccount hub links to CRM contacts
- Subaccount hub → Pipelines: navigates · Subaccount hub links to pipelines
- Subaccount hub → Funnels: navigates · Subaccount hub links to funnel management
- Subaccount hub → Workflows: navigates · Subaccount hub links to workflow automation
- Subaccount hub → Media library: navigates · Subaccount hub links to media library
- Contacts → Queries: reads/writes · Contacts are managed through the shared data layer
- Pipelines → Queries: reads/writes · Pipeline lanes and tickets persist through queries
- Funnels → Funnel editor: opens · Funnel management drills into the page editor
- Funnel editor → Queries: reads/writes · Editor state is backed by server persistence
- Funnel editor → Database: saves · Funnel pages and elements are stored in the database
- Workflows → Queries: reads/writes · Workflow builder uses server actions and queries
- Workflows → Database: saves · Workflow definitions persist in the database
- Media library → Upload API: uploads · Media UI sends files through the upload endpoint
- Upload API → UploadThing: uses · API route is configured by UploadThing helpers
- Media library → Database: lists · Media library reads stored asset metadata
- Tenant pages → Queries: renders from · Public tenant pages are assembled from persisted content