Multi-tenancy & data model

Every record in Jutsu belongs to exactly one organization, and that organization ID scopes all access. The boundary holds in both data planes: PostgreSQL rows carry an organization column, and OpenSearch events live in per-organization indices. This page explains the tenancy model and the entities it spans.

How tenancy works

Jutsu is multi-tenant by organization. A tenant is an organization, and all of its data — users, incidents, cases, credentials, events — is scoped to that organization's ID.

  • Transactional scoping. Tables in PostgreSQL carry an organization_id, and queries filter by it so one tenant never reads another's rows.
  • Search isolation. Normalized events are written to per-organization indices in OpenSearch, so a tenant's events occupy their own index space rather than a shared one.
  • Onboarding by invitation. People join an organization through invitations with an explicit lifecycle (pending, accepted, expired, revoked); members hold roles within that organization.

Per-organization indices

The ingest path writes each normalized event into a weekly, per-organization index:

org-{organizationId}-{year}-w{week}-events

Weekly rollover keeps each index bounded in size and makes age-based archival and deletion straightforward — old weeks can be dropped without touching current data. Reads use the org-{organizationId}-*-events pattern to span an organization's weeks while staying inside its tenant boundary.

Core entities

The entities below are the backbone of the data model. Field-level detail lives in the schema; this is the operator's map.

EntityKey fieldsNotes
Organizationsid, settings, per-severity SLA targetsThe tenant. Owns all other records.
Organization membersorganization, user, roleRoles include owner, admin, member, and analyst tiers (L1–L3).
Invitationsemail, statusLifecycle: pending → accepted / expired / revoked.
Usersemail, role, auth providerAuth via Google or local; platform-level role separate from org membership.
IncidentsINC-XXXX, severity, confidence, correlationSeverity critical–info; confidence 0–100; status active / resolved / closed; correlation reason, signals, and evidence.
Incident alertsalert, severity, correlation scoreThe alerts grouped into an incident.
Casesstatus, priority, severityStatus OPEN → IN_PROGRESS → PENDING → RESOLVED → CLOSED; priority P1–P4.
Case evidencekind, refEvidence of kind file, alert, or event attached to a case.
Case commentstype, bodyComments and notes on a case.
AgentSOAR credentialsprovider, resourcesConnected action providers and their resources.
AgentSOAR executionsstatus, capability, dedup keyRecords of dispatched response actions, with idempotency.
Copilot conversationsorganization, userAssistant chat threads, scoped per user and org.
Copilot messagesrole, contentMessages within a conversation (user, assistant, system).
Audit eventsactor, action, occurred atSystem and user-action audit trail.
Enum values and field names track the live database schema and can change between releases. Confirm specifics against your deployment's schema.

Relationships at a glance

Organization
├── Members ──▶ Users (via roles)
├── Invitations
├── Incidents (INC-XXXX)
│     └── Incident alerts
├── Cases (P1–P4, OPEN→CLOSED)
│     ├── Evidence (file / alert / event)
│     └── Comments
├── AgentSOAR credentials ──▶ Executions
├── Copilot conversations ──▶ Messages
└── Audit events