PushHub Customer Workspace
Purpose
The customer workspace is the authenticated product surface at https://app.pushhub.kemegames.com/dashboard. Gaming studios and digital publishers use it to connect apps, register player devices, define audiences, compose notifications, automate sends, inspect delivery, and manage organization access.
The workspace is tenant-isolated and dark-only. Interactive controls use SIGNAL brand-500; signal-400 remains reserved for AI-specific features.
Workspace access now begins through the approved trial provisioning path documented in docs/TRIAL_APPROVAL_FLOW.md: marketing request, Keme Admin approval, email CTA, password setup, then first workspace login. Direct public registration redirects to the trial request path in the production UI.
Competitive baseline
The July 2026 workspace expansion was informed by official product documentation from:
- OneSignal: application setup, users and segments, campaigns, journeys, templates, message reports, engagement trends, audience activity, and data export.
- Firebase Cloud Messaging: notification composition, segment targeting, custom payloads, test sends, A/B testing, delivery reporting, and BigQuery export.
- Airship: project-per-app organization, message and automation composers, message-level reports, payload inspection, activity history, delivery reasons, and aggregate engagement reports.
- Pushwoosh: app and account reporting, message history, campaign and journey performance, custom dashboards, exports, segment insights, device growth, and channel breakdowns.
The resulting PushHub baseline is app-scoped operations plus organization-wide access, billing, auditability, and credentials. Cross-channel email/SMS/in-app messaging is intentionally outside the current push-focused domain model.
Information architecture
Workspace
- Command center — real delivery metrics, recent campaigns, setup checklist, and plan usage.
- Apps — create, inspect, configure, and remove game applications.
Audience
- Players & devices — paginated registered device inventory with platform and activity state.
- Segments — reusable filter definitions with server-evaluated audience estimates.
Messaging
- Campaigns — lifecycle views for drafts, scheduled sends, running sends, completed sends, and cancellations.
- Campaign composer — content, template application, custom JSON payload, all/segment/device targeting, A/B variants, review, save draft, send-now, and scheduling.
- Automations — event-triggered notification rules with templates, delay, activation, update, and deletion.
- Templates — reusable notification content.
- Experiments — A/B campaign visibility and results.
Insights
- Analytics — recorded-only delivery funnel, 7/30/90-day time series, quality rates, campaign context, and CSV export.
- Delivery logs — event-level status, recipient, platform, timestamps, failure diagnostics, filters, pagination, and CSV export.
Developer
- Launch checklist — recorded provider, device, and accepted-push evidence for every active app.
- App setup — provider console for Android (managed or BYO Firebase), Apple (APNs
.p8), Huawei Push Kit, and Amazon Device Messaging with verification, health, and disconnect; active-device selection, real test push, and delivery-policy controls. - API credentials — one-time secret display, hashed storage, scopes, last use, and revocation.
Organization
- Team & roles — owner, admin, developer, and analyst access.
- Audit trail — actor, action, resource, origin, filtering, pagination, and export.
- Billing & usage — apps, devices, monthly notifications, team limits, plan, and renewal state.
- Workspace settings — organization name/logo and related operational links.
Backend additions and contract repairs
GET /api/v1/campaigns/{id}returns campaign detail.GET /api/v1/notifications/logsreturns tenant-filtered, app-scoped paginated delivery events.- App analytics now return app identity, active device count, gap-filled daily time series, and real delivery/open/failure values.
PUT /api/v1/event-triggers/{id}updates trigger configuration and activation.DELETE /api/v1/event-triggers/{id}deletes a trigger.- Campaign status filtering is enforced.
- Frontend contracts now match backend query/body requirements for campaigns, templates, members, billing usage, and event triggers.
- App and API-key controllers now resolve the authenticated
company_idclaim emitted by the JWT service; registration consumes the current login-response contract. - App platform and campaign target fields accept and return their documented enum names in JSON. Numeric request values remain accepted for existing API clients.
- Workspace JWTs emit
company_rolein addition to standard role claims so owner/admin permission checks work consistently. - Login-time company membership lookup bypasses tenant query filters because authentication happens before a workspace JWT establishes tenant context.
- Unauthorized workspace responses redirect to
/login. - Workspace operations expose tenant-scoped readiness, provider health, exact audience estimates, seven-day delivery diagnostics, test delivery, and delivery-policy management under
/api/v1/workspace. - Campaign send-now now remains draft until a worker atomically claims it; scheduled campaigns are dispatched by the scheduler at their UTC instant instead of being queued early.
- App delivery policies enforce overnight quiet hours in an explicit IANA time zone and an exact rolling 24-hour per-device cap. Policy-denied events are retained as
Suppressedlogs with an actionable reason.
All delivery-log queries retain the existing EF Core company filter. App, campaign, and event-trigger reads also resolve through tenant-filtered repositories.
Data integrity decisions
- No workspace screen fabricates activity, rates, audience size, platform distribution, or hourly behavior.
- Empty workspaces show setup guidance and explicit empty states.
- An app may be created without a provider credential. App setup handles delivery connection later; the campaign composer can save a message as
Draftwithout devices or a provider, and cannot queue delivery to an empty audience. - Audience estimates are evaluated by the segment service after creation.
- Campaign detail uses recorded notification logs for sent, delivered, opened, failed, delivery rate, and open rate.
- The workspace overview and Analytics page count sent, delivered, opened, and failed with the same rules as campaigns: sent means the push provider accepted the notification, failures are counted separately, suppressed notifications count as neither, and delivery and open rates are shares of sent.
- The A/B Tests page compares variants by their live per-variant counts, which add up to the campaign totals. It names a winner only for a completed campaign whose variants were all sent and whose open rates differ.
- API and provider secrets are never read back after storage.
- Segment audiences come from each segment's current rules at send time: right before the delivery worker selects devices, it re-evaluates every segment of the campaign over the app's active devices, rewrites the stored segment memberships, and refreshes the segment's estimated reach. Devices registered after a segment was saved are included; devices that stopped matching or were deactivated are dropped. Segment IDs from another app or company are ignored.
- Segment audience estimates evaluate the same rules over the same active app devices (deduplicated across segments) without writing memberships, so the composer shows what a send would reach at that moment and never invents an audience count.
- Frequency-cap reservations are atomic in Redis. A provider failure releases its reservation, while policy-storage failure suppresses delivery rather than bypassing customer safeguards.
Responsive behavior
- Desktop uses a persistent 272 px navigation rail.
- Tablet and mobile use an accessible overlay navigation drawer.
- Data tables retain horizontal scrolling where column density is operationally important.
- Page actions collapse and wrap without hiding critical controls.
Verification
- Frontend:
npm run build - API:
dotnet build PushHub.API/PushHub.API.csproj -c Release - Production smoke coverage verifies login, apps, campaigns, templates, analytics, delivery logs, members, audit logs, API keys, billing, readiness, app health, SDK onboarding, test-device discovery, audience estimates, diagnostics, and service health after deployment.
scripts/verify-workspace.shperforms authenticated production checks with a short-lived, correctly normalized company-role token generated from protected server configuration. Its only POST is the non-mutatingAllaudience estimate; it never designates a test device, sends a notification, changes data, or prints the secret or token.PushHub.PhaseTwoChecksverifies quiet-hour boundaries and DST behavior, validation, suppression state, credential diagnostics, Redis concurrency, reservation release, tenant isolation, and rolling-window pruning.
The legacy test project was moved to .NET 9 with current dependencies, but its older fixtures still use superseded domain constructors. That test-fixture migration is separate from the workspace implementation; the deployable API and frontend projects compile successfully.
Security maintenance
- Workspace members can recover access from
/forgot-password. The API returns a neutral response for every address, sends active accounts a 30-minute single-use link through Resend, stores only the token hash, and revokes older open recovery tokens when a new link is issued or used. - AutoMapper was upgraded from vulnerable
13.0.1to patched15.1.1for CVE-2026-32933. - IdentityModel packages were aligned to
8.14.0. - API credentials remain one-time-view secrets.
- Provider credentials remain write-only in the customer UI.
Managed mobile providers
App setup is the provider console. Apple connects with an uploaded .p8 token-authentication key (encrypted, verified with Apple, production or sandbox) instead of an operator-mounted key file. Huawei Push Kit and Amazon Device Messaging are optional connections for devices without Google Play services. Every connection shows its state, last verification, and a Verify now action; Owners and Admins can rotate or disconnect customer-owned connections. PushHub re-verifies connections daily and emails Owners and Admins when one fails or recovers. A suspended workspace stays readable, but changes return 403 COMPANY_SUSPENDED and all sending stops. Readiness treats FCM (Android) and APNs (iOS) as required and HMS/ADM as optional. The full workflow is in docs/PROVIDER_CONNECTIONS.md.
Android setup now leads with PushHub Managed: the workspace shows provider lifecycle, project health, recovery state, and a versioned configuration download without asking the customer to operate Firebase. Bring-your-own Firebase remains an explicit advanced option and requires both the service-account JSON and google-services.json. The detailed ownership, security, rollout, and API contract is in docs/MANAGED_PUSH_INFRASTRUCTURE.md.
Bundle-first launch console
The App setup page now presents one backend-backed signal path: provider readiness, configuration bundle, SDK connection, installation registration, explicit test-device designation, and first delivery receipt. A step is never completed from local browser state. The workspace refreshes evidence from GET /api/v1/apps/{appId}/sdk-onboarding and identifies when the minimum production proof is complete.
The install panel generates environment-specific guidance and verified artifact links for native Android (Beta), plus Unity, React Native, Flutter, and Unreal (Preview). Android consumes the generated bundle directly; adapters use the same client-safe app identity and publishable key from pushhub.json while delegating platform behavior to the native core. The UI states release maturity so Preview packages are not represented as Stable.
Developers, Admins, and Owners can inspect designated devices and safe SDK name/version/consent evidence. Only Owners and Admins can designate or revoke a device and send a real test notification. Every test send uses a fresh idempotency key, follows normal quota and delivery policy, and links to the resulting delivery log. Provider tokens, installation credentials, and server credentials never appear in the browser response. The endpoint and persistence contract is documented in docs/SDK_TEST_ONBOARDING_API.md.
App environments
Every app has a Production environment, created with the app (existing apps were backfilled by migration 018_app_environments). A Development environment (and, through the API, Staging) can be added from App setup → Client SDK access; Developers, Admins, and Owners can add one, and only Admins and Owners can remove an unused one. Production can never be deleted, and an environment that still has publishable keys or installations is kept.
Each publishable key is bound to one environment, chosen when the key is created (Production by default) and shown as a badge on the key. An SDK installation records the environment of the key that bootstrapped it, so a debug build compiled with a Development key never lands in production. No SDK option names the environment: the key decides it. Environment-scoped features such as Remote Config read the installation's environment. API: GET/POST /api/v1/apps/{appId}/environments, DELETE /api/v1/apps/{appId}/environments/{environmentId}, and POST /api/v1/apps/{appId}/client-keys with an optional environment slug or environmentId.