Commit Graph

623 Commits

Author SHA1 Message Date
Louis King ce4f0da205 test(api): cover --workers CLI branch and factory metrics path
Raise diff coverage above target by exercising the previously untested
lines:

- test_cli.py: invoke the `api` command with uvicorn.run mocked to assert
  the default path passes the app object (no workers/factory) and that
  --workers / API_WORKERS launches the env factory by import string with
  the requested worker count and factory=True.
- test_app_factory.py: add METRICS_ENABLED true/false cases that toggle
  the /metrics route, covering the env-bool parsing branch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 12:17:40 +01:00
Louis King 03603a83e2 feat(api): configurable worker processes via API_WORKERS
Add a --workers / API_WORKERS option so the API can run multiple worker
processes in a single container for multi-core concurrency, without
needing to scale containers (which would conflict with the api service's
fixed container_name and complicate per-stack ops/monitoring).

The existing create_app() carries hardcoded defaults (sqlite:///./
meshcore.db, Redis off), so forked workers cannot use it — they would
open the wrong database and run without caching. Add an env-driven
factory, create_app_from_env(), that rebuilds the app from APISettings
plus the CLI-only env vars (CORS_ORIGINS, METRICS_ENABLED,
METRICS_CACHE_TTL), mirroring the single-process resolution. workers > 1
runs uvicorn against this factory via an import string; workers == 1
keeps the single-process object path so local CLI flags still apply.

Wire API_WORKERS into the api compose service (default 1, unchanged
behaviour) and document it in the README (new "Scaling the API"
section + env table) and the v0.12 upgrading notes, including the
SQLite single-host caveat and the env-vs-CLI-flag note for workers.

Tests: create_app_from_env reads DB/Redis/MQTT/metrics from env,
honours explicit overrides, and derives the collector DB path from
DATA_HOME rather than the bare create_app default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 12:09:05 +01:00
JingleManSweep e316b656fc Merge pull request #229 from ipnet-mesh/perf/batch-dashboard-sender-queries
perf(api): batch N+1 dashboard and message sender queries
2026-06-11 11:33:32 +01:00
Louis King e1199a42cd perf(api): batch N+1 dashboard and message sender queries
Two read-only query optimisations, no schema changes.

node-count history: replace the per-day COUNT(*) loop (up to 90 full
scans of the unindexed created_at column) with two queries — a baseline
count of nodes created before the window plus one GROUP BY date()
aggregate, accumulated into the running total in Python. Results are
identical; the baseline seed keeps pre-window nodes counted from day 0.

sender-name resolution: add resolve_sender_names() to observer_utils,
batching all pubkey prefixes into two queries (names + name tags) via an
OR of indexable LIKE 'prefix%' terms instead of two queries per prefix.
Wire it into list_messages (was ~2xN per page) and the dashboard
channel-messages loop (nested per channel x per prefix). The dashboard
recent-ads block already batches on full public keys via IN(), so it is
left as-is.

Tests: add cumulative+baseline correctness for node-count and a
multi-sender batched-resolution case for messages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 11:25:01 +01:00
JingleManSweep fc8893a8bd Merge pull request #227 from ipnet-mesh/renovate/redis-8.x
Update redis Docker tag to v8
v0.12.0
2026-06-11 10:12:33 +01:00
renovate[bot] 33dc861a1a Update redis Docker tag to v8 2026-06-10 22:39:37 +00:00
JingleManSweep b9168d0ce5 Merge pull request #228 from ipnet-mesh/perf/threadpool-sqlite-concurrency
perf(api): threadpool handlers, SQLite concurrency tuning, precomputed is_observer
2026-06-10 23:38:41 +01:00
Louis King 38a57f4cd4 perf(api): run handlers in threadpool, tune SQLite, precompute is_observer
Three related performance fixes for slow (>500ms) API responses.

1. Stop blocking the event loop. Route handlers were declared `async def`
   but ran synchronous SQLAlchemy queries (and synchronous Redis calls via
   the cache decorator) directly on the event loop, serializing requests.
   Convert all handlers to sync `def` so FastAPI runs them in its
   threadpool, and make the `@cached` decorator dual-mode (sync wrapper for
   sync handlers, async wrapper preserved for a future async/Postgres path).

