- 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
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
- User accounts (email as username)
- Organizations (multi-tenant)
- Organization membership with permission levels
- Site hierarchy
- Equipment management (IP-based)
- Automated ping monitoring (5-minute intervals)
- 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 URLsinserted_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 settingsadmin- Can manage users, sites, equipment, view allmember- Can add/edit equipment, view sitesviewer- Read-only access
Sites
id(binary_id, PK)organization_id(binary_id, FK -> organizations)parent_site_id(binary_id, FK -> sites, nullable) - for hierarchyname(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 minutesinserted_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 ownertoken(string, unique) - secure random token for invite linkinvited_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 daysinserted_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_icmpor System.cmd("ping") for ping checks
Monitoring Flow:
- Worker wakes up every N seconds (configurable per equipment)
- Pings equipment IP address
- Records result in monitoring_checks table
- Updates equipment status if changed
- Creates alert if status transitions (up->down or down->up)
- Broadcasts status change via PubSub for real-time UI updates
4. Real-Time Updates
Phoenix PubSub Topics:
organization:#{org_id}:equipment:#{equipment_id}- Equipment statusorganization:#{org_id}:alerts- New alertsorganization:#{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 usersto 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 contextlib/towerops/accounts/user.ex- User schemalib/towerops/accounts/user_token.ex- Session tokenslib/towerops_web/user_auth.ex- Auth plugslib/towerops_web/controllers/user_session_controller.exlib/towerops_web/controllers/user_registration_controller.exlib/towerops_web/controllers/user_reset_password_controller.exlib/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.excontext - Create
lib/towerops/organizations/organization.exschema - Create
lib/towerops/organizations/membership.exschema - Create
lib/towerops/organizations/invitation.exschema - 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
/orgsLiveView (list user's organizations) - Create
/orgs/newLiveView (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.exfor permission checks - Add
can?/3helper function - Create
:load_current_organizationplug - 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.exto 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:
- Generate sites schema and LiveViews
- Build site hierarchy tree component
- Generate equipment schema and LiveViews
- Add IP address validation
- 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:
- Design monitoring worker architecture
- Implement ping functionality
- Create monitoring_checks schema
- Build GenServer workers for monitoring
- Add PubSub broadcasting
- 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:
- Create alerts schema
- Build alert creation logic in monitoring workers
- Create alert LiveView pages
- Add alert acknowledgment
- 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:
- Comprehensive test coverage
- UI/UX improvements
- Email alert notifications
- Performance optimization
- 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:
- Custom OTP solution with GenServer + Process.send_after
- Quantum scheduler
- 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:
:gen_icmplibrary (requires raw sockets, might need permissions)- System.cmd("ping") - simpler, cross-platform
- HTTP health checks (future enhancement)
Recommendation: System.cmd("ping") for MVP, abstract for future protocols
Decisions Made
- Email notifications: ✓ Yes - Users receive email alerts on status changes
- Multi-org users: ✓ Yes - Users can belong to multiple organizations
- Invite system: ✓ Email invitation system (secure token-based invites)
- 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
- Alert escalation: Any escalation policies (e.g., page admin if down > X minutes)?
- Retention: How long to keep monitoring_checks history?
- Equipment types: Just ping for now, or plan for SNMP, HTTP, etc.?
- Site hierarchy depth: Any limit on site nesting levels?
Status: Planning Phase - Ready to Begin Stage 1
Last updated: 2025-12-21