ITSM

CMDB

Configuration Management Database — CI classes, all attributes, relationship types, topology graph, and discovery integration.

Overview

The Configuration Management Database (CMDB) stores configuration items (CIs) — every component of your IT infrastructure and the relationships between them. CIs can be hardware, software, services, applications, network devices, or any abstraction you choose to track. The CMDB powers topology visualisation, impact analysis, change risk assessment, and incident enrichment.

CI Classes

CIs are organised into classes. Each class defines the attributes available on that CI type. FlowOS ships with the following built-in classes:

ClassSlugDescription
Business Servicebusiness_serviceAn IT service that delivers value to users. Top level in dependency chains.
ApplicationapplicationA software application. May depend on servers, databases, and services.
ServerserverA physical or virtual server. Has hardware attributes (CPU, RAM, disk).
Virtual Machinevirtual_machineA VM hosted on a hypervisor. Child of a server CI.
ContainercontainerA Docker/Kubernetes container or pod. Child of a VM or cluster.
DatabasedatabaseA database instance (Postgres, MySQL, Redis, etc.).
Network Devicenetwork_deviceRouter, switch, firewall, load balancer.
Storage Devicestorage_deviceSAN, NAS, object storage bucket.
Cloud Resourcecloud_resourceAny cloud-managed resource (EC2, GKE node pool, Lambda, etc.).
MiddlewaremiddlewareMessage broker, API gateway, cache layer, etc.
Software Packagesoftware_packageInstalled software tracked for licensing and vulnerability management.
CertificatecertificateTLS/SSL certificate with expiry tracking.
DNS Recorddns_recordA DNS entry that resolves to a service endpoint.
EndpointendpointUser device: laptop, mobile, workstation.
LocationlocationPhysical location (data centre, office, rack).
TeamteamAn organisational team CI used to link ownership across resources.

Base CI Fields (all classes)

FieldTypeRequiredDefaultDescription
idstring (ci_...)requiredautoUnique identifier. Format: ci_ + ULID.
numberstringrequiredautoHuman-readable number (CI-NNNN).
namestringrequiredDisplay name of the configuration item.
classenumrequiredCI class slug (see table above).
statusenumoptionalactiveactive · maintenance · decommissioned · retired. Affects incident impact calculations.
environmentenumoptionalproductiondevelopment · staging · production
descriptiontextoptionalFree-text description of the item.
ownerTeamstringoptionalTeam slug responsible for this CI.
ownerUserIdstring (usr_...)optionalIndividual responsible for this CI.
tagsstring[]optional[]Free-form labels.
externalIdstringoptionalID in an external CMDB, asset management tool, or cloud provider.
attributesobject (jsonb)optional{}Class-specific attributes (see below).
relationshipsobject[] (read-only)optionalcomputedAll relationships this CI participates in. Computed. See relationships section.
createdAttimestampoptionalautoRecord creation time.
updatedAttimestampoptionalautoLast modification time.

Class-Specific Attributes

server / virtual_machine

FieldTypeRequiredDefaultDescription
hostnamestringoptionalFQDN or short hostname.
ipAddressesstring[]optionalList of IPv4/IPv6 addresses.
osstringoptionalOperating system name and version.
cpuCoresintegeroptionalNumber of CPU cores.
ramGbdecimaloptionalRAM in gigabytes.
diskGbdecimaloptionalTotal disk in gigabytes.
regionstringoptionalCloud region or data centre name.
providerstringoptionalaws · gcp · azure · on_premise · other
instanceTypestringoptionalCloud instance type (e.g. m5.2xlarge).

database

FieldTypeRequiredDefaultDescription
enginestringoptionalpostgres · mysql · oracle · mssql · redis · mongodb · elasticsearch · other
versionstringoptionalDatabase engine version.
hoststringoptionalDatabase hostname or endpoint URL.
portintegeroptionalDatabase port.
databaseNamestringoptionalPrimary database/schema name.
replicationstringoptionalnone · primary · replica · multi_master
haEnabledbooleanoptionalWhether high-availability or clustering is enabled.

certificate

FieldTypeRequiredDefaultDescription
domainstringoptionalPrimary domain (CN) on the certificate.
sanDomainsstring[]optionalSubject alternative names.
issuedBystringoptionalCertificate authority name.
issuedAtdateoptionalIssue date.
expiresAtdateoptionalExpiry date. FlowOS alerts 30 and 7 days before expiry.
autoRenewbooleanoptionalWhether auto-renewal is configured.

Relationship Types

Relationships connect CIs in the topology graph. Each relationship has a type and a direction.

