Skip to content

Admin app - #2159

Open
paustint wants to merge 14 commits into
mainfrom
admin-app
Open

paustint wants to merge 14 commits into
mainfrom
admin-app

Conversation

@paustint

Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 14:40
@socket-security

socket-security Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedjose@​6.2.1210010010090100

View full report

Comment thread apps/admin-api/src/main.ts Fixed
Comment thread apps/admin-api/src/app/auth/admin-session.ts Dismissed
Comment thread apps/admin-api/src/app/auth/admin-session.ts Dismissed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved session-policy bypass, cross-record actions, domain-update races, and provisioning/billing defects block approval.

10 open findings
What changed in this PR

Adds a staff-only admin application and API for user/team administration, provisioning, and Stripe management.

Changes:

  • Adds Google authentication, encrypted sessions, and optional Cloudflare Access protection.
  • Introduces dashboards, team operations, billing tools, and audit events.
  • Integrates shared types, tests, workspace configuration, and release-note exclusions.
File Description
tsconfig.json Registers admin projects.
tsconfig.base.json Adds shared admin types alias.
scripts/​release-notes-context.mjs Excludes internal admin changes.
pnpm-lock.yaml Locks authentication dependency.
package.json Adds admin commands and dependency.
nx.json Enables admin Vite integration.
libs/​audit-logs/​src/​lib/​audit-logs.ts Adds administrative audit events.
libs/​admin/​types/​vite.config.mts Configures shared-type tests.
libs/​admin/​types/​tsconfig.spec.json Configures test compilation.
libs/​admin/​types/​tsconfig.lib.json Configures library compilation.
libs/​admin/​types/​tsconfig.json Defines library TypeScript project.
libs/​admin/​types/​src/​lib/​admin-users.types.ts Defines user contracts.
libs/​admin/​types/​src/​lib/​admin-teams.types.ts Defines team contracts.
libs/​admin/​types/​src/​lib/​admin-stripe.types.ts Defines Stripe contracts.
libs/​admin/​types/​src/​lib/​admin-metrics.types.ts Defines dashboard metrics.
libs/​admin/​types/​src/​lib/​admin-common.types.ts Defines shared API contracts.
libs/​admin/​types/​src/​lib/​__tests__/​admin-stripe.types.spec.ts Tests organization-ID validation.
libs/​admin/​types/​src/​index.ts Exports admin contracts.
libs/​admin/​types/​project.json Registers shared library.
apps/​admin/​vite.config.mts Configures SPA build and proxy.
apps/​admin/​tsconfig.spec.json Configures frontend tests.
apps/​admin/​tsconfig.json Defines frontend TypeScript project.
apps/​admin/​tsconfig.app.json Configures application compilation.
apps/​admin/​src/​styles.css Adds admin styling.
apps/​admin/​src/​main.tsx Mounts React application.
apps/​admin/​src/​app/​utils/​format.ts Formats values; currency-specific Stripe amount scaling remains unresolved.
apps/​admin/​src/​app/​utils/​class-names.ts Combines CSS classes.
apps/​admin/​src/​app/​pages/​UsersPage.tsx Adds searchable user listing.
apps/​admin/​src/​app/​pages/​TeamsPage.tsx Adds searchable team listing.
apps/​admin/​src/​app/​pages/​team-detail/​TeamMembersCard.tsx Displays and adds members.
apps/​admin/​src/​app/​pages/​team-detail/​TeamDomainsCard.tsx Manages domain approvals.
apps/​admin/​src/​app/​pages/​team-detail/​TeamDetailPage.tsx Composes team details; retained responses can leave another team's actions enabled.
apps/​admin/​src/​app/​pages/​team-detail/​TeamBillingCard.tsx Displays billing and seats.
apps/​admin/​src/​app/​pages/​team-detail/​StripeLinkResultAlert.tsx Displays Stripe-link outcomes.
apps/​admin/​src/​app/​pages/​provision-team/​provision-team.utils.ts Validates provisioning requests.
apps/​admin/​src/​app/​pages/​provision-team/​CustomerSearchStep.tsx Searches Stripe customers.
apps/​admin/​src/​app/​pages/​provision-team/​__tests__/​provision-team.utils.spec.ts Tests provisioning validation.
apps/​admin/​src/​app/​pages/​NotFoundPage.tsx Handles unknown routes.
apps/​admin/​src/​app/​pages/​LoginPage.tsx Presents Google sign-in.
apps/​admin/​src/​app/​pages/​DashboardPage.tsx Displays operational metrics.
apps/​admin/​src/​app/​layout/​AppLayout.tsx Adds navigation; failed logout still redirects and leaves its rejection unhandled.
apps/​admin/​src/​app/​hooks/​useUrlSearchQuery.ts Persists list state in URLs.
apps/​admin/​src/​app/​hooks/​useDebouncedValue.ts Debounces search input.
apps/​admin/​src/​app/​hooks/​useAsyncAction.ts Tracks asynchronous actions.
apps/​admin/​src/​app/​components/​UserPlanBadges.tsx Displays user plans.
apps/​admin/​src/​app/​components/​UserPicker.tsx Selects existing users.
apps/​admin/​src/​app/​components/​TeamRoleSelect.tsx Selects membership roles.
apps/​admin/​src/​app/​components/​Table.tsx Provides sortable tables.
apps/​admin/​src/​app/​components/​SubscriptionTable.tsx Displays subscriptions.
apps/​admin/​src/​app/​components/​StripeCustomerSection.tsx Displays and edits metadata; missing customer-ID validation permits edits to a retained customer's account.
apps/​admin/​src/​app/​components/​Spinner.tsx Indicates loading.
apps/​admin/​src/​app/​components/​SearchInput.tsx Provides search controls.
apps/​admin/​src/​app/​components/​Pagination.tsx Provides list pagination.
apps/​admin/​src/​app/​components/​PageHeader.tsx Standardizes page headings.
apps/​admin/​src/​app/​components/​KeyValueList.tsx Displays structured details.
apps/​admin/​src/​app/​components/​ExternalLink.tsx Provides external links.
apps/​admin/​src/​app/​components/​ErrorAlert.tsx Displays alerts and errors.
apps/​admin/​src/​app/​components/​EntitlementList.tsx Displays entitlements; enabled/disabled states remain inaccessible to screen readers.
apps/​admin/​src/​app/​components/​EmptyState.tsx Displays empty states.
apps/​admin/​src/​app/​components/​Card.tsx Provides content panels.
apps/​admin/​src/​app/​components/​Button.tsx Provides buttons and links.
apps/​admin/​src/​app/​components/​Badge.tsx Displays status badges.
apps/​admin/​src/​app/​components/​AuditLogTable.tsx Displays audit history.
apps/​admin/​src/​app/​app.tsx Defines SPA routes.
apps/​admin/​src/​app/​api/​admin-api-client.ts Adds API client and query hook; stale data persists across resource changes and failed requests.
apps/​admin/​src/​app/​api/​__tests__/​admin-api-client.spec.ts Tests API client behavior.
apps/​admin/​public/​favicon.svg Adds admin branding.
apps/​admin/​project.json Registers frontend targets.
apps/​admin/​postcss.config.js Enables Tailwind processing.
apps/​admin/​index.html Defines SPA document.
apps/​admin-api/​vite.config.mts Configures API tests.
apps/​admin-api/​tsconfig.spec.json Configures test compilation.
apps/​admin-api/​tsconfig.json Defines API TypeScript project.
apps/​admin-api/​tsconfig.app.json Configures API compilation.
apps/​admin-api/​src/​main.ts Starts API and serves SPA.
apps/​admin-api/​src/​app/​utils/​serializers.ts Serializes records and audit queries.
apps/​admin-api/​src/​app/​utils/​route.utils.ts Adds validated route helpers.
apps/​admin-api/​src/​app/​utils/​error-handler.ts Normalizes API errors.
apps/​admin-api/​src/​app/​teams/​teams.db.ts Queries team lists and details.
apps/​admin-api/​src/​app/​teams/​team-provisioning.service.ts Creates teams and links Stripe; entitlement synchronization and post-commit audit-failure handling remain unresolved.
apps/​admin-api/​src/​app/​teams/​team-members.service.ts Adds members; upgrading existing sessions bypasses team MFA/SSO requirements.
apps/​admin-api/​src/​app/​teams/​team-domains.service.ts Approves domains; concurrent updates can lose verified domains from login configuration.
apps/​admin-api/​src/​app/​teams/​provisioning-checks.ts Evaluates provisioning conflicts.
apps/​admin-api/​src/​app/​teams/​__tests__/​provisioning-checks.spec.ts Tests provisioning checks.
apps/​admin-api/​src/​app/​stripe/​stripe.client.ts Initializes Stripe client.
apps/​admin-api/​src/​app/​stripe/​stripe-summaries.ts Summarizes Stripe records.
apps/​admin-api/​src/​app/​stripe/​stripe-customers.service.ts Searches and updates customers; truncated subscription history can omit active Team subscriptions from review and conflict checks.
apps/​admin-api/​src/​app/​routes/​api.routes.ts Defines protected admin endpoints.
apps/​admin-api/​src/​app/​metrics/​dashboard.db.ts Queries dashboard metrics.
apps/​admin-api/​src/​app/​config/​admin-env.config.ts Validates admin settings.
apps/​admin-api/​src/​app/​auth/​google-oauth.ts Implements Google OAuth flow.
apps/​admin-api/​src/​app/​auth/​cloudflare-access.ts Validates Access JWTs.
apps/​admin-api/​src/​app/​auth/​auth.routes.ts Defines sign-in and logout.
apps/​admin-api/​src/​app/​auth/​auth.middleware.ts Enforces sessions and CSRF protection.
apps/​admin-api/​src/​app/​auth/​admin-session.ts Encrypts session and OAuth cookies.
apps/​admin-api/​src/​app/​auth/​admin-access.ts Evaluates admin access.
apps/​admin-api/​src/​app/​auth/​__tests__/​auth.middleware.spec.ts Tests authorization middleware.
apps/​admin-api/​src/​app/​auth/​__tests__/​admin-session.spec.ts Tests encrypted cookies.
apps/​admin-api/​src/​app/​auth/​__tests__/​admin-access.spec.ts Tests access decisions.
apps/​admin-api/​project.json Registers API build targets.
.release-it.json Excludes admin-scoped changelog entries.
.env.example Documents admin configuration.
.claude/​skills/​conventional-commit/​SKILL.md Documents admin commit scope.
.claude/​commands/​release-notes.md Documents admin release-note exclusions.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/admin-api/src/app/teams/team-domains.service.ts
Comment thread apps/admin-api/src/app/teams/team-members.service.ts Outdated
Comment thread apps/admin/src/app/api/admin-api-client.ts Outdated
Comment thread apps/admin/src/app/components/StripeCustomerSection.tsx
Comment thread apps/admin/src/app/pages/team-detail/TeamDetailPage.tsx
Comment thread apps/admin-api/src/app/stripe/stripe-customers.service.ts Outdated
Comment thread apps/admin-api/src/app/teams/team-provisioning.service.ts Outdated
Comment thread apps/admin-api/src/app/teams/team-provisioning.service.ts
Comment thread apps/admin/src/app/layout/AppLayout.tsx Outdated
Comment thread apps/admin/src/app/utils/format.ts Outdated
@paustint