2. Tune SQLite for concurrency. Enable WAL, busy_timeout and
   synchronous=NORMAL on every connection, and size the pool above the
   threadpool so handlers don't wait on connections. In-memory SQLite is
   guarded (no overflow-pool kwargs).

3. Precompute an indexed `nodes.is_observer` flag. The `observer=true`
   filter scanned ~68k+ event rows to find a handful of observers (the
   advertisements page calls it with limit=500). Replace the 5-way OR of
   subqueries with `WHERE nodes.is_observer = ?`. The collector sets the
   flag on first observation (in add_event_observer); the cleanup job
   clears it once a node's events are all pruned; a migration adds the
   column/index and backfills from the existing union.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 23:35:39 +01:00
JingleManSweep 1f4445e875 Merge pull request #226 from ipnet-mesh/feat/redis-caching
feat: add optional Redis caching layer for API endpoints
2026-06-10 21:58:29 +01:00
Louis King f30786c95a Tweaked upgrading docs 2026-06-10 21:51:58 +01:00
Louis King fb435a53c4 test: add coverage for Redis caching layer
Add 29 new tests covering previously uncovered code paths:
- redis.py: delete(), close(), string value decoding
- cache.py: serialization branches (pydantic, dict, list), set error fallback
- app.py: lifespan Redis init (enabled/disabled), cache close on shutdown
- app.py: X-Cache middleware (HIT/MISS/no-status)
- app.py: /health/ready Redis status (connected/unreachable/omitted)
- cli.py: Redis banner output, create_app param passthrough
- Route key builders: dashboard/stats, dashboard/message-activity,
  channels, messages
2026-06-09 23:30:29 +01:00
Louis King 385d1ab141 feat: add optional Redis caching layer for API endpoints
Add Redis-backed response caching for read-heavy API endpoints (nodes,
advertisements, messages, channels, dashboard, profiles) with configurable
TTL, key prefix isolation, and graceful fallback when Redis is unavailable.

New files:
- common/redis.py: CacheBackend, NullCache, RedisCacheBackend
- api/cache.py: @cached decorator, sorted_query_string helper
- tests/test_api/test_cache.py: 23 unit tests

Changes:
- pyproject.toml: add redis[hiredis] dependency
- common/config.py: 8 Redis settings on APISettings
- api/cli.py: Redis Click options + startup banner
- api/app.py: Redis lifespan init/cleanup, X-Cache middleware, health check
- 6 route files: apply @cached decorator to list endpoints
- docker-compose.yml: Redis service (cache profile), env vars
- docker-compose.dev.yml: Redis port exposure
- .env.example, README.md, AGENTS.md, docs/upgrading.md: documentation

Redis is disabled by default (REDIS_ENABLED=false). Enable with
--profile cache and REDIS_ENABLED=true.
2026-06-09 23:08:49 +01:00
JingleManSweep a4419a8987 Merge pull request #223 from ipnet-mesh/renovate/daisyui-5.x-lockfile
Update dependency daisyui to v5.5.23
v0.11.1
2026-06-07 14:53:18 +01:00
renovate[bot] fc3a11ece3 Update dependency daisyui to v5.5.23 2026-06-07 13:48:51 +00:00
JingleManSweep cdb383fb2b Merge pull request #224 from ipnet-mesh/renovate/codecov-codecov-action-7.x
Update codecov/codecov-action action to v7
2026-06-07 14:48:10 +01:00
renovate[bot] b685333790 Update codecov/codecov-action action to v7 2026-06-07 13:45:33 +00:00
JingleManSweep 673d8c11c5 Merge pull request #225 from ipnet-mesh/feat/expand-radio-config-vars
Split NETWORK_RADIO_CONFIG into individual env vars and add FEATURE_R…
2026-06-07 14:44:43 +01:00
Louis King 6fd93aaa07 Add test for radio config settings fallback coverage
Exercise the else branches in create_app() where radio params
fall back to WebSettings defaults when passed as None.
2026-06-07 14:41:18 +01:00
Louis King f7d9901c9b Split NETWORK_RADIO_CONFIG into individual env vars and add FEATURE_RADIO_CONFIG flag
- Replace single NETWORK_RADIO_CONFIG comma-delimited string with six
  individual environment variables: NETWORK_RADIO_PROFILE, _FREQUENCY,
  _BANDWIDTH, _SPREADING_FACTOR, _CODING_RATE, _TX_POWER
- Radio config fields now use raw numeric types (float/int) with units
  applied dynamically via RadioConfig.format_for_display()
- Add FEATURE_RADIO_CONFIG feature flag to control radio config panel
  visibility on the home page (default: enabled)
- Remove from_config_string class method (no backwards compatibility)
- Update Click CLI options, create_app() signature, and _build_config_json()
- Update docker-compose.yml, .env.example, README.md, AGENTS.md
- Add upgrading.md v0.12.0 section with migration instructions
- Add test coverage for schema, config, and feature flag
2026-06-07 14:35:40 +01:00
JingleManSweep 187b0b7ce1 Merge pull request #222 from ipnet-mesh/feat/channel-model
Add database-backed channels with role-based visibility and web dashboard
v0.11.0
2026-06-04 14:39:55 +01:00
Louis King 9f79ceac14 Add test coverage for channels feature and fix CLI ResourceWarning
Add 39 new tests across 7 files to improve patch coverage:

- test_messages: sort desc/asc branches, channel visibility edge cases
- test_channels: operator role visibility filtering
- test_dashboard: tag name resolution, sender names, operator visibility
- test_config: feature dependency auto-disable rules (dashboard, map, members)
- test_letsmesh_decoder: reload_keys, _enrich_payload_decoded, guards
- test_cli: channel list/add/remove/enable/disable, _import_channels,
  seed command with channels.yaml