TypeDirectionDescription
depends_onA → BA cannot function without B. Used for upstream dependency mapping.
runs_onA → BA (app/container) runs on B (server/VM). Physical/virtual hosting.
hosted_byA → BA (DB/service) is hosted by B (cloud provider/data centre).
connects_toA ↔ BNetwork connectivity. Non-directional dependency.
part_ofA → BA is a component of B (rack-level or cluster membership).
owned_byA → BA is owned/managed by B (team CI or user).
usesA → BA uses B (e.g. app uses a shared library or DNS record).
backs_up_toA → BA is backed up to B (backup target).
fails_over_toA → BA fails over to B in a HA or DR setup.
monitorsA → BA (monitoring tool CI) monitors B.

Hardware, Network & Compliance Fields

Beyond the base fields, every CI (regardless of class) carries a set of hardware, network, data-centre and monitoring/compliance attributes directly on the record — these are plain schema fields, not entries in the free-form attributes bag.

Network & hardware

FieldTypeRequiredDefaultDescription
ipAddressstringoptionalnullPrimary IPv4/IPv6 address.
macAddressstringoptionalnullMAC address of the primary network interface.
fqdnstringoptionalnullFully-qualified domain name.
osNamestringoptionalnullOperating system name, e.g. "Ubuntu", "Windows Server".
osVersionstringoptionalnullOS version or build string.
cpuCountnumberoptionalnullNumber of CPUs / vCPUs.
cpuTypestringoptionalnullCPU model/type.
ramGbnumberoptionalnullRAM in gigabytes.
storageGbnumberoptionalnullTotal storage in gigabytes.

Data centre & virtualisation

FieldTypeRequiredDefaultDescription
datacenterstringoptionalnullData centre or facility name.
rackstringoptionalnullRack identifier.
rackUnitstringoptionalnullRack-unit (U) position.
clusterstringoptionalnullCluster name (VM/container host cluster).
virtualHostIdObjectId (ref CI)optionalnullThe CI this one runs on, e.g. a hypervisor host.
containerImagestringoptionalnullContainer image name.
containerRegistrystringoptionalnullRegistry the image was pulled from.
networkZonestringoptionalnullNetwork/security zone, e.g. "dmz", "internal".
vlanstringoptionalnullVLAN identifier.

Monitoring & compliance

FieldTypeRequiredDefaultDescription
monitoringEnabledbooleanoptionalfalseWhether this CI is actively monitored.
showOnStatusPagebooleanoptionalfalseWhether health is surfaced on a public status page.
monitoringToolIdstringoptionalnullIdentifier of the external monitoring tool tracking this CI.
backupEnabledbooleanoptionalfalseWhether backups are configured for this CI.
backupSchedulestringoptionalnullBackup schedule description/cron.
lastBackupAtdateoptionalnullTimestamp of the last successful backup.
patchGroupstringoptionalnullPatch/maintenance group this CI belongs to.
lastPatchedAtdateoptionalnullTimestamp this CI was last patched.
openIncidentCountnumberoptional0Count of currently open incidents linked to this CI.
complianceStatusenumoptionalunknowncompliant · non_compliant · unknown. Set automatically by CI Compliance drift scans (see below).
discoverySourceenumoptionalmanualmanual · agent · agentless · import — how this CI record was populated.
lastDiscoveredAtdateoptionalnullLast time automated discovery updated this record.
dataQualityScorenumber (0-100, read-only)optionalnullField-completeness score. See Data Quality Score below.

CI Lifecycle Transition Validation

CIs use a 9-state lifecycle: ordered · installed · configured · active · maintenance · inactive · decommissioning · retired · disposed. A model-level hook enforces which transitions are legal:

From statusAllowed next statuses
orderedinstalled, retired
installedconfigured, active, retired
configuredactive, maintenance, retired
activemaintenance, inactive, decommissioning, retired
maintenanceactive, inactive, retired
inactiveactive, maintenance, decommissioning, retired
decommissioningretired
retireddisposed
disposednone — terminal state

Any other transition is rejected with an error of the form Invalid lifecycle transition: active → ordered. Allowed: maintenance, inactive, decommissioning, retired, and the save fails — the status change is not persisted.

Only enforced on document .save()
This check runs inside a Mongoose pre('save') hook, so it only fires when a CI document is saved via .save() — which happens on CI creation. The standard PATCH /api/cmdb/cis/:id update endpoint applies changes with findOneAndUpdate, which does not run save middleware, so status changes made through that endpoint are not currently checked against this table.

