Agent Skillsnetalertx/NetAlertX › netalertx-database-patterns

netalertx-database-patterns

GitHub

提供NetAlertX Devices表写入路径审计及*Source字段归属机制指南,辅助设计数据写入、审计日志及触发器方案。

.github/skills/database-patterns/SKILL.md netalertx/NetAlertX

Trigger Scenarios

设计涉及Devices表写入的功能 实现审计或历史日志记录 选择触发器与Python钩子方案

Install

npx skills add netalertx/NetAlertX --skill netalertx-database-patterns -g -y
More Options

Non-standard path

npx skills add https://github.com/netalertx/NetAlertX/tree/main/.github/skills/database-patterns -g -y

Use without installing

npx skills use netalertx/NetAlertX@netalertx-database-patterns

指定 Agent (Claude Code)

npx skills add netalertx/NetAlertX --skill netalertx-database-patterns -a claude-code -g -y

安装 repo 全部 skill

npx skills add netalertx/NetAlertX --all -g -y

预览 repo 内 skill

npx skills add netalertx/NetAlertX --list

SKILL.md

Frontmatter
{
    "name": "netalertx-database-patterns",
    "description": "NetAlertX database architecture patterns. Use this when designing features that write to the Devices table, implementing audit\/history logging, or choosing between trigger-based vs Python-hook approaches."
}

Database Patterns

Devices Table — Write-Path Inventory

Before implementing any feature that reads or writes the Devices table, audit ALL write paths. The table is modified from many locations — missing one path is a correctness bug.

Known production write paths (as of 2026-07-04):

File Function Fields written
server/models/device_instance.py setDeviceData() All user-editable fields
server/models/device_instance.py updateField() Any single field (workflows)
server/models/device_instance.py updateDeviceColumn() Any single column
server/models/device_instance.py deleteDevices() etc. DELETE operations
server/scan/device_handling.py update_devices_data_from_scan() Scan-derived fields
server/scan/device_handling.py update_vendors_from_mac() devVendor, devVendorSource
server/scan/device_handling.py Name resolution block devName, devFQDN, *Source
server/scan/device_handling.py update_ipv4_ipv6() devPrimaryIPv4, devPrimaryIPv6
server/scan/device_handling.py update_icons_and_types() devIcon, devType
server/scan/device_handling.py update_presence_from_CurrentScan() devPresentLastScan
server/scan/device_handling.py update_devLastConnection_from_CurrentScan() devLastConnection
server/scan/device_handling.py update_devPresentLastScan_based_on_*() devPresentLastScan
server/db/authoritative_handler.py enforce_source_on_user_update() *Source columns
server/db/authoritative_handler.py lock_field() / unlock_field() *Source columns
server/models/notification_instance.py clearPendingEmailFlag() devLastNotification
server/plugins/db_cleanup/script.py cleanup_database() DELETE operations

Key insight: Most scan functions use sql.executemany() — there is no per-row Python state available. Python hooks before/after executemany require a pre-fetch+diff pattern that is expensive and error-prone.


*Source Fields — Attribution System

The FIELD_SOURCE_MAP in server/db/authoritative_handler.py defines 10 fields that carry write attribution via paired *Source columns:

FIELD_SOURCE_MAP = {
    "devMac":           "devMacSource",
    "devName":          "devNameSource",
    "devFQDN":          "devFQDNSource",
    "devLastIP":        "devLastIPSource",
    "devVendor":        "devVendorSource",
    "devSSID":          "devSSIDSource",
    "devParentMAC":     "devParentMACSource",
    "devParentPort":    "devParentPortSource",
    "devParentRelType": "devParentRelTypeSource",
    "devVlan":          "devVlanSource",
}

*Source values: 'USER', 'LOCKED', 'NEWDEV', or a plugin prefix (e.g., 'ARPSCAN', 'NSLOOKUP').

These fields are updated in the same transaction as the primary field. A SQLite AFTER UPDATE trigger can read NEW.devNameSource to obtain correct attribution without any extra context-passing.

Attribution rules for features that need changedBy:

Field category Attribution
In FIELD_SOURCE_MAP COALESCE(NULLIF(NEW.<field>Source, ''), 'system')
User-only fields (devGroup, devComments, devFavorite, devOwner, devLocation, etc.) 'user:api' — only setDeviceData() writes these
Auto-computed fields (devIcon, devType, devPrimaryIPv4, devPrimaryIPv6) 'system'
*Source fields themselves 'system'

Cross-Cutting Concerns — Prefer SQLite Triggers Over Python Hooks

