Skip to content

Admin Guide

Covers the internal admin console at /admin/*. Access requires users.isAdmin = true with an appropriate adminRole (super_admin, psychologist, reviewer, publisher, manager, or full_admin) — role/permission enforcement lives in the admin layout itself, not in middleware.ts. Admin login is separate: /admin/login.

1. Console Map

SectionPurpose
dashboard (with mdd-requests, submissions-search, super-admin sub-areas)Cross-org overview, MDD request management, global submission search, and a super-admin-only tier
organizations (+ [organizationId])Per-organization administration
billingPlan/feature/subscription administration
prompts (+ [id], [id]/edit)AI prompt template management and versioning
llm-servicesLLM provider/model routing configuration per feature
foundersFounder-level administration
psychometric-candidatesPsychometric assessment candidate administration
success-profiles (+ [id])Success-profile template administration
knowledge-baseRAG knowledge-base content management
chat-ragChat widget / RAG configuration
crmCRM data administration
web-scraperJob-listing scraper administration (benchmarking data)
data-migrationData migration tooling
oauthThird-party OAuth client (app) management
jobsBackground job visibility/management
maintenancePlatform maintenance tooling
yareta-xA distinct product area (see yareta_x schema/GraphQL domain)

2. Prompt Management (/admin/prompts)

Every AI-generated section in the product — DNA scoring, Traffic Light evaluation, MDD report sections, team summaries, User Pulse scoring — is driven by a prompt template stored in the system_prompts table, editable here without a code deploy. Each prompt carries:

  • A unique slug, category, and promptType.
  • The actual promptTemplate text (LangChain-compatible, with {{variable}} placeholders).
  • Optional per-prompt LLM overrides — provider, model, fallback provider/model, temperature, max tokens — which take priority over the feature-level default set in LLM Services (§3).
  • Full version history (promptVersions), with the ability to restore a prior version.

A critical operational detail: the prompt template string also exists in application code (e.g. src/prompts/investor-team-summary.ts for the team-summary prompt). Editing a prompt’s default text in code does not automatically update the live database row that the LLM actually reads from — the DB row is what’s live. To push a code-level prompt change into the database, either trigger the forceUpdatePrompts GraphQL mutation (forceUpdatePrompts(promptSlugs: [...])) or syncPromptsFromCode, or run a direct SQL UPDATE against system_prompts (see the Maintenance Guide for the safe pattern). If a prompt change was made in code but production behavior hasn’t changed, check whether the DB row was actually updated before assuming the code change is broken — this has been an observed source of confusion (a stale DB prompt missing a code-side safety instruction has previously caused a live LLM hallucination incident; see the Troubleshooting Guide).

3. LLM Services (/admin/llm-services)

A single page controlling which provider (OpenAI, Anthropic, Google, Groq) and model each named service uses, with optional fallback provider/model and temperature/max-token settings — this is the mechanism described in the Technical Design doc. Changing a service’s provider/model here takes effect immediately (cached in memory, invalidated on update) with no deploy required. Use this page — not an environment variable change — to switch a feature’s model.

4. Organizations & Billing (/admin/organizations, /admin/billing)

Manage per-organization plan assignment, subscription state, and custom enterprise pricing overrides. /admin/billing covers the plan/feature catalog itself (credit costs per feature, margin overrides). Direct credit adjustments (addCreditsMutation, deductCreditsMutation) are available for manual corrections — use these deliberately and check creditUsageHistory afterward to confirm the adjustment landed as expected, since credit logic includes idempotency protections that can make a manual adjustment behave unexpectedly if retried.

5. OAuth App Management (/admin/oauth)

The only way to provision a third-party OAuth client — there is no self-service registration (see the API Documentation). When creating a client: the client secret is shown exactly once — capture it immediately and hand it to the integrator through a secure channel, since it cannot be retrieved again (only regenerated, which invalidates the old one). Double-check redirect_uris are exact and complete before saving — the platform matches them by exact string, not prefix.

6. Data Migration & Maintenance (/admin/data-migration, /admin/maintenance)

Data migration tooling here is distinct from D1 schema migrations (wrangler d1 migrations) — this is for moving/reconciling application data (e.g. between organizations, or during a data cleanup). Treat any bulk operation here with the same caution as a direct database write, since these actions typically bypass the normal validation paths a GraphQL mutation would apply. See the Maintenance Guide for routine maintenance tasks.

7. Jobs (/admin/jobs)

Visibility into background job status across the queue system — useful for confirming whether a stuck submission’s AI processing actually ran, failed, or is still queued, before escalating to engineering. Cross-reference with the Troubleshooting Guide for common stuck-job causes (insufficient credits, a paused cron sync, D1 contention).

8. Developer API Keys (/[slug]/developer)

Note this lives under the org workspace, not /admin — an organization’s own members (not platform super-admins) issue their own Developer API keys here for headless integrations against /api/v1. Full key-lifecycle detail is in the API Documentation. This is a distinct credential from the org-level Zapier API keys and outbound Webhook signing secrets covered in the User Guide’s Organization Settings section — the three are not interchangeable.

9. Security notes for admins

A few standing gaps admins should factor into day-to-day decisions, not just incident response (full detail: KNOWN-GAPS.md):

  • otp_whitelist: any email address added here skips OTP verification entirely on login. Treat adding an email to this table as granting a login-bypass credential, not a convenience setting — audit its contents periodically.
  • Third-party CRM/integration API keys are stored in plaintext, not hashed, in lovable_integrations.apiKey and export_crm_apikeys.apiKey. Anyone with D1 read access to those tables can read the raw key. Rotate a key immediately if you suspect the underlying database access was over-shared, not just if the key itself leaked.
  • Inbound webhooks from CRM integrations are not uniformly signature-verified. If you enable Attio or the legacy Airtable webhook for an organization, know that those routes accept any POST to their URL as genuine — there is no cryptographic check tying the payload to the real Attio/Airtable account. Bae HQ is the one integration that verifies correctly. Treat this as a reason to keep integration webhook URLs unlisted/unguessable, not as a solved problem.
  • /admin/* access enforcement lives in the admin layout component, not in middleware.ts. If a new admin-only page or API route is added without going through the existing layout/route-group pattern, it will not automatically inherit isAdmin/adminRole enforcement — this has to be checked deliberately for any new admin surface.
  • Customer-created outbound webhook secrets are shown once, like OAuth client secrets (§5). If a customer reports losing their webhook signing secret, there is no “reveal” option in the current UI — the only path is deleting the webhook and creating a new one with a new secret. Let customers know this up front rather than after they’ve lost it.

10. Chat Widget Configuration (/admin/chat-rag)

This is where a Yareta-brandable chat widget is configured for an organization to embed on their own website — see the User Guide’s note on this for the customer-facing side. There is currently no self-service equivalent under /[slug]/organization-settings; every widget is created and issued from here.

Each widget config includes: display title, logo URL, primary color, welcome message, input placeholder text, display mode (a floating launcher vs. an inline drawer), and an optional FAQ list. Separately from the visual settings, a config also controls what the widget can actually answer from: which prompt(s) it uses, which knowledge-base collections it can search, how many results it retrieves and at what minimum relevance score, and which LLM provider/model powers it. A config can also be flagged as the platform-wide widget, in which case it’s shown site-wide rather than for one organization.

Once a config is saved, use the copy embed code action next to it to get the exact snippet to hand to the customer — an <iframe> pointing at /chat-widget?config=<the config's slug>. Handing out the wrong slug, or a slug for a disabled config, is the most likely cause of a customer reporting their embedded widget shows a blank/error state — the widget page itself just says to check the config parameter is present and correct, which isn’t very informative for a non-technical customer, so it’s worth checking this yourself first if they report an issue rather than sending them that message directly.


Related documents: User Guide · API Documentation · Maintenance Guide · Troubleshooting Guide · Incident Response Guide