Master Documentation
Exhaustive Technical Reference · Quantyx Admin Portal
Table of Contents
Quantyx Solutions
Master Technical Documentation
Exhaustive Reference · Architecture · Data Model · Backend · Frontend · Compliance
Version 1.0 · September 2026
https://quantyxsolutions.base44.app
Confidential
This document is intended for internal engineering staff and authorised developers. It describes the full architecture, data model, and security posture of the Quantyx admin portal.
1. Architecture & Overview
1.1 What is Quantyx?
Quantyx Solutions is a multi-tenant SaaS administration platform built on the Base44 backend-as-a-service. It serves as a single command center for an operator managing multiple SaaS products — onboarding subscriber organisations, tracking subscriptions and billing, running a support ticketing desk with OTP-gated account access, publishing a token-gated Knowledge Base, monitoring customer health and revenue, and maintaining GDPR / compliance posture.
The application exposes two distinct surfaces:
- Admin Portal — the authenticated staff workspace (sidebar + topbar shell). Access is controlled by Base44 Auth plus a
TeamMemberrecord with granular per-product, per-module permissions. - Client Portal — a token-based, public surface (
/portal/*) where client organisations view their tickets, reply to agents, complete onboarding, and set passwords. No Base44 login is required; sessions are issued viaClientPortalSessionmagic links.
1.2 Technology Stack
| Layer | Technology |
|---|---|
| Frontend framework | React 18 + Vite (ESM) |
| Styling | Tailwind CSS with CSS-variable design tokens, shadcn/ui component library, lucide-react icons |
| Routing | react-router-dom v6 (BrowserRouter, nested layout routes) |
| Data / state | @tanstack/react-query, Base44 SDK entities, React Context (AppContext, PermissionsContext) |
| Charts | recharts (solid lines only — no dashed/dotted patterns per design policy) |
| Rich text | react-quill (Knowledge Base editor + rendered .kb-content styles) |
| Maps / 3D / DnD | react-leaflet, three.js, @hello-pangea/dnd (available, used selectively) |
| Backend | Base44 BaaS — entities (JSON schemas), auth, scheduled/entity automations |
| Server runtime | Deno (backend functions in base44/functions/*/entry.ts) |
| PDF generation (server) | jsPDF — used by generateInvoice to produce A4 invoice PDFs server-side |
| PDF generation (client) | jsPDF + html2canvas — used by this documentation page for standalone export |
| Payments | Stripe (via shared paymentGateway abstraction) + configurable PaymentGateway records |
| External validation | EU VIES REST API (VAT number validation) |
1.3 High-Level Architecture
┌─────────────────────────────────────────────────────────────────┐
│ src/App.jsx — AuthProvider → QueryClientProvider → Router │
│ └─ AuthenticatedApp │
│ ├─ Public routes: /portal/* and /kb/:productId │
│ └─ <AppLayout> (admin shell, wraps protected routes) │
│ ├─ AppProviders (user, products, notifications, │
│ │ PermissionsProvider) │
│ ├─ Sidebar (product switcher + nav, permission-filtered) │
│ ├─ TopBar (search, notifications, profile) │
│ └─ <Outlet/> → routed page │
└─────────────────────────────────────────────────────────────────┘
│
┌────────────────┴───────────────────┐
▼ ▼
Base44 SDK (client) Backend Functions (Deno)
base44.entities.<Name>.{list, base44/functions/<name>/entry.ts
filter,get,create,update,delete} — invoked via base44.functions.invoke()
base44.auth.{me,logout,...} — or via external HTTP (webhooks)1.4 Navigation Structure (Sidebar)
The sidebar (src/components/layout/Sidebar.jsx) renders a permission-filtered list of nav items. Each item declares a module gate checked against the current user's TeamMember permission sets.
| Label | Path(s) | Module gate |
|---|---|---|
| Dashboard | /, /dashboard, /revenue-analytics | dashboard |
| Organisations | /organisations | organisations |
| Customer Success | /customer-relationships | organisations |
| Tickets | /tickets | tickets |
| Billing | /payments, /credit-notes | payments |
| GDPR Requests | /gdpr-requests | dashboard |
| Notifications | /notifications | dashboard |
| Knowledge Base | /knowledge-base | knowledge_base |
| Settings | /settings, /team | settings |
| Master Docs | /master-documentation | dashboard |
1.5 Authentication & Permissions Model
Authentication is owned by the Base44 platform (tokens, sessions, email verification). The app never implements its own auth backend.
base44.auth.me()returns the current platform user;base44.auth.logout()ends the session.- Every authenticated admin user is mapped to a
TeamMemberrecord (matched byuser_id, statusactive). - Platform users with
role === 'admin'are treated as super admins even without a TeamMember record. - Users with no active TeamMember record hit an
AccessPendingScreen(seeAppLayout).
Permissions are resolved in src/lib/PermissionsContext.jsx and exposed via usePermissions():
- Module access — each permission set declares a level (
none | read | write | admin) per module:dashboard, organisations, tickets, payments, otp_access, settings, knowledge_base. The highest level across all sets wins. - Organisation scoping —
accessible_organisation_idsrestricts which client orgs a user can see (empty = all). - Settings scoping —
accessible_settings_sectionsrestricts which Settings tabs are visible.
Enforcement happens in two places:
- Frontend —
PermissionGuardwraps routes;canAccessModule/canAccessOrganisationfilter data and UI. - Backend — sensitive functions (e.g.
initiateOnboarding,generateInvoice) re-check the TeamMember permission level before acting, so a crafted client request cannot bypass the gate.
Idle session timeout
useIdleTimeout warns at 25 min and force-logs-out at 30 min of inactivity, surfaced via SessionTimeoutWarning.1.6 Design System
Design tokens live in src/index.css (:root light + .dark) and are mapped to Tailwind in tailwind.config.js. The palette is a polished slate/indigo light theme. Key tokens: --primary (indigo), --success, --warning, --destructive, plus sidebar-specific tokens. The font is Inter. StatusBadge (src/components/ui/StatusBadge.jsx) centralises all status pill styling across org/ticket/payment/onboarding/health/sentiment statuses.
2. Data Model
All data is stored as Base44 entities (JSON schemas in base44/entities/*.jsonc). Every record automatically includes id, created_date, updated_date, and created_by_id — these are not redeclared in the schemas below. Entities are accessed client-side via base44.entities.<Name> and server-side via base44.asServiceRole.entities.<Name>.
Access control note
PermissionGuard + backend permission re-checks inside functions. See §7 for the full compliance treatment.2.1 Core / Platform
User base44/entities/User.jsonc
Built-in. Read-only: id, created_date, full_name, email. Editable: role (admin | user). Platform admins (role='admin') are super admins. User records cannot be created/imported — users join via base44.users.inviteUser(email, role).
| Field | Type | Notes |
|---|---|---|
| role | enum: admin, user | Platform-level role. admin = super admin. |
TeamMember base44/entities/TeamMember.jsonc
Maps a platform User to an internal staff member with a role template and per-product permission sets. The central record for all access control.
| Field | Type | Required | Description |
|---|---|---|---|
| user_id | string | — | Linked platform User id |
| full_name | string | — | Display name |
| string | ✓ | Login email | |
| role_template | enum: super_admin, support_agent, finance, custom | ✓ | Default permission template |
| status | enum: active, invited, deactivated | — | Only active members can log in |
| avatar_url | string | — | |
| permission_sets | array<object> | — | Per-product grants (see below) |
| last_login | date-time | — |
Each permission_sets[] entry:
| Field | Type | Description |
|---|---|---|
| saas_product_id | string | Product this grant applies to |
| saas_product_name | string | Denormalised for display |
| modules | object | Per-module level: none/read/write/admin for dashboard, organisations, tickets, payments, otp_access, settings, knowledge_base |
| accessible_organisation_ids | string[] | Orgs this user can access (empty = all) |
| accessible_settings_sections | enum[] | company, products, email, invoice, otp (empty = all) |
SaasProduct base44/entities/SaasProduct.jsonc
Represents one of the SaaS products the operator manages. Carries billing config, OTP config, and KB secret.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | ✓ | Product name |
| description | string | — | |
| api_base_url | string | — | Product API base URL |
| api_key_hint | string | — | |
| otp_callback_url | string | — | Where OTP verification requests are sent |
| stripe_account_id | string | — | Platform Stripe account (shared) |
| kb_secret | string | — | HMAC secret signing Knowledge Base access tokens |
| status | enum: active, inactive, maintenance | — | Defaults active |
| logo_url | string | — | |
| color_accent | string | — | |
| default_currency | string | — | ISO 4217, default GBP |
| supported_currencies | string[] | — | Currencies clients can be billed in |
| supported_payment_methods | enum[] | card, sepa_debit, bacs_debit, ach_debit, ideal, bancontact, sofort, au_becs_debit | |
| stripe_tax_enabled | boolean | — | Auto VAT/GST via Stripe Tax |
| otp_expiry_minutes | number | — | Default 15 |
| otp_session_duration_minutes | number | — | Default 30 |
| support_admin_user_id | string | — | Primary support admin |
| support_team_member_ids | string[] | — | Backup support team |
| escalation_enabled | boolean | — | Escalate to super admins if no response |
| invoice_template_reminder | object{subject,body} | — | |
| invoice_template_overdue | object{subject,body} | — |
CompanyProfile base44/entities/CompanyProfile.jsonc
The operator's own company details — used for invoice branding, bank details, portal link origin, and sidebar logo.
| Field | Type | Description |
|---|---|---|
| company_name | string (required) | Legal name |
| trading_name | string | |
| logo_url | string | Shown in sidebar + invoices |
| registered_address_line1/line2, city, county, postcode, country | string | Registered address |
| phone, email, support_email, website | string | Contact details. website origin used for portal magic links |
| company_registration_number, vat_number | string | |
| bank_name, bank_account_name, bank_account_number, bank_sort_code, bank_iban, bank_swift_bic | string | Bank transfer details on invoices |
| payment_terms_days | number | Default 15 — invoice due date = invoice date + this |
| invoice_notes | string | Footer notes on invoices |
| opening_cash_balance | number | Starting bank balance (cash position) |
SubscriptionPlan base44/entities/SubscriptionPlan.jsonc
A pricing tier for a product. Supports flat and metered billing models.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | ✓ | Plan name |
| saas_product_id | string | ✓ | Owning product |
| plan_code | string | ✓ | Unique code |
| tier | enum: starter, growth, pro, enterprise | ✓ | |
| currency | string | — | ISO 4217, default GBP |
| billing_model | enum: flat, metered | — | Default flat |
| tax_code | string | — | Stripe Tax product tax code |
| metered_metric | string | — | What is measured (metered) |
| included_units | number | — | Units before overage |
| overage_unit_price | number | — | Price per unit beyond included |
| price_monthly_gbp | number | ✓ | Monthly price |
| price_annual_gbp | number | — | Annual price |
| billing_cycle | enum: monthly, annual | — | Default monthly |
| features | object | — | max_users, max_tickets_per_month, max_storage_gb, api_calls_limit, modules_enabled[], priority_support, custom_branding, api_access, webhooks_enabled, sla_response_hours |
| stripe_price_id_monthly / _annual | string | — | Stripe price IDs |
| status | enum: active, archived | — | |
| setup_fee_gbp | number | — | One-time setup fee |
| contract_template_url | string | — |
2.2 Tenancy & Onboarding
Organisation base44/entities/Organisation.jsonc
A subscriber organisation on a product. The central tenancy record — most other entities reference it.
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | Product this org subscribes to |
| company_name | string | ✓ | |
| status | enum: prospect, trial, active, suspended, churned | — | Lifecycle status |
| subscription_plan_id | string | — | |
| plan_type | enum: starter, growth, pro, enterprise | — | |
| mrr | number | — | Monthly recurring revenue |
| primary_contact_name/email/phone | string | — | |
| company_address, company_website, industry, company_size | string | — | |
| billing_cycle | enum: monthly, annual | — | |
| billing_currency | string | — | ISO 4217, default GBP |
| country | string | — | Customer country for tax determination |
| vat_number | string | — | Customer VAT/GST/Tax ID |
| vat_validated | boolean | — | Validated via VIES/Stripe |
| tax_exempt | boolean | — | No tax charged (reverse-charge B2B) |
| subscription_start_date, subscription_renewal_date | date | — | |
| stripe_customer_id, stripe_subscription_id | string | — | |
| payment_method_type | enum: card, direct_debit, bank_transfer, invoice | — | |
| admin_notes | string | — | |
| last_activity_date | date-time | — | |
| active_users_count | number | — | |
| logo_url | string | — | |
| onboarding_workflow_id | string | — | Linked OnboardingWorkflow |
| encryption_key_version | number | — | Default 1 |
| data_classification | enum: standard, sensitive, restricted | — | Default standard |
| health_status | enum: healthy, at_risk, critical | — | Auto-calculated |
| health_score | number | — | 0-100, auto-calculated |
| health_checked_at | date-time | — | |
| sentiment_status | enum: happy, neutral, unhappy, unknown | — | Manually set by account team |
| sentiment_updated_at, sentiment_updated_by_name | — |
ClientUser base44/entities/ClientUser.jsonc
A user within a client organisation who can access the Client Portal. Passwords are SHA-256 hashed (salt = user id).
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| full_name | string | — | |
| string | ✓ | ||
| role | enum: business_admin, business_user | ✓ | |
| status | enum: active, suspended, revoked | — | |
| invited_by_id, invited_by_name, invited_at | — | ||
| revoked_at, revoked_reason | — | ||
| password_hash | string | — | SHA-256(salt+password) |
| has_set_password | boolean | — | |
| password_reset_token, password_reset_expires | — | ||
| last_login | date-time | — |
ClientPortalSession base44/entities/ClientPortalSession.jsonc
Token-based session for the Client Portal. Issued via magic link or password login; no Base44 auth required.
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| user_id | string | — | Linked ClientUser (null for magic-link-only) |
| session_token | string | ✓ | The token carried in ?token= query param |
| session_type | enum: onboarding, billing, settings, support | ✓ | |
| expires_at | date-time | ✓ | |
| created_at, last_accessed_at | date-time | — | |
| ip_address | string | — | |
| status | enum: active, expired, revoked | — | Default active |
OnboardingWorkflow base44/entities/OnboardingWorkflow.jsonc
Tracks an organisation through the 8-stage onboarding lifecycle from prospect to active.
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| subscription_plan_id | string | ✓ | |
| status | enum: draft, invite_sent, contract_pending, contract_signed, payment_setup, payment_verified, provisioning, active, failed | — | Default draft |
| current_stage | number | — | Default 1 |
| total_stages | number | — | Default 8 |
| invited_by_id, invited_by_name | — | ||
| primary_contact_email, primary_contact_name, company_name | ✓ | ||
| billing_cycle | enum: monthly, annual | — | |
| contract_document_id, contract_signed_at, contract_signed_by | — | ||
| stripe_customer_id, stripe_subscription_id | — | ||
| payment_method_type | enum: card, direct_debit, bank_transfer, invoice | — | |
| payment_setup_completed_at | date-time | — | |
| provisioning_config | object | modules_configured[], api_keys_generated, webhooks_configured, custom_domain, branding_configured | |
| activated_at, failed_at, failure_reason, notes | — |
2.3 Support
Ticket base44/entities/Ticket.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | |
| organisation_id | string | ✓ | |
| ticket_number | string | — | Human-readable ID |
| subject | string | ✓ | |
| description | string | — | |
| status | enum: open, in_progress, pending_client, resolved, closed | — | Default open |
| priority | enum: critical, high, medium, low | — | Default medium |
| assigned_agent_id, assigned_agent_name | — | ||
| organisation_name | string | — | Denormalised |
| sla_hours | number | — | Default 24 |
| resolved_at, closed_at | date-time | — | |
| resolution_summary | string | — | |
| tags | string[] | — | |
| source | enum: client_portal, email, admin_created | — | Default admin_created |
| is_encrypted | boolean | — | Default true |
| encryption_key_version | number | — | Default 1 |
TicketMessage base44/entities/TicketMessage.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| ticket_id | string | ✓ | |
| saas_product_id | string | — | |
| sender_type | enum: agent, client, system | ✓ | |
| sender_name, sender_id | string | — | |
| content | string | ✓ | |
| is_internal_note | boolean | — | Default false |
| attachment_urls | string[] | — |
OtpSession base44/entities/OtpSession.jsonc
Time-limited OTP exchange letting a support agent request, and a client approve, temporary account access.
| Field | Type | Required | Description |
|---|---|---|---|
| ticket_id | string | ✓ | |
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| requesting_agent_id, requesting_agent_name | — | ||
| otp_code | string | — | Generated code sent to client |
| status | enum: pending, verified, active, expired, revoked | — | Default pending |
| expires_at | date-time | — | |
| verified_at, session_started_at, session_ends_at, session_ended_at | date-time | — | |
| end_reason | enum: timeout, manual, revoked | — | |
| verification_channel | enum: email, in_app, both | — | |
| verified_via | enum: email, in_app | — | |
| verification_ip | string | — |
SlaPolicy base44/entities/SlaPolicy.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | |
| name | string | ✓ | |
| tier | enum: starter, growth, pro, enterprise | ✓ | |
| first_response_hours | number | — | Default 24 |
| resolution_hours | number | — | Default 72 |
| priority_overrides | object | Per-priority response/resolution hours for critical/high/medium/low | |
| service_credit_percent | number | — | Credit on breach |
| is_active | boolean | — | Default true |
2.4 Billing & Revenue
Payment base44/entities/Payment.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | |
| organisation_id | string | ✓ | |
| organisation_name | string | — | |
| amount | number | ✓ | |
| currency | string | — | Default GBP |
| status | enum: paid, pending, failed, refunded, overdue | — | Default pending |
| gateway | enum: stripe, direct_debit, bank_transfer, other | — | Default stripe |
| billing_cycle | enum: monthly, annual | — | Default monthly |
| stripe_payment_intent_id, stripe_invoice_id, stripe_subscription_id | string | — | |
| invoice_number, invoice_pdf_url | string | — | |
| description | string | — | |
| payment_date | date-time | — | |
| due_date | date | — | |
| retry_count, next_retry_date | — | Dunning | |
| refund_reason | string | — | |
| subscription_plan_id | string | — | |
| billing_period_start, billing_period_end | date | — | |
| is_encrypted | boolean | — | Default true |
| payment_method_last4, payment_method_brand | string | — | |
| is_late | boolean | — | Default false |
| days_overdue | number | — | Default 0 |
CreditNote base44/entities/CreditNote.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| original_payment_id, original_invoice_number | string | — | |
| credit_note_number | string | — | |
| amount | number | ✓ | |
| currency | string | — | Default GBP |
| reason | enum: refund, billing_error, goodwill, cancellation, other | ✓ | |
| status | enum: issued, applied, void | — | Default issued |
| stripe_credit_note_id | string | — | |
| issued_by_id, issued_by_name | — | ||
| notes | string | — |
PaymentGateway base44/entities/PaymentGateway.jsonc
Configurable additional gateways (PayPal, Square, Adyen, etc.) managed in Settings → OTP & Payment Config.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | ✓ | |
| type | enum: stripe, paypal, square, authorize.net, adyen, wix_payments, other | ✓ | |
| api_key, secret, publishable_key | string | — | |
| webhook_url, webhook_secret | string | — | |
| status | enum: active, inactive, test_mode | — | Default inactive |
| is_primary | boolean | — | Default false |
| configuration | object | merchant_id, client_id, environment (sandbox/production) |
DunningPolicy base44/entities/DunningPolicy.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | |
| name | string | ✓ | |
| max_retries | number | — | Default 3 |
| retry_days | number[] | — | Default [1,3,5] |
| suspend_after_days | number | — | Default 14 |
| email_template_1, email_template_2, email_template_final | string | — | |
| is_active | boolean | — | Default true |
UsageRecord base44/entities/UsageRecord.jsonc
Usage metrics for metered billing plans, reported via the reportUsage function.
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| subscription_plan_id | string | — | |
| metric | string | ✓ | api_calls, storage_gb, active_users, … |
| quantity | number | ✓ | |
| unit | string | — | calls, GB, users |
| period_start, period_end | date | ✓ | |
| reported_by | string | — | API key or system |
| overage | number | — | Units beyond included_units |
2.5 Compliance & Audit
GdprRequest base44/entities/GdprRequest.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| request_type | enum: data_access, data_erasure, data_portability, rectification, objection | ✓ | |
| status | enum: received, in_review, in_progress, completed, rejected | — | Default received |
| requested_by_name, requested_by_email | string | — | |
| details | string | — | |
| assigned_to_id, assigned_to_name | — | ||
| due_date | date | — | GDPR: response within 30 days |
| completed_at | date-time | — | |
| resolution_notes | string | — |
TaxValidation base44/entities/TaxValidation.jsonc
Immutable audit record of each VAT validation (VIES or manual).
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | — | |
| saas_product_id | string | — | |
| vat_number | string | ✓ | |
| country_code | string | — | ISO 3166-1 alpha-2 |
| is_valid | boolean | ✓ | |
| validation_source | enum: vies, stripe, manual | — | Default vies |
| validated_name, validated_address | string | — | Returned by VIES |
| validation_date | date-time | — | |
| request_identifier | string | — | VIES audit identifier |
ComplianceCert base44/entities/ComplianceCert.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | |
| cert_type | enum: soc2_type1, soc2_type2, iso27001, iso27017, iso27018, gdpr, hipaa, pci_dss, fedramp | ✓ | |
| status | enum: active, in_progress, expired, not_started | — | Default not_started |
| issuer | string | — | Auditor / certification body |
| valid_from, valid_until | date | — | |
| document_url | string | — | |
| notes | string | — |
AuditLog base44/entities/AuditLog.jsonc
Append-only event log. Written by backend functions for every significant action.
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id, organisation_id, ticket_id, otp_session_id | string | — | Context ids |
| actor_id, actor_name | string | — | |
| actor_type | enum: admin, agent, finance, system, client | — | |
| event_type | string | ✓ | e.g. onboarding_initiated, vat_validation, payment_overdue |
| event_description | string | ✓ | Human-readable |
| metadata | object | — | Structured detail |
| ip_address | string | — |
2.6 Security / Encryption
EncryptedData base44/entities/EncryptedData.jsonc
Stores AES-256-GCM ciphertext plus IV, salt, auth tag. Created by encryptData, decrypted by decryptData.
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| data_type | enum: ticket, payment, document, configuration, message, custom | ✓ | |
| source_entity, source_entity_id | string | — | Back-reference to origin record |
| encrypted_data | string | ✓ | Hex ciphertext |
| iv | string | ✓ | Hex IV |
| salt | string | ✓ | Hex salt |
| auth_tag | string | ✓ | Hex GCM auth tag |
| key_version | number | — | Default 1 |
| encrypted_by_id | string | — | |
| created_at, last_accessed_at | date-time | — | |
| access_count | number | — | Default 0 |
EncryptedDataKey base44/entities/EncryptedDataKey.jsonc
Per-org, per-key-type encryption key record. Keys are derived from ENCRYPTION_MASTER_KEY via scrypt/PBKDF2.
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| key_type | enum: org_data, tickets, payments, documents, api_credentials | ✓ | |
| encrypted_key | string | ✓ | Derived key material reference |
| key_version | number | — | Default 1 |
| created_by_id | string | — | |
| created_at, last_rotated_at | date-time | — | |
| status | enum: active, revoked | — | Default active |
2.7 Knowledge Base
KbCategory base44/entities/KbCategory.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | |
| name | string | ✓ | |
| description | string | — | |
| sort_order | number | — | Default 0 |
KbTopic base44/entities/KbTopic.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| saas_product_id | string | ✓ | |
| saas_product_name | string | — | Denormalised |
| category_id, category_name | string | — | |
| title | string | ✓ | |
| summary | string | — | Plain-text snippet for search |
| body | string | — | Rich-text HTML (Quill) |
| tags | string[] | — | |
| status | enum: draft, published, archived | — | Default draft |
| version | number | — | Incremented on publish |
| sort_order | number | — | Default 0 |
| author_name | string | — | |
| published_at | date-time | — | |
| published_by_name | string | — | |
| view_count | number | — | Default 0 |
KbVersion base44/entities/KbVersion.jsonc
Immutable snapshot of a topic each time it is published — enables version history.
| Field | Type | Required | Description |
|---|---|---|---|
| topic_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| version | number | ✓ | |
| title | string | ✓ | |
| body | string | ✓ | HTML snapshot |
| published_by_name | string | — | |
| published_at | date-time | — |
2.8 CRM & Notifications
OrganisationInteraction base44/entities/OrganisationInteraction.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| interaction_type | enum: call, email, meeting, note, other | ✓ | Default note |
| summary | string | ✓ | |
| outcome_sentiment | enum: positive, neutral, negative | — | Default neutral |
| interaction_date | date-time | — | |
| created_by_id, created_by_name | — |
SurveyResponse base44/entities/SurveyResponse.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | ✓ | |
| survey_type | enum: nps, csat, ces | — | Default nps |
| score | number | ✓ | NPS 0-10, CSAT 1-5, CES 1-7 |
| comment | string | — | |
| trigger | enum: post_resolution, periodic, onboarding, manual | — | Default periodic |
| ticket_id | string | — | For post-resolution surveys |
| respondent_name, respondent_email | — |
Notification base44/entities/Notification.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| recipient_user_id | string | ✓ | |
| saas_product_id | string | — | |
| type | enum: new_ticket, ticket_update, ticket_resolved, otp_request, otp_verified, payment_failed, sla_breach, system | ✓ | |
| title | string | ✓ | |
| message | string | ✓ | |
| link_type | enum: ticket, organisation, payment, otp_session | — | |
| link_id | string | — | |
| is_read | boolean | — | Default false |
| is_email_sent | boolean | — | Default false |
Document base44/entities/Document.jsonc
| Field | Type | Required | Description |
|---|---|---|---|
| organisation_id | string | ✓ | |
| saas_product_id | string | — | |
| file_name | string | ✓ | |
| file_url | string | ✓ | |
| file_type | string | — | |
| file_size_kb | number | — | |
| uploaded_by_id, uploaded_by_name | — | ||
| description | string | — | |
| category | enum: contract, invoice, identity, technical, other | — | Default other |
3. Backend Functions
Backend functions live in base44/functions/<name>/entry.ts and run on the Deno runtime. They are invoked from the client via base44.functions.invoke('name', payload) or reached externally over HTTP (e.g. Stripe webhooks). Each function creates a client with createClientFromRequest(req), authenticates via base44.auth.me() (except public endpoints), and uses base44.asServiceRole to bypass user context where needed.
Shared modules
base44/shared/paymentGateway.ts abstracts Stripe customer/subscription/tax creation across functions. base44/shared/kbToken.ts signs/verifies HMAC Knowledge Base access tokens.3.1 Onboarding Lifecycle
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| initiateOnboarding | admin / organisations write | Creates an Organisation (status prospect) + OnboardingWorkflow (stage 1/8) from company + plan details. Validates plan belongs to product. Computes MRR from plan price & billing cycle. Writes AuditLog. Re-checks TeamMember organisations write permission. |
| sendOnboardingInvite | admin | Sends the onboarding invite email to the primary contact, advances workflow to invite_sent. |
| signContract | admin / client (session) | Records contract signature on the OnboardingWorkflow (contract_signed, stage 4), stores signed document. |
| setupPayment | client (session_token) | Called from the Client Portal. Validates ClientPortalSession, creates Stripe customer + subscription via paymentGateway abstraction, sets workflow to payment_verified (stage 6), org to trial, creates a pending Payment, calculates tax, then invokes generateInvoice. Writes AuditLog as actor_type client. |
| activateSubscription | admin | Final activation: workflow → active (stage 8), org → active, sets subscription dates, provisions config. |
| notifyOnboardingStage | system/admin | Sends stage-transition notification emails to the client contact. |
| notifyOnboardingStageChange | system/admin | Notifies internal team when an onboarding stage changes. |
3.2 Billing & Payments
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| generateInvoice | admin / payments write | Builds a branded A4 PDF invoice server-side with jsPDF (header, bill-to, line items, tax, totals, bank details, footer). Embeds CompanyProfile logo. Calculates tax via calculateTax. Uploads the PDF via Core.UploadFile, stores invoice_number/due_date/invoice_pdf_url on the Payment, creates a Document record, and notifies the finance team. Idempotent — returns existing invoice if already generated. Re-checks TeamMember payments write permission. |
| sendInvoiceReminder | admin/scheduled | Sends a reminder email 15 days before an invoice due date using the product reminder template. |
| checkOverduePayments | admin/scheduled | Scans pending payments with past due_date, marks them overdue (status=overdue, is_late, days_overdue), notifies finance team, writes AuditLog. Scheduled daily at 09:00. |
| notifyPaymentFailed | entity (Payment update) | Notifies finance team when a payment status becomes failed. |
| notifyPaymentOverdue | entity (Payment update) | Notifies finance team when a payment becomes overdue. |
| notifyOverduePayment | entity (Payment update) | Additional overdue notification (older variant). |
| stripeWebhook | public (Stripe signature) | Verifies Stripe webhook signature with STRIPE_WEBHOOK_SECRET. Handles invoice.payment_succeeded (→ paid), invoice.payment_failed (→ failed, retry_count+1, next_retry in 3 days), customer.subscription.updated (maps subscription status to payment status). Uses asServiceRole. |
| testGateway | admin | Tests a PaymentGateway connection (action=test_connection). |
stripeWebhook event handling
switch (event.type) {
case 'invoice.payment_succeeded': // Payment → paid, store payment_date + intent/invoice ids
case 'invoice.payment_failed': // Payment → failed, retry_count++, next_retry_date = +3 days
case 'customer.subscription.updated': // map {active:paid, past_due:pending, unpaid:pending,
// canceled:refunded, incomplete:pending}
}3.3 Tax
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| validateVatNumber | admin | Validates a VAT number via the EU VIES REST API for EU member states (falls back to format check for non-EU or VIES errors). Stores an immutable TaxValidation record, updates Organisation.vat_validated + vat_number, writes AuditLog. Returns validated name/address. |
3.4 Support & Tickets
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| notifyNewTicket | entity (Ticket create) | Notifies support admins/agents when a ticket is created. |
| notifyTicketAssigned | admin/system | Notifies an agent when a ticket is assigned to them. |
| notifyTicketUpdate | entity (Ticket update) | Notifies relevant parties on ticket updates. |
| notifyTicketStatusChange | admin/system | Notifies on status transitions (e.g. resolved, closed). |
| assignTicketAgent | admin | Assigns a ticket to an agent, updates assigned_agent_id/name. |
| requestScreenShareAccess | agent | Creates an OtpSession (status pending) requesting temporary client account access for a ticket; sends OTP code to the client contact via notifyOTPRequest. |
| verifyScreenShareOTP | client | Verifies the OTP code submitted by the client; if valid, activates the OtpSession (status active) for the configured session duration. |
| notifyOTPRequest | system | Sends the OTP request email to the client contact with the code and expiry. |
3.5 Client Portal
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| clientPortalAuth | public | Two actions: login (password) — verifies ClientUser password_hash (SHA-256 of salt+id+password), checks org not suspended/churned, issues an 8h ClientPortalSession; magic_link — issues a 24h session and emails a magic link. Portal URL origin derived from CompanyProfile.website. |
| createPortalSession | public | Legacy magic-link issuer: verifies email matches org primary contact, blocks suspended/churned orgs, creates a 7-day support session, emails the link. |
| setClientPassword | client (token) | Sets/updates a ClientUser password using a reset token; hashes and stores password_hash, sets has_set_password. |
3.6 Organisation & Customer Health
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| calculateOrgHealth | admin/scheduled | Recalculates health_score (0-100) for all active/trial orgs: starts at 100, −20 per overdue/failed payment (max −40), −15 if >3 open tickets, −15/−30 for >30/60 days inactive. Maps to health_status (≥70 healthy, ≥40 at_risk, else critical). Updates Organisation. Scheduled daily at 02:00. |
| notifyOrgStatus | admin/system | Notifies on organisation status changes. |
| notifyOrganisationStatusChange | admin/system | Notifies internal team when an org status changes (e.g. suspended, churned). |
| syncOrgAccess | admin | Synchronises accessible_organisation_ids / access scoping for a team member. |
| linkTeamMemberOnLogin | system | On login, links a platform User to a TeamMember record by email. |
3.7 Knowledge Base
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| generateKbToken | admin | Generates a signed HMAC test access token for a product + user email using the product kb_secret, so the team can verify the public KB wiring. |
| draftKbTopic | admin | Creates/updates a draft KbTopic (status draft). |
| publishKbTopic | admin | Publishes a KbTopic: sets status published, increments version, creates an immutable KbVersion snapshot, sets published_at/by. |
| getKbContent | public (token) | Public endpoint serving KB content to authenticated end-users of a product. Verifies the HMAC token signed with the product kb_secret; enforces that the user is an active, authenticated user of the product. |
3.8 Security & System
| Function | Auth | Purpose & Key Logic |
|---|---|---|
| encryptData | admin | Encrypts arbitrary JSON with AES-256-GCM. Derives a per-org key from ENCRYPTION_MASTER_KEY via scrypt. Returns ciphertext + IV + salt + auth_tag + key_version. Creates an EncryptedDataKey record on first use. |
| decryptData | admin | Decrypts an EncryptedData record: re-derives the key from ENCRYPTION_MASTER_KEY + stored salt via PBKDF2 (100k iterations, SHA-256), verifies the GCM auth tag, returns plaintext JSON. |
| checkUserPermission | admin | Server-side permission check helper — verifies a user has a required module level. |
| reportUsage | public (API key) | Records a UsageRecord for metered billing (metric, quantity, period). Called by product systems. |
| generateContract | admin | Generates a contract document for an onboarding workflow. |
3.9 Function Invocation Patterns
From the client (admin)
const res = await base44.functions.invoke('validateVatNumber', {
organisation_id, vat_number, country_code
});
// res.data holds the JSON responseFrom a backend function (service role)
await base44.asServiceRole.functions.invoke('generateInvoice', { payment_id: payment.id });External HTTP (Stripe webhook)
Register in Stripe at https://quantyxsolutions.base44.app/functions/stripeWebhook, subscribing to invoice.payment_succeeded, invoice.payment_failed, customer.subscription.updated.
4. Frontend & Routing
The frontend is a React SPA. src/App.jsx is the router and hosts all platform wrappers (AuthProvider, QueryClientProvider, BrowserRouter, Toaster). Routes are split into public Client Portal routes and authenticated admin routes wrapped by <AppLayout>.
4.1 Route Map
| Path | Component | Guard / Notes |
|---|---|---|
| /portal/login | ClientPortalLogin | Public — client portal entry |
| /portal/dashboard | ClientPortalDashboard | Public — token auth |
| /portal/tickets/:id | ClientPortalTicketDetail | Public — token auth |
| /portal/onboard | ClientPortalOnboarding | Public — onboarding flow |
| /portal/set-password | ClientPortalSetPassword | Public — token-based |
| /kb/:productId | KbPublic | Public — HMAC token-gated KB |
| /, /dashboard, /revenue-analytics | DashboardHub | AppLayout — tabs: Overview / Product / Revenue |
| /organisations | Organisations | AppLayout — organisations module |
| /organisations/:id | OrganisationProfile | AppLayout — multi-tab org detail |
| /tickets, /tickets/:id | Tickets / TicketDetail | AppLayout — tickets module |
| /payments, /credit-notes | BillingHub | PermissionGuard payments — tabs: Payments / Credit Notes |
| /gdpr-requests | GdprRequests | AppLayout |
| /notifications | Notifications | AppLayout |
| /customer-relationships | CustomerSuccess | PermissionGuard organisations |
| /team, /team/:id | SettingsHub / TeamMemberProfile | PermissionGuard settings (admin) |
| /settings, /settings/products/:id | SettingsHub / ProductDetail | PermissionGuard settings |
| /onboarding, /onboarding/success | Onboarding / OnboardingSuccess | AppLayout |
| /knowledge-base, /knowledge-base/:id | KnowledgeBase / KnowledgeBaseProduct | PermissionGuard knowledge_base |
| /master-documentation | MasterDocumentation | AppLayout — this page |
| * | PageNotFound |
4.2 Application Shell
| File | Responsibility |
|---|---|
| src/components/layout/AppLayout.jsx | Defines AppProviders (loads user, products, notification count; wraps PermissionsProvider) and the AppLayout shell (Sidebar + TopBar + Outlet). Handles access-pending and idle-timeout states. |
| src/components/layout/Sidebar.jsx | Collapsible nav, product switcher, permission-filtered nav items, company logo from CompanyProfile. |
| src/components/layout/TopBar.jsx | Product context, search, notification bell with unread count, profile dropdown, role badge. |
| src/components/layout/TabHub.jsx | Generic tabbed hub wrapper used by DashboardHub / BillingHub / SettingsHub. |
| src/components/layout/DashboardHub.jsx | Tabs: GlobalDashboard / Dashboard / RevenueAnalytics. |
| src/components/layout/BillingHub.jsx | Tabs: Payments / CreditNotes. |
| src/components/layout/SettingsHub.jsx | Tabs: Settings / Team (Team tab only for settings admins). |
4.3 Key Pages
| Page | Description |
|---|---|
| GlobalDashboard | Portfolio-level overview: MRR/ARR, revenue trends, product snapshots, operational alerts, product health table. Permission-filtered. |
| Dashboard | Per-product analytics: KPIs, revenue & subscriber charts, recent tickets, top orgs, renewals. |
| RevenueAnalytics | MRR/ARR/NRR/GRR, churn, MRR movement, tier breakdown, 90-day renewal pipeline. |
| Organisations | Searchable/filterable list of subscriber orgs with status, plan, MRR, health. |
| OrganisationProfile | Multi-tab org detail: Overview, Billing, Tickets, Documents, Users, Interactions, Usage, Tax, Client Portal Preview, Lifecycle. In-place edit, suspend/churn actions, VAT validation, document upload. |
| Tickets / TicketDetail | Ticket list + Kanban; detail with conversation thread, OTP access panel, screen-share panel, SLA timer. |
| Payments | Revenue summary, trend chart, searchable payment table with row expansion, invoice PDF download, CSV export. |
| CreditNotes | Issue/track credit notes with KPIs and status lifecycle. |
| Onboarding | 8-step wizard: company details → product/plan → review → submit (calls initiateOnboarding). |
| CustomerSuccess | CRM: health stats, at-risk table, recent interactions feed, survey feedback. |
| GdprRequests | GDPR request queue with 30-day deadlines, status workflow, creation form. |
| KnowledgeBase / KnowledgeBaseProduct | KB admin: categories, topics, Quill editor, version drawer, publish flow. |
| Settings | Tabbed: Company Profile, SaaS Products, Email Templates, Invoice Templates, OTP & Payment Config, SLA Policies, Dunning Policies, Compliance. |
| Team | Team member list, invite with role templates, PermissionEditor for granular per-product access. |
| ClientPortal* | Client-facing portal: login, dashboard, ticket detail, onboarding, set-password. Token-based. |
| KbPublic | Public KB view for end-users, HMAC token-gated per product. |
4.4 Component Catalog
| Directory | Components |
|---|---|
| ui/ | StatusBadge, StatCard, SlaTimer + shadcn primitives (button, card, dialog, table, tabs, select, etc.) |
| tickets/ | OtpAccessPanel, ScreenSharePanel, TicketKanban |
| organisation/ | UsageTab, OrgUsersTab, ClientPortalPreviewTab, RelationshipTab, TaxValidationTab, SentimentSelector, LifecycleTimeline, HealthSignalsCard, InteractionLogPanel |
| crm/ | CrmHealthStats, RecentInteractionsFeed, AtRiskTable |
| customer-success/ | SurveyFeedbackTab |
| dashboard/ | PortfolioRevenueChart, SubscriberStatusDonut, TierBreakdownCharts, ProductSnapshotCard, OperationalAlerts, ProductMixCharts, ProductHealthTable, MrrMovementChart |
| settings/ | CompanyProfileSettings, SlaPoliciesTab, DunningPoliciesTab, ComplianceCertsTab |
| products/ | ProductTierBuilder, ProductPlansTab |
| templates/ | EmailPreview, InvoicePreview |
| kb/ | KbVersionDrawer, KbSearch, KbTopicViewer, KbTopicEditor, KbEditor |
| docs/ | DocPrimitives, DocOverview, DocDataModel, DocBackend, DocFrontend, DocAutomations, DocIntegrations, DocCompliance, DocDeployment (this document) |
4.5 State & Data Fetching
AppContext(in AppLayout) — current user, products list, current product, unread notification count.PermissionsContext— resolved permissions,canAccessModule,canAccessOrganisation,canAccessSettingsSection,getModuleLevel.AuthContext— auth loading/error states, login redirect.- Entities are read with
base44.entities.<Name>.list/filter/get; realtime via.subscribe()(used for notifications and ticket messages). @tanstack/react-queryis available for query caching; most pages use local state + direct SDK calls.
Conventions
@/ alias. Pages/components are default-exported. Tailwind classes are literal strings. Icons come from lucide-react. Charts use solid lines only.5. Automations
Automations run backend functions automatically — on a schedule, on entity record changes, or on connector webhook events. They are managed via the Base44 dashboard or the automation tools. The app currently runs seven active automations.
5.1 Scheduled Automations
| Name | Function | Schedule | Purpose |
|---|---|---|---|
| Daily Customer Health Calculation | calculateOrgHealth | Every day at 02:00 | Recalculates health_score/health_status for all active & trial organisations. |
| Daily Overdue Payment Check | checkOverduePayments | Every day at 09:00 | Flags pending payments past their due_date as overdue, notifies finance, writes audit log. |
| Daily Invoice Reminder | sendInvoiceReminder | Every day at 08:00 | Sends payment-reminder emails 15 days before an invoice due date. |
5.2 Entity-Triggered Automations
| Name | Function | Entity | Event | Purpose |
|---|---|---|---|---|
| Notify Admins on New Ticket | notifyNewTicket | Ticket | create | Notifies support admins/agents when a ticket is created. |
| Notify Agent on Ticket Update | notifyTicketUpdate | Ticket | update | Notifies the assigned agent on ticket updates. |
| Notify Payment Failed | notifyPaymentFailed | Payment | update | Notifies finance team when a payment status becomes failed. |
| Notify Overdue Payment | notifyOverduePayment | Payment | update | Notifies finance team when a payment becomes overdue. |
No connector automations active
stripeWebhook) registered directly in Stripe, not a connector automation.6. Integrations & Environment
6.1 Core Integrations (built-in)
Always available via base44.integrations.Core.<Endpoint>:
| Endpoint | Use in Quantyx |
|---|---|
| InvokeLLM | LLM calls (optional features). Supports file_urls and add_context_from_internet (Gemini models only). Optional model selection. |
| SendEmail | Transactional emails — onboarding invites, OTP requests, invoice reminders, overdue notices, magic links. Reaches registered users always; non-registered addresses require a paid plan + custom domain. |
| UploadFile | Uploads generated invoice PDFs and client documents to storage; returns a file_url. |
| UploadPrivateFile | Uploads to private storage (returns file_uri for signed URLs). |
| CreateFileSignedUrl | Creates time-limited signed download URLs for private files. |
| GenerateImage | AI image generation. |
| GenerateSpeech | TTS audio generation. |
| GenerateVideo | AI video generation. |
| TranscribeAudio | Audio transcription (Whisper). |
| ExtractDataFromUploadedFile | Extracts structured data from CSV/XLSX/JSON/PDF/images. |
6.2 Stripe (Payments)
Stripe is the primary payment gateway, accessed through the shared base44/shared/paymentGateway.tsabstraction (createCustomer, createSubscription, calculateTax,formatCurrency). The stripeWebhook function receives Stripe events over HTTP.
Stripe setup steps
- Set
STRIPE_SECRET_KEYandSTRIPE_WEBHOOK_SECRETas environment variables (Base44 dashboard → Settings → Environment Variables). - Register the webhook endpoint in Stripe at
https://quantyxsolutions.base44.app/functions/stripeWebhook. - Subscribe to
invoice.payment_succeeded,invoice.payment_failed,customer.subscription.updated. - Use
sk_test_...keys for development,sk_live_...for production; re-register the webhook per environment.
Optional stripe_tax_enabled on each SaasProduct enables automatic VAT/GST via Stripe Tax; plan tax_code maps to Stripe Tax product tax codes.
6.3 EU VIES (VAT Validation)
The validateVatNumber function calls the EU VIES REST API (ec.europa.eu/taxation_customs/vies/rest-api/check-vat-number) for EU member states, falling back to a format check for non-EU or unreachable VIES. Results are stored in TaxValidation and reflected on the Organisation.
6.4 Environment Variables / Secrets
| Variable | Required by | Purpose |
|---|---|---|
| STRIPE_SECRET_KEY | stripeWebhook, setupPayment, generateInvoice (via paymentGateway) | Stripe API authentication |
| STRIPE_WEBHOOK_SECRET | stripeWebhook | Verifies Stripe webhook signatures |
| ENCRYPTION_MASTER_KEY | encryptData, decryptData | Master secret from which per-org AES-256-GCM keys are derived (scrypt/PBKDF2) |
Where to set secrets
6.5 Available App Connectors (not yet connected)
The platform supports OAuth connectors (Google Workspace, Slack, GitHub, Salesforce, HubSpot, Notion, Jira, Linear, etc.) but none are currently authorized. When needed, use get_connectors_info → request_oauth_authorization (shared) or register_workspace_connector (app-user/BYO).
7. Security & Compliance
Quantyx is designed to handle sensitive client organisational data and support regulated SaaS products. This section documents the full compliance posture across access control, encryption, GDPR, OTP-gated access, audit logging, and data classification.
7.1 Authentication & Session Security
- Admin Portal — Base44-owned auth (token-based sessions, email verification). The app never implements its own auth backend.
- Idle timeout —
useIdleTimeoutwarns at 25 min and force-logs-out at 30 min (SessionTimeoutWarning). - Client Portal — token-based sessions (
ClientPortalSession): 8h for password login, 24h for magic link, 7h for legacy createPortalSession. Sessions carry an IP address and can be revoked. - Client passwords — SHA-256 hashed with a per-user salt (user id); stored in
ClientUser.password_hash.has_set_passwordgates login. - Suspended/churned orgs — portal login and session creation are blocked for
suspended/churnedorganisations.
7.2 Role-Based Access Control (RBAC)
Access is enforced in two layers — frontend gates and backend re-checks — so a crafted client request cannot bypass permissions.
Permission model
- Each staff user maps to a
TeamMemberwith arole_template(super_admin, support_agent, finance, custom) and one or morepermission_sets. - Each permission set grants a level (
none | read | write | admin) per module:dashboard, organisations, tickets, payments, otp_access, settings, knowledge_base. The highest level across sets wins. accessible_organisation_idsscopes which client orgs a user can see (empty = all).accessible_settings_sectionsscopes which Settings tabs are visible (empty = all).- Platform users with
role='admin'are super admins (bypass all gates).
Enforcement points
| Layer | Mechanism |
|---|---|
| Frontend routes | PermissionGuard wraps protected routes; redirects on insufficient access. |
| Frontend data/UI | usePermissions() filters nav, lists, and actions; canAccessOrganisation scopes records. |
| Backend functions | initiateOnboarding, generateInvoice, etc. re-check TeamMember module level before acting. |
| Access-pending | Authenticated users with no active TeamMember (and not platform admin) see AccessPendingScreen. |
Row-Level Security
accessible_organisation_ids filter. If stricter DB-level isolation is later required, RLS rules can be added per entity under the rls key in each schema.7.3 Data Encryption at Rest
Sensitive client data is encrypted with AES-256-GCM (authenticated encryption) via the encryptData/decryptData functions.
- Key derivation — a 256-bit key is derived per organisation + key-type from
ENCRYPTION_MASTER_KEYusing scrypt (encryptData) / PBKDF2 with 100,000 iterations and SHA-256 (decryptData). - Key records —
EncryptedDataKeytracks per-org keys (status active/revoked, key_version, last_rotated_at) for key rotation. - Ciphertext record —
EncryptedDatastoresencrypted_data(hex),iv,salt,auth_tag,key_version, plus anaccess_countand back-reference to the source entity. - Integrity — the GCM auth tag is verified on decryption, detecting any tampering.
- Flagging —
Ticket.is_encryptedandPayment.is_encryptedmark records whose sensitive payload is encrypted.
Production hardening
EncryptedDataKey.encrypted_key (wrapped by a KMS-managed master key) and rotate ENCRYPTION_MASTER_KEY with dual-key overlap during rotation.7.4 GDPR & Data Subject Rights
The GdprRequest entity tracks data-subject requests with a statutory 30-day response deadline.
| Request type | Right |
|---|---|
| data_access | Right of access (Art. 15) |
| data_erasure | Right to be forgotten (Art. 17) |
| data_portability | Data portability (Art. 20) |
| rectification | Rectification (Art. 16) |
| objection | Objection (Art. 21) |
- Each request has a status workflow (
received → in_review → in_progress → completed/rejected), an assignee, adue_date(30 days), andresolution_notes. - The
GdprRequestsadmin page surfaces overdue and imminent-deadline requests. Organisation.data_classification(standard | sensitive | restricted) flags the sensitivity of stored data to prioritise handling.
7.5 OTP-Gated Account Access
Support agents can request temporary access to a client's account via a time-limited OTP exchange — the client must explicitly approve.
Agent (in TicketDetail) → requestScreenShareAccess creates OtpSession (status=pending), generates otp_code → notifyOTPRequest emails code to client contact Client (via portal/email) → verifyScreenShareOTP verifies code → OtpSession status=active session window = product.otp_session_duration_minutes (default 30) Expiry → status=expired (end_reason=timeout) Agent/manual revoke → status=revoked
- OTP expiry:
SaasProduct.otp_expiry_minutes(default 15) — how long the code is valid. - Session duration:
SaasProduct.otp_session_duration_minutes(default 30) — how long access stays active after approval. - Verification channel (
email | in_app | both) and IP address are recorded for audit. - Every OTP event is written to
AuditLog.
7.6 Audit Logging
The AuditLog entity is an append-only event trail. Backend functions write to it for every significant action.
| Field | Purpose |
|---|---|
| actor_type | admin / agent / finance / system / client |
| actor_id, actor_name | Who performed the action |
| event_type | e.g. onboarding_initiated, vat_validation, payment_overdue, payment_setup_completed |
| event_description | Human-readable summary |
| metadata | Structured detail (ids, amounts, plan, etc.) |
| saas_product_id, organisation_id, ticket_id, otp_session_id | Context ids |
| ip_address | Where available |
Examples of audited events: onboarding initiation, VAT validation, payment setup completion, payment overdue marking, invoice generation.
7.7 Compliance Certifications
The ComplianceCert entity tracks each product's certification posture: soc2_type1/type2, iso27001/27017/27018, gdpr, hipaa, pci_dss, fedramp, with status (active | in_progress | expired | not_started), issuer, validity window, and document URL. Managed in Settings → Compliance.
7.8 Knowledge Base Access Control
End-user KB access is token-gated. The getKbContent public endpoint verifies an HMAC token signed with the product's kb_secret, ensuring only authenticated, active users of a product can read its KB. generateKbToken (admin-only) mints test tokens. KB topic edits are versioned via KbVersion snapshots on publish.
7.9 Data Classification Summary
| Classification | Meaning | Handling |
|---|---|---|
| standard | Routine business data | Default access controls |
| sensitive | Personal or confidential data | Encrypted at rest (EncryptedData), access scoped |
| restricted | Regulated / high-risk data | Encryption + strict org scoping + audit on every access |
8. Deployment & Operations
8.1 Published Application
The app is published at https://quantyxsolutions.base44.app. For external webhook URLs (e.g. Stripe), use https://quantyxsolutions.base44.app/functions/<functionName>. From inside app code, invoke functions through the SDK (base44.functions.invoke(...)), not an absolute URL.
8.2 Custom Domain
A custom domain can be connected for the public-facing surfaces. The clientPortalAuth function derives the portal magic-link origin from CompanyProfile.website (falling back to the platform domain), so updating the website field in Settings → Company Profile updates the magic-link base URL. For links a user clicks in the UI, prefer the connected custom domain.
8.3 Local Development
# install dependencies npm install # run the dev server (Vite) npm run dev # build for production npm run build
The project is Vite + React (ESM). Use @/ import aliases. Backend functions run on the Deno runtime and are edited in base44/functions/*/entry.ts.
8.4 Environment Setup Checklist
| Step | Where | Detail |
|---|---|---|
| Set STRIPE_SECRET_KEY | Base44 → Settings → Env Vars | sk_test_... or sk_live_... |
| Set STRIPE_WEBHOOK_SECRET | Base44 → Settings → Env Vars | whsec_... from Stripe webhook endpoint |
| Set ENCRYPTION_MASTER_KEY | Base44 → Settings → Env Vars | Strong random secret for AES key derivation |
| Register Stripe webhook | Stripe Dashboard → Developers → Webhooks | https://quantyxsolutions.base44.app/functions/stripeWebhook |
| Configure CompanyProfile | Settings → Company Profile | Company name, logo, address, bank details, payment_terms_days, website (portal origin) |
| Create SaasProduct(s) | Settings → SaaS Products | Name, API base, OTP callback, billing config, kb_secret |
| Create SubscriptionPlans | Product detail page | Tiers, pricing, Stripe price IDs, tax codes |
| Invite team members | Team page | Role template + per-product permission sets |
| Set SLA & Dunning policies | Settings → SLA / Dunning | Per product/tier |
8.5 Operational Automations (always-on)
calculateOrgHealth— daily 02:00 — keeps health scores fresh.checkOverduePayments— daily 09:00 — flags overdue invoices.sendInvoiceReminder— daily 08:00 — 15-day pre-due reminders.- Entity automations fire on Ticket create/update and Payment update (see §5).
8.6 Monitoring & Maintenance
- Audit trail — query
AuditLogfor any action's actor, time, and metadata. - Notifications — the in-app bell +
Notificationspage surface system and finance alerts; unread count is realtime-subscribed inAppProviders. - Automation health — check
last_run_statusandconsecutive_failuresvia the automations tools. - Key rotation — rotate
ENCRYPTION_MASTER_KEYwith overlap;EncryptedDataKey.key_versionsupports versioned decryption.
8.7 Extending the App
- New entity — add
base44/entities/<Name>.jsonc(full JSON schema, no placeholders); access viabase44.entities.<Name>. - New backend function — add
base44/functions/<name>/entry.ts; reuse shared logic inbase44/shared/; test withtest_backend_function. - New page — add
src/pages/<Name>.jsx, import + add a<Route>insrc/App.jsx, and a sidebar nav item inSidebar.jsx. - New automation — use
create_automation(scheduled / entity / connector). - New connector —
get_connectors_info→ authorize or register, then build connector-backed features.
8.8 Known Limitations & Future Hardening
- RLS is application-layer only; add DB-level RLS rules if regulatory requirements demand enforced row isolation.
- Encryption keys are derived on demand from the master secret; wrap derived keys with a KMS-managed master key for full production hardening.
- Stripe is the only connected payment processor; additional gateways are configurable via
PaymentGatewayrecords and thetestGatewayfunction. - No OAuth connectors are connected yet; the platform supports them when needed.