Skip to main content
CYPEX Documentation
Support
v2.0.0 Latest stable release View changelog ->

Organizations setup guide

10 min read

This page is the operational counterpart to the conceptual pages in the Organizations section. It targets operators who run CYPEX, the PostgreSQL Application Platform, in production and need to perform the four day-to-day jobs: create, edit, and disable organizations; give users access to an organization; configure org-scoped application visibility (Schema Access); and troubleshoot misconfigurations.

For the why behind the model, see the conceptual pages linked below.

Concepts you need first

Read these four pages before walking through the procedures:

Quick Navigation

This guide is organized as step-by-step procedures followed by a troubleshooting section and a performance callout:

Info
Who can do what. Reading the organization list is open to system admins and organization admins. Creating, editing, deleting, and mapping roles to organizations are system-admin operations. An organization admin therefore sees the Organizations & Data Scope page without the Create Organization button.

How to create an organization

  1. Open Admin PanelOrganizations. The page is titled Organizations & Data Scope.

Organizations list in the admin panel

The Organizations & Data Scope list view in the CYPEX admin panel.

The Organizations & Data Scope list view in the CYPEX admin panel.
  1. Click Create Organization. The button is visible to system admins only.

  2. Fill in the form:

    • Organization Name (name) — the display name shown throughout the admin panel.
    • Company Name (company_name) — the legal entity behind the organization.
    • Organization Domain (organization_domain) — the URL-safe slug. The field sanitizes your input as you type.
    • Description — optional free text.
    • Organization Status, under Status & Settings — leave enabled for a live organization.

Create Organization form

The Create Organization form, with Organization Name, Company Name, Organization Domain, Description, and Organization Status.

The Create Organization form, with Organization Name, Company Name, Organization Domain, Description, and Organization Status.
Tip
Slug rules. organization_domain must be non-empty and contain only lowercase letters, digits, and hyphens. Uniqueness is enforced by the organization_domain_unique constraint on cypex.t_organization, so a collision surfaces as a failed save rather than a field-level validation message. Pick a different slug, or rename the organization that already holds it. See Organization hierarchy and assignment for the full invariants.
  1. Click Create Organization to save.
Tip
Auto-provisioned primary module. Saving registers a module named cypex_<organization_domain> in cypex.t_module and maps it to the organization as its primary module in cypex.t_module_organization, inside the same transaction as the organization insert. This is a catalog entry: the physical PostgreSQL schema is created separately when you enable a schema for the organization under Schema Access. A freshly created organization therefore never has zero modules and never has zero primary modules.
  1. Confirm the new row in the Organizations & Data Scope list. The list shows Users (users holding a role mapped to this organization) and Schemas (modules the organization can reach). A new organization starts at zero users and one schema.

How to edit an organization

  1. Open Admin PanelOrganizations.
  2. Click the row for the organization you want to edit.
  3. Change the fields you need and click Update Organization.
Warning
Renaming the organization_domain. The slug is unique across all organizations, enforced at the database level on both create and update. An update that would duplicate an existing slug fails the save. Pick a different slug, or free up the existing one first.

How to disable an organization

  1. Open Admin PanelOrganizations.
  2. Click the row for the organization you want to disable.
  3. Turn off Organization Status and save.
Warning
What disabling does and does not do. Clearing Organization Status sets is_active = false on cypex.t_organization. No row-level security policy reads this column — org scoping is driven by the organization_ids claim in the caller’s JWT — so a user with a live session keeps their access until the token is reissued. Treat the flag as an administrative marker, and revoke the role’s organization mapping under Roles if you need to cut access immediately.
Info
Delete is permanent and cascades widely. Deleting removes the cypex.t_organization row outright. Foreign keys with ON DELETE CASCADE propagate to the organization’s module and role mappings and to its owned records in t_ui, t_notification, t_file, t_report, t_query_group, t_export_job, t_import_job, and the connector tables. Other organizations' data and the permission audit log are unaffected. Export anything you need before deleting.

How to give users access to an organization

Data scope is attached to roles, not to individual users. A user reaches an organization’s data because the role they hold is mapped to it.

  1. Open Admin PanelRoles.
  2. Find the role and click the View Details icon.
  3. In the role details dialog, switch to the Organizations tab and click Edit Assignments.
  4. Add at least one organization the role should reach.

Organization Mapping Editor

Adding an organization mapping to an existing role.

Adding an organization mapping to an existing role.
Info
Business rule. An Organization Member or Organization Administrator role must be mapped to at least one organization, or the save fails. A System Administrator role must be mapped to none — it already has global reach, and the admin panel rejects a mapping. See Capabilities vs Data Scope.
  1. Save the assignment.

  2. Verify the mapping. cypex.t_role_organization stores the role by name:

    1
    2
    3
    4
    
    SELECT ro.role_name, o.organization_domain
    FROM cypex.t_role_organization ro
    JOIN cypex.t_organization o ON o.id = ro.organization_id
    ORDER BY ro.role_name, o.organization_domain;
    
  3. Have the affected users sign out and back in. Organization mappings are carried in the organization_ids JWT claim and only take effect on the next token issue.

How to configure org-scoped application visibility (Schema Access)

  1. Open Admin PanelSchema Access.
Info
Module = Schema. In CYPEX, “Module” and “Schema” refer to the same concept — a PostgreSQL schema. See What is an Organization?.
  1. Pick the organization you want to configure.
  2. Add a module/schema to the organization.

