# Moderator access MineGeo checks `public.profiles.role` on the server for every moderation request. A contributor cannot change their own role through the website or Supabase's public API. No Discord role, JWT metadata, or additional plugin is required. 1. Have the moderator sign in to MineGeo and open their dashboard once. 2. In the **MineGeo** Supabase project, open **Authentication → Users** and copy that person's user UUID. 3. Open **Table Editor → public.profiles**, find the matching `id`, and set `role` to `moderator`. Keep the existing ID and display name. 4. The moderator can open `/moderation`, inspect each location in 360°, approve a submitted map, return it with feedback, unpublish a map, and resolve community reports. The role takes effect on the next request. Alternatively, the project owner can run this in Supabase's SQL Editor, replacing the email with the intended account: ```sql insert into public.profiles (id, role) select id, 'moderator' from auth.users where lower(email) = lower('moderator@example.com') on conflict (id) do update set role = excluded.role returning id, role; ``` The query must return the intended user's ID. An empty result means the person has not signed in with that email yet. To remove moderator access, change that profile's role back to `contributor`. Treat the website role separately from Supabase organization membership: moderators do not need access to your Supabase project or its secret key. The existing test moderator account is a verification fixture; it does not grant access to your personal account. # Community reports and map ban appeals Signed-in players can use **Report content** on a published map page to report the entire map, or during a game to report the current panorama. Reports include a category, a 10–2000 character explanation, and an optional HTTP/HTTPS evidence link. The website derives panorama identity from the player's accessible game round; it retains the reported immutable revision for moderator inspection. Owners cannot report their own maps. Each person can have only one open or confirmed report per map until its ban is appealed successfully; dismissed reports can be corrected and resubmitted. In `/moderation`, inspect the reported surface map and 360° locations, then **Confirm report · add strike** or **Dismiss report**, with written feedback. Pending and dismissed reports never count toward bans. Each distinct reporter can contribute one confirmed strike. Confirming the third report atomically unpublishes the map and blocks publication. The ban applies to the map, not the owner's account. Existing games retain their original revisions; the map disappears from the public catalog and cannot start new games. The owner opens the banned map from `/dashboard` and uses **Appeal map ban**. One appeal can await review at a time. Moderators can inspect the map and approve or reject the appeal with feedback. Rejection keeps the ban and permits another appeal with new information. Approval restores the last published revision, resets the three-strike counter, closes pending reports from the old cycle, and preserves all report and appeal history. A moderator cannot confirm their own report, confirm reports on their own map, or approve their own map's appeal. Contribution uploads older than five days are hidden from the dashboard and the owner's **Player submissions** list. Nothing is deleted: direct contribution links, accepted panoramas, and quota accounting still work. The cutoff uses the contribution's creation time, including pending submissions. Apply `supabase/migrations/20261006074343_content_reports_and_appeals.sql` after all previous migrations before deploying this website. All new decision functions and the appeal table are restricted to the server service role, and appeal RLS is enabled. Run `tests/sql/moderation.sql` against a database with six test accounts (the transaction rolls back), or run the isolated local verification: ```sh npm install --prefix .data/sql-verification --no-save --package-lock=false @electric-sql/pglite@0.3.14 node scripts/test-moderation-sql.mjs ``` The reporting migration was applied to the configured **MineGeo** Supabase project on October 6, 2026 after `/api/v1/moderation` returned `PGRST205` for the missing `map_appeals` table. The live Data API now successfully reads moderation maps, open reports, and the appeal queue. Appeal RLS is enabled, and public roles cannot read appeals or execute moderation decisions. The earlier `map_refresh_fixes` migration remains unapplied; applying it was rejected by automatic approval review as outside this reporting fix. # First beta map Published-map updates now have their own review state. Owners approve player submissions first and submit the combined map update; **Approve update** publishes a new immutable revision. Returning an update with feedback keeps the previous version playable. See [panorama contributions](panorama-contributions.md). After deploying the updated website and worker: 1. Open the private draft in `/dashboard`. Use **Look around** to inspect its complete panorama, including terrain near the edge of the export. 2. Keep at least five usable locations. Saved exclusions can now be restored after a reload. Locations removed by older versions cannot be recovered unless the original capture manifest is available. 3. Save and submit the map for review. 4. A moderator opens `/moderation`, checks **Inspect 360° locations**, and approves the map. It then appears in **Play & maps** and visitors can play without signing in. The rendering fix must run on existing images as well as new uploads. This session repaired the private draft `00ff0076-cae1-4a0d-ab81-9014833309f4` in Supabase while preserving its ten selected locations, metadata and original terrain upload. Refresh its preview to see the corrected textures. For another completed private plugin draft with the same rendering issue: ```sh npm run repair:panoramas -- ``` This command renders and verifies the original terrain first, then replaces the draft's private media. It refuses published revisions, maps under review, and active/failed processing jobs. For failed processing, use the existing `npm run reprocess -- ` recovery workflow instead. Server-generated views retain simplified lighting and biome color approximations; entities, custom packs and dynamic sign text remain outside the capture scope.