Commit graph

1876 commits

Author SHA1 Message Date
99507eeaaf
fix: update e2e tests to use otplib v13 API and load .env
- Change tsconfig to use ESNext modules
- Add type: module to package.json
- Update auth.setup.ts to use generateSync instead of authenticator.generate
- Install and configure dotenv to load environment variables
- Add dotenv.config() to playwright.config.ts
2026-03-06 15:53:10 -06:00
659490c405
fix: access role from membership association in create_test_user script
Organizations have memberships with roles, not direct role attribute
2026-03-06 15:47:34 -06:00
b3af717013
fix: update e2e scripts to use correct TOTP API
- Fix create_test_user.exs to use create_totp_device instead of create_user_credential
- Update TOTP_SETUP.md to reference UserTotpDevice schema and user_totp_devices table
- Fix function signatures to match Accounts.create_totp_device(user_id, device_name, secret)
- Add terms_of_service_consent and privacy_policy_consent to user registration
2026-03-06 15:46:11 -06:00
70c82ba8f1
refactor: remove emoji from e2e scripts and docs
- Remove emoji from create_test_user.exs output
- Remove emoji from setup.sh
- Keep emoji in test files (used for matching actual app emoji)
2026-03-06 15:43:02 -06:00
cc3ca1c7de
feat: add site search to trace
Trace can now search sites by name, location, or address. Selecting
a site shows all devices at that site with status and recent alerts.
2026-03-06 15:37:23 -06:00
0bdec8653f
docs: add TOTP setup guide and test user creation script
- Add comprehensive TOTP_SETUP.md with multiple setup options
- Create scripts/create_test_user.exs for automated test user creation
- Update .gitignore to exclude Playwright browser binaries and artifacts
- Update README to reference TOTP setup guide
2026-03-06 15:06:23 -06:00
882a5d7eab
fix: display count sensor values as integers instead of floats
Connection counts (IPv4/IPv6, DHCP leases) were showing as floats
(e.g. 1270.0) in executor output, change detection messages, and
chart tooltips/axes. Now displayed as integers everywhere.
2026-03-06 15:03:30 -06:00
17bf1f83e8
feat: add Playwright e2e test suite
- Set up Playwright in dedicated e2e directory
- Multi-environment support (local, staging)
- TOTP authentication handling with otplib
- Test coverage for organizations, devices, alerts, status indicators
- Helper utilities for common test operations
- Comprehensive README with setup and usage instructions
- Setup script for quick initialization
2026-03-06 15:02:56 -06:00
c86ca57864
feat: add real-time status emoji updates in page titles
Dynamically update page title emoji when device/alert status changes:
- Add PubSub broadcasts when alerts are created/resolved
- Create StatusTitleComponent LiveComponent to subscribe to alert changes
- Add StatusTitle JavaScript hook to update document.title in real-time
- Subscribe to organization:alerts channel on LiveView mount
- Push emoji update events when alert status changes

This provides immediate visual feedback in browser tabs when
critical/warning/healthy status changes without requiring page refresh.
2026-03-06 14:49:44 -06:00
a2ce5817a2
fix: use transparent background for stoplight favicon
Replace white background with transparent for better appearance
in browser tabs with different background colors.
2026-03-06 14:46:02 -06:00
9bef1b289d
feat: add status emoji to page titles
Add colored circle emoji (🔴/🟡/🟢) to page titles based on organization
health status:
- 🔴 Red: Critical alerts (device_down, agent_offline, severity 1)
- 🟡 Yellow: Warning alerts (severity 2 or any active alerts)
- 🟢 Green: No active alerts

Provides at-a-glance status visibility in browser tabs.

Note: Favicon remains static stoplight, only page title is dynamic.
2026-03-06 14:45:02 -06:00
100245975a
refactor: reduce complexity in global pricing validation
Extract validation logic into separate functions to reduce:
- Cyclomatic complexity from 12 to acceptable levels
- Nesting depth from 3 to 2

Improves code maintainability and passes Credo checks.
2026-03-06 14:44:33 -06:00
c110832b42
Revert "feat: add status emoji to page titles"
This reverts commit f3873e0da7.
2026-03-06 14:43:13 -06:00
f3873e0da7
feat: add status emoji to page titles
Add colored circle emoji (🔴/🟡/🟢) to page titles based on organization
health status:
- 🔴 Red: Critical alerts (device_down, agent_offline, severity 1)
- 🟡 Yellow: Warning alerts (severity 2 or any active alerts)
- 🟢 Green: No active alerts