CMDB Data Quality Score

Each CI carries a computed dataQualityScore (0–100) that reflects how complete its record is. The score is a weighted sum over 18 fields — a field counts as “present” if it is not null, undefined, an empty string, or 0:

FieldTypeRequiredDefaultDescription
ownerIdweight 10optionalCounted if set.
supportGroupIdweight 10optionalCounted if set.
nameweight 5optionalAlways set on valid CIs.
ciClassweight 5optionalAlways set on valid CIs.
serialNumberweight 5optional
assetTagweight 5optional
locationweight 5optional
datacenterweight 5optional
environmentweight 5optional
ipAddressweight 5optional
osNameweight 5optional
ramGbweight 5optionalA value of exactly 0 counts as missing.
cpuCountweight 5optionalA value of exactly 0 counts as missing.
healthStatusweight 5optional
lastDiscoveredAtweight 5optional
monitoringEnabledweight 5optionalfalse counts as missing (falls back to 0).
purchaseCostweight 5optionalA value of exactly 0 counts as missing.
vendorNameweight 5optional

The earned weight divided by the total (100) is rounded to the nearest integer and stored on dataQualityScore.

Also only recalculated on .save()
Like the lifecycle check above, this is a pre('save') hook, so it is recalculated when a CI is created but not when it is edited through the standard update endpoint (which uses findOneAndUpdate).

CI Configuration Compliance

Baseline & drift detection for CI configuration, gated behind the feature_ci_compliance flag. A baseline captures the expected value of one or more fields, scoped to either specific CIs (ciIds) or an entire CI class (ciClass). Baselines can be typed by hand or captured from a live CI via snapshotFromCiId.

FieldTypeRequiredDefaultDescription
namestringrequiredBaseline name.
descriptionstringoptionalFree-text description.
ciClassstringoptionalScope: apply to all CIs of this class.
ciIdsObjectId[]optionalScope: specific CIs. Takes precedence over ciClass.
snapshotobjectrequiredMap of field name → expected value.

Running POST /compliance/baselines/:id/scan loads every CI in scope and, for each one, compares the live value of each field named in the snapshot against the expected value (via a JSON string comparison). Any mismatch is recorded as a { field, expected, actual } drift entry. If a CI has one or more drifted fields its status is drifted, otherwise compliant — and the scan writes that result straight back onto the CI's complianceStatus field (non_compliant / compliant). Drift results are upserted per (baseline, CI) pair, so re-running a scan updates the existing record rather than duplicating it.

A drift item can be marked remediated via POST /compliance/drift/:id/remediate — this only changes the drift record's status (and records who/when); it does not modify the CI or re-scan it.

bash
POST /api/cmdb/compliance/baselines
{
  "name": "Prod DB baseline",
  "ciClass": "database",
  "snapshotFromCiId": "665f1...",
  "snapshot": { "osVersion": "", "patchGroup": "", "backupEnabled": "" }
}

Software Asset Management (SAM)

SAM, gated behind feature_sam, is a set of read-mostly views built on top of the existing InstallBase collection (see Install Base below) filtered to assetClass in software/license. It does not introduce a new storage model.

FieldTypeRequiredDefaultDescription
GET /dashboardendpointoptionalHeadline counts: total, active (lifecycleState=in_use), expired, expiringSoon (30 days), overAllocated (quantityUsed > quantity), and an overall complianceRate.
GET /softwareendpointoptionalPaginated list of software/license InstallBase records, filterable by status, licenseType, supplierName, search (product name).
GET /complianceendpointoptionalGroups records by productName and sums quantity (entitled) vs quantityUsed. Status per product: over_allocated, at_limit, or compliant; surplus = entitled − used.
GET /expiringendpointoptionalRecords whose licenseExpiry or warrantyExpiry falls within `days` (default 30, max 365). Emits a cmdb.install_base_expiring event per record.
POST /normalizeendpointoptionalStub product-name normalizer: returns existing productName values that fuzzy-match the input (case-insensitive substring), for future canonicalisation.
GET /publishersendpointoptionalDistinct, sorted list of supplierName values across software/license assets.

CI ↔ ITSM Linking

Bidirectional linking between CIs and Incidents, Changes, and Problems. Attaching or detaching a CI on either side re-resolves the record's business-service linkage (via the CMDB impact-linkage service) so that businessServiceId/impactedServiceIds stay in sync with the current set of affected CIs.

  • Incident — primary ciId plus an affectedCiIds array.
  • ChangeRequestaffectedCiIds array plus derived impactedServiceIds.
  • Problem — a single rootCauseCiId plus an affectedCiIds array.

A combined view is available per CI at GET /cis/:id/affected-records, returning all non-closed incidents, changes, and problems that reference it (as primary, root cause, or affected CI).

Alert Storm Suppression

When a CI has autoCreateIncident enabled (or the tenant default is on) and its health status changes to down or degraded, FlowOS auto-creates an incident — but repeated flapping shouldn't flood the queue with duplicate incidents. Alert suppression windows prevent that:

  1. 1

    A health update arrives (manual PATCH/POST /cis/:id/health, or an external monitoring push to POST /monitoring/push) with a new status of down or degraded.

  2. 2

    FlowOS checks for an AlertSuppression record for that CI with status: 'active' whose startedAt falls within the last ci.suppressionWindowMinutes (default 5) minutes.

  3. 3

    If one is found, the alert is suppressed: suppressedCount and alertCount are incremented and lastAlertAt is updated — no new incident is created.

  4. 4

    If none is found, a new incident is created (priority critical for down, high for degraded), and — if ci.maxAlertsBeforeSuppress (default 3) is greater than 0 — a fresh AlertSuppression window is opened, linked to that incident.

FieldTypeRequiredDefaultDescription
ciIdObjectId (ref CI)requiredCI this suppression window applies to.
startedAtdaterequiredWhen the window opened.
lastAlertAtdaterequiredTimestamp of the most recent alert seen (suppressed or not).
alertCountnumberoptional1Total alerts observed in this window, including the triggering one.
suppressedCountnumberoptional0How many of those alerts were suppressed (i.e. did not create an incident).
linkedIncidentIdObjectId (ref Incident)optionalThe incident created when the window opened.
statusenumoptionalactiveactive · resolved.
resolvedAtdateoptionalSet when resolved.
The CI-level knobs are suppressionWindowMinutes (default 5) and maxAlertsBeforeSuppress (default 3). In the current implementation maxAlertsBeforeSuppress only gates whether a suppression window is opened at all (must be > 0) — it is not used as a hard cap on alertCount. There is also no scheduled job that flips old windows to resolved; a window simply stops matching once its startedAt falls outside the lookback, and the next alert for that CI opens a new one.

Install Base — Asset Inventory

The InstallBase collection tracks individual hardware, software, cloud, virtual, and license assets — separate from (but optionally linked to) a CMDB CI via ciId. It carries financial, lifecycle, assignment, and ITSM-linkage detail that doesn't belong on the CI record itself.

FieldTypeRequiredDefaultDescription
ciIdObjectId (ref CI)optionalLinked configuration item, if any.
assetClassenumoptionalsoftwarehardware · software · cloud · virtual · license · other
lifecycleStateenumoptionalin_useon_order · in_stock · in_use · in_maintenance · retired · disposed · lost_stolen
quantitynumberoptional1Units/seats entitled (e.g. licenses purchased).
quantityUsednumberoptional1Units/seats currently allocated. Used by SAM compliance checks.
purchaseCostnumberoptional0Original purchase cost.
currentValuenumberoptional0Current book value.
depreciationMethodenumoptionalnonestraight_line · declining_balance · none
depreciationYearsnumberoptional0Useful life in years.
assignedUserIdObjectId (ref User)optionalUser this asset is assigned to.
assignedDepartmentstringoptional
licenseExpirydateoptionalFor software/license assets.
warrantyExpirydateoptionalFor hardware assets.
linkedIncidentIdsObjectId[] (ref Incident)optionalIncidents raised against this asset.
linkedChangeIdsObjectId[] (ref ChangeRequest)optionalChanges affecting this asset.

GET /install-base accepts status, type/assetClass, and customerId filters, plus two added for cross-linking asset views into other record types: ciId (powers the “Assets” tab on a CI detail page) and assignedUserId (powers an “Equipment” tab on an employee/user detail page).

The write endpoints accept a few legacy aliases for compatibility: nameproductName, assetTypeassetClass, manufacturermake, poNumberpurchaseOrderNumber, and a status string (e.g. "ordered", "deployed") that is mapped onto the real lifecycleState enum.

Depreciation & Expiry Jobs

Asset Depreciation Calculator

Runs monthly (1st of the month at 02:00 UTC — checked every 15 minutes, guarded so it fires once per month). It recalculates currentValue on CmdbCi records (not InstallBase records) that have depreciationMethod of straight_line or declining_balance, a status other than retired/disposed, purchaseCost > 0, and a purchaseDate.

text
ageYears = (now - purchaseDate) / 365.25 days
depYears = ci.depreciationYears ?? 5

