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>
This commit is contained in:
2026-04-12 11:16:49 -04:00
parent f871f86284
commit a8a03b59d5

206
README.md
View File

@@ -1,36 +1,200 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
# OverSnitch
## Getting Started
A self-hosted dashboard for monitoring Overseerr/Jellyseerr users — who's requesting, how much storage they're consuming, how often they actually watch what they request, and whether anything needs your attention.
First, run the development server:
Built with Next.js 16, TypeScript, and Tailwind CSS.
---
## Features
- **Leaderboard** — per-user request count, total storage, average GB per request, and optional Tautulli watch stats (plays, watch hours), each ranked against the full userbase
- **Alerting** — automatic alerts for stalled downloads, neglected requesters, and abusive patterns, with open/close state, notes, and auto-resolve when conditions clear
- **SWR caching** — stats are cached server-side for 5 minutes and seeded from localStorage on the client, so the dashboard is instant on return visits
---
## Setup
### 1. Clone and install
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
git clone https://gitea.thewrightserver.net/josh/OverSnitch.git
cd OverSnitch
npm install
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
### 2. Configure environment
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
Create `.env.local` in the project root:
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
```env
# Required
SEERR_URL=http://overseerr:5055
SEERR_API=your_overseerr_api_key
## Learn More
RADARR_URL=http://radarr:7878
RADARR_API=your_radarr_api_key
To learn more about Next.js, take a look at the following resources:
SONARR_URL=http://sonarr:8989
SONARR_API=your_sonarr_api_key
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
# Optional — enables watch time stats and ghost/watch-rate alerts
TAUTULLI_URL=http://tautulli:8181
TAUTULLI_API=your_tautulli_api_key
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
# Optional — if your services use self-signed certs
# NODE_TLS_REJECT_UNAUTHORIZED=0
```
## Deploy on Vercel
### 3. Run
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
```bash
npm run dev # development
npm run build && npm start # production
```
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
---
## Alerts
Alerts are generated on every stats refresh and persisted in `data/alerts.json` (gitignored). They have two states — **Open** and **Closed** — and can be manually closed with a per-category cooldown, or auto-resolved when the underlying condition clears.
### Content alerts
These are keyed per piece of media, not per user. If multiple users requested the same item, they're grouped into a single alert.
---
#### Not Downloaded
> A movie or TV show was approved but no file exists in Radarr/Sonarr.
| Parameter | Default | Description |
|---|---|---|
| `UNFULFILLED_MIN_AGE_DAYS` | `3` | Minimum days since approval before alerting. Prevents noise on brand-new requests. |
- Skipped entirely if Radarr reports `isAvailable: false` (unreleased) or Sonarr reports `status: "upcoming"`.
- **Auto-resolves** when the file appears (i.e. `sizeOnDisk > 0`).
- Manual close cooldown: **3 days**.
---
#### Incomplete Download
> An ended TV series has been partially downloaded (less than 90% of episodes on disk).
| Parameter | Default | Description |
|---|---|---|
| `UNFULFILLED_MIN_AGE_DAYS` | `3` | Same minimum age as above. |
| Completion threshold | `90%` | Series below this are flagged. Hardcoded. |
- Only fires for series with `status: "ended"` in Sonarr. Continuing shows are excluded because missing episodes may simply not have aired yet.
- Percentage is calculated as `episodeFileCount / totalEpisodeCount`, not Sonarr's `percentOfEpisodes` (which counts against monitored episodes only and would be inaccurate here).
- **Auto-resolves** when completion reaches 90%+.
- Manual close cooldown: **3 days**.
---
#### Pending Approval
> A request has been sitting unapproved for too long.
| Parameter | Default | Description |
|---|---|---|
| `PENDING_MIN_AGE_DAYS` | `7` | Minimum days a request must be pending before alerting. |
- One alert per request item, not per user.
- Skipped if the content is unreleased (same availability checks as above).
- **Auto-resolves** when the request is approved or declined.
- Manual close cooldown: **3 days**.
---
### User behavior alerts
These fire once per user. Ghost Requester takes priority over Low Watch Rate — a user will only ever have one behavior alert open at a time. Both require the user to be "established" (at least one request older than `USER_MIN_AGE_DAYS`) to avoid flagging new users.
> Requires Tautulli to be configured (except Frequent Declines).
| Parameter | Default | Description |
|---|---|---|
| `USER_MIN_AGE_DAYS` | `14` | Days since oldest request before a user is eligible for behavior alerts. |
---
#### Ghost Requester
> A user has made several requests but has never watched anything on Plex.
| Parameter | Default | Description |
|---|---|---|
| `MIN_REQUESTS_GHOST` | `5` | Minimum total requests before flagging. |
- Manual close cooldown: **14 days**.
---
#### Low Watch Rate
> A user watches a small fraction of what they request.
| Parameter | Default | Description |
|---|---|---|
| `MIN_REQUESTS_WATCHRATE` | `10` | Minimum requests before the ratio is considered meaningful. |
| `LOW_WATCH_RATE` | `0.2` | Ratio of `plays / requests` below which an alert fires (default: under 20%). |
- Manual close cooldown: **14 days**.
---
#### Frequent Declines
> A user has had multiple requests declined in a rolling window.
| Parameter | Default | Description |
|---|---|---|
| `MIN_DECLINES` | `3` | Minimum declined requests in the lookback window. |
| `DECLINE_LOOKBACK_DAYS` | `60` | Rolling window in days. |
- Does not require Tautulli.
- Manual close cooldown: **14 days**.
---
### System alerts
#### No Tautulli Watch Data
> Tautulli is configured but no plays matched any Overseerr user.
This usually means emails don't align between the two services. Check that users have the same email address in both Overseerr and Tautulli (or that display names match as a fallback).
- Manual close cooldown: **1 day**.
---
## Alert lifecycle
```
Condition detected
[OPEN] ◄──────────────────────────────────────┐
│ │
┌────┴───────────────┐ Cooldown │
│ │ expires │
▼ ▼ │
Condition Manually │
clears closed │
│ │ │
▼ ▼ │
[AUTO-RESOLVED] [CLOSED] ──── Condition ────────┘
no cooldown cooldown returns after
reopens suppresses cooldown
immediately re-open
```
- **Auto-resolved** alerts have no cooldown and will reopen immediately if the condition returns.
- **Manually closed** alerts suppress re-opening for a category-specific number of days (see cooldowns above).
- Reopening a manually closed alert via the UI clears the cooldown immediately.