Skip to content

Add limits and api key handling to dashboard - #1298

Merged
ebma merged 14 commits into
stagingfrom
add-limits-and-key-to-dashboard
Aug 3, 2026
Merged

Add limits and api key handling to dashboard#1298
ebma merged 14 commits into
stagingfrom
add-limits-and-key-to-dashboard

Conversation

@gianfra-t

Copy link
Copy Markdown
Contributor

No description provided.

@netlify

netlify Bot commented Jul 31, 2026

Copy link
Copy Markdown

Deploy Preview for vortexfi ready!

Name Link
🔨 Latest commit b228085
🔍 Latest deploy log https://app.netlify.com/projects/vortexfi/deploys/6a7060a562870c0008585b03
😎 Deploy Preview https://deploy-preview-1298--vortexfi.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Jul 31, 2026

Copy link
Copy Markdown

Deploy Preview for vrtx-dashboard canceled.

Name Link
🔨 Latest commit b228085
🔍 Latest deploy log https://app.netlify.com/projects/vrtx-dashboard/deploys/6a7060a612b7d60008ca183a

@netlify

netlify Bot commented Jul 31, 2026

Copy link
Copy Markdown

Deploy Preview for vortex-sandbox ready!

Name Link
🔨 Latest commit b228085
🔍 Latest deploy log https://app.netlify.com/projects/vortex-sandbox/deploys/6a7060a500990800081bb182
😎 Deploy Preview https://deploy-preview-1298--vortex-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@gianfra-t gianfra-t changed the title [WIP] Add limits and api key handling to dashboard Add limits and api key handling to dashboard Jul 31, 2026
@gianfra-t
gianfra-t requested a review from Copilot July 31, 2026 12: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.

Pull request overview

Adds dashboard management for monthly corridor limits and user API credentials, backed by new API contracts and services.

Changes:

  • Adds unified authenticated limits retrieval and dashboard display.
  • Adds credential pairing, creation, listing, and revocation.
  • Updates SDK guidance, OpenAPI documentation, security specs, and tests.

Reviewed changes

Copilot reviewed 49 out of 50 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/shared/src/services/brla/schemas.ts Validates provider limit periods.
packages/shared/src/services/brla/schemas.test.ts Tests BRLA limit parsing.
packages/shared/src/endpoints/limits.endpoints.ts Defines limits contracts.
packages/shared/src/endpoints/index.ts Exports limits contracts.
packages/sdk/src/VortexSdk.ts Clarifies registration credentials.
packages/sdk/README.md Updates API-key guidance.
docs/security-spec/07-operations/api-surface.md Documents limits endpoint security.
docs/security-spec/05-integrations/brla.md Documents BRL limit handling.
docs/security-spec/05-integrations/alfredpay.md Documents Alfredpay usage aggregation.
docs/security-spec/01-auth/api-keys.md Documents credential pairing.
docs/api/pages/09-fiat-corridors.md Documents corridor limits.
docs/api/pages/03-authentication-and-partner-keys.md Updates key-management documentation.
docs/api/pages/02-quick-start-with-the-sdk.md Updates SDK authentication guidance.
docs/api/openapi/vortex.openapi.json Adds limits and credential schemas.
docs/api/openapi/vortex.openapi.d.ts Regenerates OpenAPI types.
apps/dashboard/src/services/api/limits.service.ts Adds limits API client.
apps/dashboard/src/services/api/api-keys.service.ts Adds credential API client.
apps/dashboard/src/services/api/api-client.ts Supports DELETE request bodies.
apps/dashboard/src/routeTree.gen.ts Registers new dashboard routes.
apps/dashboard/src/routes/_app/limits.tsx Adds limits page.
apps/dashboard/src/routes/_app/api-keys.tsx Adds API-keys page.
apps/dashboard/src/hooks/useLimits.ts Fetches approved-corridor limits.
apps/dashboard/src/hooks/useApiKeys.ts Manages credential queries.
apps/dashboard/src/domain/api-credentials.ts Groups paired key records.
apps/dashboard/src/domain/api-credentials.test.ts Tests credential grouping.
apps/dashboard/src/components/limits/LimitsCard.tsx Displays monthly usage.
apps/dashboard/src/components/layout/AppSidebar.tsx Adds navigation entries.
apps/dashboard/src/components/api-keys/CreateApiCredentialDialog.tsx Implements credential creation.
apps/dashboard/src/components/api-keys/ApiCredentialsTable.tsx Lists and revokes credentials.
apps/dashboard/e2e/support/mockBackend.ts Mocks limits and key APIs.
apps/dashboard/e2e/limits.spec.ts Tests limits UI.
apps/dashboard/e2e/api-keys.spec.ts Tests credential lifecycle.
apps/api/src/test-utils/fake-world/fake-anchors.ts Adds fake limit periods.
apps/api/src/models/apiKey.model.ts Adds credential identifiers.
apps/api/src/database/migrations/055-add-credential-id-to-api-keys.ts Migrates credential pairing.
apps/api/src/api/services/limits.service.ts Resolves unified limits.
apps/api/src/api/services/limits.service.test.ts Tests limit resolution.
apps/api/src/api/services/alfredpay/alfredpay.helpers.ts Aggregates monthly usage.
apps/api/src/api/services/alfredpay/alfredpay.helpers.test.ts Tests usage aggregation.
apps/api/src/api/services/alfredpay/alfredpay-limits.service.ts Adds ARS limits.
apps/api/src/api/services/alfredpay/alfredpay-limits.service.test.ts Tests ARS indexing.
apps/api/src/api/routes/v1/limits.route.ts Adds authenticated limits route.
apps/api/src/api/routes/v1/index.ts Mounts limits routes.
apps/api/src/api/routes/v1/api-keys.route.ts Updates revocation documentation.
apps/api/src/api/controllers/userApiKeys.controller.ts Adds paired credential handling.
apps/api/src/api/controllers/userApiKeys.controller.test.ts Tests key lifecycle changes.
apps/api/src/api/controllers/limits.controller.ts Validates limits requests.
apps/api/src/api/controllers/limits.controller.test.ts Tests request rejection.
apps/api/src/api/controllers/admin/partnerApiKeys.controller.ts Pairs partner credentials.
.agents/skills/vortex-integration/SKILL.md Updates integration guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const { name, expiresAt } = (req.body ?? {}) as CreateApiKeyBody;

try {
const baseName = name?.trim() || "API Key";
Comment on lines 133 to 134
createdAt: { [Op.gte]: startsAt, [Op.lt]: endsAt },
currentPhase: "complete",
Comment on lines 53 to 54
const activeKeyCount = await ApiKey.count({ where: { isActive: true, partnerId: null, partnerName: null, userId } });
if (activeKeyCount + 2 > MAX_ACTIVE_KEYS_PER_USER) {
return;
}

if (expirationDate.getTime() <= Date.now()) {
Comment on lines +108 to +109
delete usedLimit.month;
expect(() => aveniaAccountLimitsSchema.parse(body)).toThrow();
Every authenticated endpoint takes:
- Header: `X-API-Key: sk_<env>_<32chars>`
- Body field: `"publicKey": "pk_<env>_<...>"`
- Quote body field: `"apiKey": "pk_<env>_<...>"`
Comment thread docs/api/openapi/vortex.openapi.json Outdated
Comment on lines +736 to +739
"credentialId": {
"description": "Shared identifier for the public and secret records. Null only for ambiguous legacy records.",
"type": ["string", "null"]
},

@ebma ebma left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review summary

I reviewed the latest implementation and the production migration implications. The limits work is coherent, and the code head immediately before the documentation-only commit had green test and CI checks. The remaining concern is that an API credential is still modeled as two independently valid rows, with a nullable correlation ID that controllers and clients must interpret correctly. That leaves lifecycle and authorization invariants distributed across the API, dashboard, and migration.

The main actionable findings are inline:

  • P1: revocation can disable only one half of a credential.
  • P2: public and secret values from different credentials are not rejected at the authentication boundary.
  • P2: expired rows still consume the active credential cap.
  • P2: the migration infers credential relationships from mutable display names.

I recommend retaining distinct public and secret values but representing them as one credential record with one profile subject, optional managing partner, environment, expiry, and atomic revocation lifecycle. Self-service and delegated credentials should use the same service; users without an interactive signup should receive unique managed profiles, never a shared dummy identity.

I published the full implementation and production rollout plan in docs/plans/api-credential-unification.md. Before production, run the digest backfill, explicitly map or reissue every active pair, provision missing managed profiles, and make deployment fail closed unless active legacy, unpaired, and ownerless rows are all zero. Digest backfill alone does not establish pair or profile ownership.

Comment thread apps/api/src/api/controllers/userApiKeys.controller.ts Outdated
Comment thread apps/api/src/api/controllers/userApiKeys.controller.ts Outdated
Comment thread apps/api/src/models/apiKey.model.ts Outdated
Comment thread apps/api/src/database/migrations/055-add-credential-id-to-api-keys.ts Outdated

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.

Pull request overview

Copilot reviewed 125 out of 126 changed files in this pull request and generated no new comments.

Suppressed comments (8)

apps/api/src/api/controllers/auth.controller.ts:93

  • If markManagedProfileClaimed hits a database error after Supabase has already minted the session, the outer catch reports “Invalid OTP or OTP expired” and withholds the valid tokens. Keep this post-auth bookkeeping best-effort like entity creation; on failure, skip eager entity creation so a technical profile is not accidentally given one.
      const managedSubjectType = await markManagedProfileClaimed(result.user_id);

apps/api/src/api/routes/v1/ramp-info.route.ts:19

  • This route does not run optional Supabase auth, and the controller only accepts req.credential, so the documented Authorization: Bearer form always returns CREDENTIAL_REQUIRED. Add session authentication and resolve the profile from either the session or credential, while defining how mixed identities are handled.
    packages/sdk/scripts/delete-api-key.ts:61
  • The list endpoint returns { credentials: [...] }, not { apiCredentials: [...] }, so this script crashes before presenting a credential to revoke. Map the wire property to the local name (or rename all accesses).
    apps/api/src/api/services/rampInfo.service.ts:29
  • This aggregates provider records from every customer entity owned by the profile. Ramp execution resolves only the active/default entity, so an approved inactive individual entity can make canBuy/canSell true while the active business entity is pending and registration will fail. Resolve the same effective entity as registration without creating an entity for technical profiles.
    apps/api/src/api/services/rampInfo.service.ts:9
  • This duplicates the shared corridor matrix and ignores customer type. For example, an approved AR business record is reported as buy/sell capable even though packages/shared/src/corridors.ts:11-26 defines AR as individual-only. Derive corridor/provider support from CORRIDOR_CAPABILITIES and isCorridorSupportedForCustomerType, including customerType in the query.
    docs/operations-api-credential-rollout.md:26
  • The documented preflight gate is not implemented: validateManifest verifies ownership and key environment but never compares the two legacy expiresAt values with each other or the manifest, and its partner lookup does not require isActive. The runbook therefore promises rejection while the migration can silently accept expiry disagreement or an inactive partner; enforce these checks before relying on this rollout gate.
    packages/sdk/scripts/fetch-api-keys.ts:55
  • GET /v1/api-credentials returns { credentials: [...] }, but this cast and the following accesses expect apiCredentials; the first .length access therefore throws at runtime. Normalize the actual response property before using the existing local name.
    apps/dashboard/src/components/limits/LimitsCard.tsx:16
  • API amount fields are decimal strings, but converting them to Number can lose precision or overflow, producing an incorrect progress percentage for large limits. Compute the bounded ratio with a decimal-safe representation instead of binary floating point.

@ebma
ebma merged commit bdc93d9 into staging Aug 3, 2026
7 checks passed
@ebma
ebma deleted the add-limits-and-key-to-dashboard branch August 3, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants