Status: snapshot artifact. Qualia is no longer actively maintained as a commercial product. This repo is kept under an MIT license as a reference for anyone building AI-powered audit tooling. Issues + PRs are not actively reviewed. Fork freely.
Qualia is a Vite/React web app plus a Figma plugin backed by Supabase.
Design teams create projects, upload screenshots or flows, and Qualia generates structured UX audits (scores, issues, recommendations) using AI running in Supabase Edge Functions.
- Projects & personas: Capture mission, persona, constraints, language, and scope for each project.
- Single-screen & flow audits: Upload one screen or an ordered flow (2–10 images) for analysis.
- AI-driven UX analysis: Supabase Edge Functions call AI to generate scores, issue lists, and “one big thing” summaries.
- Per-issue feedback & re-audits: Designers can agree/disagree with findings; feedback is stored and used as high-priority context in future audits.
- Context documents: Attach Notion pages, Google Drive docs, or uploaded files as extra context for audits.
- Figma plugin: Run audits directly from Figma, sync flows, and optionally draw highlights back on the canvas.
- Quotas & analytics: Enforced daily usage limits and analytics dashboards for adoption and performance.
- SPA built with React + TypeScript, using Vite as the build tool.
- UI built with Tailwind CSS, shadcn-ui, and Radix UI components.
- Routing with
react-router-domundersrc/App.tsx. - Data fetching and caching with @tanstack/react-query.
- Supabase JS client for auth, database, and storage access.
- Analytics via PostHog, with consent handled in the app.
Key entry points:
src/main.tsx– React bootstrap.src/App.tsx– Routes, global providers (React Query, language, auth), and analytics.src/pages/*.tsx– Screens likeIndex,Dashboard,Project,Analytics,Settings,Auth,PluginAuth, and integration callbacks.
- Database & storage: Supabase Postgres schemas and RLS policies defined in
supabase/migrations/*.sql. - Edge Functions (Deno + TypeScript) in
supabase/functions/*/index.ts, including:analyze-ui– Core UX analysis for screenshots/flows.explain-reaudit-delta,generate-feedback-response– Re-audit and feedback explanation flows.- Figma-related:
figma-auth,manage-figma-token,fetch-figma-snapshot,fetch-figma-flow,plugin-analyze,plugin-upload-image,plugin-projects,plugin-issue-feedback,promote-plugin-audit. - Drive/Notion:
google-drive-auth,google-drive-fetch,notion-auth,notion-fetch,extract-project-context,summarize-context,integration-status. - Misc:
check-contrast,send-contact,delete-account.
- Shared logic under
supabase/functions/_shared/*for:- Prompt construction and AI calls.
- Quota checks.
- Token encryption/management.
- Figma and integration utilities.
- Lives in
figma-plugin/:manifest.json– Plugin metadata and permissions.src/code.ts– Main plugin thread: inspects selection, exports images, and draws issue highlights.src/ui/*– React UI for plugin auth, project selection, running audits, and viewing/submitting feedback.src/ui/api.ts– HTTP client for talking to Supabase Edge Functions.- Built via
esbuild(figma-plugin/esbuild.config.mjs).
- Framework: React + TypeScript.
- Bundler: Vite.
- Styling: Tailwind CSS, shadcn-ui, Radix UI, custom CSS.
- Routing:
react-router-dom. - Data:
@tanstack/react-query, Supabase client. - UI & UX:
sonner(toasts),driver.js(product tours),embla-carousel-react,react-resizable-panels,react-day-picker,recharts,lucide-react. - Testing: Vitest + Testing Library.
- Linting: ESLint 9 + TypeScript ESLint.
- Database/auth/storage: Supabase.
- Business logic: Supabase Edge Functions (Deno + TypeScript).
- AI orchestration: Edge Functions calling Google Gemini via
GEMINI_API_KEY.
- Runtime: Figma plugin API.
- Language: TypeScript.
- UI: React, bundled with esbuild.
High-level layout:
src/– Web app source.pages/– Top-level routes (landing, dashboard, project, analytics, settings, auth, callback pages).components/– Reusable UI and domain components (audit forms, upload zones, project cards, context doc UIs, etc.).contexts/– Auth and language contexts.hooks/– Data and UI hooks for projects, audits, personas, context docs, integrations, daily limits, product tours, etc.services/– Thin Supabase-backed services (projects, audits, feedback, integrations, context docs, analytics).integrations/– Supabase client and DB types.lib/– Utilities (API helpers, analytics, feature flags, PDF export, text extraction, date formatting).utils/translations/– String dictionaries for multi-language support.styles/– Global styles and product tour CSS.
supabase/config.toml– Supabase project config.migrations/– Database schema and RLS migrations.functions/– Edge Functions (*/index.ts) and shared helpers (_shared/*).
figma-plugin/manifest.json– Figma plugin manifest.src/code.ts– Main plugin thread.src/ui/*– Plugin React UI and API client.esbuild.config.mjs– Build configuration.
public/– Static assets.- Tooling:
vite.config.ts,vitest.config.ts,tailwind.config.ts,eslint.config.js,tsconfig*.json,vercel.json.
- Node.js (LTS recommended) and npm.
- A Supabase project with:
- Database migrations from
supabase/migrations/applied. - Edge Functions enabled and deployed.
- Database migrations from
- (Optional but recommended) Accounts and apps for:
- Figma (for plugin + OAuth).
- Google Cloud (Drive OAuth + Picker).
- Notion (OAuth).
git clone <YOUR_GIT_URL>
cd qualia-mvp
npm installCreate a .env file at the repo root based on .env.example and fill in the values below.
These are read via import.meta.env and configured in vite.config.ts:
VITE_SUPABASE_URL– Supabase project URL (from Supabase dashboard).VITE_SUPABASE_PUBLISHABLE_KEY– Supabase anon/public key.VITE_SUPABASE_PROJECT_ID– Supabase project ID (used for metadata and links).VITE_POSTHOG_KEY– PostHog project API key for analytics.VITE_POSTHOG_HOST– Optional PostHog host (defaults to PostHog cloud when not set).VITE_GOOGLE_APP_ID– Google Cloud project number for Drive Picker.VITE_GOOGLE_API_KEY– Google API key for Drive Picker.
Additionally, the app honors:
POSTHOG_API_KEY– Alternative forVITE_POSTHOG_KEY.POSTHOG_HOST– Alternative forVITE_POSTHOG_HOST.
See
src/integrations/supabase/client.ts,src/lib/posthog.ts, andsrc/hooks/use-drive-picker.tsfor how these are used.
Configure these in the Supabase project settings (Environment Variables). They are accessed via Deno.env.get in the various functions.
-
Core Supabase config
SUPABASE_URLSUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEY
-
App URL
APP_URL– Base URL of the deployed web app (used in OAuth redirects and plugin links).
-
AI
GEMINI_API_KEY– Google Gemini API key, used byanalyze-uiand the other analysis functions.
-
Figma integration
FIGMA_CLIENT_IDFIGMA_CLIENT_SECRETFIGMA_TOKEN_ENCRYPTION_KEY– Key for encrypting stored Figma tokens.PLUGIN_ANALYZE_IMAGE_SOURCE– Controls how plugin images are sourced (e.g., from Figma vs uploaded URLs).
-
Drive / Notion integrations
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETNOTION_CLIENT_IDNOTION_CLIENT_SECRETINTEGRATION_ENCRYPTION_KEY– Symmetric key for encrypting integration and Figma tokens.
-
Email
RESEND_API_KEYRESEND_FROM_EMAIL
For more detailed setup of Google Drive and Notion, see
supabase/functions/README-DRIVE-NOTION.md.
FEATURE_DRIVE_NOTION_IMPORT– Frontend feature flag (boolean-like string) to enable/disable the Drive/Notion import UX.- Defined in
src/lib/feature-flags.tsand used around the Dashboard/import features.
- Defined in
Several Postgres triggers and pg_cron jobs read shared values from the
private.cron_config table at runtime (URL, allowlists, webhook secrets).
The seed migration supabase/migrations/20260523189500_set_db_settings.sql
ships with placeholder values — edit it before applying to a fresh
project, or UPSERT the real values manually:
INSERT INTO private.cron_config (name, value) VALUES
('functions_base_url', 'https://<YOUR_REF>.supabase.co/functions/v1'),
('operator_email', '<your-operator-email>'),
('showcase_publisher_emails', '<your-operator-email>,<additional-email>'),
('welcome_webhook_secret', '<openssl rand -base64 32>'),
('retention_webhook_secret', '<openssl rand -base64 32>'),
('storage_cron_secret', '<openssl rand -base64 32>')
ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value;The three webhook/cron secrets must match the corresponding Edge Function
env vars (WEBHOOK_SECRET, RETENTION_CRON_SECRET, STORAGE_CRON_SECRET)
or the cron jobs and triggers will return 401. The two stores (Postgres
private.cron_config row + Edge Function env var) have no foreign key
between them — keep them in sync manually, and smoke-test by manually
firing the cron command body via SELECT net.http_post(...) and asserting
status_code = 200 in net._http_response.
Some identifiers are baked into config files that Vercel/Figma schemas don't allow to be templated. Edit these by hand for your fork:
figma-plugin/manifest.json—networkAccess.allowedDomains: replacehttps://qualia-ux.comwith your app's domain. Without this, the plugin can'tfetchyour backend from inside Figma.vercel.json—rewrites[].destinationfor/mcpand/mcp-auth: replacezujbauyrpisjdqmjhmgr.supabase.cowith your Supabase project ref. Seeagent_docs/danger-zones.md→ "vercel.json — Strict Schema" for why these can't be env-templated.supabase/config.toml—project_id: replace with your ref. This is public-by-design (already exposed via the anon key in the web bundle).figma-plugin/esbuild.config.mjs— already readsAPP_URLfrom env viadefine. ExportAPP_URL=https://your-domain.combeforenpm run buildinsidefigma-plugin/.
- See
e2e/fixtures/README.mdfor the Playwright opt-in fixture pattern (BYOK Gemini key, Figma OAuth) — without these, ~7 e2e tests skip with clear messages. - See
docs/analytics/queries/README.mdfor the operator-filter pattern used by all 18 analytics queries (gitignored_operator_emails.local.sql).
From the repo root:
# Start the web app (Vite dev server)
npm run devBy default, Vite is configured to:
- Bind to all interfaces (
host: '::'). - Use port 8080.
You can customize host/port via standard Vite environment variables or CLI flags.
For a production build:
npm run build # Production build
npm run preview # Preview the production build locallyMigrations live under supabase/migrations/. To apply them to your Supabase project, either:
- Use the Supabase Studio migration tools, or
- Use the Supabase CLI:
supabase link --project-ref <YOUR_PROJECT_REF>
supabase db push(Adjust for your workflow if you manage migrations differently.)
Each function has its own folder under supabase/functions/ with an index.ts. After configuring env vars, deploy them with the Supabase CLI:
supabase functions deploy <function-name>See supabase/functions/ for the full list of functions.
The plugin lives in figma-plugin/ and is built with TypeScript + React UI.
The plugin currently uses hard-coded URLs in figma-plugin/src/ui/api.ts:
SUPABASE_FUNCTIONS_BASE– Supabase Functions base URL (e.g.https://<project>.supabase.co/functions/v1).QUALIA_APP_URL– Qualia web app base URL (e.g.https://qualia-ux.com).- Derived constants like:
PLUGIN_AUTH_IFRAME_URL–${QUALIA_APP_URL}/plugin-authQUALIA_SETTINGS_URL–${QUALIA_APP_URL}/settingsQUALIA_PROJECTS_URL–${QUALIA_APP_URL}/dashboard
If you self-host Qualia, update these constants to match your deployment and Supabase project.
cd figma-plugin
npm install
# One-off build
npm run build
# Or watch mode during development
npm run devThe build outputs dist/code.js, dist/ui.html, and dist/ui.js, which are referenced by manifest.json.
- In Figma, open Plugins → Development → Import plugin from manifest.
- Select
figma-plugin/manifest.json. - With
npm run devrunning, make changes to the plugin code and reload in Figma to see updates.
Ensure your Supabase Edge Functions are deployed and accessible from the Figma environment (CORS, network permissions, and Supabase config.toml/JWT verification settings).
Run tests with Vitest:
npm run test # Single run
npm run test:watch # Watch modeRun linting with ESLint:
npm run lintThe web app is a standard Vite SPA and can be deployed to:
- Vercel (see
vercel.jsonfor CSP and headers), or - Any static hosting provider that can serve the Vite build output.
Typical static deployment flow:
npm run build
# Deploy the contents of the `dist/` directory to your hosting providerEnsure that:
APP_URLmatches the final deployed URL.- Supabase env vars (in both frontend and Edge Functions) are configured with this URL for redirects and links.
Edge Functions and database live entirely in Supabase:
- Functions are deployed via the Supabase CLI (
supabase functions deploy ...) or via the dashboard. - Database migrations are applied via Supabase migrations (CLI or Studio).
Make sure the function URLs and APP_URL are consistent with the web and plugin deployments.
npm run dev– Start the web app dev server.npm run build– Production build for the web app.npm run build:dev– Development-mode build.npm run preview– Preview the production build.npm run lint– Run ESLint over the project.npm run test,npm run test:watch– Run tests.figma-plugin/npm run build– Build the Figma plugin bundle.figma-plugin/npm run dev– Watch and rebuild the plugin during development.
- Database schema and RLS policies: see
supabase/migrations/. - Drive and Notion integration details: see
supabase/functions/README-DRIVE-NOTION.md. - Supabase shared logic and patterns: see
supabase/functions/_shared/*.
If you’re extending Qualia, consider:
- Reusing existing services in
src/services/and hooks insrc/hooks/. - Respecting quotas and feedback flows by going through the existing Edge Functions instead of calling AI directly.