Provides at-a-glance status visibility in browser tabs.
2026-03-06 14:42:55 -06:00
e278d320ce
design: improve stoplight favicon with transparent background
Make circles more prominent with transparent background and better spacing.
2026-03-06 14:36:32 -06:00
45579813bd
design: update favicon to stoplight style with app colors
Replace standard favicon with stoplight design using red (#ef4444),
yellow (#eab308), and green (#22c55e) circles matching the app's
status indicator colors.
2026-03-06 14:33:29 -06:00
ac2547e7c9
Merge branch 'feature/dynamic-global-pricing' 2026-03-06 14:04:12 -06:00
6e2bba4e88
docs: update changelogs for dynamic pricing feature 2026-03-06 14:00:58 -06:00
9a4aa57521
feat: update marketing pricing from $3 to $2/device/month 2026-03-06 13:58:58 -06:00
a5e26745ae
feat: add global pricing defaults UI to admin orgs page 2026-03-06 13:58:29 -06:00
4f102f4acc
feat: add Admin.update_global_pricing with Stripe integration 2026-03-06 13:55:12 -06:00
ee918c2eda
feat: add best-effort subscription migration to new price 2026-03-06 13:52:28 -06:00
6d3fc15f4a
fix: allow data URLs in CSP for dynamic favicon
The dashboard status indicator favicon (colored circle) uses canvas
to generate a data URL that's set as the favicon. This was blocked
by CSP in staging/production because default-src didn't include data:.

Added data: to default-src directive to fix favicon not updating in
browser tabs when device status changes.
2026-03-06 13:51:31 -06:00
a813f56d1d
feat: add StripeClient.update_subscription_price 2026-03-06 13:50:11 -06:00
3e74ac5897
feat: add StripeClient.create_price for metered billing 2026-03-06 13:47:54 -06:00
448ed20401
feat: dynamic global billing defaults from ApplicationSettings 2026-03-06 13:44:03 -06:00
a16ce2b9dd
feat: add decimal type support to ApplicationSetting 2026-03-06 13:34:37 -06:00
7d61d8fb0a
feat: seed global billing settings in application_settings 2026-03-06 13:26:50 -06:00
c0546814aa
docs: add deployment instructions for staging and production 2026-03-06 13:21:21 -06:00
ffb61641bb
docs: design for dynamic global pricing configuration 2026-03-06 13:18:47 -06:00
2ae7a2680a
fix: clear stale Dokku deploy lock before pushing
cancel-in-progress kills the CI job mid-deploy but Dokku's server-side
lock persists, causing subsequent deploys to hang indefinitely.
2026-03-06 13:06:18 -06:00
9229e6e920
fix: remove internal details from public changelog 2026-03-06 13:03:36 -06:00
e161aaab83
docs: update changelogs for billing overrides and interface stats fix 2026-03-06 13:02:55 -06:00
cc53dd6a64
fix: access interface stats through latest_stat association
The template accessed if_in_octets/if_out_octets directly on the
Interface struct, but these fields live on InterfaceStat. Access
through interface.latest_stat with nil guard to prevent KeyError
when the association is not loaded.
2026-03-06 13:02:21 -06:00
9aec87636b
feat: per-organization billing override admin UI
Allow superadmins to override free device limits and per-device pricing
on a per-organization basis. Overrides cascade through subscription
limits, billing calculations, and user-facing settings display.

- Add custom_free_device_limit and custom_price_per_device to organizations
- Add billing_override_changeset with validation
- Update SubscriptionLimits.effective_device_limit to respect overrides
- Update Billing to use effective free count and price per device
- Add Admin.update_billing_overrides with audit logging
- Add override editing UI to /admin/organizations
- Update org settings page to show effective limits/pricing
2026-03-06 13:02:05 -06:00
1d98cda79d
fix: configure Watchtower to only monitor agent container
Add WATCHTOWER_SCOPE=towerops environment variable to generated
docker-compose templates. This prevents Watchtower from monitoring
unrelated containers on the same Docker host (e.g., Dokku apps).

Without scope filtering, Watchtower would attempt to monitor all
containers with watchtower.enable=true label, causing warnings
for missing images and unnecessary monitoring overhead.
2026-03-06 12:38:44 -06:00
d17b7baba4
fix: correct 'More' navigation translation from 'or' to 'More' 2026-03-06 12:26:18 -06:00
721c1f2481
feat: branch-based deployment (main → staging, production → prod)
- main branch: auto-deploy to Dokku staging
- production branch: build Docker image and deploy to K8s production
- Add DEPLOYMENT.md with workflow documentation
- Create production branch for manual production deployments

Breaking change: pushing to main no longer deploys to production
2026-03-06 12:22:05 -06:00
3a5da6f68c
test(activity_feed): add comprehensive test coverage
- Test empty activity list
- Test preseem sync logs with correct DateTime format
- Test duration formatting with integer precision
- Test sync logs without duration
- Test grouping by minute
- Test sorting by timestamp descending
- Test limit parameter
- Test date range filtering
- Test organization isolation
- Test different sync statuses (success, failed, partial)
- Test count_by_type functionality
2026-03-06 12:22:05 -06:00
70718a53dc
fix(activity_feed): show integer milliseconds without decimal point 2026-03-06 12:22:04 -06:00
73daad48a5
fix: convert NaiveDateTime to DateTime for activity feed sorting
- date_trunc fragment returns NaiveDateTime without timezone
- Convert to UTC DateTime before returning from preseem sync query
- Fixes DateTime.compare/2 function clause error when sorting activities
- All activity timestamps now consistently use DateTime with timezone
2026-03-06 12:22:04 -06:00
2ba5a3fd7b
fix: replace max(uuid) with array_agg for preseem sync logs
- PostgreSQL's max() function doesn't work on UUID types
- Use array_agg to get first ID from grouped results instead
- Matches pattern already used for status field
- Fixes crash on /activity page when preseem sync logs exist
2026-03-06 12:22:04 -06:00
CI
bf7004c770 chore: update towerops-web image to git.mcintire.me/graham/towerops-web:main-1772816933-2a61626 [skip ci] 2026-03-06 17:16:12 +00:00
2a61626135
feat: allow script to work with both test and live Stripe keys
- Accept both sk_test_ and sk_live_ API keys
- Show mode indicator (TEST/LIVE) in output
- Adjust webhook URL based on mode (localhost for test, towerops.net for live)
- Add warning when using test mode
- Useful for testing billing setup before going live
2026-03-06 11:08:07 -06:00
13631595a7
fix: handle spaces in JSON when extracting Stripe IDs
- Update grep patterns to match JSON with spaces after colons
- Fixes false 'Error creating meter' message when meter created successfully
- Applies to meter ID and price ID extraction
2026-03-06 11:08:07 -06:00
3e721b9395
fix: check for existing billing meter before creating
- First check if a meter with 'devices_monitored' event exists
- Reuse existing meter ID if found
- Only create new meter if none exists
- Fixes error when meter already exists in Stripe account
2026-03-06 11:08:07 -06:00
d3aa602ba4
feat: add production Stripe billing setup script
- Interactive script to create production billing meter and price
- Prompts for live API key and product ID
- Creates billing meter with 'devices_monitored' event
- Creates metered price at $1/device/month
- Outputs kubectl command for creating k8s secret
- Includes setup instructions for webhook configuration
2026-03-06 11:08:06 -06:00
d0e7eb4308
feat: add Stripe meter ID configuration
- Add stripe_meter_id to dev, runtime, and test configs
- Add STRIPE_METER_ID to k8s deployment secret references
- Use real Stripe meter and price IDs from Stripe setup
- Meter: mtr_test_61UHPU067veEZ7bhl41S77kvnTfgyODY
- Price: price_1T81XBS77kvnTfgyPlw1jF8N ($1/device/month)
- Include setup script for Stripe billing configuration
2026-03-06 11:08:06 -06:00
20f05584dc
fix: use k8s secret for Stripe env vars instead of hardcoded values
- Changed from hardcoded placeholder values to secretKeyRef
- References towerops-billing secret (with optional: true)
- Won't crash if secret doesn't exist yet
- User can create secret later with real Stripe keys
2026-03-06 11:08:06 -06:00
7d2f1fd860
feat: add BillingSyncWorker to dev Oban cron schedule
- Enables daily billing sync at 3 AM UTC in development
- Matches production configuration for testing
- All 54 billing tests passing
2026-03-06 11:08:05 -06:00