12 Commits

Author SHA1 Message Date
b2c1642065 Add per-user detail pages with activity chart and request history
Each user in the leaderboard links to a profile page showing stat cards,
a line chart (requests / storage / watch hours, 1W–1Y timeframes, raw or
normalized, plus a Storage Load mode), and a full request history sorted
newest-first. Includes Overseerr media status codes (1–5), Tautulli watch
history aggregation, and a server-side raw cache so the user API route can
enrich requests without re-fetching everything.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 17:26:47 -04:00
641a7fd096 Add settings UI, Discord notifications, and alert detail improvements
- Settings modal (gear icon) lets you configure all service URLs and API
  keys from the dashboard; values persist to data/settings.json with
  process.env as fallback so existing .env.local setups keep working
- Per-service Test button hits each service's status endpoint and reports
  the version on success
- Discord webhook support: structured embeds per alert category (requesters,
  approval age, episode progress, watch-rate stats) sent on new/reopened
  alerts only — already-open alerts don't re-notify
- Alert detail page restructured: prose descriptions replaced with labelled
  fields, episode progress bar for partial TV, watch-rate stat block,
  View in Radarr/Sonarr/Seerr action buttons, requester names link to
  Overseerr profiles, timestamps moved inline with status
- Tab state is pure client state (no ?tab= in URL); router.back() used
  on alert detail for clean browser history

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 14:57:07 -04:00
2374bad7ba Sync open alert count in localStorage on status toggle
After closing or reopening an alert, patch the cached dashboard stats
in localStorage so the summary card and tab badge reflect the new
count immediately when navigating back, without waiting for a refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 12:04:21 -04:00
d0bd17ed7e Add system comments on close events
Manual close: "Manually closed."
Auto-resolve: "Condition resolved — alert closed automatically."
(reopen comments were already in place)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:59:31 -04:00
4b2c82cf90 Add Radarr/Sonarr links and richer metadata to alert detail
- Thread titleSlug through RadarrMovie/SonarrSeries → MediaEntry →
  AlertCandidate, building a direct mediaUrl server-side at alert
  generation time (RADARR_URL/movie/slug, SONARR_URL/series/slug)
- Alert detail page: single-column full-width layout, metadata chips
  row showing opened/closed dates, media type, and a "View in Radarr/
  Sonarr" external link button when available
- Comments section sits below the full-width overview card

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:50:23 -04:00
c86b8ff33a Rework alert comments: authors, system events, wider layout
- Add author field ("user" | "system") to AlertComment
- System comments are automatically added when an alert is reopened
  by the engine ("Alert reopened — condition is still active.") or
  manually via the UI ("Manually reopened.")
- Alert detail page redesigned with a two-column layout (3/5 detail,
  2/5 comments) at lg breakpoint
- System comments render as centered event dividers with a gear icon;
  user comments render as avatar + bubble

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:44:51 -04:00
bf83c1a779 Preserve alert history when reopening
When a closed alert reopens (condition still present, no active
cooldown), keep firstSeen and comments intact. The alert is the same
incident continuing — closing and reopening should not erase history.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:40:42 -04:00
6fa246d3c4 Rework alert cooldown model
Content alerts (unfulfilled, pending, tautulli-no-matches) now have
zero cooldown on manual close — they reopen immediately on the next
refresh if the condition still exists. Closing is an acknowledgment
of the current state, not a suppression of future alerts.

User-behavior alerts (ghost, watchrate) keep a cooldown (7 days) so
a single manual close isn't immediately undone by the next refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:38:05 -04:00
8fe61cdeb8 Revise alert parameters and ghost requester logic
- UNFULFILLED_MIN_AGE_DAYS → UNFULFILLED_MIN_AGE_HOURS (default 12h)
  so new requests don't sit a full 3 days before alerting
- Incomplete Download threshold: 90% → 100% (any missing episode fires)
- PENDING_MIN_AGE_DAYS: 7 → 2
- Ghost Requester reworked: instead of checking lifetime plays = 0,
  now checks whether the user's last Tautulli activity predates their
  last N (default 5) approved requests — catches people who request
  but don't watch their recent content
- Removed Frequent Declines alert
- Add tautulliLastSeen to UserStat to support the ghost rework
- Update README to reflect all changes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:34:55 -04:00
a8a03b59d5 Add project README
Documents setup, environment variables, all alert types with their
tunable parameters and cooldowns, and the alert lifecycle diagram.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:16:49 -04:00
f871f86284 Build OverSnitch dashboard
Full implementation on top of the Next.js scaffold:

- Leaderboard with per-user request count, storage, avg GB/req, and
  optional Tautulli watch stats (plays, watch hours), each with dense
  per-metric rank (#N/total)
- SWR cache on /api/stats (5-min stale, force-refresh via button);
  client-side localStorage seed so the UI is instant on return visits
- Alerting system: content-centric alerts (unfulfilled downloads,
  partial TV downloads, stale pending requests) and user-behavior
  alerts (ghost requester, low watch rate, declined streak)
- Partial TV detection: flags ended series with <90% of episodes on disk
- Alert persistence in data/alerts.json with open/closed state,
  auto-resolve when condition clears, manual close with per-category
  cooldown, and per-alert notes
- Alert detail page rendered as a server component for instant load
- Dark UI with Tailwind v4, severity-colored left borders, summary
  cards with icons, sortable leaderboard table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 11:13:57 -04:00
Josh Wright
ef061ea910 Initial commit from Create Next App 2026-04-10 20:23:17 -04:00