Social
The social layer is the spine of the site: the feed is the homepage, and most other areas post into it or link out of it.
The feed (RMHarks)
A post is an RMHark. The feed at / is the site’s index route (app/routes/_site/index.tsx) — not a marketing page.
Route |
What it is |
/
|
The timeline. |
/thread/:rootId
|
A post and its replies, threaded. |
/u/:userid/post/:postid
|
A single post in the context of its author. |
/moments/:id
|
A moment. |
/tag/:tag
|
Everything tagged with a hashtag. |
/explore
|
Discovery surface. |
/search
|
Universal search. |
/bookmarks
|
Posts you saved. |
/lists, /lists/:id
|
User-curated lists. |
/embed/post/:id
|
Embeddable single-post view (top-level, no shell). |
Where the code lives. lib/feed/ handles timeline assembly, ranking, personalization, cursors and mentions. lib/feed-types.ts defines the FeedItem contract the client renders against, and lib/feed-sse.ts is the event bus behind live updates. Components are in components/feed/ — which also owns the site-wide layout system (SiteShell, PageLayout, ContextRail, AnimatedMain).
Live updates ride SSE over createBus() from lib/realtime-bus.server.ts — a local EventEmitter with optional Redis fan-out, so a single-process deployment works without Redis and a multi-process one stays coherent with it. hooks/useFeedSSE is the client half.
Important
Every engagement mutation — like, comment, bookmark, follow, post — goes through
lib/social/engagement.server.ts. It owns the counters, SSE fanout,
notifications, XP, quest progress, achievements and webhook emission that each
of those actions triggers. The in-app routes and the public API both call it, so
a post created through the API awards XP exactly like one from the composer.
Adding a side effect anywhere else silently creates two behaviours.
Profiles and identity
Route |
What it is |
/u/:userid
|
A public profile. |
/settings
|
Account, appearance, privacy, notifications. |
/achievements, /progress
|
Progression surfaces. |
/wrapped, /recap
|
Periodic personal summaries. |
Handles are allocated at signup (lib/handle.ts, wired into lib/auth.ts). Rendering a user anywhere goes through userDisplaySelect / resolveUser in lib/user-display.ts — the shared Prisma selection that includes cosmetics — with useFreshUser/stores/userDisplayStore on the client so names and avatars update live rather than going stale mid-session.
Auth is Better Auth (lib/auth.ts): Discord, Google and GitHub OAuth, email/password, and passkeys, with Stripe and a customSession plugin that injects the subscription tier into the session. Custom user fields are username, handle, isAdmin, isVerified.
Messaging and groups
Route |
What it is |
/messages, /messages/:conversationId
|
Direct messages. |
/groups, /groups/:id
|
Group chats. |
/communities, /c/:slug
|
Communities. |
/spaces/:id
|
A live space. |
lib/messages.server.ts and lib/conversation.server.ts back DMs; lib/group-chat/ and lib/group-chats.server.ts back group chats; lib/communities/ and lib/community.server.ts back communities. /spaces redirects to /communities — the surface was folded in, and the old URL was kept rather than broken.
Notifications and presence
lib/notifications.server.ts is the single entry point for creating a notification. It respects the user’s preference matrix and mirrors to web push via lib/push/send.server.ts, so a caller doesn’t have to know whether the user wants push. Unread counts come from lib/useUnreadCount.ts and lib/useNotificationCount.ts.
Presence lives in lib/presence.server.ts with lib/usePresenceHeartbeat.ts on the client and the shared PEER_GRACE_MS grace window in lib/shared/realtime/types.ts — the same constant the realtime servers read, so a client and server never disagree about when a peer counts as gone.
Moderation
lib/moderation/ and lib/moderation.server.ts handle reports and enforcement; lib/admin-review.server.ts and lib/admin-audit.server.ts back the review queue and its audit trail. UserStrike and UserMute are the enforcement records. Admin surfaces live under /admin and are gated in one place — app/routes/_site/admin/route.tsx bounces anyone without isAdmin, so individual admin pages carry no gate of their own.
Social¶
The social layer is the spine of the site: the feed is the homepage, and most other areas post into it or link out of it.
The feed (RMHarks)¶
A post is an RMHark. The feed at
/is the site’s index route (app/routes/_site/index.tsx) — not a marketing page.Route
What it is
/The timeline.
/thread/:rootIdA post and its replies, threaded.
/u/:userid/post/:postidA single post in the context of its author.
/moments/:idA moment.
/tag/:tagEverything tagged with a hashtag.
/exploreDiscovery surface.
/searchUniversal search.
/bookmarksPosts you saved.
/lists,/lists/:idUser-curated lists.
/embed/post/:idEmbeddable single-post view (top-level, no shell).
Where the code lives.
lib/feed/handles timeline assembly, ranking, personalization, cursors and mentions.lib/feed-types.tsdefines theFeedItemcontract the client renders against, andlib/feed-sse.tsis the event bus behind live updates. Components are incomponents/feed/— which also owns the site-wide layout system (SiteShell,PageLayout,ContextRail,AnimatedMain).Live updates ride SSE over
createBus()fromlib/realtime-bus.server.ts— a localEventEmitterwith optional Redis fan-out, so a single-process deployment works without Redis and a multi-process one stays coherent with it.hooks/useFeedSSEis the client half.Important
Every engagement mutation — like, comment, bookmark, follow, post — goes through
lib/social/engagement.server.ts. It owns the counters, SSE fanout, notifications, XP, quest progress, achievements and webhook emission that each of those actions triggers. The in-app routes and the public API both call it, so a post created through the API awards XP exactly like one from the composer. Adding a side effect anywhere else silently creates two behaviours.Profiles and identity¶
Route
What it is
/u/:useridA public profile.
/settingsAccount, appearance, privacy, notifications.
/achievements,/progressProgression surfaces.
/wrapped,/recapPeriodic personal summaries.
Handles are allocated at signup (
lib/handle.ts, wired intolib/auth.ts). Rendering a user anywhere goes throughuserDisplaySelect/resolveUserinlib/user-display.ts— the shared Prisma selection that includes cosmetics — withuseFreshUser/stores/userDisplayStoreon the client so names and avatars update live rather than going stale mid-session.Auth is Better Auth (
lib/auth.ts): Discord, Google and GitHub OAuth, email/password, and passkeys, with Stripe and acustomSessionplugin that injects the subscriptiontierinto the session. Custom user fields areusername,handle,isAdmin,isVerified.Messaging and groups¶
Route
What it is
/messages,/messages/:conversationIdDirect messages.
/groups,/groups/:idGroup chats.
/communities,/c/:slugCommunities.
/spaces/:idA live space.
lib/messages.server.tsandlib/conversation.server.tsback DMs;lib/group-chat/andlib/group-chats.server.tsback group chats;lib/communities/andlib/community.server.tsback communities./spacesredirects to/communities— the surface was folded in, and the old URL was kept rather than broken.Notifications and presence¶
lib/notifications.server.tsis the single entry point for creating a notification. It respects the user’s preference matrix and mirrors to web push vialib/push/send.server.ts, so a caller doesn’t have to know whether the user wants push. Unread counts come fromlib/useUnreadCount.tsandlib/useNotificationCount.ts.Presence lives in
lib/presence.server.tswithlib/usePresenceHeartbeat.tson the client and the sharedPEER_GRACE_MSgrace window inlib/shared/realtime/types.ts— the same constant the realtime servers read, so a client and server never disagree about when a peer counts as gone.Moderation¶
lib/moderation/andlib/moderation.server.tshandle reports and enforcement;lib/admin-review.server.tsandlib/admin-audit.server.tsback the review queue and its audit trail.UserStrikeandUserMuteare the enforcement records. Admin surfaces live under/adminand are gated in one place —app/routes/_site/admin/route.tsxbounces anyone withoutisAdmin, so individual admin pages carry no gate of their own.