- Run ruff format on setup.py to fix pre-existing style violations
- Add CredentialProfile import to models/__init__.py so SQLAlchemy
can resolve the Device.credential_profile relationship in tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SQLAlchemy couldn't resolve ForeignKey("snmp_profiles.id") because
there's no SNMPProfile ORM model — profiles are managed via raw SQL.
The FK constraint exists at the DB level via migration 039. The ORM
column is now a plain UUID.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- POST /tenants/{tenant_id}/devices/bulk endpoint with rate limiting
- bulk_add_with_profile service validates profile ownership and type compatibility
- Duplicate IP check prevents adding same IP twice in one tenant
- TCP reachability check for RouterOS devices, skipped for SNMP (UDP)
- Per-device result reporting with partial success support
- Device model updated with device_type, snmp_port, snmp_version, snmp_profile_id columns
- Audit logging for bulk add operations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SQLAlchemy model mapping to credential_profiles table (migration 037)
- CredentialProfileCreate with model_validator enforcing per-type required fields
- CredentialProfileUpdate with conditional validation on type change
- CredentialProfileResponse without any credential fields (write-only)
- Device model updated with credential_profile_id FK and relationship
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create Alembic migration 035 with site_alert_rules and site_alert_events tables, RLS policies, and GRANT
- Add SiteAlertRule/SiteAlertEvent ORM models with enums for rule_type, severity, state
- Add Pydantic schemas for rule/event CRUD and signal history points
- Add SIGNAL_DEGRADATION_THRESHOLD_DB, ALERT_EVALUATION_INTERVAL_SECONDS, TREND_DETECTION_INTERVAL_SECONDS to Settings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create sectors table migration (034) with RLS and devices.sector_id FK
- Add Sector ORM model with site_id and tenant_id foreign keys
- Add SectorCreate/Update/Response/ListResponse Pydantic schemas
- Implement sector_service with CRUD and device assignment functions
- Add sectors router with GET/POST/PUT/DELETE and device sector assignment
- Register sectors router in main.py
- Add sector_id and sector_name to Device model and DeviceResponse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Migration 033 creates wireless_links with state machine, missed_polls, RLS
- WirelessLink model with LinkState enum (discovered/active/degraded/down/stale)
- Register DeviceInterface, WirelessLink, LinkState in models __init__
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Migration 032 creates device_interfaces with RLS, MAC index, unique(device_id, name)
- DeviceInterface SQLAlchemy model with all columns and device relationship
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add migration 030 with sites table, RLS policy, and device site_id FK
- Add Site SQLAlchemy model with tenant isolation
- Add site_id nullable FK and relationship to Device model
- Add sites relationship to Tenant model
- Register Site in models __init__.py
- Add SiteCreate, SiteUpdate, SiteResponse, SiteListResponse schemas
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move Base to app/models/base.py so alembic env.py can import it
without triggering engine creation (which connects to hardcoded DB)
- Update all 13 models to import Base from app.models.base
- Pin golangci-lint to latest (supports Go 1.25)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add RouterConfigSnapshot model with Transit ciphertext config_text
and SHA-256 plaintext hash for deduplication
- Add RouterConfigDiff model for unified diffs between snapshots
- Add RouterConfigChange model for parsed semantic changes
- Export all three from app.models barrel file
- Add unit tests for importability, table names, columns, and types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>