Copy link
Copy Markdown
Contributor Author

Went through the Copilot file-summary finding that had no review thread. It was valid:

  • apps/admin/src/app/components/EntitlementList.tsx: fixed. Heroicons always render aria-hidden="true", so the aria-labels on the icons were never announced. The enabled/disabled state is now visually hidden text next to each label.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 16:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread apps/admin-api/src/app/teams/team-members.service.ts
Comment thread apps/admin-api/src/app/teams/team-members.service.ts Outdated
Comment thread apps/admin/src/app/utils/format.ts
@jetstream-bot-agent

Copy link
Copy Markdown

Went through Copilot's file-summary notes that didn't become review threads — one was valid:

  • apps/admin/src/app/components/EntitlementList.tsx — fixed, enabled/disabled is now announced via visually hidden text instead of icon color only (d372b6d).

@paustint paustint added the admin Internal admin app (staff only); excluded from release notes label Oct 16, 2026
Copilot AI balanced review requested due to automatic review settings October 17, 2026 13:33
paustint and others added 11 commits October 17, 2026 08:36
…okup

Adds apps/admin-api (Express), apps/admin (React + Tailwind) and libs/admin/types.

- Google OAuth sign-in restricted to the Workspace domain plus an email allowlist,
  encrypted session cookie, CSRF header check and optional Cloudflare Access JWT check
