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:
206
README.md
206
README.md
@@ -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
|
```bash
|
||||||
npm run dev
|
git clone https://gitea.thewrightserver.net/josh/OverSnitch.git
|
||||||
# or
|
cd OverSnitch
|
||||||
yarn dev
|
npm install
|
||||||
# or
|
|
||||||
pnpm dev
|
|
||||||
# or
|
|
||||||
bun dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
# Optional — enables watch time stats and ghost/watch-rate alerts
|
||||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user