Schema Access — add a module

Adding a module/schema to an organization in the Schema Access editor.

Adding a module/schema to an organization in the Schema Access editor.
Tip
Safe to retry. Adding a module that is already assigned is a no-op, not an error. You do not need to check whether the assignment exists first.
  1. Each organization has exactly one primary module — the default namespace for organization-scoped custom queries and autogenerated views, not a routing target for user data. It is set automatically when the organization is created and is marked with a Primary chip. There is currently no admin-panel control for changing which module is primary.
  2. Remove any modules the organization should no longer reach. Removal is scoped to that organization; other organizations’ mappings are untouched.

Troubleshooting

User can’t see any data after the upgrade

Cause: The user’s role has no t_role_organization mapping, or their JWT is missing the org_id claim.

Solution:

  1. Inspect the user’s access token and confirm org_id, organization_ids, and isOrganizationAdmin are present and non-null. Decode the payload with any JWT tool, or from a shell:

    1
    
    cut -d. -f2 <<<"$TOKEN" | base64 -d 2>/dev/null | jq .
    

    organization_ids is omitted when the set is empty, and is not present on refresh tokens — check an access token.

  2. Query the mapping:

    1
    2
    3
    4
    5
    
    -- t_role_organization stores the role as a name, not an OID.
    SELECT ro.role_name, o.organization_domain
    FROM cypex.t_role_organization ro
    JOIN cypex.t_organization o ON o.id = ro.organization_id
    WHERE ro.role_name = '<role_name>';
    

    If the query returns zero rows, the role has no organization membership. Add the mapping via Admin Panel → Roles, then have the user re-authenticate.

User can see data from another organization

Cause: One of three — the record belongs to a module mapped to the other organization, a stale JWT carrying an old org_id, or an incorrect t_role_organization mapping.

Solution:

  1. cypex.t_object is a metadata catalog and carries no organization_id. Object visibility is resolved through the module mapping, so check that instead:

    1
    2
    3
    4
    5
    
    SELECT o.object_name, m.module_name, mo.organization_id, mo.is_primary
    FROM cypex.t_object o
    JOIN cypex.t_module m ON m.id = o.module_id
    JOIN cypex.t_module_organization mo ON mo.module_id = m.id
    WHERE o.id = <object_id>;
    

    For records in your own application tables, query the organization_id column on the table itself.

  2. Inspect the JWT’s org_id claim. If it does not match the organization the record belongs to, the user is acting under the wrong context — log them out and back in.

  3. Inspect t_role_organization for the user’s role. If the role is mapped to the wrong organization, fix the mapping and have the user re-login.

An organization admin is denied an action

Cause: Organization admins can read the organization list and see the users in their own organizations, but cannot create, edit, or delete organizations, or map roles to them. Those actions are reserved for system admins, and the admin panel refuses them rather than hiding the failure.

Solution: Sign in with a system-admin account, or ask a system admin to perform the action. If a control you expect is missing rather than failing, the admin panel has already hidden it for your admin level — the Create Organization button, for example, is not rendered for organization admins.

Duplicate domain error on save

Cause: The organization_domain you tried to save already exists for another organization. Uniqueness is enforced by a database constraint on both create and update, so the failure surfaces as a save error rather than a field-level validation message.

Solution: Pick a different slug, or rename the existing organization to free up the domain.

Adding the same module twice succeeds

Cause: By design. A module can be assigned to an organization only once, and re-assigning it is treated as a no-op rather than an error.

Solution: No action needed. The operation is safe to retry.

Audit log shows ACCESS_DENIED

Cause: ACCESS_DENIED entries in cypex_log.t_permission_audit_log come from two checks: an organization admin reaching into an internal CYPEX schema (org_admin_cannot_access_internal_schemas), and a caller acting on an organization outside their mapped set (org_out_of_scope). The reason is recorded inside the row’s context payload, not in a dedicated column — read it with context ->> 'reason'.

Solution: For org_out_of_scope, add the missing mapping under Roles and have the user re-authenticate so the new organization_ids claim is minted. Internal schemas remain system-admin only by design. See Capabilities vs Data Scope.

Performance considerations

CYPEX scopes tenant data with row-level security and an organization_id column, not with declarative partitioning. Filtering by organization is cheap because the multi-tenancy migrations add B-tree indexes on organization_id for the framework tables (t_ui, t_notification, t_file, t_report, t_query_group, t_export_job, t_import_job, t_function_metadata), plus partial indexes on cypex.t_organization for the active-organization lookups the admin panel performs.

Indexing custom entity tables

Custom entity tables you add to your CYPEX application are your responsibility — the framework indexes do not cover them.

  • Give each table an organization_id column and index it. A (organization_id, <natural_key>) composite is what gives the planner its selectivity against the RLS predicate.
  • Put organization_id first in a composite index. The leftmost-column rule applies — (name, organization_id) does not help WHERE organization_id = ? AND name = ?.
  • Use partial indexes for boolean flags. A plain index on a boolean column is rarely useful; a partial index such as WHERE is_active = true is what keeps filtered list views fast at scale.
  • Give cross-org aggregates their own index shape. system-admin dashboards that span all organizations will full-scan if they reuse the per-org index.
  • Run ANALYZE after bulk loads. Importing a large batch for a single organization leaves stale planner statistics and can route the next query to a sequential scan.