Player Domain¶
Status: ๐ง Partial โ Player, User, Team, Reputation, FirstLogin model family, and
PlayerWarpKnowledgestorage are all committed.nickname, the ARIA trust/abuse counters,is_suspect/is_wanted,suspect_until,suspect_team_snapshot, andwanted_untilare shipped Player columns.PlayerCentralBankAccountis shipped (migrationd1e4a7b2c908, deposit paths re-pointed).TakeoverIntentremains design-only. (re-verified 2026-08-21 vs Sectorwars2102 HEAD46bce720; substance unchanged โ Bank + withdraw routes per banner body still accurate)
User accounts, the in-game Player row, the first-login onboarding flow, teams, reputation, and messaging.
Schema status¶
Per ADR-0066 D-V1, schema-level implementation status is consolidated here. Field descriptions describe the target schema.
Design-only columns โ present in the spec, not yet committed:
PlayerTradingProfile,AIRecommendation: model classes exist; columns above are the launch target.PlayerCentralBankAccount: shipped (migrationd1e4a7b2c908; cascade deposit paths re-pointed). Withdraw routes shipped (PR #580,f98c5ba8) โcentral_bank_service.py'sENTRY_WITHDRAW_CREDITS/ENTRY_WITHDRAW_COMMODITYledger constants are now consumed by live withdraw-credits/withdraw-commodity routes, docking-gated per ADR-0054 (full withdraw at Starport Prime; non-Prime credit withdraw allowed under the access-override). Player-client UI panel shipped separately (PR #582).TakeoverIntent: entire model is design-only โ schema below describes the launch target.PlayerWarpKnowledge's ARIA hint-generation and player-facing reveal surfacing (see../FEATURES/gameplay/aria-companion.mdยง Warp discovery) are Release-tier; the storage table itself is committed.
All other columns on this page are committed, including nickname, aria_trust_score, aria_blocked_until, aria_violation_count, is_suspect, is_wanted, suspect_until, suspect_team_snapshot, and PlayerWarpKnowledge's storage schema.
User¶
Source: services/gameserver/src/models/user.py
Purpose: Authentication-layer account. One User may own one Player (game state) and/or AdminCredentials. Subscription / billing flags live here.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| username | String(50) | unique, not null | |
| String(255) | unique, nullable | optional | |
| is_active | Boolean | default true | |
| is_admin | Boolean | default false | |
| last_login | DateTime | nullable | |
| deleted | Boolean | default false | soft delete |
| paypal_subscription_id, subscription_tier, subscription_status | String | nullable | galactic_citizen etc. |
| subscription_started_at, subscription_expires_at | TIMESTAMP | nullable |
Relationships:
- player (1:1, cascade), admin_credentials (1:1, cascade), player_credentials (1:1, cascade), mfa_secret (1:1, cascade).
- oauth_accounts, refresh_tokens, mfa_attempts (1:many).
- owned_regions โ Region.
Player¶
Source: services/gameserver/src/models/player.py
Purpose: In-game state for a user โ credits, turns, reputation snapshot, location, ship pointer, ARIA AI counters, and regional citizenship.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| user_id | UUID FK users.id | unique, not null, CASCADE | 1:1 with User |
| nickname | String(50) | nullable, unique index | Optional in-game callsign. Set via the first-login confirmation step (see ../SYSTEMS/first-login.md#completion-side-effects-complete_first_login) โ gated on player Yes/No after extraction-and-validation; 3โ20 chars; alphanumeric + _ + - + single internal space; profanity- and impersonation-filtered; unique across all Players. NULL means no callsign set; UI falls back to User.username. |
| credits | Integer | default 10000 | |
| turns | Integer | default 1000 | |
| reputation | JSONB | default {} | per-faction reputation snapshot. Drop-approved (ADR-0093 item 26) โ superseded by the Reputation per-faction row model; DROP pending the migration that removes this column. |
| personal_reputation | Integer | default 0 | -1000..+1000 alignment (migration fe22441146b1) |
| reputation_tier | String(50) | default Neutral |
cached tier name |
| name_color | String(20) | default #FFFFFF |
UI color cache |
| military_rank | String(50) | default Recruit |
rank progression |
| rank_points | Integer | default 0 | |
| aria_bonus_multiplier | Float | default 1.0 | 1.0-1.5 (migration f4a5b6c7d8e9) |
| aria_consciousness_level | Integer | default 1 | 1-5 |
| aria_relationship_score | Integer | default 25 | 0-100 |
| aria_total_interactions | Integer | default 0 | |
| aria_trust_score | Float | default 1.0 | 0.0โ1.0; player-facing trust counter that ARIA's content-policy and abuse-detection layer reads. Drops on policy violations (jailbreak attempts, prompt injection, abusive content). Recovers slowly with sustained legitimate interaction. See ../OPERATIONS/aria.md, ../SYSTEMS/aria-dialogue.md. |
| aria_blocked_until | DateTime | nullable | Auto-block timer set when trust hits a floor; ARIA refuses interaction until expiry. Admin can clear via the trust-reset endpoint. |
| aria_violation_count | Integer | default 0 | Cumulative count of policy violations triggering trust drops. Resets on admin trust-reset; drives escalation thresholds (warn โ soft-block โ hard-block). |
| current_ship_id | UUID FK ships.id | nullable, SET NULL | |
| home_sector_id, current_sector_id | Integer | default 1 | integer sector numbers |
| is_docked | Boolean | default false | |
| current_port_id | UUID FK stations.id | nullable, SET NULL | station player is docked at (migration 5f5a988bdbb1); FK targets stations |
| is_landed | Boolean | default false | |
| current_planet_id | UUID FK planets.id | nullable, SET NULL | |
| team_id | UUID FK teams.id | nullable, SET NULL | |
| attack_drones, defense_drones, mines, genesis_devices | Integer | defaults 0 | aggregated counters |
| insurance | JSONB | nullable | |
| last_game_login | DateTime | nullable | distinct from User.last_login |
| turn_reset_at | DateTime | nullable | |
| settings | JSONB | default {} | UI / language / audio / accessibility / privacy / notifications / active bounties / emergent_rep_throttle daily faction-rep counters (see below) โ full shape in jsonb-schema.md#playersettings |
| first_login | JSONB | default | quick flag, separate from FirstLoginSession trail |
| is_active | Boolean | default true | in-game deactivation |
| home_region_id, current_region_id | UUID FK regions.id | nullable | |
| is_galactic_citizen | Boolean | default false | unlocks cross-region travel |
| is_suspect | Boolean | default false | temporary "gray" flag (separate from persistent personal_reputation); fires from early-window Cargo Wreck salvage and similar antisocial-but-not-criminal actions. While true, fed-space immunity is suspended and name color renders gray/yellow. See ../FEATURES/gameplay/ranking.md#suspect-status-temporary-flag. |
| suspect_until | DateTime | nullable | timestamp when is_suspect auto-clears; max cumulative 4 hours from first triggering event. |
| suspect_team_snapshot | UUID[] | nullable | Per ADR-0061 S-V4 โ frozen team-mate set captured at suspect-status acquisition. Team-mate exemptions during the grace window evaluate against this snapshot, not live team membership. Mid-grace team changes don't affect existing exemptions; the snapshot is taken once at first acquisition and not refreshed by extension events. Cleared when is_suspect clears. NULL when not flagged; empty array when the player had no team. |
| is_wanted | Boolean | default false | persistent "criminal" flag fired by piloting a ship reported stolen. While true, name renders red, fed-space immunity suspended, NPC patrols hunt, automatic bounty placed, daily personal-reputation drain. Clears when the pilot leaves the stolen ship. See ../FEATURES/gameplay/ranking.md#wanted-status, ../SYSTEMS/ship-registry.md. |
| wanted_until | DateTime | nullable | โ
Shipped 2026-08-04 (wanted_service.py). Fixed-duration auto-clear timestamp for the Severe-severity black-market bust Wanted trigger only โ refreshed to now + 24h (NO-CANON magnitude) on every bust, swept by a scheduler job. NULL for the stolen-ship and reputation-recovery triggers (condition-based clears via recompute_is_wanted(), parallel field to suspect_until). Stolen-ship + personal_reputation < โ500 writers shipped 2026-08-04 (6143a14e / boarding sync 2652c798). |
Daily faction-rep throttle (per ADR-0056 N-V1): daily_faction_rep_consumed / daily_faction_rep_consumed_date are not dedicated Player columns โ they live under Player.settings["emergent_rep_throttle"] (JSONB). The bucket tracks the sum of positive faction-rep deltas applied today across all factions, compared against a single global daily pool (Launch: 100 rep / day) by apply_emergent_action before a rep delta lands, and rolls over by local date. The two cascade-redemption actions per ADR-0056 N-F2 bypass this counter.
ADR-0056's multi-account detection also gates planet-settlement contests (the settle_contest surface, ADR-0091 ยง8 Amendment A) โ a HARD-flagged cluster member is ineligible to contest (settle) a planet. See ../OPERATIONS/multi-account-detection.md.
Relationships:
- user โ User.
- ships โ Ship (1:many, FK Ship.registered_owner_id per ADR-0008); current_ship โ Ship (FK current_ship_id, post-update).
- team โ Team (FK team_id); team_membership โ TeamMember (1:1).
- faction_reputations โ Reputation (1:many).
- planets (many-to-many via player_planets), stations (many-to-many via player_stations).
- discovered_sectors โ Sector.
- genesis_devices โ GenesisDevice (1:many โ note: this shadows the integer counter genesis_devices defined on the same class earlier; the relationship wins at runtime).
- combat_logs_as_attacker, combat_logs_as_defender โ CombatLog.
- created_warp_tunnels โ WarpTunnel.
- market_transactions โ resource.MarketTransaction (resource-enum table); enhanced_market_transactions โ market_transaction.MarketTransaction (commodity-string table).
- first_login_sessions (1:many), first_login_state (1:1).
- regional_memberships โ RegionalMembership; inter_regional_travels โ InterRegionalTravel.
- AI: trading_profile, ai_recommendations, aria_memories, aria_market_intelligence, aria_exploration_map, aria_trading_observations, ai_assistant.
- commanded_fleets โ Fleet; fleet_memberships โ FleetMember.
- drones โ Drone; drone_deployments โ DroneDeployment.
Note: the genesis_devices name is overloaded (integer column + relationship). In practice the relationship overwrites the column attribute. The integer counter is still backed by the database column; access via Player.__table__.c.genesis_devices if you need it.
PlayerTradingProfile¶
Source: services/gameserver/src/models/ai_trading.py (PlayerTradingProfile)
Purpose: Per-player trading profile that aggregates ARIA's view of how the player trades โ risk tolerance, commodity preferences, performance metrics. Distinct from ARIATradingPattern (Trade DNA per-pattern); this is the player-level summary.
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| player_id | UUID FK players.id | unique, CASCADE | 1:1 with Player |
| risk_tolerance | Float | default 0.5 | 0.0 = ultra-conservative; 1.0 = high-risk |
| preferred_commodities | JSONB | default [] |
array of commodity names ordered by player preference |
| avoided_sectors | JSONB | default [] |
array of sector compound IDs the player consistently avoids |
| ai_assistance_level | String(10) | default medium |
minimal / medium / full (see ../FEATURES/gameplay/aria-companion.md#player-controlled-assistance-level) |
| notification_preferences | JSONB | default {} |
per-event notification toggles (route_alerts, market_alerts, combat_alerts, genesis_alerts) |
| last_active_sector | UUID FK sectors.id | nullable | most recent sector the player traded from |
| average_profit_per_trade | Float | default 0.0 | rolling average across the trading history |
| total_trades_analyzed | Integer | default 0 | denominator for the rolling averages |
| created_at, updated_at | DateTime | defaults |
Relationships: player (1:1).
The model class exists; the schema fields above are the launch target. Currently unused beyond the relationship reference. (See "Schema status" at the top of this file.)
AIRecommendation¶
Source: services/gameserver/src/models/ai_trading.py (AIRecommendation)
Purpose: Persistent record of a recommendation ARIA surfaced to the player, with feedback-loop fields the trading pattern fitness loop reads.
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| player_id | UUID FK players.id | indexed, CASCADE | |
| recommendation_type | String(20) | not null | buy / sell / route / avoid |
| recommendation_data | JSONB | not null | service-private opaque shape (see ./jsonb-schema.md for redaction rules) |
| confidence_score | Float | default 0.5 | 0.0โ1.0 |
| expected_profit | Numeric | nullable | predicted profit in credits |
| risk_assessment | String(10) | default medium |
low / medium / high |
| reasoning | Text | nullable | human-readable explanation surfaced in the UI |
| priority_level | Integer | default 3 | 1 (lowest) โ 5 (highest); drives surface-priority in companion panel |
| created_at | DateTime | indexed, default utcnow | |
| expires_at | DateTime | nullable, indexed | recommendation auto-purges past this point |
| accepted | Boolean | nullable | NULL = pending; True = player accepted; False = player explicitly dismissed |
| accepted_at | DateTime | nullable | |
| outcome_profit | Numeric | nullable | actual profit captured post-hoc; feeds Trade DNA fitness |
| outcome_timestamp | DateTime | nullable | |
| feedback_score | Integer | nullable | 1โ5 player rating |
| feedback_text | Text | nullable | optional player commentary |
Relationships: player (FK).
The model class exists; columns above are the launch target. Recommendation generation, acceptance tracking, outcome attribution, and the feedback loop into Trade DNA are all design-stage. Anti-gaming on the feedback loop is documented in ../OPERATIONS/aria.md#recommendation-anti-gaming. (See "Schema status" at the top of this file.)
FirstLoginSession + Friends¶
Source: services/gameserver/src/models/first_login.py
Purpose: Captures the AI-driven onboarding dialog where the player tries to claim a starter ship from a guard; logs negotiation outcomes and drives starting state.
FirstLoginSession¶
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| player_id | UUID FK players.id | not null, CASCADE | |
| started_at | DateTime | server default now | |
| completed_at | DateTime | nullable | |
| ai_service_used | Boolean | default false | |
| fallback_to_rules | Boolean | default false | |
| guard_name, guard_title, guard_trait, guard_description | String | nullable | personality bundle (migration ec92f8afd44a) |
| guard_base_suspicion | Float | nullable | |
| ship_claimed | Enum ship_choice |
nullable | what player tried to claim |
| extracted_player_name | String | nullable | |
| negotiation_skill | Enum negotiation_skill_level |
nullable | WEAK/AVERAGE/STRONG |
| final_persuasion_score | Float | nullable | |
| outcome | Enum dialogue_outcome |
nullable | SUCCESS/PARTIAL_SUCCESS/FAILURE |
| awarded_ship | Enum awarded_ship_type |
nullable | |
| starting_credits | Integer | nullable | |
| negotiation_bonus_flag, notoriety_penalty | Boolean | nullable | |
| client_info, performance_metrics | JSONB | nullable |
Relationships: player, dialogue_exchanges (1:many cascade), ship_options (1:1 cascade).
DialogueExchange¶
Per-turn record of the negotiation. Key columns: session_id (FK), sequence_number, npc_prompt, player_response, topic, persuasiveness, confidence, consistency, key_extracted_info JSONB, detected_contradictions ARRAY(String). AI logging fields (migration 6acc65ee7a72): ai_provider, ai_system_prompt, ai_user_prompt, ai_raw_response, believability, current_suspicion, response_time_ms, estimated_cost_usd, tokens_used.
ShipPresentationOptions¶
Per-session ship offering. Columns: session_id FK, available_ships ARRAY(String), escape_pod_present (default true), rarity_roll (0-100), special_event_active, seed_value.
ShipRarityConfig¶
Static config: ship_type (unique), rarity_tier (1-5), spawn_chance (0-100), base_credits, and three persuasion thresholds (weak_threshold, average_threshold, strong_threshold). Several migrations rebalance these (2e78250f47bc, 6b1d95a38c98, c5e32c313020).
PlayerFirstLoginState¶
Tracks completion across sessions. Columns: player_id (unique FK), has_completed_first_login, current_session_id (FK), attempts, last_attempt_at, completion bools (claimed_ship, answered_questions, received_resources, tutorial_started), and history arrays previous_ship_claims, previous_dialogue_strategies.
Team¶
Source: services/gameserver/src/models/team.py
Purpose: Player alliance with shared treasury, sector claims, and reputation aggregation policy.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| name | String(80) | unique, not null | |
| description | Text | nullable | |
| leader_id | UUID | nullable | not a FK constraint; resolved via Player.team_id and the leader check |
| reputation_calculation_method | String(20) | default AVERAGE |
Deprecated (2026-08-04, DECISIONS team-reputation-calculation-method-canonical / 093c38ee) โ TeamReputation.calculation_method is now the SSOT; this column is comment-only-deprecated, retained pending a Max-gated DROP, never read/written by the service. See FEATURES/gameplay/factions-and-teams.md ยง reputation. |
| tag | String(10) | nullable | display tag |
| logo | String | nullable | URL |
| is_public | Boolean | default true | |
| max_members | Integer | default 4 | |
| sector_claims | ARRAY(Integer) | default [] | claimed sector numbers |
| home_sector_id | Integer | nullable | |
| recruitment_status | String(20) | default OPEN |
OPEN/INVITE_ONLY/CLOSED |
| treasury_credits, treasury_fuel, treasury_organics, treasury_equipment, treasury_technology, treasury_luxury_items, treasury_precious_metals, treasury_raw_materials, treasury_plasma, treasury_bio_samples, treasury_dark_matter, treasury_quantum_crystals | Integer | default 0 | shared treasury per resource |
| total_credits, total_planets | Integer | default 0 | aggregates |
| combat_rating, trade_rating | Float | default 0.0 | |
| join_requirements, member_roles, resource_sharing, invitation_codes | JSONB | defaults |
Relationships:
- members โ Player (1:many via Player.team_id).
- team_members โ TeamMember (1:many cascade) โ adds roles/permissions on top of plain membership.
- reputation โ TeamReputation (1:1 cascade).
- controlled_sectors โ Sector.
- drones, fleets, messages.
TeamMember¶
Per-member roles/permissions. Columns: team_id FK, player_id FK, role (LEADER/OFFICER/MEMBER/RECRUIT), joined_at, permissions JSONB, individual booleans can_invite, can_kick, can_manage_treasury, can_manage_alliances, last_active, contribution_credits JSONB.
Reputation¶
Source: services/gameserver/src/models/reputation.py
Purpose: Per-(player, faction) reputation row with a 17-tier enum and effects flags.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| player_id | UUID FK players.id | not null, CASCADE | |
| faction_id | UUID FK factions.id | not null, CASCADE | |
| current_value | Integer | default 0 | numeric score |
| current_level | Enum reputation_level |
default NEUTRAL | 17 tiers from PUBLIC_ENEMY (-8) to EXALTED (+8) |
| title | String(50) | default Neutral |
display |
| decay_paused | Boolean | default false | |
| history | JSONB | default [] | |
| trade_modifier | Float | default 0 | |
| port_access_level | Integer | default 0 | |
| combat_response | String(50) | default neutral |
one of friendly (Honored+), neutral (default), cautious (mid-negative), hostile (Hostile/Hated band), attack_on_sight (Public Enemy / Criminal). Drives NPC patrol behavior toward the player at faction-flagged stations and in faction-controlled sectors. |
| is_locked | Boolean | default false | admin lock |
| lock_reason, lock_expires, special_status | mixed | nullable |
Relationships: player, faction.
Indexes (per ADR-0051 SK32) โ ๐ design-only, not built (corrected 2026-08-04: models/reputation.py's __table_args__ carries none of these; verified via direct read, no UniqueConstraint or Index present beyond the implicit PK). The design intent, still SK32's canonical target:
- (player_id, faction_id) UNIQUE composite โ primary access pattern: "what's my rep with faction X."
- (faction_id, current_value DESC) โ leaderboard queries ("top reputation with faction X").
- (player_id) โ full scan over a player's faction rows.
Canonical query patterns documented to keep new query authors aware. New patterns require an index review.
TeamReputation¶
Aggregated team reputation. Columns: team_id (unique FK), calculation_method (AVERAGE/LOWEST/LEADER), faction_reputation JSONB, history JSONB, last_recalculated, next_recalculation, pending_notifications JSONB.
PlayerCentralBankAccount¶
Per ADR-0050. Region-independent depository at the Central Nexus, operated by the Galactic Concord. One account per player. Stores credits and commodities indefinitely. Receives planet-safe transfers and station credit-compensation fallbacks during region-termination cascades; players withdraw at any Starport Prime dock in the Central Nexus. Cross-link surfaces (per ADR-0065 R-O2): the cascade-deposit flow lives in ../SYSTEMS/region-lifecycle.md; the subscription-tier-driven Bank-access semantics live in ../OPERATIONS/monetization.md.
| name | type | constraints | notes |
|---|---|---|---|
| player_id | UUID FK players.id | PK, not null | One account per player |
| credits | Integer | not null, default 0 | Liquid; transfer to wallet free at any Starport Prime |
| commodities | JSONB | not null, default {} |
{ore: 5000, organics: 2000, ...} per the canonical commodity enum |
| ledger | JSONB | not null, default [] |
Append-only entries describing deposits/withdrawals for player audit. Each entry: {timestamp, type, amount, source, notes, access_override}. access_override BOOLEAN (per ADR-0054 X-I3) flags cascade-deposit entries that grant Bank withdrawal access regardless of current GC subscription status. |
| created_at, updated_at | DateTime | server defaults |
Operations (per ../SYSTEMS/region-lifecycle.md Bank service):
- Deposit โ only by the cascade orchestrator (planet-safe transfer, station credit-compensation fallback). No normal player-side deposit; the Bank is a one-way recipient from cascade events.
- Withdraw credits โ instant, free, at any Starport Prime dock.
- Withdraw commodities โ 1 turn per 100 units (rounded up); to player's ship cargo; at any Starport Prime dock; subject to ship cargo space.
The ledger entries persist for the player's lifetime as audit history. Common entry types: cascade_safe_transfer (with 20% loss flag if Path A), cascade_station_compensation (50%-acquisition fallback), withdraw_credits, withdraw_commodity.
Bank access during GC lapse (per ADR-0054 X-I3): Bank operations normally require an active Galactic Citizen subscription. If a player's GC subscription has lapsed but their account holds credits/commodities deposited via cascade compensation (i.e., the ledger has at least one prior entry with access_override = true), withdrawals remain enabled FIFO until those access-override balances are drawn down. Logic: deposits made by the cascade orchestrator carry access_override = true; withdrawals consume the oldest access-override entries first; once the cumulative access-override balance reaches zero, normal GC-required gating resumes. This prevents the regress where a region terminates, the player's assets land in the Bank, then GC lapses and traps the assets.
TakeoverIntent¶
Per ADR-0050. Records a player's intent to take over a Suspended/Grace region while the PayPal payment flow runs. Cleaned up by a periodic sweep on expiry.
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| region_id | UUID FK regions.id | not null | The region being taken over |
| caller_user_id | UUID FK users.id | not null | The player making the offer |
| approval_url | String | not null | PayPal flow approval URL returned to client |
| status | Enum (pending, won, lost, transferred, failed, expired) |
default pending |
Per ADR-0058 A-F3. State machine: pending โ won (claim accepted, region transfer follows), pending โ lost (claim rejected by serializer; escrow refunded in same tx), won โ transferred (transfer succeeded), won โ failed (transfer failed; escrow refunded; region stays with old owner), pending โ expired (PayPal flow window timed out). Every transition is atomic. |
| created_at | DateTime | server default | |
| expires_at | DateTime | not null | created_at + 1 hour (the PayPal flow window) |
| completed_at | DateTime | nullable | Set when commit_takeover() runs |
Indexes: (region_id, status) for "pending intents on this region"; (expires_at) for the periodic-sweep cleanup; (region_id) WHERE status = 'pending' for the SELECT FOR UPDATE serializer per ADR-0058 A-F3.
Concurrent-claim serialization (per ADR-0058 A-F3): when multiple takeover claims race on the same region, the takeover handler opens a transaction and runs SELECT * FROM regions WHERE id = :region_id FOR UPDATE before evaluating the claim. First commit wins (status = 'won'); concurrent claims see the won state inside their own lock acquisition and reject (status = 'lost') with the offer escrow refunded inside the same transaction. No temporal window where money is held without a corresponding ownership state.
PlayerWarpKnowledge¶
Source: services/gameserver/src/models/player_warp_knowledge.py:54 (migrations f1a4d7b2c9e3 + fea17cc334a8). The storage table is committed. ARIA's hint-generation and the player-facing reveal surfacing described below (see ../FEATURES/gameplay/aria-companion.md ยง Warp discovery) are Release-tier.
Per ADR-0045 and ADR-0065 R-I3. Per-player warp discovery state โ the source of truth for "what does this player know about the warp graph." Map-visibility queries read against it; ARIA reads it for hint generation per ADR-0045.
| Column | Type | Constraints | Notes |
|---|---|---|---|
| player_id | UUID FK players.id | not null, CASCADE | composite PK part 1 |
| warp_id | UUID | not null | composite PK part 2; references either sector_warps or WarpTunnel (polymorphic per warp_type). |
| warp_type | Enum (sector_warp, warp_tunnel) |
not null | Disambiguates the polymorphic FK target. |
| discovered_at | DateTime | not null | First time this player became aware of the warp (any source). |
| discovery_source | Enum (personal_visit, warp_jumper_scan, corp_share, aria_hint) |
not null | How the discovery happened. corp_share propagation may upgrade to personal_visit later (record updates, not duplicates). |
| corp_shared_at | DateTime | nullable | Set when a corp-mate's discovery propagates to this player. Distinct from discovered_at so the system can distinguish first-hand from second-hand knowledge. |
Composite PK: (player_id, warp_id).
Indexes:
- (player_id) โ "what does this player know" (the dominant query).
- (warp_id) โ "who knows about this warp" (rare; for ops/audit queries).
The Nexus warp visibility filter per ADR-0064 R-V3 reads this table โ free-tier players who have a corp-mate's discovered_at set on the Nexus warp are still excluded from the visible-on-map set, because the filter intersects this table with the player's subscription tier.
Message¶
Source: services/gameserver/src/models/message.py
Purpose: Player-to-player and team messaging with threading and moderation.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| sender_id | UUID FK players.id | not null, indexed | |
| recipient_id | UUID FK players.id | nullable, indexed | null for team messages |
| team_id | UUID FK teams.id | nullable, indexed | null for direct messages |
| subject | String(255) | nullable | |
| content | Text | not null | |
| sent_at | DateTime | default utcnow, indexed | |
| read_at | DateTime | nullable | |
| deleted_by_sender, deleted_by_recipient | Boolean | defaults false | soft delete per side |
| thread_id | UUID | indexed | conversation grouping |
| reply_to_id | UUID FK messages.id | nullable | direct reply |
| message_type | String(20) | default player |
player/team/system |
| priority | String(10) | default normal |
low/normal/high/urgent |
| flagged | Boolean | default false | |
| flagged_reason | String(255) | nullable | |
| moderated_at | DateTime | nullable | |
| moderated_by | UUID FK users.id | nullable | admin user |
| moderation_status | String(16) | nullable | Added 2026-08-06 โ was missing from this table. Audit-trail status; NULL = visible (default), 'deleted' = moderator-removed from player-facing reads but the row + moderator stamps are kept for the audit log (see FEATURES/gameplay/messaging.md "Moderated messages remain in the database"). 'redacted'/'blocked' are [NO-CANON] reserved values for the separately-gated redact/block moderation actions (messaging.md ยง moderation, launch-target per its own ๐ง Partial marker) โ not yet live vocabulary. |
Relationships: sender, recipient, team, reply_to (self-ref), moderator (User).
Composite indexes: (recipient_id, read_at), (team_id, sent_at), (thread_id, sent_at).
Auth side-tables (referenced)¶
PlayerCredentials, AdminCredentials (see ./admin.md), OAuthAccount, RefreshToken, MFASecret, MFAAttempt all hang off User 1:1 or 1:many. They are mechanical auth plumbing โ no game logic โ and not expanded here.