Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ name: CI
on:
workflow_call:
pull_request:
push:
branches:
- main

permissions:
contents: read
Expand Down
56 changes: 5 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,14 @@
# Augur

## Overview

Discord bot for requesting movies and TV shows through [Seerr](https://github.com/seerr-team/seerr).

## Quick start

You need a Discord server where you can install an app, a reachable Seerr instance, Docker with Compose, and a Seerr API
key. Create the key in Seerr's administration/settings area; the exact menu label can vary between Seerr releases.

Clone or download this repository, then open its directory. With Git:

```sh
git clone https://github.com/mayvqt/Augur.git
cd Augur
```

1. In the [Discord Developer Portal](https://discord.com/developers/applications), create an application and add a bot.
Install it with the `bot` and `applications.commands` scopes. Grant the bot View Channel, Send Messages, Embed Links,
and Manage Messages; administrators also need Manage Server to configure approval messages.
2. Copy the example environment file and fill in the Discord token, Seerr API key, Seerr URLs, and any optional settings:

```sh
cp .env.example .env
$EDITOR .env
```

3. Start Augur:

```sh
docker compose up -d
```

4. Check startup with `docker compose logs -f augur`. In Discord, run `/link`, open the settings page, and save the
Discord ID shown by the bot in your Seerr notification settings. Then use `/request query:<title>` to search and
submit a request. Server administrators can use `/approvals enable channel:#approvals` for approval cards.

`AUGUR_SEERR_BASE_URL` must be reachable from the Augur container. The sample Seerr URL is intentionally a host
placeholder: this Compose file starts Augur only, so `http://seerr:5055` works only when a container named `seerr` is on
the same Docker network. For a separate Seerr installation, use its LAN hostname or IP and port instead. The public URL
is the browser-facing address that Augur sends to users for account linking.

Approval cards cover all Seerr request sources, notify linked requesters of the decision, and are removed two minutes
after approval or decline. State is stored in `./data`.

See [commands and approval permissions](docs/features.md) before enabling approval cards, and
[upgrades and backups](docs/releases.md#upgrading-and-rolling-back) before updating an existing installation.

## Documentation

- [Configuration](docs/configuration.md)
- [Features](docs/features.md)
- [Unraid](docs/unraid.md)
- [Releases](docs/releases.md)
- [Security](SECURITY.md)
- [Development](docs/development.md)
- Get started: [Setup](docs/setup.md) and [Configuration](docs/configuration.md)
- Run Augur: [Operations](docs/development/operations.md) and [Unraid](docs/unraid.md)
- Use the bot: [Capabilities](docs/capabilities.md) and [Commands and approvals](docs/features.md)
- Contribute: [Development](docs/development/README.md) and [Security](SECURITY.md)
- Follow releases: [Release notes](docs/releases.md)
- [License](LICENSE)
- [Issues](https://github.com/mayvqt/Augur/issues)

Expand Down
14 changes: 14 additions & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Capabilities

Augur lets Discord members search Seerr, preview a movie or show, choose TV
seasons, submit a request, and review their recent requests without leaving
Discord. Members can opt in or out of direct messages for approvals, declines,
and availability.

Server administrators can send pending Seerr requests to a Discord channel as
approval cards. Those cards also cover requests created outside Discord. Augur
polls Seerr for request decisions and availability, remembers delivery state
across restarts, and can expose private health, readiness, and metrics endpoints.

For exact commands and permissions, see [Commands and approvals](features.md).
For deployment settings, see [Configuration](configuration.md).
33 changes: 9 additions & 24 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
# Development

Use the Go version declared in [`go.mod`](../go.mod). Run automated checks from
the repository root:

```sh
gofmt -l ./cmd ./internal
go mod tidy -diff
go test ./...
go vet ./...
go test -race ./...
CGO_ENABLED=0 go build ./cmd/augur
```

The formatting command should print no paths. Tests use temporary SQLite files
and fake clients/transports; they do not need live Discord or Seerr credentials.
[CI](../.github/workflows/ci.yml) also runs static analysis, dependency vulnerability
checks, and a container build with entrypoint smoke tests. Image publishing reuses
these same gates. CI pins action commits and analysis tool versions; update the
pins deliberately and validate their checks before release.

For manual integration testing, follow the [setup instructions](../README.md#quick-start)
with a dedicated Discord application/server, Seerr instance, and isolated data.
`docker compose up --build` starts a live bot, reads local configuration/secrets,
and mounts `./data`; it is not an automated test. Stop the test deployment with
`docker compose down` when finished.
Start with the [development task index](development/README.md). It links to the
code map, architecture, storage, validation, operations, and documentation
guides.

For a manual integration test, follow the [setup guide](setup.md)
with a dedicated Discord application and server, a test Seerr instance, and an
isolated data directory. `docker compose up --build` starts a real bot and uses
the secrets in your local environment; stop it with `docker compose down` when
you finish.
13 changes: 13 additions & 0 deletions docs/development/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Development task index

Pick the page that matches the work:

- [Codebase map](codebase-map.md) — packages, entry points, and ownership.
- [Architecture](architecture.md) — Discord, Seerr, background work, and trust boundaries.
- [Data](data.md) — SQLite tables, migrations, identifiers, and retention.
- [Validation](validation.md) — focused checks, manual interaction checks, and CI.
- [Operations](operations.md) — deployment, backups, health, releases, and rollback.
- [Documentation conventions](documentation-conventions.md) — where public information belongs.

The repository [README](../../README.md) indexes user and operator guides.
Security-sensitive work also needs [Security](../../SECURITY.md).
36 changes: 36 additions & 0 deletions docs/development/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Architecture

`cmd/augur` loads configuration and creates an `app.Runner`. The runner owns
the Discord connection, Seerr client, SQLite store, optional health server, and
background monitor. Discord handlers ask the runner to perform application
operations; protocol details stay in `internal/discordbot` and `internal/seer`,
and durable state stays in `internal/storage`.

## Sources of truth

- Discord owns server membership, channel permissions, interaction identity,
messages, and component events.
- Seerr owns linked users, request permissions, quotas, request decisions, and
media availability.
- SQLite owns Augur's subscriptions, delivery decisions, approval-channel
settings, rendered-message references, and notification preferences.
- `config.json` supplies defaults; environment variables override supported
fields at startup. [Configuration](../configuration.md) is the public contract.

Commands and component IDs are public interaction contracts. Seerr endpoints and
Discord payloads are external contracts: check their current official
documentation, then cover changes with fake clients or transports before using a
dedicated live test environment.

## Trust and concurrency

The Discord token, Seerr API key, user IDs, guild/channel IDs, request details,
and database are sensitive. Approval actions use the configured Seerr API key,
so the Manage Server or Administrator permission check is a security boundary.
Account-name matching must never replace explicit Seerr linking.

The runner serializes lifecycle changes and approval reconciliation separately.
Background polling, Discord callbacks, and shutdown can overlap. Keep operations
idempotent, make state changes durable before sending notifications where
practical, bound retries and waits, and honor context cancellation. SQLite uses
one connection and WAL mode; do not add parallel database owners.
17 changes: 17 additions & 0 deletions docs/development/codebase-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Codebase map

| Path | What lives here |
| --- | --- |
| `cmd/augur` | Process entry point, signal handling, configuration loading, and logging setup. |
| `internal/app` | Application lifecycle, request/approval coordination, polling, health endpoints, and metrics. |
| `internal/config` | JSON and environment configuration, defaults, normalization, and validation. |
| `internal/discordbot` | Discord session lifecycle, slash commands, buttons, previews, approval cards, formatting, and delivery cache. |
| `internal/seer` | Seerr HTTP client, account links, requests, status, and user lookup. |
| `internal/storage` | SQLite schema, migrations, subscriptions, approvals, notification preferences, and scans. |
| `internal/safelog` | Log redaction and safe error output. |
| `Dockerfile`, `docker-entrypoint.sh`, `docker-compose.yml` | Container build, startup, ownership, and example deployment. |
| `unraid` | Unraid application template. |
| `.github/workflows` | CI, dependency review, image publishing, and release announcements. |

Tests sit beside the packages they cover. Update this map when a package takes
on a new responsibility or a top-level area is added.
27 changes: 27 additions & 0 deletions docs/development/data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Data and migrations

`internal/storage/store.go` is the schema and migration source of truth. The
`schema_migrations` ledger records applied versions. Current tables store:

- request subscriptions and availability completion;
- approval settings per Discord server;
- approval-message IDs and decisions;
- notification preferences per Discord user; and
- decision-notification deduplication.

Discord, guild, channel, message, Seerr request, and media IDs are identifiers,
not proof of authorization. Re-check permissions at the action boundary. The
database may reveal account relationships and request history, so treat it and
its backups as private.

Migrations run in transactions and move forward only. Add a new numbered
migration; never edit or delete a version that may already be applied. Prefer an
expand/contract sequence when a rolling transition needs old and new code to
coexist. Startup rejects a migration version newer than the binary understands
instead of risking changes to a future schema.

Each schema change needs tests for a fresh database, upgrade from every affected
supported version, preservation of existing rows, repeat startup, and failure
behavior. Keep SQL and migration compatibility in `internal/storage`. Restore
the full data directory for rollback; an older binary may not understand a newer
schema.
27 changes: 27 additions & 0 deletions docs/development/documentation-conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Documentation conventions

Write for the person using the page. Keep installation steps in
[Setup](../setup.md), settings in [Configuration](../configuration.md), command help in [Features](../features.md), shipped scope in
[Capabilities](../capabilities.md), release changes in [Releases](../releases.md),
and contributor details in this directory. Link instead of repeating a procedure.
Do not add empty roadmap or known-issues pages; add one only when there is accepted
future work or a reproduced issue worth publishing.

For a risky integration change, keep the agreed design stable while work is in
progress and record test evidence separately. List the external operations,
check Discord and Seerr behavior against their official documentation, cover it
with deterministic fakes, and make any live test clearly opt-in.

## Documentation impact map

| If you change... | Also update... |
| --- | --- |
| A command, message, approval, or notification | [Features](../features.md), [Capabilities](../capabilities.md) when scope changes, and the README if navigation changes |
| Configuration or setup | [Setup](../setup.md), [Configuration](../configuration.md), Unraid docs when affected, and their nearest index |
| Package ownership or architecture | [Codebase map](codebase-map.md), [Architecture](architecture.md), and this index |
| Schema, identifiers, or retained state | [Data](data.md), [Operations](operations.md) when upgrades change, and this index |
| Tests, tools, interaction states, or CI | [Validation](validation.md) and this index |
| Credentials, permissions, or disclosure | [Security](../../SECURITY.md), the relevant architecture/data/operations page, and the nearest index |
| Deployment, backup, health, rollback, or release | [Operations](operations.md), [Releases](../releases.md), and public setup/configuration pages that changed |

Add new documentation domains here and to the nearest index.
34 changes: 34 additions & 0 deletions docs/development/operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Operations

Run Augur with the smallest practical permissions: one writable `/data`
mount, outbound access to Discord and Seerr, and no public inbound port unless
the optional health server is deliberately exposed to a private monitoring
network. Keep the Discord token, Seerr API key, `.env`, `config.json`, data
directory, and diagnostics private. Redact IDs and request details when they are
not needed to diagnose a problem.

## Back up, upgrade, and roll back

1. Record the current immutable image tag or digest and read the release notes.
2. Stop Augur, then copy the entire data directory and deployment configuration
to restricted off-host storage.
3. Restore that backup into a separate test location and confirm the bot starts,
retains approval settings and subscriptions, and can read the database.
4. Deploy a published version tag or digest, then check logs, a harmless command,
a synthetic request, and any configured approval channel.

`latest` moves and is not a rollback reference. Migrations run at startup and
are forward-only. To roll back across a schema change, stop Augur, restore the
matching pre-upgrade data, and start the previous immutable image. Local state
created after the backup is lost; requests already sent to Seerr are not undone.

When enabled, `/healthz` reports that the health process is running, `/readyz`
checks readiness and SQLite access, and `/metrics` exposes counters. These
endpoints are unauthenticated, so bind them privately. A release is complete only
after the exact revision passes CI, the published artifact is tied to that
revision, and post-deploy health and Discord/Seerr checks succeed.

The release sequence is: update [release notes](../releases.md), run the final CI
gate, create an annotated `vX.Y.Z` tag, publish the matching GitHub release,
verify the versioned image, and announce any operator action. Repairs that change
Discord messages, Seerr requests, or SQLite state must be explicit and opt-in.
33 changes: 33 additions & 0 deletions docs/development/validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Validation

Start with the narrowest useful check:

| Change | Focused check |
| --- | --- |
| Application coordination or health | `go test ./internal/app` |
| Discord commands, cards, or formatting | `go test ./internal/discordbot` |
| Seerr protocol | `go test ./internal/seer` |
| SQLite or migrations | `go test ./internal/storage` |
| Configuration or redaction | `go test ./internal/config ./internal/safelog` |
| CLI startup | `go test ./cmd/augur` |
| Release binary | `CGO_ENABLED=0 go build -trimpath -o /tmp/augur ./cmd/augur` |

Run `gofmt -w` on touched Go files. For performance work, include a
representative before/after benchmark or trace and a regression limit.

Discord changes also need a manual pass in a dedicated server with synthetic
requests. Check command discovery, keyboard use in Discord clients, ephemeral and
public responses, missing links, empty search/results, API errors, expired
components, permission denial, DM-disabled users, and shutdown during polling.
Check narrow and desktop Discord layouts when card content changes. Live Discord
or Seerr tests are opt-in and must never use production tokens or data.

Use the Go version in `go.mod`. Do not install tools or download dependencies
without approval. Reuse a module cache only when `go.sum`, the Go toolchain,
OS/architecture, and installed module tree match the revision; otherwise use a
clean locked environment or stop.

The final gate is the complete `CI` workflow in `.github/workflows/ci.yml` on
the exact revision. It checks formatting, `go mod tidy -diff`, whitespace,
tests, vet, the race detector, pinned Staticcheck and govulncheck versions, the
release build, Docker build, entrypoint behavior, and runtime ownership.
31 changes: 3 additions & 28 deletions docs/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,9 @@ tag is published. Pin production deployments to a published semver tag; use `lat

- Standardize project documentation and harden release automation.

- Refuse to open database state created by a newer Augur version.
- Reject zero-padded root user/group IDs in container configuration.
- Clarify setup, account linking, approval permissions, and backup procedures.

## Release procedure

Release checklist:

1. Preflight: run the full checks in [`development.md`](development.md), review migration notes, and build and
smoke-test the image.
2. Tag: create an annotated semver tag, for example `git tag -a v1.2.3 -m "v1.2.3"`.
3. Publish: push the tag and create the matching GitHub release, then verify the published container image.
4. Announce the release with upgrade notes and supported changes.

## Upgrading and rolling back

1. Read the release notes and record the image tag you currently use. Choose an
image tag listed on the [published release](https://github.com/mayvqt/Augur/releases);
Git tags include a `v` prefix, while versioned container tags omit it.
2. Stop Augur with `docker compose stop augur`, then back up the entire `data/`
directory and your deployment configuration. Keep the backup private: it
contains account IDs, request state, and possibly credentials.
3. Set `image:` in `docker-compose.yml` to the chosen container tag, run
`docker compose pull augur`, then `docker compose up -d augur`.
4. Check `docker compose logs --tail=100 augur`, then verify `/request` and any
approval channel you use.

Database migrations run on startup. Do not edit or delete applied migrations.
An older image may not support a newer database schema. To roll back, stop Augur,
restore the matching pre-upgrade data backup when required by the release notes,
and start the previous image tag. Restoring a backup loses local changes made
since that backup; Seerr requests already submitted are not undone.
Release and upgrade procedures live in [Operations](development/operations.md).
This page is only for changes that shipped or are ready for the next release.
Loading