SuperAPI AI Directory

portal-backend-app

Coding & development

View repository

Updated 10-16 08:09

About this skill

portal-backend-app · monorepo independent backend App development

Independent backend = its own process + its own DB, consuming the TDT issued by Portal. This file covers the operating sequence and red lines; read the specific contracts as needed references/(a self-contained reference distilled for this skill; the authoritative source is the portal repository docs/, and in case of conflict the portal repository prevails). This skill describeswithin the portal monorepodual-package pattern—when the server is in another repo, use the portal-external-app skill instead.

Read references by task

Task Read
introspection contract / four gates / service account / client_credentials / revocation references/gate-and-tokens.md
registration wiring / scope catalog / deployment wiring / API conventions / usage reporting / config tab references/wiring-and-conventions.md

Reference implementation:apps/spms-server/src/lib/gate.ts + identity.ts(the isomorphic auth layer of each server).

Full-chain checklist for creating a new backend App

Complete in order; each step has an existing template to copy (for light business copy todo-server, for heavy business copy lms-server):

  1. dual package:apps/<key>-server(Bun + Elysia, dev port takes a free 4xxx) + apps/<key>-app(for the frontend see the portal-micro-app skill). DB naming xgent-<key>。
  2. auth layer: copy spms-server/src/lib/gate.ts + identity.tswholesale, change the listingKey/scope constants. Do not hand-write introspection logic.
  3. Checklist and wiring(for locations and rules see wiring-and-conventions.md §1): ACL Manifest → manifests.ts;listing → LISTING_DEFS; service account → SA_DEFS; exchange → EXCHANGE_WIRING; scope can only fall within its own namespace.
  4. Seed: write the App's own seed/bootstrap as anon-destructivestandalone script (db:seed is portal-only + destructive).
  5. dev:all: hook server+app into the root package.json 's concurrently; never run a single dev script stacked.
  6. Deployment wiringdo it all at once (Caddy allowlist / compose profile / DEPLOYABLE_APP_SERVICES / Dockerfile COPY new workspace / build:apps in series)—for per-item symptoms see wiring-and-conventions.md §2; miss one and production will 404/fail to start.
  7. Verification script:apps/<key>-server/scripts/verify-*.ts covers TDT/isolation/ACL/core business, hook it into apps/api/scripts/verify-all.ts. A feature without a verify script does not count as delivered.

Four gates (every protected endpoint must pass)

Introspection POST /api/tokens/introspect(service account Basic) then: ① (claims.listingKey ?? claims.aud) === 本服务 listingKey; ② required scope ∈ claims.scopes; ③ for structural management operations check claims.role === "admin"; ④ fine-grained bypass || permissions 命中 PID(data scope takes the widest).

If the endpoint is aplatform-level cross-tenantoperation, add beyond the four gates claims.isPlatformAdmin === true: this value is the global identity that Portal computes in real time on each introspection based on user_id , and is not in the JWT.role / bypass only represents the TDT's current tenant and cannot replace this gate; nor does it accept self-reported frontend headers/fields.

Getting it wrong is the hard shape of a full 401:

  • the introspection response goes through a unified envelope,declared in data in:claims = body.data ?? body;
  • active:false issuccessfulintrospection (invalid token), not a transport error; result cached ≤60s;
  • Service-state TDT (kind:"service", no user_id)authorized by scope only, do not go through PID gate;
  • active:true introspection result always carries boolean isPlatformAdmin; service state is always false, identity change propagation is constrained by downstream ≤60s cache limit;
  • Tenant isolation always claims.tenant_id, never trust the request body; rate limiting self-built (aud, tenant) per-minute window.

For complete fields and service account details see references/gate-and-tokens.md。

API and data conventions (mandatory review, details in wiring-and-conventions.md §3)

  • Business state does not use HTTP status codes: always 200 + {ok, data|error}; data not found = 200 + data:null not 404.
  • List endpoints use server-side pagination (Page<T>); dictionary tables uniformly sort(tree/sibling order preserved seq)。
  • migrationhand-written SQL(drizzle-kit generate is known broken in this repo).
  • Audit writes POST /api/v1/audit, do not self-build auditing; tenant configuration goes through the application configuration tab trio (wiring-and-conventions.md §5); do not do "contact sync"; metering goes through usage reporting (wiring-and-conventions.md §4).

Verification

Change complete = that server's verify-*.ts all green + bun run verify:all no regression + (when there is a UI surface) browser walkthrough. Dev key points: introspection prefers service account Basic (x-resource-key only DEV_MOCK_OAUTH=true and recognizes only FILES_RESOURCE_KEY one); backend script login uses a user without 2FA (e.g. liming)。