feat(portal): add SSR operations and exclusive groups
This commit is contained in:
+2
-1
@@ -30,7 +30,8 @@ This OKF bundle is the product record for implemented and proposed behavior. Sto
|
||||
* [US-014 — Receive standardized API errors](us-014-problem-details.md) - Application APIs return RFC 9457 Problem Details.
|
||||
* [US-015 — Deploy and operate securely](us-015-platform-operations.md) - Operators have reproducible builds, migrations, credentials, and security controls.
|
||||
* [US-016 — Build and publish versioned releases](us-016-automated-releases.md) - Gitea Actions publish the Velocity JAR and web and migration images.
|
||||
* [US-017 — Control admission with groups](us-017-group-access.md) - Administrators assign users to groups that explicitly grant Minecraft access.
|
||||
* [US-017 — Control admission with groups](us-017-group-access.md) - Each user has one effective group that explicitly controls Minecraft access.
|
||||
* [US-018 — Monitor community account activity](us-018-admin-dashboard.md) - Administrators review registrations, monthly activity, denials, and risky networks.
|
||||
|
||||
# Tracking
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
## 2026-08-01
|
||||
|
||||
* **Refine**: Make group assignment exclusive with default fallback, add group deletion, automatically synchronize Discord nicknames with status notices, expose filterable event details, add an SSR operations dashboard, and improve accessibility.
|
||||
* **Extend**: Add SoMC Portal branding, live Discord identity details, admin guild configuration visibility, and fail-closed group-based Minecraft admission.
|
||||
* **Refine**: Group repeated access networks, confirm linked Discord nickname changes before mutation, and add DMG Games sponsorship attribution.
|
||||
* **Extend**: Add shared Pino logging with credential redaction and actionable web and Discord runtime diagnostics.
|
||||
|
||||
@@ -3,7 +3,7 @@ type: User Story
|
||||
title: Manage linked accounts from the dashboard
|
||||
description: Authenticated users maintain their profile and active Java Edition accounts.
|
||||
tags: [player, dashboard, minecraft, profile]
|
||||
timestamp: 2026-08-01T22:34:31Z
|
||||
timestamp: 2026-08-01T23:10:59Z
|
||||
story_id: US-005
|
||||
status: verified
|
||||
---
|
||||
@@ -20,10 +20,10 @@ As a registered player, I want to manage my profile and linked Minecraft account
|
||||
- [x] The user can soft-remove an active account.
|
||||
- [x] The user can choose exactly one active primary account.
|
||||
- [x] Removing a primary account promotes another active account when one exists.
|
||||
- [x] Name and primary changes preview the expected Discord nickname and require explicit confirmation before either profile mutation occurs.
|
||||
- [x] Name, primary, and account-removal changes automatically synchronize the expected Discord nickname and report the result.
|
||||
- [x] The dashboard shows recent portal and game IP observations with classification and available location.
|
||||
- [x] The dashboard shows the user's Discord display name, username, guild nickname, and immutable Discord ID.
|
||||
- [x] The dashboard shows effective access groups and whether each group grants Minecraft access.
|
||||
- [x] The dashboard shows the single effective access group and whether it grants Minecraft access.
|
||||
- [x] The user can revoke the current session by signing out.
|
||||
|
||||
# Implementation
|
||||
@@ -34,7 +34,7 @@ As a registered player, I want to manage my profile and linked Minecraft account
|
||||
|
||||
# Validation
|
||||
|
||||
Server actions verify the current session, constrain every account lookup by the authenticated user ID, and require the explicit Discord confirmation field before name or primary-account mutations. Confirmation parsing is covered by [`apps/web/src/lib/dashboard-change-confirmation.test.ts`](../apps/web/src/lib/dashboard-change-confirmation.test.ts).
|
||||
Server actions verify the current session and constrain every account lookup by the authenticated user ID. Nickname result announcements are covered by [`apps/web/src/components/nickname-notice.test.tsx`](../apps/web/src/components/nickname-notice.test.tsx).
|
||||
|
||||
# Related Stories
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ type: User Story
|
||||
title: Keep Discord nicknames synchronized
|
||||
description: Preferred names and primary Minecraft usernames determine community guild nicknames.
|
||||
tags: [player, admin, discord, identity]
|
||||
timestamp: 2026-08-01T18:43:58Z
|
||||
timestamp: 2026-08-01T23:10:59Z
|
||||
story_id: US-006
|
||||
status: verified
|
||||
---
|
||||
@@ -16,10 +16,11 @@ As a community member, I want my Discord nickname to reflect my preferred name a
|
||||
|
||||
- [x] Given a preferred name and primary account, then the nickname format is `First name (MinecraftUsername)`.
|
||||
- [x] Given Discord's 32-character limit, then the preferred-name portion is shortened while preserving the Minecraft username.
|
||||
- [x] Given no remaining Minecraft account, then administrative synchronization falls back to the preferred name.
|
||||
- [x] User name and primary changes display the proposed nickname before confirmation.
|
||||
- [x] Given no remaining Minecraft account, then synchronization uses `First name (TBD)`.
|
||||
- [x] User name, first-account, primary, and account-removal changes synchronize the nickname automatically without a second confirmation step.
|
||||
- [x] Successful synchronization shows the exact new nickname in a dismissible status notice.
|
||||
- [x] Discord failures show an assertive error notice without falsely claiming synchronization completed.
|
||||
- [x] Administrator name, primary, and primary-removal operations synchronize the nickname automatically.
|
||||
- [x] Discord failures are reported without falsely claiming the requested profile change completed.
|
||||
- [x] A protected administrative retry action can synchronize the current desired nickname.
|
||||
|
||||
# Implementation
|
||||
@@ -27,6 +28,7 @@ As a community member, I want my Discord nickname to reflect my preferred name a
|
||||
- [`packages/minecraft/src/index.ts`](../packages/minecraft/src/index.ts)
|
||||
- [`apps/web/src/app/account/actions.ts`](../apps/web/src/app/account/actions.ts)
|
||||
- [`apps/web/src/app/admin/(console)/users/actions.ts`](../apps/web/src/app/admin/%28console%29/users/actions.ts)
|
||||
- [`apps/web/src/components/nickname-notice.tsx`](../apps/web/src/components/nickname-notice.tsx)
|
||||
|
||||
# Validation
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ type: User Story
|
||||
title: Enforce registration at the Velocity proxy
|
||||
description: Online-mode Java connections are admitted only after a fail-closed account-manager decision.
|
||||
tags: [minecraft, velocity, whitelist, security]
|
||||
timestamp: 2026-08-01T22:34:31Z
|
||||
timestamp: 2026-08-01T23:10:59Z
|
||||
story_id: US-009
|
||||
status: verified
|
||||
---
|
||||
@@ -22,7 +22,7 @@ As a registered player, I want the Velocity proxy to recognize my approved Java
|
||||
- [x] Username fallback applies only when the stored account has no UUID.
|
||||
- [x] Successful fallback backfills UUID and canonical username.
|
||||
- [x] Changed usernames are persisted and audited.
|
||||
- [x] Registered players are allowed only when at least one assigned group has access enabled.
|
||||
- [x] Registered players are allowed only when their single effective group has access enabled; explicit assignments override the default group.
|
||||
- [x] Unknown players, group-disabled players, API failures, malformed responses, and unauthorized requests fail closed with registration guidance.
|
||||
- [x] The plugin records the real Velocity connection IP and supports Java Edition online mode only.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ type: User Story
|
||||
title: Preserve a CloudEvents-style audit trail
|
||||
description: Authentication, UI, account, Discord, network, and game actions create searchable immutable-style events.
|
||||
tags: [audit, cloudevents, security, events]
|
||||
timestamp: 2026-08-01T18:43:58Z
|
||||
timestamp: 2026-08-01T23:10:59Z
|
||||
story_id: US-010
|
||||
status: verified
|
||||
---
|
||||
@@ -19,7 +19,8 @@ As an operator, I want security and identity activity recorded consistently, so
|
||||
- [x] Portal access, magic-link creation and consumption, account changes, nickname changes, VPN blocks, and game decisions are recorded.
|
||||
- [x] Username changes learned from Velocity create their own event.
|
||||
- [x] Administrative actions include the acting SSO identity in event data.
|
||||
- [x] Events can be inspected globally and from an individual admin user view.
|
||||
- [x] Events can be filtered by operator-friendly view and selected event types globally and from an individual user view.
|
||||
- [x] Every listed event links to a detail page showing its complete CloudEvents envelope and formatted JSON data.
|
||||
- [x] `published_at` reserves an outbox path for future Kafka publishing.
|
||||
|
||||
# Implementation
|
||||
@@ -28,6 +29,7 @@ As an operator, I want security and identity activity recorded consistently, so
|
||||
- [`packages/database/src/schema.ts`](../packages/database/src/schema.ts)
|
||||
- [`apps/web/src/lib/audit.ts`](../apps/web/src/lib/audit.ts)
|
||||
- [`apps/web/src/app/admin/(console)/events/page.tsx`](../apps/web/src/app/admin/%28console%29/events/page.tsx)
|
||||
- [`apps/web/src/app/admin/(console)/events/[eventId]/page.tsx`](../apps/web/src/app/admin/%28console%29/events/%5BeventId%5D/page.tsx)
|
||||
|
||||
# Validation
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ type: User Story
|
||||
title: Deploy and operate the platform securely
|
||||
description: Operators have repeatable builds, migrations, credential provisioning, configuration, and security checks.
|
||||
tags: [operations, security, database, deployment]
|
||||
timestamp: 2026-08-01T21:37:26Z
|
||||
timestamp: 2026-08-01T23:10:59Z
|
||||
story_id: US-015
|
||||
status: verified
|
||||
---
|
||||
@@ -21,6 +21,8 @@ As a platform operator, I want reproducible deployment and security controls, so
|
||||
- [x] The Velocity Gradle wrapper produces a tested shaded JAR.
|
||||
- [x] Environment examples document database, Keycloak, Discord, trusted proxy, and ProxyCheck settings without secrets.
|
||||
- [x] The web application sets CSP, framing, MIME, referrer, and permissions headers.
|
||||
- [x] Database-backed user and administrator pages render as dynamic React Server Components with server-side data access.
|
||||
- [x] Core pages provide keyboard focus indication, a skip link, labelled controls, table semantics, live status messaging, sufficient text contrast, and reduced-motion support.
|
||||
- [x] The web runtime provides a dependency-free health endpoint for orchestration probes.
|
||||
- [x] Web and Discord bot runtimes emit structured Pino logs with credential-field redaction and safe operational context.
|
||||
- [x] npm dependency audit and Semgrep security review complete without findings at the last verified change.
|
||||
@@ -35,6 +37,7 @@ As a platform operator, I want reproducible deployment and security controls, so
|
||||
- [`plugins/velocity/build.gradle.kts`](../plugins/velocity/build.gradle.kts)
|
||||
- [`apps/web/next.config.ts`](../apps/web/next.config.ts)
|
||||
- [`packages/logging/src/index.ts`](../packages/logging/src/index.ts)
|
||||
- [`docs/accessibility.md`](../docs/accessibility.md)
|
||||
|
||||
# Validation
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ type: User Story
|
||||
title: Control Minecraft admission with groups
|
||||
description: Administrators assign users to groups and enable Minecraft access through explicit group policy.
|
||||
tags: [admin, groups, authorization, velocity, security]
|
||||
timestamp: 2026-08-01T22:36:20Z
|
||||
timestamp: 2026-08-01T23:10:59Z
|
||||
story_id: US-017
|
||||
status: verified
|
||||
---
|
||||
@@ -14,20 +14,22 @@ As an administrator, I want to organize registered users into access groups, so
|
||||
|
||||
# Acceptance Criteria
|
||||
|
||||
- [x] Every registered user implicitly belongs to the protected `everyone` group.
|
||||
- [x] The `everyone` group is created with Minecraft access disabled.
|
||||
- [x] Administrators can create groups with access disabled by default.
|
||||
- [x] Administrators can add and remove users from non-default groups.
|
||||
- [x] A registered user can have at most one explicit group assignment.
|
||||
- [x] Users without an explicit assignment fall back to the protected `everyone` group.
|
||||
- [x] The `everyone` group remains created with Minecraft access disabled.
|
||||
- [x] Administrators can create groups with access disabled by default and move users between groups.
|
||||
- [x] Administrators can enable or disable Minecraft admission for each group.
|
||||
- [x] A registered player is admitted when any assigned group has access enabled.
|
||||
- [x] A registered player is denied when none of their groups has access enabled.
|
||||
- [x] Admission follows only the user's effective group; default and explicit-group access are never combined.
|
||||
- [x] Administrators can delete non-default groups, returning affected users to `everyone`.
|
||||
- [x] The protected default group cannot be deleted.
|
||||
- [x] Group creation, membership, and access-policy changes are audited.
|
||||
- [x] Users and administrators can inspect the user's effective group assignments.
|
||||
- [x] Users and administrators can inspect the user's single effective group assignment.
|
||||
|
||||
# Implementation
|
||||
|
||||
- [`packages/database/src/schema.ts`](../packages/database/src/schema.ts)
|
||||
- [`packages/database/drizzle/0002_simple_queen_noir.sql`](../packages/database/drizzle/0002_simple_queen_noir.sql)
|
||||
- [`packages/database/drizzle/0003_smiling_silver_samurai.sql`](../packages/database/drizzle/0003_smiling_silver_samurai.sql)
|
||||
- [`apps/web/src/app/admin/(console)/groups/page.tsx`](../apps/web/src/app/admin/%28console%29/groups/page.tsx)
|
||||
- [`apps/web/src/app/admin/(console)/groups/[groupId]/page.tsx`](../apps/web/src/app/admin/%28console%29/groups/%5BgroupId%5D/page.tsx)
|
||||
- [`apps/web/src/app/api/velocity/access/route.ts`](../apps/web/src/app/api/velocity/access/route.ts)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
type: User Story
|
||||
title: Monitor community account activity
|
||||
description: Administrators use a server-rendered dashboard to review registrations, monthly activity, denials, and risky networks.
|
||||
tags: [admin, dashboard, metrics, security, ssr]
|
||||
timestamp: 2026-08-01T23:10:59Z
|
||||
story_id: US-018
|
||||
status: verified
|
||||
---
|
||||
|
||||
# User Story
|
||||
|
||||
As an administrator, I want an operational dashboard of account and game activity, so that I can understand community growth and quickly investigate access risks.
|
||||
|
||||
# Acceptance Criteria
|
||||
|
||||
- [x] The administrator landing page is a dashboard rather than a settings form.
|
||||
- [x] The dashboard graphs new registered users by UTC day for the previous 14 days.
|
||||
- [x] Monthly active users count distinct users observed through portal or game activity in the previous 30 days.
|
||||
- [x] Monthly active Minecraft accounts count distinct linked accounts observed in the previous 30 days.
|
||||
- [x] The dashboard shows login denials from the previous 24 hours.
|
||||
- [x] Recent VPN, proxy, and Tor observations link to affected user records.
|
||||
- [x] The graph includes an accessible title, description, point labels, and textual values.
|
||||
- [x] Dashboard queries and rendering execute server-side without client-side data fetching.
|
||||
- [x] Deployment-managed guild settings and denial messaging remain available on a dedicated settings page.
|
||||
|
||||
# Implementation
|
||||
|
||||
- [`apps/web/src/app/admin/(console)/page.tsx`](../apps/web/src/app/admin/%28console%29/page.tsx)
|
||||
- [`apps/web/src/app/admin/(console)/settings/page.tsx`](../apps/web/src/app/admin/%28console%29/settings/page.tsx)
|
||||
- [`apps/web/src/lib/admin-metrics.ts`](../apps/web/src/lib/admin-metrics.ts)
|
||||
|
||||
# Validation
|
||||
|
||||
- Missing-day chart behavior is covered by [`apps/web/src/lib/admin-metrics.test.ts`](../apps/web/src/lib/admin-metrics.test.ts).
|
||||
- The Next.js production build reports the dashboard and database-backed console pages as dynamic server-rendered routes.
|
||||
|
||||
# Related Stories
|
||||
|
||||
- [Preserve a CloudEvents-style audit trail](us-010-audit-events.md)
|
||||
- [Deploy and operate the platform securely](us-015-platform-operations.md)
|
||||
- [Block anonymized account additions](us-008-vpn-blocking.md)
|
||||
Reference in New Issue
Block a user