straight_line:
  annualDepreciation = purchaseCost / depYears
  newValue = max(0, purchaseCost - annualDepreciation * ageYears)

declining_balance (double-declining):
  fixedRate = 2 / depYears
  newValue = max(0, purchaseCost * (1 - fixedRate) ^ ageYears)

The result is rounded to 2 decimal places and written to currentValue only if it differs from the stored value by more than $0.01.

Asset Expiry Check

Runs daily at 09:00 UTC across every active tenant (also invocable on demand as cron script cmdb_install_base_expiry_check). It scans non-retired/disposed InstallBase records whose licenseExpiry, warrantyExpiry, or contractExpiry falls within the next 30 days.

For each matching record, recipients are the asset's assignedUserId plus, if it is linked to a CI, that CI's ownerId and technicalOwnerId. A system notification is created per recipient for each of the license/warranty dates that is actually within the window — type asset_expiry_critical if ≤ 7 days out, otherwise asset_expiry_warning — with a title, body, and meta: { assetId, expiryType, daysUntilExpiry }.

contractExpiry is part of the query that selects which records are “expiring”, but the notification step only generates alerts for the licenseExpiry and warrantyExpiryfields — a record pulled in solely because its contract is expiring soon won't itself produce a notification.

API Quick Reference

GET
/api/v1/cmdb/items

List CIs with class, status, and tag filters

POST
/api/v1/cmdb/items

Create a CI

GET
/api/v1/cmdb/items/:id

Get CI with all attributes and relationships

PATCH
/api/v1/cmdb/items/:id

Update CI fields and attributes

DELETE
/api/v1/cmdb/items/:id

Retire (soft-delete) a CI

POST
/api/v1/cmdb/items/:id/relationships

Add a relationship to another CI

DELETE
/api/v1/cmdb/items/:id/relationships/:relId

Remove a relationship

GET
/api/v1/cmdb/topology

Get full topology graph as { nodes, edges }

GET
/api/v1/cmdb/items/:id/impact

Get upstream/downstream impact chain for a CI

CI Compliance

GET
/api/cmdb/compliance/baselines

List compliance baselines

POST
/api/cmdb/compliance/baselines

Create a baseline (optionally from a CI snapshot)

POST
/api/cmdb/compliance/baselines/:id/scan

Run a drift scan against all CIs in scope

GET
/api/cmdb/compliance/drift

List drift results, filterable by baselineId/status/ciId

POST
/api/cmdb/compliance/drift/:id/remediate

Mark a drift item remediated

GET
/api/cmdb/compliance/summary

Aggregate compliance rate across all CIs

Software Asset Management

GET
/api/sam/dashboard

Headline license compliance metrics

GET
/api/sam/software

List software/license assets

GET
/api/sam/compliance

Per-product entitled vs. used license counts

GET
/api/sam/expiring

Software/license assets expiring within N days

POST
/api/sam/normalize

Suggest canonical product names

GET
/api/sam/publishers

Distinct publisher/supplier list

CI ↔ ITSM Linking

GET
/api/cmdb/cis/:id/affected-records

Combined open incidents, changes, and problems for a CI

POST
/api/cmdb/cis/:id/incidents/:incidentId/link

Link an incident to a CI

POST
/api/cmdb/cis/:id/changes/:changeId/link

Link a change to a CI

POST
/api/cmdb/cis/:id/problems/:problemId/root-cause

Set a CI as a problem's root cause

POST
/api/cmdb/incidents/:id/affected-cis

Attach one or more CIs to an incident

POST
/api/cmdb/changes/:id/affected-cis

Attach one or more CIs to a change

POST
/api/cmdb/problems/:id/affected-cis

Attach one or more CIs to a problem

Health & Alert Suppression

GET
/api/cmdb/health/dashboard

Healthy/degraded/down counts across all CIs

PATCH
/api/cmdb/cis/:id/health

Set CI health status (may trigger auto-incident + suppression)

GET
/api/cmdb/cis/:id/health-history

Health change event history for a CI (last 100 events)

POST
/api/cmdb/monitoring/token

Generate a token for external monitoring push

POST
/api/cmdb/monitoring/push

Token-authenticated external health push (no JWT)

Install Base

GET
/api/cmdb/install-base

List assets — filterable by status, assetClass, ciId, assignedUserId

POST
/api/cmdb/install-base

Create an asset record

PATCH
/api/cmdb/install-base/:id

Update an asset record

GET
/api/cmdb/install-base/expiring

Assets with license/warranty expiry within 30 days