Settings & Administration — Technical Reference
This page covers the data models, permission engines, API authentication keys, and workspace toggles behind the Settings & Administration module.
Data Models
workspaces
Stores tenant workspaces.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
name | text | Workspace name |
icon_url | text | URL to the custom workspace icon logo stored in the public workspace_icons bucket |
settings | jsonb | Workspace settings, including modules feature flags |
subscribe_footer_enabled | boolean | Master toggle to include a subscribe link at the bottom of transactional emails (default true) |
subscribe_footer_message | text | Plain text displayed before the link (default 'Want to stay updated?') |
subscribe_footer_link_text | text | Clickable link text for the subscribe action (default 'Subscribe to our emails') |
created_at | timestamptz | Record creation timestamp |
updated_at | timestamptz | Last updated timestamp |
workspace_users
Maps users to workspaces with specific roles.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
workspace_id | uuid | Workspace ID — FK → workspaces.id (ON DELETE CASCADE) |
user_id | uuid | User ID — FK → user_profiles.id (ON DELETE CASCADE) |
role | text | Workspace permissions: 'owner', 'admin', or 'member' |
created_at | timestamptz | Association creation timestamp |
workspace_invitations
Tracks pending invites sent to new or existing users.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
workspace_id | uuid | Workspace ID — FK → workspaces.id (ON DELETE CASCADE) |
email | text | Invitee email address |
role | text | Target workspace role: 'admin' or 'member' |
token | uuid | Secure token used in invitation URLs |
invited_by | uuid | Inviter profile — FK → user_profiles.id |
accepted_at | timestamptz | Timestamp when invitation was accepted (default NULL) |
created_at | timestamptz | Record creation timestamp |
notifications
Stores system alerts and logs for workspace integrations and automations.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
workspace_id | uuid | Workspace ID — FK → workspaces.id (ON DELETE CASCADE) |
type | text | Alert category (e.g., 'automation_depth_limit', 'info', 'mention') |
title | text | Header summary of the alert |
body | text | Full description text |
payload | jsonb | Context metadata for deep-linking and debugging (defaults to '{}') |
notification_key | text | Optional unique key used to group/debounce similar alerts |
count | integer | Count of times this alert has occurred (for debounced alerts) |
target_user_id | uuid | FK → user_profiles.id (ON DELETE CASCADE) — targeted user recipient (NULL for workspace-wide) |
actor_id | uuid | FK → user_profiles.id (ON DELETE SET NULL) — user who triggered the notification |
entity_type | text | Associated entity category (e.g. 'contact', 'task', 'appointment') |
entity_id | uuid | Associated entity primary key |
email_sent | boolean | Whether an email alert has been sent for this notification |
created_at | timestamptz | Record creation timestamp |
updated_at | timestamptz | Last updated timestamp |
notification_reads
Junction table tracking individual workspace user read states.
| Column | Type | Description |
|---|---|---|
notification_id | uuid | Primary key — FK → notifications.id (ON DELETE CASCADE) |
user_id | uuid | Primary key — FK → auth.users (ON DELETE CASCADE) |
read_at | timestamptz | Timestamp when user marked the notification as read |
notification_preferences
Tracks channel delivery preferences (In-App, Email) for each notification category per user.
| Column | Type | Description |
|---|---|---|
user_id | uuid | Primary key — FK → auth.users (ON DELETE CASCADE) |
category | text | Primary key — Preference type: discussions, task_assigned, custom_workflow, broadcast_result, bounce_or_spam |
in_app | boolean | Enable in-app notification center alerts (default true) |
email | boolean | Enable email delivery alerts (default true) |
created_at | timestamptz | Record creation timestamp |
updated_at | timestamptz | Last updated timestamp |
user_profiles
Stores user account profiles and preferences.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
email | text | User's email address |
first_name | text | First name |
last_name | text | Last name |
timezone | text | Workspace-configured IANA timezone (e.g., America/Chicago). Controls user interface datetime localization and CSV export alignment. |
mention_email_pref | text | User preference for @mention email delivery ('immediate', 'digest', or 'never') |
is_super_admin | boolean | Flag indicating platform super-admin privileges |
country | text | User's country, populated during onboarding/gating |
region_state | text | User's US state code, populated for US residency validation |
onboarding_completed | boolean | Flag indicating if the user has completed the onboarding flow |
created_at | timestamptz | Record creation timestamp |
updated_at | timestamptz | Last updated timestamp |
Permissions & RBAC Architecture
Ownership Transfer Action
Workspace ownership is moved atomically via a transaction:
- Demotes the current owner to Admin status (
UPDATE workspace_users SET role = 'admin' WHERE role = 'owner' AND workspace_id = ...). - Promotes the target user to Owner status (
UPDATE workspace_users SET role = 'owner' WHERE user_id = ... AND workspace_id = ...). If either operation fails, the transaction rolls back.
Super-Admin Bypass
Users with is_super_admin = true set on their user_profiles profile bypass all workspace role checks. The requireRole() helper checks this flag first, granting Super Admins global access to transfer ownership, modify roles, and configure system settings.
Invitation URL Accept Endpoint
Workspace invitations route invitees to:
GET /api/invitations/accept?token={TOKEN}The server validates the token against workspace_invitations. If matched, the user is added to workspace_users. New users are redirected to signup first.
Developer API Keys
Key Generation and One-Time View
Workspace public API keys are generated using cryptographically secure random bytes with a production prefix:
pk_live_[random-string]To preserve security:
- The full key is displayed once in the UI on generation and is never recoverable.
- Only the prefix
pk_live_YOUR_PREFIXis stored in the database for tracking. - Client-side calls are recommended to route requests through a server-side proxy holding the key securely to avoid exposing keys in browser code.
Module Toggles System
JSONB Feature Flag Storage
Optional modules (Companies, Deals, Appointments, Courses, Agreements) are gated per workspace using JSONB flags on workspaces.settings:
{
"modules": {
"companies": true,
"deals": true,
"appointments": false,
"courses": true,
"agreements": true
}
}Context Propagation Flow
- Server Fetch: The
getUserWithWorkspaces()server action reads workspace metadata and settings. - Context Provider:
WorkspaceProvidermapssettings.modulesto the client-side state. - UI Filtering: The sidebar links and cross-module tabs filter visibility based on this context.
Notification Center Architecture
Unified Dispatcher Engine & Preference-Based Routing
The CRM utilizes a centralized server-side dispatch engine (src/lib/actions/dispatch-engine.ts) to manage background notification delivery:
- Preference Verification: Before dispatching, the engine checks the recipient's settings in
notification_preferences. A notification is only delivered if the channel (in_apporemail) is enabled for that category. - Delivery Paths:
- In-App Alerts: Inserts records directly into the
notificationstable. Unread state tracking is managed by mapping user reads in thenotification_readstable. - Email Alerts: The engine compiles structured HTML templates (e.g.
notification-template.tsormention-template.ts) and sends them via the Resend SMTP integration. - Timezone Resolution: The dispatcher bulk-queries recipient timezone configurations from
user_profilesconcurrently to avoid N+1 query waterfalls. Raw ISO string fields in the payload tagged withisDate=trueand timestamp values in mention digests are dynamically formatted according to the recipient's local timezone. Try-catch blocks ensure that formatting errors fallback to UTC to preserve email layout integrity.
- In-App Alerts: Inserts records directly into the
- Non-blocking execution (
after()): The dispatcher integrates with the Next.jsafter()API. This allows the primary server action (such as note creation or task assignment) to immediately return a successful HTTP response to the client, while template rendering and SMTP network calls execute asynchronously in the background.
Task Assignment Triggers
Manual and automated task creations trigger real-time dispatches:
- Assignee Alerts: Automatically dispatches alerts to the assigned coworker.
- Self-Assignment Guard: Excludes dispatches if the assignee matches the actor (
created_by), preventing redundant notifications. - Dynamic Context Collection: Captures task IDs, contact associations, due dates, and action links, embedding them in structured context tables (
detailRows) in fallback email alert templates.
Database Performance Enhancements
- Batch Email Resolution (
resolve_user_emailsRPC): A PostgreSQL helper function (resolve_user_emails(p_user_ids)) takes an array of user UUIDs and returns email mappings in a single query, bypassing individual user profile query waterfalls. - markAllAsRead Batch-Upsert: Replaces row-by-row updates with a single batch
upserton thenotification_readstable to mark all visible notifications read at once, saving roundtrips. - Unread Count Optimization: The
getUnreadCountmethod is optimized to use a PostgREST!innerjoin againstnotification_readsto retrieve count variables efficiently.
Deduplication and Grouping
To prevent dashboard alert flooding, notifications (e.g. email bounces, spam complaints, and loop-protection depth limit hits) are grouped:
- Events with matching triggers are rolled into a single notification.
- An incrementing count (e.g.,
x50) is appended to the notification body. - When incremented, the notification is marked unread for all users.
Retention Limits
The system maintains a maximum of 50 workspace-wide notifications per workspace. A background routine automatically deletes the oldest workspace-wide records (target_user_id IS NULL) when new ones are created. Private user-targeted mention notifications are excluded from this limit to prevent system notifications from evicting active user mentions.
Workspace Notification Join-Date Gating
To prevent new workspace members from viewing old notifications sent before they joined the workspace:
- Membership Join-Date Gating: Retrieves the user's membership join date (
created_atin theworkspace_userstable) using a private helpergetMembershipJoinDatewith the PostgRESTmaybeSingle()modifier to safely fetch the record without throwing exceptions. - Concurrent Lookup Execution: The
getNotificationsandgetUnreadCountserver actions fetch the user's notification preferences and membership join date concurrently usingPromise.allto optimize performance. - Nested Query Gating: Applies a nested PostgREST logical expression to filter the
notificationstable, excluding any workspace-wide alerts (target_user_id IS NULL) created before the user's membership join date. - Filtered Read Actions: The
markAllAsReadaction is refactored to only target notifications that are currently visible to the user, ensuring that old notifications remain unread and hidden. - Unread Count Join: Flips the read query inside
getUnreadCountto count base notification records using an inner join onnotification_readsto check if a user-specific read entry exists, ensuring accurate unread counts matching the filtered list.
Global Search Engine
PostgreSQL RPC Function (global_search)
The global search feature is powered by a custom database function global_search(p_workspace_id, p_query, p_modules) which queries multiple tables in a single round-trip using UNION ALL.
- Search Queries:
- Contacts: Matches
first_name,last_name,email, andphone. - Companies: Matches
name,domain, andphone(gated bycompaniesmodule toggle). - Deals: Matches
titleand joinspipeline_stagesto retrieve the active stage/pipeline (gated bydealsmodule toggle). - Events: Matches
nameandlocation. - Tasks: Matches
title. - Broadcasts: Matches
subject. - Forms: Matches
name.
- Contacts: Matches
- Attendee Resolution (Lateral Join): Due to the removal of
appointments.contact_idfor many-to-many appointments, the query joins attendee records using a resilientLEFT JOIN LATERALagainstappointment_external_attendees, preventing duplicate results while preserving search visibility for external contacts. - Limits: Returns up to 5 most recently updated records per entity type.
- Security: Defined as
SECURITY INVOKER, inheriting the calling user's Supabase permissions and respecting the workspace boundary.
Navigation and Deep-linking
When selecting a search result:
- Tasks: Appends
?taskId={ID}to redirect and auto-open the task details drawer on the/taskspage. - Deals: Constructs the URL dynamically using the parent pipeline ID:
/deals/{pipeline_id}/{deal_id}. - Other Entities: Direct navigation to their detail path (e.g.,
/contacts/{id},/companies/{id},/events/{id},/broadcasts/{id},/forms/{id}).
Dashboard Performance Engine
PostgreSQL RPC Function (get_dashboard_metrics)
To optimize the workspace dashboard loading time, Gordon CRM uses a consolidated metrics database function: get_dashboard_metrics(p_workspace_id, p_since, p_until, p_since_date).
- Metrics Consolidated:
- Counts: Total contact count, new leads in the past 30 days, active campaigns, upcoming events (within range), and scheduled broadcasts.
- Revenue: 30-day product sales revenue, 30-day event registration revenue, and 30-day paid deal payments.
- Pipeline board: Value of open deals, and count/value of deals won in the past 30 days.
- Activity Feed: Generates a unified JSONB array containing the 10 most recent activity feed logs (new contacts, sent emails, Stripe product purchases, event registrations, and campaign enrollments) using a sorted
UNION ALLquery.
- Performance benefits: Consolidates 6 separate parallel database queries into a single database look-up, reducing TTFB metrics latency by approximately 75%.
- Security: Runs as
SECURITY INVOKER, ensuring Supabase workspace RLS boundaries are strictly maintained.
Workspace Switching Architecture
To provide a premium workspace-switching experience, the CRM utilizes a Command-Palette style fuzzy-search dialog (WorkspaceSwitchDialog) featuring keyboard navigation and instant rendering.
- Layout Jitter Prevention: Eliminates layout shifted page flickers on desktop displays by locking body overflow to hidden and replacing Radix dialog overlay absolute centering styles (
inset: 0) with viewport-sized overlays (width: 100vw; height: 100vh). - Autofocus Soft-Keyboard Bypass: Suppresses Radix Dialog's native
onOpenAutoFocusevent on the search input overlay to prevent the soft keyboard from automatically popping up on mobile and tablet devices when the switcher opens. - Eager WorkspaceIcon Loading: Workspace avatar icons rendered in the switcher list configure the Next.js
<Image>component with theloading="eager"prop. This bypasses Next.js IntersectionObserver lazy-loading for client-side modal portals, eliminating visual avatar pop-in delays when the switcher is toggled open, while preserving initial page load performance since list items are only mounted when the switcher is opened. - Triple-Layer Transition Model:
- Immediate Inject: Injects raw DOM layout elements immediately on mouse click.
- Layout Pre-Hydrate Script: A synchronous HTML script executes during layout rendering to parse and check
localStoragefor the workspace preference, initializing settings immediately. - Hydrated Transition Handoff: Hands control smoothly to the React
WorkspaceSwitchOverlaycomponent once hydration completes.
Workspace Deletion Architecture
To prevent "zombie" or orphaned states, workspace deletion follows a strict database-first order of operations implemented in the deleteSystemWorkspace server action:
- Security Guard & Authorization: Verification that the caller has super-admin privileges (
is_super_admin = trueonuser_profiles). - Existence & Last Workspace Verification: Checks that the workspace exists, and that the total count of workspaces in the system is greater than 1.
- Database Invariant Trigger: Migration
073installs aBEFORE DELETEtriggerguard_last_workspaceon theworkspacestable. If a database delete is attempted and would leave zero workspaces, the database transaction raises an exception and rolls back:CREATE OR REPLACE FUNCTION prevent_last_workspace_delete() RETURNS TRIGGER AS $$ BEGIN IF (SELECT count(*) FROM workspaces) <= 1 THEN RAISE EXCEPTION 'Cannot delete the last workspace in the system'; END IF; RETURN OLD; END; $$ LANGUAGE plpgsql; - Gather External References: Query
sender_identitiesto compile list ofresend_domain_ids andtracking_subdomains. This metadata must be gathered before deleting the database row. - Database Deletion (Point of No Return): Executes the
DELETEquery on theworkspacestable. Because all child tables (likecontacts,deals,events, etc.) define theirworkspace_idforeign keys withON DELETE CASCADE, this operation instantly and completely purges all tenant database records in a single transactional unit. If this step fails, the system rolls back and no external API calls are made. - Best-Effort External Resource Purge: Once database cascading is successful, the action executes a series of asynchronous cleanup blocks. Errors in these calls are caught and logged but do not roll back the deletion, preventing third-party API issues from trapping the application in an un-deletable state:
- Resend Sending Domains: Deletes corresponding domains using the Resend API (
removeDomain). - Vercel Tracking Subdomains: Deletes tracking CNAME records via Vercel's API (
removeVercelDomain). - Supabase Storage Clean: Purges files and folders associated with the workspace ID from both
workspace_assetsandworkspace_iconsbuckets.
- Resend Sending Domains: Deletes corresponding domains using the Resend API (
Responsive Dialogs & Sheets (ResponsiveSheet)
To optimize the mobile user experience, the CRM systematically replaces standard modal dialogs with the controlled ResponsiveSheet component.
- Polymorphic Rendering: Renders as a standard centered
<Dialog>overlay on desktop, and a touch-responsive bottom<Drawer>on mobile viewports. - Mobile Occlusion & Sizing:
- Sets a dynamic
80dvhmaximum height bound to prevent content from extending into device safe-area notches or being occluded by software keyboards. - Implements ref-based portal scroll tracking that automatically moves the viewable content into focus when an input field receives focus.
- Fixes viewport jumping issues on Android Chrome by disabling auto-focus on mounts and adapting the drawer boundaries.
- Sets a dynamic
- Layout Alignment: Standardizes button actions to a responsive flow: stacked vertically on small viewports (with the primary action button on top) and aligned side-by-side on desktop (
flex-col-reverse sm:flex-row). - Sheet & Dialog Focus Prevention: Dialog and Sheet components (such as
AutomationDetailDialogandDependenciesDrawer) hook into Radix'sonOpenAutoFocusevent and invokepreventDefault()to prevent the browser from automatically highlighting the close (X) button on mount, avoiding distracting focus rings. - Tailwind v4 Animation Compatibility: Uses
tw-animate-cssimported inglobals.cssto enable keyframe transition utilities across Shadcn/ui and Radix components under Tailwind v4. Conflictingtransition ease-in-outstyles are removed from sheet containers to prevent overriding keyframe-based transform animations.
Mobile Select & Checkbox Optimizations
To resolve layout clipping and touch interaction jumps on mobile devices:
- Radix Select Boundary Bypass: Hides the
SelectScrollUpButtonandSelectScrollDownButtoncomponents withincomponents/ui/selectconditionally when in popper mode. This prevents touch boundary conflicts and scroll jumping bugs on iOS/Android viewports. - Accessible Checkbox Controls: Checkboxes are styled with a thicker
2pxborder, slate-500 resting color, solid white background, and custom emerald hover transition states for improved visibility and accessibility. - Viewport Padding Constraints: Applied
py-12vertical padding across all authentication layouts (login, signup, password reset, etc.) to ensure forms are scrollable and inputs are not clipped or hidden by virtual keyboards on mobile screens.
Standardized Settings Dashboard Headers
All workspace settings and administrative configuration dashboards feature a unified visual hierarchy:
- Platform, Limits, Modules, Users, Workspaces, Members, Branding, Developers, Agreements, and Integrations are styled with left-justified title/subtitle layouts.
- Each page embeds a clean, standardized
<- Settingsbreadcrumb navigation link at the top-left, enabling quick back-navigation on mobile and desktop views alike.
User Onboarding & Gating
The platform implements an automated validation flow during user signups, invitations, and login sequences to enforce compliance and geographical access rules.
Geo-Gating & US Residency Check
- Access Restrictions: During account creation, registration, and OAuth callbacks, the backend evaluates the user's location. The system enforces policy gating that blocks/restricts platform access based on the user's country.
- US Residency Gating: Users registering from or residing in the United States must provide their region or state (stored as
region_stateon their profile). For OAuth-registered users whose profiles lack this data, step 2 of the onboarding wizard prompts for state validation. - US-Only Access Banner: Integrated across signup, invitation, and onboarding layouts is a custom banner (
us-residency-banner.tsx) declaring US-only access, combined with state group listings usingSelectGroupfor clean state selections.
Multi-Step Onboarding Wizard
The onboarding flow (/onboarding) guides users sequentially:
- Legal Policy Verification: Evaluates platform policies (
/policies) and requires users to accept agreements before proceeding to general account onboarding. - Predictive DPA (Data Processing Agreement): Users who will become workspace owners are required to sign the DPA upfront alongside terms of service to prevent post-creation navigation loops.
- Workspace Setup: Converted to the brand's emerald styling and Montserrat "Go" logo inline SVG. Compiles steps down to 3 by omitting the mobile/notifications placeholder.
- Deleted Workspace Recovery: If a user's active workspaces are deleted, they are routed to a clean, progress-bar-free view to recreate a workspace and immediately proceed to the dashboard.
- No-Access Waitlist Screen: Renamed to "Awaiting Workspace Access" and equipped with a session-clearing sign-out button to cleanly break middleware authentication redirection loops.
Timezone Selection (TimezoneSelect)
The user profile page utilizes the searchable <TimezoneSelect /> component:
- Searchable Dropdown: Replaces legacy static timezone selectors with search and filter capabilities.
- Friendly Name Mapping: Resolves and displays friendly localized timezone descriptions (e.g. America/Chicago).
- Client Auto-Detection: To prevent hydration mismatch warnings between server-rendered and client-rendered HTML, timezone auto-detection is performed client-side inside a
useEffectmount hook.
Workspace Invitation Portal & UI Upgrades
- Invitation Routing (
/accept-invite): The public acceptance page routes prospective team members. The server-side wrapper page resolves token payloads, loading invitation states, account conflicts, and existing session routing. - Onboarding Actions:
getInvitationDetails(token): Looks up workspace metadata (name, logo, inviter profile) dynamically.acceptInviteSignup&acceptInviteLogin: Coordinates existing account login or new account signup under a single action set.
- Radix Hydration Check: To prevent Radix switches and selects from rendering unhydrated default empty states when a user directly navigates to their notification preferences, a client-side mounting lifecycle hook is introduced. The layout renders the loading skeleton during server-side pre-fetching and client hydration, stabilizing Radix input displays and eliminating ARIA hydration warnings.
- Snappier Sheet and Menu Animations: Slide and fade durations inside CSS selectors (e.g.
SheetContentandSheetOverlay) are adjusted to 200ms entry and 150ms exit. This accelerates drawer visual sweeps (like the dependency drawer) and mobile menu actions.
Profile Security & Current Password Validation
To secure user profiles against unauthorized modifications:
- Mandatory Password Verification: Updating account emails or passwords requires entering the user's current password.
- verifyCurrentPassword: A backend helper verifies credentials using a non-persistent Supabase client (preventing caching of auth tokens).
- Password Reset: The
sendProfilePasswordResetaction sends reset emails for active session password recoveries, with recovery links integrated within security settings.
App URL Resolution Utility (getAppUrl)
Base URL configuration is centralized inside src/lib/utils/get-url.ts using getAppUrl():
- Vercel Environments: Automatically checks
process.env.NEXT_PUBLIC_VERCEL_URLandprocess.env.NEXT_PUBLIC_SITE_URLto resolve base domains dynamically in preview deployments. - Protocol Safety: Enforces
http://for local hostnames (e.g.localhost:3000) to prevent SSL validation errors during development, and defaults tohttps://for production domains lacking a protocol prefix.
Atomic Ownership Transfer RPC (094_transfer_ownership_rpc.sql)
To prevent data inconsistency where a workspace could end up with zero owners or multiple owners, ownership transfer utilizes a database-level SECURITY DEFINER function:
- Atomic Operation: Demotes the current owner to Admin and promotes the target user to Owner in a single database transaction unit.
- RPC Invocation: The
updateMemberRoleserver action calls this stored proceduretransfer_workspace_ownershipdirectly rather than running multiple sequential UPDATE statements.
Concurrent Invitation Acceptance Tolerance
- Bypass Unique Constraint Violations: When multiple users attempt to accept the same invite token simultaneously, the backend catches database error code
23505(unique constraint violation onworkspace_users) and resolves the concurrency conflict gracefully.
Row-Level Security (RLS)
All tables enforce tenant-level isolation using the get_user_workspace_ids() helper.
| Table | SELECT | INSERT | UPDATE | DELETE |
|---|---|---|---|---|
workspaces | Workspace members | Authenticated | Owners / Admins | Super Admin |
workspace_users | Workspace members | Owners / Invitees | Owners | Owners / Admins (standard members only) |
workspace_invitations | Workspace members | Admin+ | N/A | Admin+ |
notifications | Workspace members (targeted or workspace-wide) | System API | System API | Admin+ |
notification_reads | Current user | Current user | N/A | N/A |
notification_preferences | Current user | Current user | Current user | N/A |
user_profiles | Current user + workspace coworkers | Authenticated | Current user | N/A |
Concurrent State Transitions & Double-Submit Protection
useTransition and startTransition Guards
To prevent duplicate API writes, layout freezing, or accidental multi-submissions when users perform workspace changes or resource modifications, the CRM leverages React's localized transition hooks:
- State Hooks: The
useTransitionhook is initialized across primary components, includingCoursesSection,EventsSection,FormDetailClient, andSystemWorkspacesPage. - Async Execution Closures: Destructive or database-modifying promise chains (such as Supabase writes, state refetches, and Next.js
router.refresh()cache clears) are wrapped insidestartTransitioncalls to ensure Next.js coordinates revalidation. - Double-Submit Controls Gating: Action elements, buttons, workspace selectors, and dialog submission buttons are bound directly to the transition's
isPendingstate. The UI automatically disables pointer interactions, displays loading feedback, and prevents double-clicking while background server component synchronization runs.
Database Schema & Codebase Type Safety
Supabase Types Synchronization
The codebase maintains typed Supabase bindings in src/types/supabase.ts. This file is synchronized with database schema updates by running the local update-types script, ensuring full type safety and alignment between PostgreSQL database changes and the Next.js React codebase.