- Provision a team linked to an existing Stripe customer/quote, re-apply the Stripe link,
  and send/resend/revoke invitations (emails only go out on an explicit admin action)
- Search and view teams and users, dashboard KPI tiles
- New ADMIN_* audit log actions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fHLkLy4QS7pgaQqqnpVnM
…seat-mode wording

- Paginate users and teams; filter users by plan (team/professional/free) and sort by last login or created
- Plan status counts active team membership, not only personal subscriptions
- Approve a team domain (marks it verified and updates the login configuration)
- Add existing users to a team without an invitation, during provisioning or from the team page
- Rename billing mode to seat mode (follow subscription / fixed by agreement) with accurate descriptions
- Generic login page, admin favicon, SQL script to seed fake users locally

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fHLkLy4QS7pgaQqqnpVnM
Team and user billing cards read the customer straight from Stripe and let an
admin set or clear metadata.productionOrgId, which Checkout only collects from
buyers who go through it. Also flags a seat limit that Stripe has not synced
yet and says plainly that re-linking only triggers the webhook.
The session cookie is a bearer token. When Access is in front, a cookie now only
works from the Access session of the admin it was issued to, and sign-in refuses
a Google account that differs from the Access identity.
…notes digest

The admin app is staff-only. The context script sets admin PRs and `(admin)`
commits aside under "Excluded", and the commit and release-notes guides say to
use the `admin` scope and PR label, which `.github/release.yml` already excludes
from GitHub Release notes.
…omain

Every writer rebuilds LoginConfiguration.domains from the team's verified
records, so two concurrent changes on one team could each miss the other's
uncommitted record and the later write silently removed a domain from SSO and
domain auto-join. The main API's verify/delete paths and the admin approval
now lock the login configuration row before reading the records.
Stripe's entitlement summary event only fires when entitlements change, so a
customer whose subscription started before it was linked to a team (as admin
provisioning does) never synced and the team kept all-false entitlements until
someone opened its billing page. Writes the team's entitlements directly
rather than through fetchAndUpdateEntitlements, which branches on customer
metadata that can still read USER while a team is being auto-created.
…'s URL

useApiQuery kept the previous path's data across a change of path and after a
failed fetch, so moving between two users or teams could leave the first
record's billing and member actions live under the second one's URL. Data from
another path is now dropped unless the caller opts in with keepPreviousData,
which only the list and search views and the provisioning wizard do.
Patching a member's live sessions with the new membership granted team access
without the team's login rules, and a new team requires MFA by default.
Revoking the sessions instead makes the next sign-in enforce them, the same
outcome the main API reaches by revoking sessions that violate the policy.
- Rate limit every request ahead of the Cloudflare Access check
- Page through all current subscriptions; status=all with a 20 item page
  could hide an active Team plan behind older canceled ones
- Log rather than throw a failed audit write once the team has committed, so
  the Stripe link still runs and the admin lands on the new team
…ent display

- A failed logout leaves the session cookie in place, so it now shows a
  retryable error instead of navigating to the sign-in page
- Scale Stripe amounts by Stripe's zero and three decimal currency lists
- Announce entitlement state with visually hidden text, since heroicons are
  always aria-hidden and ignored the aria-label

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread apps/api/src/app/services/stripe.service.ts Outdated
Copilot AI balanced review requested due to automatic review settings October 17, 2026 13:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new privileged application spans authentication, session handling, and billing operations that require final human validation.

4 open issues
1 file not reviewed
  • pnpm-lock.yaml: Generated file

Review effort: Balanced

…action

Revocation ran after the membership committed and only logged a failure, so
a failed delete left pre-team sessions live without the team's MFA/SSO
rules, and a retry 409'd on the existing membership. Provisioning also
skipped it entirely when its audit write threw.
…starts

Subscription schedule events run the team sync before a future-start
subscription exists, and the entitlement pull then wiped the access granted
at provisioning. The pull now needs an active subscription; revoking access
when one ends is left to the entitlement summary event, which fires on every
change.
Copilot AI balanced review requested due to automatic review settings October 18, 2026 13:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Privileged authentication and production billing workflows need human review, alongside resolving post-mutation bookkeeping failures.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Prevent post-commit audit failures from reporting mutations as failed

apps/​admin-api/​src/​app/​teams/​team-members.service.ts:84

[P2] Keep post-commit audit failures from reporting successful mutations as failed. recordMembersAdded can reject after membership creation and session revocation commit, so the UI reports “User not added” and retrying hits the existing-membership conflict. The same problem occurs after domain approval in team-domains.service.ts:72–78 and after Stripe saves the production org id in stripe-customers.service.ts:79–96 (including the linked-account reads). Catch and explicitly log this post-mutation bookkeeping failure while returning the saved result, matching team-provisioning.service.ts:101–114 and 152–163. Add failure-path tests confirming that persisted changes still return success.

4 resolved since last review
1 file not reviewed
  • pnpm-lock.yaml: Generated file

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

admin Internal admin app (staff only); excluded from release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants