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

403 lines
13 KiB
Markdown

# 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**:
```elixir
# 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**:
```elixir
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