Fix ResourceWarning in channel CLI commands by moving db.dispose()
into try/finally blocks to ensure sessions close before engine disposal.
2026-06-04 14:37:26 +01:00
Louis King f8c2a7bb40 Rename channel visibility 'public' to 'community'
- Rename ChannelVisibility.PUBLIC to ChannelVisibility.COMMUNITY
- Update stored value from 'public' to 'community' across model, schema, API, CLI, and frontend
- Add Alembic migration to update existing database rows
- Consolidate upgrade docs: merge v0.11.0, v0.12.0, v0.13.0 into single v0.11.0 section
- Add i18n visibility level translation keys (en, nl)
- Update section headings on channels page to use t() for i18n
- Keep visibility badges lowercase per UI design
2026-06-04 14:07:12 +01:00
Louis King 1491c49ef7 Refactor channels page layout and improve nav ordering
- Group channel cards by visibility with section headings
- Move channels before messages in all nav menus for logical grouping
- Add optgroup labels (Standard/Custom) to message channel filter
- Capitalize built-in "Test" channel name for consistency
- Shorten "Advertisements" to "Adverts" in UI labels
- Lay out channel cards with side-by-side QR codes
- Shrink homepage nav cards for better fit
2026-05-20 15:14:41 +01:00
Louis King 3ad288433d Removed old agent skills 2026-05-20 14:13:22 +01:00
Louis King 5f6d44c7b8 Add database-backed channels with role-based visibility and web dashboard
Replaces env-var channel keys with a Channel database model and periodic
DB refresh in the collector. Adds Channels dashboard page with QR codes,
channel visibility filtering on messages/dashboard APIs, and channel card
navigation to filtered messages view.
2026-05-20 00:37:05 +01:00
JingleManSweep d2579dd51d Merge pull request #221 from ipnet-mesh/docs/fix-readme-observer-notes
Update README observer section to match current packetcapture config
2026-05-19 20:33:34 +01:00
JingleManSweep 7638f21e93 Merge branch 'main' into docs/fix-readme-observer-notes 2026-05-19 20:31:42 +01:00
JingleManSweep 9a98e35d53 Merge pull request #209 from ipnet-mesh/renovate/lit-html-3.x-lockfile
chore(deps): update dependency lit-html to v3.3.3
2026-05-19 20:25:07 +01:00
JingleManSweep dd2d1006aa Merge branch 'main' into docs/fix-readme-observer-notes 2026-05-19 20:23:32 +01:00
JingleManSweep 09907efa0f Merge branch 'main' into renovate/lit-html-3.x-lockfile 2026-05-19 20:23:06 +01:00
JingleManSweep 564f81fc6f Merge pull request #220 from ipnet-mesh/renovate/daisyui-5.x-lockfile
chore(deps): update dependency daisyui to v5.5.20
2026-05-19 20:22:48 +01:00
Louis King 1d4d046b41 Update README observer section to match current contrib/packetcapture config 2026-05-19 20:21:40 +01:00
renovate[bot] dda36d70d4 chore(deps): update dependency daisyui to v5.5.20 2026-05-19 00:59:34 +00:00
renovate[bot] b1c58d0124 chore(deps): update dependency lit-html to v3.3.3 2026-05-18 20:47:32 +00:00
JingleManSweep 50609016a3 Merge pull request #219 from ipnet-mesh/fix/packet-capture-default-compose-vars
Added default Compose vars
2026-05-18 21:46:57 +01:00
Louis King c7ec0362c3 Added default Compose vars 2026-05-18 21:44:45 +01:00
JingleManSweep 197992c0a9 Merge pull request #218 from ipnet-mesh/chore/gitignore-fixes
Updated gitignore
2026-05-18 21:39:52 +01:00
Louis King 4c6f8d19e8 Updated gitignore 2026-05-18 21:37:34 +01:00
JingleManSweep 452a1a270b Merge pull request #217 from ipnet-mesh/fix/packet-capture-typo
Updates
2026-05-18 21:19:38 +01:00
Louis King bd21044c84 Updates 2026-05-18 21:12:22 +01:00
JingleManSweep 8f9cc8219b Merge pull request #216 from ipnet-mesh/chore/packet-capture-tweaks
Updates
2026-05-18 21:09:08 +01:00
Louis King 994ecb61aa Updates 2026-05-18 21:06:47 +01:00
JingleManSweep f2ebaacb22 Merge pull request #215 from ipnet-mesh/chore/add-meshrank-contrib
Updated meshcore-packet-capture contrib example to support MeshRank
2026-05-18 16:43:49 +01:00
Louis King 59c24dd64a Updated meshcore-packet-capture contrib example to support MeshRank 2026-05-18 16:41:46 +01:00
JingleManSweep 9f184da07e Merge pull request #214 from ipnet-mesh/feat/sqlite3-docker-image
feat: add sqlite3 CLI to Docker image for database debugging
2026-05-17 16:45:11 +01:00
Louis King 66f3578bfe feat: add sqlite3 CLI to Docker image for database debugging
Operators can now exec into containers to inspect and query the SQLite
database directly without ad-hoc package installs that are lost on restart.
2026-05-17 16:43:05 +01:00
JingleManSweep cdb0c4ab4c Merge pull request #213 from ipnet-mesh/fix/advertisement-frequency
feat: add route type tracking and flood-only defaults for advertisements
v0.10.5
2026-05-15 21:06:59 +01:00
Louis King ec897e21e8 fix: improve advert type badge and observer count UX
- Move route type badge left of observer count on mobile cards
- Hide route type badge when unknown instead of showing 'Unknown'
- Change observer count badge to badge-primary for visibility
- Remove satellite dish icon from observer count badge
2026-05-15 21:05:08 +01:00
Louis King 9afff5bc70 feat: add route type tracking and flood-only defaults for advertisements
Track advertisement route type (flood/transport_flood/direct/transport_direct)
and node advert timestamp to distinguish zero-hop from flood adverts, improve
deduplication with 300s buckets, and default all dashboard/ad-API queries to
flood-only (including NULL for historical records).
2026-05-15 20:55:48 +01:00
JingleManSweep 2d5bea2460 Merge pull request #212 from ipnet-mesh/fix/recent-adverts-timestamps
fix: add public_key filter to advertisements API
2026-05-15 19:20:52 +01:00