towerops/IMPLEMENTATION_PLAN.md
Graham McIntire c52f313e2d
1. User Authentication
- Full auth system with email/password (using phx.gen.auth)
  - Login, registration, password reset
  - Session management with remember-me functionality
  - Magic link login support

  2. Organization Management
  - Multi-tenant organization system
  - Organizations schema with unique slugs
  - Automatic organization creation when users register
  - Organization switcher UI at /orgs

  3. Membership System
  - Users can belong to multiple organizations
  - 4 permission levels: Owner, Admin, Member, Viewer
  - Complete permission matrix implemented
  - Join/leave organizations

  4. Invitation System
  - Email-based invitations with secure tokens
  - 7-day expiration on invites
  - Track who invited and who accepted

  5. Authorization
  - Full policy system (Organizations.Policy)
  - can?(membership, :action, :resource) helper
  - Enforced via plugs in router

  6. LiveView Pages
  - /orgs - List all your organizations
  - /orgs/new - Create new organization
  - /orgs/:slug - Organization dashboard (placeholder)

  7. Database Schema
  - users table
  - organizations table
  - organization_memberships table
  - organization_invitations table
  - All migrations run successfully
2025-12-21 13:31:59 -06:00

13 KiB

TowerOps - Network Monitoring & Alerting Platform

Implementation Plan

Overview

Multi-tenant network monitoring and alerting application for tracking network equipment health via ping monitoring.

Core Requirements

  1. User accounts (email as username)
  2. Organizations (multi-tenant)
  3. Organization membership with permission levels
  4. Site hierarchy
  5. Equipment management (IP-based)
  6. Automated ping monitoring (5-minute intervals)
  7. Alerting system

Data Model Design

Users

  • id (binary_id, PK)
  • email (string, unique, username)
  • hashed_password (string)
  • confirmed_at (utc_datetime, nullable)
  • inserted_at / updated_at (utc_datetime)

Organizations

  • id (binary_id, PK)
  • name (string)
  • slug (string, unique) - for URLs
  • inserted_at / updated_at (utc_datetime)

OrganizationMemberships

  • id (binary_id, PK)
  • organization_id (binary_id, FK -> organizations)
  • user_id (binary_id, FK -> users)
  • role (enum: owner, admin, member, viewer)
  • inserted_at / updated_at (utc_datetime)
  • Unique constraint on (organization_id, user_id)

Permission Levels:

  • owner - Full control, can delete org, manage all settings
  • admin - Can manage users, sites, equipment, view all
  • member - Can add/edit equipment, view sites
  • viewer - Read-only access

Sites

  • id (binary_id, PK)
  • organization_id (binary_id, FK -> organizations)
  • parent_site_id (binary_id, FK -> sites, nullable) - for hierarchy
  • name (string)
  • description (text, nullable)
  • location (string, nullable)
  • inserted_at / updated_at (utc_datetime)

Equipment

  • id (binary_id, PK)
  • site_id (binary_id, FK -> sites)
  • name (string)
  • ip_address (string)
  • description (text, nullable)
  • status (enum: up, down, unknown)
  • last_checked_at (utc_datetime, nullable)
  • last_status_change_at (utc_datetime, nullable)
  • monitoring_enabled (boolean, default: true)
  • check_interval_seconds (integer, default: 300) - 5 minutes
  • inserted_at / updated_at (utc_datetime)

MonitoringChecks (historical log)

  • id (binary_id, PK)
  • equipment_id (binary_id, FK -> equipment)
  • status (enum: success, failure)
  • response_time_ms (integer, nullable)
  • checked_at (utc_datetime)
  • Index on (equipment_id, checked_at)

Alerts

  • id (binary_id, PK)
  • equipment_id (binary_id, FK -> equipment)
  • alert_type (enum: equipment_down, equipment_up)
  • triggered_at (utc_datetime)
  • acknowledged_at (utc_datetime, nullable)
  • acknowledged_by_id (binary_id, FK -> users, nullable)
  • resolved_at (utc_datetime, nullable)
  • email_sent_at (utc_datetime, nullable)
  • inserted_at / updated_at (utc_datetime)

OrganizationInvitations

  • id (binary_id, PK)
  • organization_id (binary_id, FK -> organizations)
  • email (string)
  • role (enum: admin, member, viewer) - cannot invite as owner
  • token (string, unique) - secure random token for invite link
  • invited_by_id (binary_id, FK -> users)
  • accepted_at (utc_datetime, nullable)
  • accepted_by_id (binary_id, FK -> users, nullable)
  • expires_at (utc_datetime) - invites expire after 7 days
  • inserted_at / updated_at (utc_datetime)

Architecture Components

1. Authentication & Authorization

Use Phoenix.LiveView built-in patterns:

  • Email/password authentication
  • Session-based auth with LiveView
  • Password reset via email

Authorization Strategy:

  • Context-based permissions (organization-scoped)
  • Plugs for organization membership verification
  • LiveView mount hooks for permission checks
  • Helper functions: can?(user, :action, resource)

2. Multi-Tenancy

Organization Scoping:

  • All queries scoped by current_organization
  • LiveView assigns: @current_user, @current_organization, @current_membership
  • Router organization switcher for users in multiple orgs
  • URL structure: /orgs/:org_slug/sites, /orgs/:org_slug/equipment

3. Monitoring System

Background Job Architecture:

  • Use GenServer or DynamicSupervisor for monitoring workers
  • One worker per equipment (or batched by site)
  • Quantum or similar for scheduling (or custom OTP solution)
  • Use :gen_icmp or System.cmd("ping") for ping checks

Monitoring Flow:

  1. Worker wakes up every N seconds (configurable per equipment)
  2. Pings equipment IP address
  3. Records result in monitoring_checks table
  4. Updates equipment status if changed
  5. Creates alert if status transitions (up->down or down->up)
  6. Broadcasts status change via PubSub for real-time UI updates

4. Real-Time Updates

Phoenix PubSub Topics:

  • organization:#{org_id}:equipment:#{equipment_id} - Equipment status
  • organization:#{org_id}:alerts - New alerts
  • organization:#{org_id}:sites - Site changes

LiveView Integration:

  • Subscribe to relevant topics on mount
  • Handle PubSub messages to update assigns
  • Stream-based updates for lists

5. UI Structure

LiveView Pages:

  • /login, /register - Authentication
  • /orgs - Organization list/switcher
  • /orgs/:slug/dashboard - Overview, active alerts, recent changes
  • /orgs/:slug/sites - Site hierarchy tree view
  • /orgs/:slug/sites/:id - Site detail with equipment list
  • /orgs/:slug/equipment - All equipment list
  • /orgs/:slug/equipment/:id - Equipment detail with check history
  • /orgs/:slug/alerts - Alert history
  • /orgs/:slug/settings - Org settings, members

Components:

  • Organization switcher (header)
  • Site tree navigator
  • Equipment status badge
  • Alert list/feed
  • Permission-based action buttons

Implementation Stages

Stage 1: Foundation & Authentication

Goal: User authentication and basic org structure Success Criteria:

  • Users can register/login with email
  • Users can create organizations
  • Users can switch between organizations
  • Basic navigation structure
  • Tests passing

Detailed Tasks:

1.1 User Authentication

  • Run mix phx.gen.auth Accounts User users to scaffold auth system
  • Review and customize generated code (email as username)
  • Update user registration to create first organization
  • Add tests for auth flows

Files Created:

  • lib/towerops/accounts.ex - User context
  • lib/towerops/accounts/user.ex - User schema
  • lib/towerops/accounts/user_token.ex - Session tokens
  • lib/towerops_web/user_auth.ex - Auth plugs
  • lib/towerops_web/controllers/user_session_controller.ex
  • lib/towerops_web/controllers/user_registration_controller.ex
  • lib/towerops_web/controllers/user_reset_password_controller.ex
  • lib/towerops_web/controllers/user_settings_controller.ex
  • Migrations for users and user_tokens tables

1.2 Organizations & Memberships

  • Create migration: mix ecto.gen.migration create_organizations
  • Create migration: mix ecto.gen.migration create_organization_memberships
  • Create migration: mix ecto.gen.migration create_organization_invitations
  • Create lib/towerops/organizations.ex context
  • Create lib/towerops/organizations/organization.ex schema
  • Create lib/towerops/organizations/membership.ex schema
  • Create lib/towerops/organizations/invitation.ex schema
  • Add slug generation for organizations (use Ecto changeset)
  • Add tests for organizations context

Migration Details:

# organizations table
create table(:organizations, primary_key: false) do
  add :id, :binary_id, primary_key: true
  add :name, :string, null: false
  add :slug, :string, null: false
  timestamps(type: :utc_datetime)
end
create unique_index(:organizations, [:slug])

# organization_memberships table
create table(:organization_memberships, primary_key: false) do
  add :id, :binary_id, primary_key: true
  add :organization_id, references(:organizations, type: :binary_id, on_delete: :delete_all)
  add :user_id, references(:users, type: :binary_id, on_delete: :delete_all)
  add :role, :string, null: false
  timestamps(type: :utc_datetime)
end
create unique_index(:organization_memberships, [:organization_id, :user_id])
create index(:organization_memberships, [:user_id])

1.3 Multi-Org Navigation

  • Create organization switcher LiveView component
  • Add current_organization plug to router
  • Create /orgs LiveView (list user's organizations)
  • Create /orgs/new LiveView (create organization)
  • Update router with organization-scoped routes
  • Add breadcrumb navigation component
  • Add tests for organization switching

Router Structure:

scope "/", ToweropsWeb do
  pipe_through [:browser, :require_authenticated_user]

  live "/orgs", OrgLive.Index
  live "/orgs/new", OrgLive.New
end

scope "/orgs/:org_slug", ToweropsWeb do
  pipe_through [:browser, :require_authenticated_user, :load_current_organization]

  live "/", DashboardLive
  # Future: sites, equipment, etc.
end

1.4 Authorization System

  • Create lib/towerops/organizations/policy.ex for permission checks
  • Add can?/3 helper function
  • Create :load_current_organization plug
  • Add permission checks to LiveView mount callbacks
  • Add tests for authorization

Permission Matrix:

Action Owner Admin Member Viewer
View org
Edit org settings
Delete org
Manage members
Add/edit equipment
View equipment

1.5 Basic UI & Layouts

  • Update layouts.ex to include org switcher in header
  • Create organization badge component
  • Style navigation with Tailwind
  • Add flash message styling
  • Ensure responsive design

Stage 2: Sites & Equipment Management

Goal: CRUD for sites and equipment Success Criteria:

  • Users can create/edit/delete sites
  • Sites can have parent sites (hierarchy)
  • Users can add equipment to sites
  • Equipment has IP address and basic info

Tasks:

  1. Generate sites schema and LiveViews
  2. Build site hierarchy tree component
  3. Generate equipment schema and LiveViews
  4. Add IP address validation
  5. Permission checks on all actions

Stage 3: Monitoring System

Goal: Automated ping monitoring Success Criteria:

  • Equipment is pinged every 5 minutes
  • Status updates in real-time
  • Monitoring checks are logged

Tasks:

  1. Design monitoring worker architecture
  2. Implement ping functionality
  3. Create monitoring_checks schema
  4. Build GenServer workers for monitoring
  5. Add PubSub broadcasting
  6. Update LiveView to receive real-time updates

Stage 4: Alerting

Goal: Alert generation and management Success Criteria:

  • Alerts created on status changes
  • Users can view alert history
  • Users can acknowledge alerts

Tasks:

  1. Create alerts schema
  2. Build alert creation logic in monitoring workers
  3. Create alert LiveView pages
  4. Add alert acknowledgment
  5. Alert notifications in UI

Stage 5: Polish & Production

Goal: Production-ready application Success Criteria:

  • All tests passing
  • Polished UI with Tailwind
  • Email notifications configured
  • Production deployment ready

Tasks:

  1. Comprehensive test coverage
  2. UI/UX improvements
  3. Email alert notifications
  4. Performance optimization
  5. Documentation

Technical Decisions

Database

  • PostgreSQL with Ecto
  • Use binary_id (UUID) for all primary keys (already configured)
  • Indexes on foreign keys and frequently queried fields

Background Jobs

Options:

  1. Custom OTP solution with GenServer + Process.send_after
  2. Quantum scheduler
  3. Oban (more heavyweight but robust)

Recommendation: Start with custom OTP, migrate to Oban if needed

Real-time Communication

  • Phoenix PubSub for server-side messaging
  • LiveView for UI updates
  • No WebSocket client code needed

Ping Implementation

Options:

  1. :gen_icmp library (requires raw sockets, might need permissions)
  2. System.cmd("ping") - simpler, cross-platform
  3. HTTP health checks (future enhancement)

Recommendation: System.cmd("ping") for MVP, abstract for future protocols


Decisions Made

  1. Email notifications: ✓ Yes - Users receive email alerts on status changes
  2. Multi-org users: ✓ Yes - Users can belong to multiple organizations
  3. Invite system: ✓ Email invitation system (secure token-based invites)
  4. Check intervals: ✓ Customizable per equipment (stored in equipment.check_interval_seconds)

Additional Schema Needed

Based on decisions:

  • OrganizationInvitations table for email invite workflow
  • email_sent_at field in Alerts for tracking email delivery

Open Questions

  1. Alert escalation: Any escalation policies (e.g., page admin if down > X minutes)?
  2. Retention: How long to keep monitoring_checks history?
  3. Equipment types: Just ping for now, or plan for SNMP, HTTP, etc.?
  4. Site hierarchy depth: Any limit on site nesting levels?

Status: Planning Phase - Ready to Begin Stage 1

Last updated: 2025-12-21