Skip to main content

System Overview

NearSync is a single-codebase, manifest-driven multi-tenant SaaS platform built on a Turborepo monorepo. Three user-facing applications and a set of shared internal packages share a unified backend powered by Supabase (PostgreSQL, Auth, Storage, Edge Functions, Realtime).

The system supports two operational models:

  • Managed: Clients share a NearSync-hosted Supabase instance, isolated by org_id and row-level security (RLS).
  • BYOK (Bring Your Own Keys): Clients deploy the same application code against their own Supabase project.

Zero code forks. Customization is entirely runtime-driven via the SystemManifest -- a JSON document stored in the database that controls module availability, feature flags, branding, security policies, and operational limits.


High-Level Topology

+-------------------------------------------------------------------+
| Internet |
+-------------------------------+-----------------------------------+
|
+--------------------+--------------------+
| | |
v v v
admin.nearsync.tech portal.nearsync.tech nearsync.tech
| | |
v v v
+-------------------------------------------------------------------+
| Vercel Deployment (Git-driven, no GitHub Actions) |
+-------------------------------------------------------------------+
| admin-dashboard client-portal marketing-website |
| (React + Vite) (React + Vite) (React + Vite) |
+-------------------------------+-----------------------------------+
| All share
| shared packages
v
+-------------------------------------------------------------------+
| Turborepo Workspace |
+-------------------------------------------------------------------+
| @nearsync/types |
| @nearsync/supabase-client @nearsync/ai-service |
| @nearsync/theme-engine @nearsync/state-store |
| @nearsync/shared-logic @nearsync/ui-system |
| @nearsync/comms-service @nearsync/import-engine |
| @nearsync/eslint-config @nearsync/tsconfig |
+-------------------------------+-----------------------------------+
|
v
+-------------------------------------------------------------------+
| Supabase (Auth, DB, Storage, Realtime) |
+-------------------------------------------------------------------+
| PostgreSQL Auth Storage Edge Functions Realtime Channels |
| org_id multi-tenancy (Managed) |
| RLS on tenant-scoped tables |
+-------------------------------------------------------------------+
| | |
v v v
hyper-worker standalone External APIs
(services) edge functions (Google, Stripe, Twilio,
Gemini, Canva, HubSpot...)

Beyond the three Vercel-hosted SPAs, the backend runs on Supabase edge functions (the hyper-worker gateway plus standalone OAuth and cron functions). NearSync also exposes a public API and MCP server at api.nearsync.tech -- proxied through a small Vercel edge project -- and developer documentation at docs.nearsync.ai.

Deployment Boundary

All application code (frontend and edge functions) is deployed together from a single Git repository via Vercel Git integration. No GitHub Actions orchestration -- Vercel's CI/CD pipeline handles builds, test execution, and rollouts.

Branch strategy:

  • main -- production
  • stage -- staging preview environment

Intelligent builds: Each Vercel project uses npx turbo-ignore to skip rebuilding unaffected applications when only one package changes.


Application Layer

Three React + Vite single-page applications serve distinct user personas.

1. Admin Dashboard (admin.nearsync.tech)

Purpose: Internal operations platform for NearSync HQ and enterprise admin users.

Package: @nearsync/admin-dashboard Auth requirement: JWT from Supabase; must have admin or operator role.

Lazy-Loaded Modules:

#ModuleDescription
1IntelligenceAnalytics dashboard, system health
2DashboardsCustom dashboard builder (white-label components)
3CommsWhatsApp, Email, Voice (via Twilio)
4SalesCRM, leads, pipeline, forecast
5MarketingCampaign management, email sequences
6WebsiteLanding page builder, SEO, analytics
7ProjectsProject tracking, sprints, backlog
8OperationsResource allocation, capacity planning
9SupportTicketing, knowledge base, customer feedback
10PeopleHRMS, org chart, payroll, attendance
11FinanceInvoicing, expense tracking, payment reconciliation
12SystemUser management, roles, audit logs, Sentinel monitoring
13BookmarksQuick links, saved searches
14User SettingsProfile, preferences, MFA

Each module is code-split and loaded on-demand via React.lazy() + Suspense. Module availability is gated by the ModuleGuard component, which checks the SystemManifest.

2. Client Portal (portal.nearsync.tech)

Purpose: Client-facing self-service platform.

Package: @nearsync/client-portal Auth requirement: JWT from Supabase; must have client role.