When a feature needs to intercept every write to the Devices table (audit logging, computed columns, cascading logic), prefer a SQLite AFTER UPDATE / AFTER INSERT trigger over Python-layer hooks.

Why:

  • Triggers catch all 14+ write paths automatically, including executemany() bulk updates
  • Zero modifications to existing write-path functions (DRY)
  • Self-healing: future write paths are automatically covered
  • Attribution is available via NEW.*Source fields (see above)

When Python hooks are still appropriate:

  • The logic needs access to Python objects, settings, or services not available in SQL
  • The feature only fires from one or two known write paths
  • The logic is too complex to express in SQL (multi-table joins with app-layer business logic)

Trigger Performance Pattern

CREATE TRIGGER trg_example
AFTER UPDATE ON Devices
FOR EACH ROW
-- Guard: short-circuit entire body when feature is disabled (zero cost)
WHEN (SELECT CAST(setValue AS INTEGER) FROM Settings WHERE setKey = 'FEATURE_ENABLED') > 0
BEGIN
  -- Per-field conditional insert
  INSERT INTO SomeTable (devGUID, column, oldVal, newVal, changedBy, ts)
  SELECT NEW.devGUID, 'devName', OLD.devName, NEW.devName,
         COALESCE(NULLIF(NEW.devNameSource, ''), 'system'),
         datetime('now', 'utc')
  WHERE OLD.devName IS NOT NEW.devName
    AND instr(',' || (SELECT setValue FROM Settings WHERE setKey = 'TRACKED_FIELDS') || ',', ',devName,') > 0;
  -- Repeat for each tracked field...
END;

Performance: The Settings table is tiny (~100 rows) and stays in SQLite's page cache. Per-row Settings reads inside triggers are effectively in-memory lookups. The WHEN guard makes the disabled state zero-cost.


Snapshot vs Event-Sourced Audit Logging

When implementing change history, always use event-sourced (per-field rows) not snapshots (full row copies).

Event-sourced Snapshot
Storage Small — only changed fields Large — all 40+ columns every mutation
Filter by field O(log n) via index O(n) — must diff every adjacent pair
Filter by source O(log n) via index Not possible without diffing
changedBy attribution Embedded at write time Not available without extra context
Retention calculation Simple timestamp DELETE Same, but much higher storage

At 1000 devices, 5-min scan interval, 14-day retention: snapshot storage ≈ 280 MB/day. Event-sourced storage for the same workload is typically <1 MB/day (most scans produce no tracked field changes).


DevicesHistory Table — Reference Schema

CREATE TABLE IF NOT EXISTS DevicesHistory (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    devGUID      TEXT NOT NULL,
    timestamp    DATETIME DEFAULT CURRENT_TIMESTAMP,
    changedBy    TEXT NOT NULL,
    changedColumn TEXT NOT NULL,
    oldValue     TEXT,
    newValue     TEXT,
    FOREIGN KEY (devGUID) REFERENCES Devices(devGUID) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_devhist_guid_column ON DevicesHistory(devGUID, changedColumn);
CREATE INDEX IF NOT EXISTS idx_devhist_timestamp   ON DevicesHistory(timestamp);

Version History

  • 548d698 Current 2026-08-19 22:09
  • 8aec57b 2026-07-24 22:14

Same Skill Collection

.gemini/skills/devcontainer-management/SKILL.md
.gemini/skills/mcp-activation/SKILL.md
.gemini/skills/project-navigation/SKILL.md
.gemini/skills/settings/SKILL.md
.gemini/skills/skills-index/SKILL.md
.gemini/skills/testing-workflow/SKILL.md
.github/skills/api-development/SKILL.md
.github/skills/authentication/SKILL.md
.github/skills/code-standards/SKILL.md
.github/skills/database-reset/SKILL.md
.github/skills/devcontainer-configs/SKILL.md
.github/skills/devcontainer-services/SKILL.md
.github/skills/devcontainer-setup/SKILL.md
.github/skills/docker-build/SKILL.md
.github/skills/docker-prune/SKILL.md
.github/skills/mcp-activation/SKILL.md
.github/skills/plugin-run-development/SKILL.md
.github/skills/project-navigation/SKILL.md
.github/skills/sample-data/SKILL.md
.github/skills/settings-management/SKILL.md
.github/skills/skills-overview/SKILL.md
.github/skills/testing-workflow/SKILL.md

Metadata

Files
0
Version
548d698
Hash
2f1483bf
Indexed
2026-07-24 22:14

Главная - Вики-сайт
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-20 10:22
浙ICP备14020137号-1 $Гость$