Modules
Gamend keeps the contexts that define your domain and business logic.
The Accounts context.
What a user's age permits.
Oban worker that mirrors a user's external (OAuth provider) avatar into our own object storage, so avatars render from our storage/CDN instead of hotlinking the provider.
Warns a user their account is about to be deleted for inactivity.
Password hashing: Argon2id for new hashes, bcrypt still accepted for old ones.
How recently a user was seen, as the three states the UI actually draws.
Coalesces users.is_online transitions into one write per flush window.
Defines the scope of the caller to be used throughout the app.
Periodically sweeps users whose is_online flag is true but whose
last_seen_at timestamp is older than a configurable threshold.
The User schema and associated changeset functions used across the application (registration, OAuth, and admin changes).
Small helpers used to deliver transactional emails for the Accounts flow (confirmation, magic link, and email change instructions).
Functions and schema for persistent user tokens used by sessions, magic links, and email-change workflows.
Generates default usernames for new users.
The one place aggregate numbers come from. Four families
A user was seen on a UTC day. One row per (user_id, day); written once by
Gamend.Analytics.record_activity/2, never updated.
A named counter for one UTC day. Keys are free-form dotted strings owned by
the game ("level.finished", "level.started.lang:ja"); the engine only
stores and sums them. Written by Gamend.Analytics.count/3.
Mechanical checks for the conventions in docs/specs/api-conventions.md.
Apple OAuth client secret generation for Ueberauth.
Utilities for running best-effort background work.
Application cache backed by Nebulex.
L1 cache (local, in-memory).
L2 cache (partitioned topology).
This is the cache for the primary storage.
L2 cache backed by Redis.
Cache topology. The resolved levels are built from these in the host's
runtime config; Gamend.Cache itself holds the assembled structure.
Lightweight in-memory counters for cache effectiveness and overload signals, aggregated from telemetry events
Applies cache invalidations broadcast by other app instances.
Human verification for the unauthenticated browser forms, via Cloudflare Turnstile.
Context for chat messaging across lobbies, groups, and friend DMs.
Ecto schema for the chat_filter_words table — one entry of the chat word
blocklist.
Ecto schema for the chat_messages table.
Chat word filter and mutes.
Node-local hot path for chat moderation: the word blocklist and active mutes.
Canonical form for chat filter matching.
The notifications chat moderation sends: alerting admins that a report landed, warning a player, telling a player they were muted, and telling a reporter what came of their report.
Keeps the node-local chat-moderation ETS tables in sync with the database and the other app instances, and sweeps expired mutes.
Ecto schema for the chat_mutes table — a silenced chat sender.
Ecto schema for the chat_read_cursors table.
Ecto schema for the chat_reports table — a player- or filter-filed report
about a chat message.
The chat report queue.
Logs from the game client, put where the server's own logs already are.
One run of the game on one device, as seen from the server.
A lobby a client session was in.
Erlang distribution, needed for multi-node deployments and the partitioned L2 cache.
Typed reads of environment variables a plugin declared via env_vars/0.
Reads and renders Markdown content from project files and directories.
Where the server finds host-supplied content: the theme config, hook plugins, and the GeoIP database.
Connection and tuning settings for Gamend.Repo.
Virtual-currency wallets with an append-only ledger.
Append-only record of a single wallet change (grant, spend, transfer, admin adjustment). One row per balance mutation, keeping an auditable history.
A user's balance of one currency. Currencies are free-form string codes
("gold", "gems", "energy") — the game decides which exist.
Friends context - handles friend requests and relationships.
Ecto schema representing a friendship/request between two users.
Context module for group management: creating, updating, listing, joining, leaving, kicking, promoting/demoting members, and handling join requests.
Ecto schema for the groups table.
Ecto schema for the group_invites table.
Ecto schema for the group_join_requests table.
Ecto schema for the group_members join table.
Group invitations: creating, accepting, declining, cancelling, and listing/counting pending invites.
Join requests for private groups: requesting, listing, approving, rejecting, and cancelling.
Behaviour for application-level hooks / callbacks.
Registry of what a plugin declares it contributes, for observability and validation.
Default no-op implementation for Gamend.Hooks
Runtime registry for dynamic RPC function names exported by hook plugins.
Registry of game-defined protobuf schemas for typed hooks, plus the argument/result conversion that makes typed hooks callable from every transport and payload format.
Registry of game-defined protobuf schemas for KV entry data.
Registry of game-defined protobuf schemas for entity metadata.
Builds an OTP plugin bundle from plugin source code on disk.
Loads and manages hook plugins shipped as OTP applications under modules/plugins/*.
A loaded plugin descriptor.
Player item stacks — the non-fungible companion to Gamend.Economy.
A user's stack of one item. Items are free-form string codes
("health_potion", "sword", "card_374") — the game decides which exist.
metadata holds per-stack properties.
Append-only record of a single item-stack change (grant, consume, admin
adjustment) — the inventory counterpart of Gamend.Economy.LedgerEntry.
Carries the idempotency_key that makes item grants safe to retry.
Persistence for IP bans.
A persisted IP ban. expires_at is nil for permanent bans.
Durable background jobs, backed by Oban.
Generic key/value storage.
The Leaderboards context.
Ecto schema for the leaderboards table.
Ecto schema for the leaderboard_records table.
Central module for configurable validation limits.
Context module for lobby management: creating, updating, listing and searching lobbies.
Ecto schema for the lobbies table and changeset helpers.
Who is watching a lobby without being a member.
The vocabulary a lobby's state commonly uses.
Durable record of how a lobby's state evolved during a run.
Content-addressed storage for one snapshot section.
A decision worth explaining, recorded between two snapshots.
One capture of a lobby's state at a mutation entry point.
Buffers snapshots and events and bulk-inserts them.
Serialized execution using database-level advisory locks.
Reentrant, cluster-wide keyed mutex — the non-Postgres half of
Gamend.Lock.serialize/3.
Outbound email transport.
Public API for the built-in matchmaking system.
Broadcasts matchmaking events to users.
Constants for the matchmaking system.
Creates the lobby for a claimed match and notifies the players.
Match-forming logic for a group of tickets that share the same
match_params.
Ecto schema for a matchmaking ticket.
Periodic driver for the matchmaking sweep.
Notifications context – create, list, and delete persisted user-to-user notifications.
Ecto schema representing a notification sent from one user to another.
The metadata["type"] codes a notification may carry.
Default implementation for exchanging OAuth codes with providers.
Verifies Google OpenID Connect id_tokens for native/mobile sign-in flows.
Credentials and availability for the social sign-in providers.
Simple Ecto schema for OAuth session polling used by client SDKs.
Helpers for creating and retrieving short-lived OAuth sessions.
Context module for party management.
Ecto schema for the parties table.
Ecto schema for the party_invites table.
Payment catalog, purchase ledger, and entitlements.
User access grant derived from a purchase or admin/server action.
Internal product sold by one or more payment providers.
Runtime payment-provider configuration helpers.
Dedupe record for webhook and store notification events.
Maps an internal product to a provider-specific SKU or price id.
App Store Server API and StoreKit 2 adapter.
Verifies App Store JWS payloads (StoreKit signed transactions and App Store Server Notifications V2).
Google Play Billing adapter.
Steam MicroTxn adapter.
Minimal Stripe Checkout and webhook adapter.
Provider transaction record.
Provider reconciliation checkpoint.
Store credentials, per provider.
One question — "may this user do this to this thing?" — asked the same way everywhere.
Cluster-wide tracking of who is connected where.
Fixes proto3-optional presence checks in godobuf-generated GDScript.
Push context – device push-token registry and (see send_to_user/3)
server-authoritative delivery of push notifications.
Pigeon dispatcher for APNs. Configured by host_runtime.exs from the
APNS_* env vars; started by Gamend.Push.Supervisor only when that
config exists.
Delivers one push message to one token. One job per token is deliberate: FCM v1 and APNs are one-request-per-token anyway, and it buys exact per-token Oban retry/backoff — a half-delivered batch job would re-push duplicates on retry.
Pigeon dispatcher for FCM. Configured by host_runtime.exs from the
PUSH_FCM_* env vars; started by Gamend.Push.Supervisor only when
that config exists.
Expands a multi-user send into per-token DeliveryWorker jobs, in chunks,
off the caller's request path. Gamend.Push.send_to_users/3 enqueues
this above its inline threshold so a large broadcast never holds a long
transaction (SQLite is single-writer) and survives restarts. Identical args
within a minute dedupe via Oban uniqueness (double-broadcast guard).
A validated push message: what Gamend.Push.send_to_user/3 accepts and
what the delivery workers carry through job args.
Behaviour for push delivery providers.
APNs-direct provider for iOS, delivered through the
Gamend.Push.APNSDispatcher Pigeon dispatcher (token-auth .p8,
HTTP/2 over Mint). The apns-topic comes from APNS_TOPIC.
Firebase Cloud Messaging (HTTP v1) provider for Android and Web — and iOS
relay, if a game prefers Firebase over APNs-direct — delivered through the
Gamend.Push.FCMDispatcher Pigeon dispatcher, authenticated by the
Gamend.Push.Goth worker.
Zero-config default provider: logs each delivery instead of calling out —
the Storage.Local of push. Every token routed here (nothing configured,
PUSH_ADAPTER=log, or a provider whose dispatcher is down) reports success,
so the whole flow is exercisable with no credentials.
Ecto schema for a registered device push token.
Supervises the push delivery processes: the Goth worker (FCM OAuth) and the two Pigeon dispatchers.
Event-driven quest/progression engine.
One objective inside a quest definition: reach target occurrences of
event (as reported through Gamend.Quests.report_event/4).
Ecto schema for the quests table.
Ecto schema for the quest_progress table — one row per user, quest and
reset period.
One reward entry on a quest definition: amount of a currency
(via Gamend.Economy.grant/4) or an item
(via Gamend.Inventory.grant_item/4).
Ready checks: these players must each answer before this proceeds.
Ecto schema for one ready check — a moment at which a set of players must each answer before something proceeds.
Ecto schema for one player's answer inside a ready check.
Pushing game-defined realtime events to a player's socket.
Release-time equivalents of the host.* mix tasks.
Advisory locking for protecting TOCTOU (Time-of-Check-Time-of-Use) patterns.
Resolves every migration directory that belongs to a gamend deployment.
Periodically prunes old rows from unbounded tables.
Dynamic cron-like job scheduling for hooks.
Shared schema base: use Gamend.Schema instead of use Ecto.Schema.
JSON encoding for Ecto schemas under the API's null policy: string fields
encode as "" when nil and map fields as %{} — game clients (Godot in
particular) choke on null where they expect a string. Datetimes, numbers
and booleans keep null, where absence is semantic.
The declared configuration surface: every setting core, the host and its plugins expose, with its type, default, group, env var name and required level.
Declares a group of settings on a module.
WebRTC signaling: who is in a room, and relaying offers between them.
Object storage for user uploads (avatars, and future user-generated content).
Behaviour for object-storage backends.
Disk-backed storage — the default backend.
S3-compatible storage via ExAws.
Behaviour for pluggable site theming providers.
JSON-backed Theme provider. Reads one config file — from the
GAMEND_CONTENT_THEME_CONFIG setting or the host-owned default path — and
translates its text through gettext at read time.
Which leaves of a theme config are text, and which are configuration.
The server's wall clock, in milliseconds since the epoch, for sending to clients.
Bracket tournaments: registration → seeded single-elimination draw → timed rounds → champions. See TOURNAMENT_DESIGN.md.
One side of the bracket: a leader and their tournament progress.
A pairing plus a verdict: two entries that must produce a winner by
deadline_at. Never a lobby — how the pairing is played is game policy;
metadata is game scratch space (runs, lobby id, ...).
Periodic driver for tournament lifecycles: state transitions, match-ready
firing, deadline_at sweeps and recurrence spawns (Gamend.Tournaments.tick/0).
A bracket tournament occurrence.
Shared types used across Gamend contexts.
UUIDv7 Ecto type used for all primary and foreign keys.
Mix Tasks
Fills the database with enough demo data to exercise pagination and the list/detail pages at realistic sizes.
Enforces the naming and serialization conventions mechanically.
Writes content.pot from the titles and descriptions stored on quests,
leaderboards and tournaments.
One-shot migration for instances that stored translations in the database.
Writes .env.example from Gamend.Settings.all/0, grouped and
commented from each setting's declaration.
Writes the public Settings guide from Gamend.Settings.all/0.
Writes theme.pot from the strings in the theme config.
One-shot migration off one-JSON-file-per-locale.
Generates SDK stub modules from the real Gamend modules.
Generates protobuf bindings for every target from a .proto file.