Tab Structure:

TabDay-1 AccessGated BehindPurpose
OverviewYes--Dashboard, recent activity, quick stats
Brand KitYes--Logo, colors, fonts, guidelines
Design StudioYes--Website builder, visual identity setup
DiscussYes--Chat with NearSync team
HelpYes--FAQ, documentation, ticket creation
Financialsportal_onboardedInvoices, payments, billing history
Docsportal_onboardedDocument repository, contracts
Techportal_onboardedAPI keys, webhooks, setup guides (BYOK only)

The portal_onboarded flag is set by the NearSync team after the onboarding call.

Design Studio Scope (Launch):

  • Identity tab only: primary color, surface color, text color, logo (light + dark variants), favicon URL, site title
  • Writes to project_brand table
  • Changes synced to the client portal UI in real time via Realtime channels

3. Marketing Website (nearsync.tech)

Purpose: Public landing site, auth gateway, documentation.

Package: @nearsync/marketing-website Auth requirement: Optional (public pages); required for login/signup.

Pages: Pricing, features, use cases, integrations, help and support hub, login/signup gateway, and a solutions grid showcasing the platform's modules.


Package Architecture

Shared internal packages in packages/ provide common functionality across all three applications.

Critical rule: No cross-imports between apps/. All shared code lives in packages.

Dependency Graph

+----------------------+
| @nearsync/types |
| (pure types, 0 deps)|
+----------+-----------+
|
+-------------------------+--------------------+-----------+
| | |
v v v
+----------------------------+ +----------------------+ Others
| @nearsync/ | | Feature packages |
| supabase-client | | (lower coupling) |
| | | |
| - AuthProvider | +-----| - ai-service |
| - useAuth() | | | - theme-engine |
| - DB hooks | | | - state-store |
| - useSystemManifest() | | | - shared-logic |
| - Service layer base | | | - comms-service |
+----------+---------------+ | | - import-engine |
| | +----------------------+
| |
+--------------------+----------------+
| |
v v
+------------------------------+
| @nearsync/ui-system |
| |
| - Shadcn/Radix wrappers |
| - Dashboard widgets |
| - Modals, forms, tables |
| - App-agnostic components |
+----------+-------------------+
|
+--------------------------+------------------------+
| | |
v v v
+------------------+ +------------------+ +--------------------+
| admin-dashboard | | client-portal | | marketing-website |
| | | | | |
| HQ modules | | Portal tabs | | Marketing pages |
| HQ operations | | Branded portal | | Auth gateway |
+------------------+ +------------------+ +--------------------+

Package Inventory

PackageStatusPurpose
@nearsync/typesFunctionalPure TypeScript types; zero runtime dependencies. Includes SystemManifest, FeatureFlags, and auto-generated database types.
@nearsync/supabase-clientFunctionalSupabase client wrapper; AuthProvider context; useAuth hook (session, user, profile, permissions, manifest); database query builders; service layer base class.
@nearsync/ai-serviceFunctionalMulti-provider AI routing (8 providers: Gemini, OpenAI, Anthropic, Grok, Mistral, Groq, DeepSeek, Ollama); config caching for model metadata; client and server-side implementations.
@nearsync/theme-engineFunctionalCSS variable system (--app-surface, --app-background, --app-border, --accent-color); ThemeProvider context; dark mode toggle; brand color injection from SystemManifest.
@nearsync/state-storeFunctionalZustand stores for global state (modals, notifications, UI state); persisted to localStorage where applicable.
@nearsync/shared-logicFunctionalUtility functions, formatters, validators, i18n strings; no UI dependencies.
@nearsync/ui-systemFunctionalShadcn/Radix-based components; dashboard widgets (metric cards, charts); modals, forms, tables; designed for reuse across all three apps.
@nearsync/comms-serviceFunctionalWrapper for Twilio voice, WhatsApp messaging, and email.
@nearsync/import-engineFunctionalCSV/XLSX parsing, AI-powered column mapping, batch import logic, 4-step wizard UI.
@nearsync/eslint-configConfigShared ESLint rules across workspace.
@nearsync/tsconfigConfigShared TypeScript config.

Authentication and Session Management

Authentication Provider: Supabase Auth

All three applications delegate identity to Supabase's auth system, which uses PostgreSQL row-level security (RLS) to enforce multi-tenant isolation.

User --> Login/Signup Form
|
v
Supabase Auth
- Password verification (bcrypt)
- Email verification (OTP)
- OAuth (Google, GitHub, Microsoft, etc.)
|
v
JWT issued (access_token + refresh_token)
- JWT payload contains: user_id, email, custom claims
- TTL: 3600 seconds (refreshed via refresh_token)
|
v
Client stores JWT in cookie (cross-domain) or localStorage
|
v
AuthProvider wraps app tree
- Initializes Supabase client
- Fetches profile from `profiles` table
- Subscribes to `role_permissions` realtime channel
- Loads SystemManifest via useSystemManifest()
|
v
useAuth() hook provides:
{
session, // Supabase session
user, // Supabase user object
profile, // Profile record (org_id, name, avatar...)
manifest, // Full config for this org
permissions, // Role-based permissions (realtime subscribed)
isModuleEnabled(id), // boolean
isFeatureEnabled(flag), // boolean
checkPermission(key), // boolean
mfaEnabled, // TOTP enrollment status
signUp(),
signIn(),
signOut(),
}

Cross-Domain Session Storage

On production domains (admin.nearsync.tech, portal.nearsync.tech, nearsync.tech), the JWT is stored in a chunked cookie with domain=.nearsync.tech. Supabase cookies are split into 3500-byte chunks, so large JWTs span multiple cookies. When a user navigates between subdomains, the browser automatically includes the cookies and the session persists without re-login.

MFA (Multi-Factor Authentication)

TOTP enrollment via Supabase MFA API:

  1. User requests MFA enrollment.
  2. Supabase generates a QR code (TOTP secret).
  3. User scans with an authenticator app.
  4. User enters a 6-digit code.
  5. If valid, MFA is enabled on the profile.
  6. Future logins require TOTP verification.

SystemManifest Pipeline

The SystemManifest is the single source of truth for what each organization can see and do. It is a JSON document stored in the global_settings table and cached in-memory on the client.

Structure

SystemManifest {
instance: {
id: string, // org_id
tier: 'starter' | 'standard' | 'standard_plus' | 'advanced' | 'custom',
deployment: 'managed' | 'byok',
vertical: 'healthcare' | 'retail' | 'professional_services' | 'fintech' | 'custom',
region: 'us-east' | 'eu-west' | 'ap-south',
trial: boolean,
trial_expires_at: ISO8601,
},

modules: {
[moduleId]: {
enabled: boolean,
tier_required: 'starter' | 'standard' | 'standard_plus' | 'advanced',
feature_overrides: string[],
}
// 14 module IDs: intelligence, dashboards, comms, sales, marketing, website,
// projects, operations, support, people, finance, system,
// bookmarks, user_settings
},

features: {
[featureFlagId]: boolean,
// 60+ flags: ai_chat_enabled, sms_campaigns_enabled,
// inventory_sync_enabled, etc.
},

security: {
mfa_required: boolean,
session_timeout_minutes: number,
ip_whitelist: string[], // CIDR blocks
password_policy: {
min_length: number,
require_uppercase: boolean,
require_symbols: boolean,
},
enforce_saml: boolean,
saml_provider_url: string,
},

branding: {
company_name: string,
logo_url: string,
favicon_url: string,
primary_color: hex,
surface_color: hex,
text_color: hex,
support_email: string,
support_phone: string,
},

integrations: {
whatsapp: { enabled: boolean, account_id: string },
twilio: { enabled: boolean, phone_numbers: string[] },
gemini: { enabled: boolean, default_model: string },
openai: { enabled: boolean, default_model: string },
stripe: { enabled: boolean },
razorpay: { enabled: boolean },
// ... additional integrations
},

limits: {
max_users: number,
storage_gb: number,
ai_tokens_per_month: number,
crm_contacts_limit: number | null, // null = unlimited
},

operations: {
timezone: string, // IANA timezone
currency: string, // ISO 4217
date_format: string,
work_days: string[],
work_hours_start: string,
work_hours_end: string,
},
}

Note: API keys are never stored in the manifest. Integration credentials are fetched at runtime from an encrypted table and are never bundled in client code.

Manifest Lifecycle

  1. Load: When the AuthProvider mounts, the useSystemManifest() hook checks localStorage for a cached copy. On cache miss, it fetches from the global_settings table and merges with safe defaults.
  2. Subscribe: The hook subscribes to the global_settings Realtime channel. Any INSERT, UPDATE, or DELETE event triggers a re-fetch plus a localStorage update.
  3. Consume: Components use isModuleEnabled(), isFeatureEnabled(), and checkPermission() to gate UI. Branding values are injected as CSS variables by the ThemeProvider.

Module Gating

<ModuleGuard moduleId="crm">
<SalesHQ />
</ModuleGuard>
  • ModuleGuard calls isModuleEnabled() on the manifest.
  • If false, the guard renders an upsell message instead of the module.
  • If true, the child component renders normally.

Feature Flags

Fine-grained boolean flags in manifest.features control subsystems:

if (manifest.features.ai_chat_enabled) {
return <AIChat />;
}

Feature flags are per-org and can be overridden individually.


Multi-Tenancy Model

Managed (Shared Supabase Instance)

All managed clients share a single Supabase project. Isolation is enforced via the org_id column and row-level security.

Client User Logs In
|
v
Supabase Auth
- User created in auth.users table
- JWT issued with user_id claim
|
v
Profile Lookup (profiles table)
WHERE id = <user_id>
--> Resolves org_id, role, name, avatar
|
v
Every Query Scoped by org_id

RLS Policy (RESTRICTIVE):
CREATE POLICY "tenant_isolation" ON crm_contacts
AS RESTRICTIVE
FOR ALL
USING (
org_id = (
SELECT org_id FROM profiles
WHERE id = auth.uid()
)
);

RLS enforcement: Every tenant table has a RESTRICTIVE policy. Multiple policies are AND'ed together -- even if a permissive policy grants access, the org_id check still applies. This guarantees no data leaks between organizations.

Tables with org_id isolation span these logical domains: Core, CRM, Finance, HRMS, Support, Comms, Projects, Workflows, Bookings, Assets, Knowledge Base, Custom Fields, Marketing, Design and Branding, Integrations, and Admin.

BYOK (Bring Your Own Keys)

BYOK clients deploy the same application code but point to their own Supabase project via environment variables.

Key differences from the managed model:

  • No org_id needed -- single-tenant; the entire database belongs to the client.
  • Schema still deployed -- all tables with all migrations.
  • RLS still active -- enforces role-based access rather than org-based isolation (e.g., user role vs admin role).
  • Data sovereignty -- the client owns the entire database, backups, and encryption keys.
  • Monitoring -- Sentinel (metadata-only) monitors heartbeat and basic stats with no row-level visibility into client data.

Backend Architecture: Supabase + Hyper-Worker

Supabase: PostgreSQL at the Core

  • Database: tenant-scoped tables across its logical domains (CRM, Finance, HRMS, Comms, Projects, Support, Workflows, Bookings, Assets, KB, Integrations, Audit, Custom Fields, Admin).
  • Auto-Generated Types: Full TypeScript types are regenerated from the schema, providing 100% type-safe DB queries via the Supabase JS client.
  • Storage Buckets: Files (contracts, invoices, PDFs, uploaded documents) are accessed via signed URLs.
  • Realtime Channels: Used for manifest changes, RBAC updates, chat delivery, and org-scoped entity updates.

Hyper-Worker Edge Function

A single entry point (POST /functions/v1/hyper-worker) routes all backend business logic requests to appropriate service handlers.

Request flow:

  1. CORS check -- origin-locked to production domains.
  2. Auth middleware -- JWT validation. Public endpoints (webhooks, signup, login) skip auth.
  3. Rate limiter -- per-IP per-endpoint, in-memory. Returns HTTP 429 if exceeded.
  4. Route switch -- body.type dispatches to the correct service method.

15 Service Modules:

#ServiceResponsibility
1AuthServiceSignup, login, invites, welcome email, password reset, MFA enrollment
2AdminServiceAdmin-only actions (session management, system health)
3WhatsAppServiceSend/receive messages, media upload, webhook handling
4TwilioServiceVoice call tokens, call status webhooks, recording retrieval
5GoogleWorkspaceServiceGmail API, Calendar API, Meet join link generation
6GoogleDocsEngineClone template docs, inject data, export to PDF
7BookingServiceAvailability calculation, booking creation, calendar sync, reminders
8FinanceServicePayment processing, webhook handling, reconciliation
9LegalServiceDocument signing, contract templates, signature collection
10ProjectServiceProject creation, AI-powered PRD generation, client import enrichment
11ReviewsServiceGoogle Places API integration, review fetch, sentiment analysis
12WorkflowExecutorServiceVisual workflow engine, node execution, approvals, AI nodes
13AIServiceMulti-provider chat routing, token management, streaming
14CrmSyncServiceHubSpot/Salesforce OAuth, contact/deal sync, field mapping
15IntegrationsService14+ OAuth providers, token refresh, permission checking

Standalone Edge Functions

Six additional edge functions handle async, scheduled, and OAuth tasks:

  1. canva-oauth -- Canva design OAuth callback, proxy Canva API calls
  2. crm-oauth -- HubSpot/Salesforce OAuth callback, token exchange
  3. integration-oauth -- Unified OAuth callback router (14+ providers)
  4. process-reminders -- Cron-triggered; sends booking and task reminders
  5. fetch-reviews -- Cron-triggered; syncs Google Places reviews
  6. lusha-sync -- Cron-triggered; enriches leads with Lusha data

Data Layer

Database Schema: Multi-Domain Tables

DomainExamples
Coreorganizations, profiles, global_settings, audit_logs
CRMcrm_contacts, crm_companies, crm_pipelines, crm_stages
Financefinance_invoices, finance_company_expenses, finance_payments
HRMShrms_employees, hrms_attendance, hrms_payroll, hrms_benefits
Supportsupport_tickets, support_attachments, support_sla_rules
Commschat_messages, notifications, email_logs, whatsapp_messages
Projectsprojects, project_sprints, project_tasks, project_media
Workflowsworkflow_definitions, workflow_executions, workflow_approval_requests
Bookingsbookings, booking_links, booking_time_slots, booking_reminders
Assetsassets, asset_categories, asset_allocations, asset_maintenance
Knowledge Basekb_articles, kb_categories, kb_search_logs
Custom Fieldscustom_field_definitions, project_custom_fields
Marketingmarketing_campaigns, marketing_email_sequences, marketing_analytics
Design and Brandingproject_brand, design_templates, design_assets
Integrationsintegration_configs, integration_credentials, oauth_states
Adminrole_definitions, role_permissions, permission_groups

All tenant tables include an org_id column with a RESTRICTIVE RLS policy.

Auto-Generated Types

Database types are regenerated from the Supabase schema and provide exact table/column types, enum types, and Row/Insert types per table. The Supabase JS client uses these for fully type-safe queries.

Schema Management

Migrations follow a timestamp-ordered flow:

  1. Engineer creates a migration file (supabase/migrations/<timestamp>_<name>.sql).
  2. Runs locally via supabase migration up.
  3. Tests in local environment.
  4. Commits to Git.
  5. On merge to main, the Supabase CLI applies migrations during deployment.
  6. For BYOK provisioning, all migrations are replayed against the client's Supabase project.

Security Architecture

NearSync's security model is layered:

LayerMechanismScope
1CORSCross-origin requests locked to production domains
2JWT AuthenticationAll non-public endpoints require a valid Supabase JWT
3Row-Level SecurityTenant-scoped tables enforce organization isolation via RESTRICTIVE policies
4Rate LimitingPer-IP per-endpoint limits on the hyper-worker edge function
5RBACPermissions defined in role_permissions table, checked at runtime, realtime-subscribed
6API Key IsolationSensitive keys stored encrypted at rest, never bundled in client code
7BYOK Key HandlingService role key used once during provisioning, then discarded -- never persisted
8Error MonitoringSentry integration across all three apps; edge function logging; immutable audit logs

RLS in Practice

-- Example: CRM Contacts
CREATE POLICY "tenant_isolation" ON crm_contacts
AS RESTRICTIVE
FOR ALL
USING (
org_id = (SELECT org_id FROM profiles WHERE id = auth.uid())
);

RESTRICTIVE policies are evaluated first and AND with any permissive policies. A user cannot see, update, or delete rows belonging to another organization.

RBAC

Permissions are defined in the role_permissions table and checked at runtime:

if (!auth.checkPermission('finance:export_data')) {
return <div>You do not have permission to export data.</div>;
}

Permissions are realtime-subscribed, so RBAC changes take effect immediately without a page refresh.


AI Integration: Multi-Provider Architecture

NearSync integrates with 8 AI providers, automatically routing requests based on model name.

Supported Providers

ProviderFeatures
Google GeminiStreaming, vision, function calling
OpenAIStreaming, vision, function calling
Anthropic (Claude)Streaming, vision
GrokStreaming
MistralFunction calling
GroqStreaming
DeepSeekStreaming
Ollama (self-hosted)Streaming

Routing Flow

  1. The client specifies a model name (e.g., gemini-pro).
  2. The AI router looks up the provider in the catalog.
  3. The router sends the request to the hyper-worker with the model name.
  4. The hyper-worker fetches the API key from the integration_configs table (org-scoped, encrypted).
  5. The hyper-worker routes to the appropriate provider API.
  6. The response is streamed back to the client.

Configuration

AI providers are configured per-org via the SystemManifest:

manifest.integrations.gemini = {
enabled: true,
default_model: 'gemini-pro',
};

Per-module overrides are supported (e.g., one module can be locked to a specific model while others use the org default).


Custom Fields Engine

The custom fields engine allows each organization to extend any entity with additional fields, eliminating the need for industry-specific code forks.

How it works:

  • Definitions are stored in the custom_field_definitions table, scoped by org_id and entity_type (e.g., crm_contact, invoice, employee).
  • Field types supported: text, number, select, multi-select, date, boolean, URL, email, phone, currency.
  • Values are stored in entity-specific tables (e.g., crm_contact_custom_fields, invoice_custom_fields).
  • Rendering is automatic: the UI iterates over field definitions and renders the appropriate input component for each.

A healthcare client adds fields like medical_license_number and insurance_provider. A retail client adds product_sku and inventory_location. Same application code; different custom field definitions.


Workflow Engine

The visual workflow engine enables non-technical users to build automations using a node-based editor.

Node types:

Node TypePurpose
TriggerEvent-based (contact_created, invoice_paid, deal_won) or time-based
ConditionBranching logic (field comparisons, boolean checks)
ActionEffects: send WhatsApp, send email, create record, update record, call webhook
ApprovalPause execution, wait for human decision (approve/reject)
WaitDelay until a specified time; execution paused in DB, resumed by cron
AI (Pippin)AI summarization, classification, or extraction; result stored in workflow variable
OutputMark execution as success, log to audit trail

Execution model:

  • State is persisted to the workflow_executions table.
  • Paused executions (approvals, waits) are stored with resumed_at as NULL; a cron job processes resumes.
  • Full audit trail in workflow_audit_logs (immutable, append-only).

External Service Dependencies

Critical Path

ServicePurposeFallback
SupabaseDatabase, Auth, Storage, Realtime, Edge FunctionsManaged disaster recovery
ResendAll transactional emailsFallback to SMTP (manual config)

Feature-Specific

ServicePurposeFallback
Google Workspace (Gmail, Calendar, Docs, Drive)Email sync, calendar, document generationManual uploads
Facebook Graph APIWhatsApp messagingForm-based replies
StripeNon-INR paymentsManual invoicing
RazorpayINR paymentsStripe (if available in region)
TwilioVoice calls, SMSEmail-only
Google GeminiAI features, PRD generation, column mappingFallback to OpenAI
OpenAIAI chat (alternative to Gemini)Gemini (if available)
Canva APIDesign management, template libraryManual uploads
HubSpot / SalesforceCRM sync, deal trackingManual CSV import
LushaLead enrichment, data appendSkip enrichment
Google PlacesReview management, sentiment analysisSkip reviews

Conventions and Patterns

Import Rules

No cross-imports between apps. All shared code must live in packages:

// Not allowed
import { DashboardCard } from '../../../apps/admin-dashboard/src/components';

// Correct
import { DashboardCard } from '@nearsync/ui-system';

CSS Theming

All colors are set via CSS variables managed by the ThemeProvider, which reads branding values from the SystemManifest:

background-color: var(--app-surface);
border: 1px solid var(--app-border);
color: var(--accent-color);

Feature Gating

// Module gating
<ModuleGuard moduleId="crm">
<CRM />
</ModuleGuard>

// Feature flag
{manifest.features.ai_chat_enabled && <AIChat />}

// Permission check
{auth.checkPermission('finance:export_data') && <ExportButton />}

Database Queries

Type-safe queries via the Supabase JS client:

const { data, error } = await supabase
.from('crm_contacts')
.select('id, name, email')
.order('created_at', { ascending: false });

// RLS automatically scopes results by org_id