Skip to content

[API][UI] Manually add a network asset — hand-entered discovered_assets rows (source='manual') with full network-device parity (monitors, alerts, SNMP, tunnels, topology), incl. website/URL targets #5213

Description

@ToddHebebrand

Problem

An MSP cannot hand-add a network asset that a scan does not reach (a printer on an unscanned VLAN, a VPN appliance at a remote site, a customer website or SaaS endpoint) and have it behave like every other network device: appear in the unified Devices list, take monitors on the poll cycle, raise alerts, be SNMP-polled, be tunnelled to, and sit in the topology.

Split out of #4622 on 2026-09-07. #4622 stays the simpler non-network inventory record (manual_assets, option B in its spec). The rule between the two: if it has a network identity, it is a network asset and lives here; if it does not, it is a manual asset under #4622.

Current state (verified on main 2026-09-07)

  • discovered_assets has no create route at all: only approve/dismiss/link/edit/delete (apps/api/src/routes/discovery.ts), and its only writers are the scan worker and UniFi sync. ip_address is inet NOT NULL and half of discovered_assets_org_ip_unique (org_id, ip_address) (apps/api/src/db/schema/discovery.ts).
  • Standalone monitors already exist: POST /monitors takes an optional assetId and a free-text target for icmp_ping | tcp_port | http_check | dns_check (apps/api/src/routes/monitors.ts:228-231), with CreateMonitorForm and the Monitoring page. So an HTTP check on a website works today, but it is a monitor with no asset behind it and never appears in the Devices list.
  • Everything "a network device has" is keyed on a discovered_assets row: jobs/monitorWorker.ts (probe agent chosen by the asset's site), routes/monitors.ts, routes/snmp.ts, routes/monitoring.ts, routes/tunnels.ts, routes/partnerApi/inventory.ts, routes/devices/network.ts, services/networkBaseline.ts, services/aiToolsMonitoring.ts, services/discoveredAssetClassification.ts, jobs/reconcileTopology.ts. Parity therefore means: a manual network asset is a discovered_assets row.

Proposed behavior

  • POST /devices/network (or /discovery/assets) + "Add network asset" from the Devices list and the Monitoring page: org + site (required), name/label, asset type, IP and/or hostname, optional URL for website-type rows, manufacturer/model, notes, tags. Born approval_status = 'approved', type_source = 'manual'.
  • New columns on discovered_assets: source enum (scan | unifi | manual, NOT NULL, backfilled from discovery_methods/UniFi linkage), url (nullable). Add website (and possibly service) to discovered_asset_type.
  • Decision (recommendation inline): allow ip_address NULL for manual rows so websites and DNS-only targets can be assets; make discovered_assets_org_ip_unique partial on ip_address IS NOT NULL. Alternative: keep IP NOT NULL and resolve the hostname at create time — rejected because a website's IP is not stable and the row would go stale.
  • Guards, each with a test: manual rows never enter the pending-approval queue; the scan upsert on (org_id, ip_address) already respects type_source = 'manual' for type — extend the same guard to label; a scan that finds a manual row's IP updates it in place (one identity, no duplicate row); disappeared-asset events key on last_seen_at IS NOT NULL so a never-scanned manual IP does not alert on the first sweep of its subnet; host(ip_address) search and any ORDER BY ip_address are NULL-safe.
  • Export policy: classify every new column (source, urlincluded); no new cascade registration — the table is already in every list.

Acceptance criteria

  • Create a network asset with an IP from the Devices UI; it appears in the unified list's Network segment and in the partner inventory API.
  • Enable monitoring on it → ICMP/TCP/HTTP/DNS checks run on the poll cycle from a probe agent at the asset's site; alert rules fire.
  • Create a website asset with a URL and no IP; an http_check monitor attached to it shows status in the list.
  • A later scan of the same IP updates the manual row in place (no duplicate, operator-set type and label preserved).
  • Guards above covered by unit tests; export-policy suite green for the new columns.

Related

#4622 (manual non-network assets), #1424 (per-asset detail pages), #1322 (network arm), #3451 (link/unlink).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions