Flarum tracks per-discussion read state in the discussion_user pivot, storing last_read_post_number so the client resumes at the first unread post instead of recomputing it.
What this Flarum schema covers
Discussions, threaded posts, and per-user read cursors
Groups, permission strings, and access tokens
Tags with parent categories and restricted flags
Post flags, likes, and @-mentions
Notifications and email/registration token flows
Suspension and subscription state on existing tables
A few decisions the diagram can't show:
notifications has no subject_type morph column; the type string plus a free-form data JSON blob identify what each one points at.
Mentions split into one pivot per target (post_mentions_user, post_mentions_post, post_mentions_group, post_mentions_tag) rather than a single polymorphic table.
posts has a unique (discussion_id, number) index, giving every post a stable sequential position within its thread.
Suspend and Subscriptions add columns to users and discussion_user (suspended_until, a follow/ignore enum) instead of new tables.
Counters like discussions.comment_count and tags.discussion_count are denormalized, kept in sync by the app.
Good fork target for a forum where read-tracking and threaded replies matter. Most deletes are soft hides via hidden_at/hidden_user_id, and extensions write to core tables, so plan migrations around those shared columns.
Open-source discussion forum platform — Flarum is a delightfully simple discussion platform for community forums