Skip to content

Forum

Trackarr ships an in-app forum so a private community can organise outside the torrent listings. It sits at /forum, with three tables on the database side and a thin permission model layered on top.

Data model

forum_categories  ──┐
                    │ has many
forum_topics ───────┤
                    │ has many
forum_posts        ─┘
TableNotes
forum_categoriesOperator-curated structure. Each row has a name, optional description, optional Phosphor icon, optional hex color, and an order integer for sidebar sorting.
forum_topicsOne row per thread. Carries isPinned + isLocked booleans. authorId is ON DELETE SET NULL — when a user is deleted their threads remain (rendered as "[deleted]").
forum_postsReplies to a topic. Same authorId deletion semantics as topics.

Why "[deleted]" instead of cascade?

Cascading from users to forum_topics/forum_posts would have blocked every user-deletion request behind the FK. With SET NULL we can purge a spam account without losing the rest of the discussion — the contributions stay, only the byline disappears.

Permission matrix

SurfaceAnonymousUserAuthor of the rowMod/Admin
Browse categories + topics
Read a topic
Create a topic✅¹
Reply to a topic✅¹
Edit a topic / post
Delete a topic / post
Pin / Unpin
Lock / Unlock
Create / Edit / Delete a category✅ (admin only)

¹ Members cannot post in a topic that is isLocked = true. Mods/admins ignore the lock.

UI

/forum — index

A sidebar lists every category sorted by order ASC. Each category has its own colour rail and Phosphor icon when configured, otherwise the UI falls back to neutral chrome. The main pane shows the most recent topics across all categories.

/forum/category/[id] — category page

Topics are sorted: pinned first (by most-recently-updated), then everything else by most-recently-updated. Each row shows the title, author, reply count, and the relative time of the last reply.

/forum/topic/[id] — topic page

A pinned banner appears for isPinned, a lock icon for isLocked. The composer is hidden when locked unless the viewer is staff. Authors get an inline edit/delete pencil on their own posts; staff get it on every post.

/forum/new-topic — creation form

Pre-fills the category from the ?category= query param when present (e.g. the "New topic" button on a category page).

Lifecycle

                       POST /api/forum/topics


                      ┌─────────────────┐
                      │  fresh topic    │
                      └───────┬─────────┘

       ┌──────────────────────┼──────────────────────┐
       │                      │                      │
       │ POST /api/forum/posts (members + staff)
       │                      │                      │
       ▼                      ▼                      ▼
  ┌─────────┐          ┌───────────┐          ┌──────────┐
  │ replies │          │ mod pins  │          │ mod locks│
  │ accrue  │          │ /pin      │          │ /lock    │
  └─────────┘          └───────────┘          └──────────┘


                    DELETE by author or mod
                    cascades to every post
                    (FK `ON DELETE CASCADE`)

API surface

MethodPathAuthNotes
GET/api/forum/categoriespublicIndex.
GET/api/forum/categories/:idpublicCategory detail + paginated topics.
POST/api/forum/categoriesadminCreate.
PUT/api/forum/categories/:idadminEdit.
DELETE/api/forum/categories/:idadminRemove (cascades to topics + posts).
POST/api/forum/topicsuserCreate. Required: { categoryId, title, content }.
GET/api/forum/topics/:idpublicTopic + paginated posts.
DELETE/api/forum/topics/:idauthor/modRemove.
PUT/api/forum/topics/:id/pinmodToggle pin.
PUT/api/forum/topics/:id/lockmodToggle lock.
POST/api/forum/postsuserReply. Required: { topicId, content }.
PATCH/api/forum/posts/:idauthor/modEdit.
DELETE/api/forum/posts/:idauthor/modDelete.
GET/api/forum/statspublicAggregates (topic count, post count, latest reply).

Notifications

Forum activity routes through the standard notification pipeline (see Notifications). The events surfaced today are:

  • new_report_filed — when a forum post is reported, every staff member gets a notification (this is the generic report fan-out, not forum-specific).
  • report_actioned — when a moderator dismisses or resolves a report on the user's post.

The forum doesn't emit "someone replied to your thread" notifications today — that's on the roadmap.

Reporting

Forum posts are one of the four target types in Reports (target_type = 'post'). A resolved report on a post target does not cascade to a delete — moderators still need to pull the trigger manually from the post's edit/delete affordance. This is deliberate: a single report shouldn't be enough to nuke a discussion entry.

Implementation reference

ConcernFile
Schema (categories / topics / posts)packages/db/src/schema.ts
Public category + topic readsapps/api/routes/api/forum/categories/*, topics/*
Topic + post creationapps/api/routes/api/forum/topics/index.post.ts, posts/index.post.ts
Pin / lock togglesapps/api/routes/api/forum/topics/[id]/pin.put.ts, lock.put.ts
Web pagesapps/web/app/pages/forum/*

Released under the MIT License.