7.1 KiB
Backend (@openvidu-dashboard/backend)
Express 5, Inversify, Zod and the official mongodb driver; TypeScript 6 strict ESM, relative imports end in .js.
Behaviour is specified in openspec/specs/*-api, api-conventions, auth, status-api and editions-info.
Structure
src/lifecycle/startup.ts:startDashboard(options)reads the configuration, connects to MongoDB, applies the writer schema gate, builds the container, callsconfigureand the startup hooks, then listens. Exit codes go throughShutdown.run(code).src/di/container.ts:buildContainer()binds the CE services and extension tokens and registers the CE routes.TOKENS(src/di/tokens.ts) are bound withtoResolvedValuefactories, without decorators, so esbuild and Vitest need no metadata.- Routes are declared once in the
RouteRegistry(src/api/route-registry.ts): method, path under/api/v1, edition,featureof a PRO route, a uniqueoperationId(camelCase, verb first:listRooms,getRoomsSummary), tags declared first withregistry.tag(name, description), security (public,bearer,optional-bearer, plusrefreshCookiefor the auth routes), Zod schemas of params, query, body and responses, and the handler. It drives validation, authentication and the OpenAPI document (src/api/openapi.ts, only whenNODE_ENVis notproduction). - OpenAPI rules, enforced by
test/integration/openapi-document.test.tsthroughdocumentationIssues()(test/support/openapi-checks.ts): every parameter has a description (.meta({ description }); the generator lifts one set before.default()or.optional()), comma-separated lists usecsvParam()or an arrayoverride, errors without a schema getApiError,400and401are added from the input and the security, and a response only one edition answers carriesedition. - PRO routes are only locks here:
registry.lock({ method, path, feature })answers403 PRO_FEATUREafter authentication and stays out of the OpenAPI document. An edition that extends CE registers the full definition in the lock's place (mount order kept) and swaps a CE route for its extension withregistry.replace(); aprostartup that leaves a lock without a definition exits with code 1, naming it. - Extension tokens that
configurecan rebind:Features,LicenseInfo,AnalyticsCatalogue(metrics and dimensions the analytics endpoints compute) andOverviewExtension(extra overview fields, merged before theETag). Aconfigurethat throws stops the startup with code 1. - A resource slice is
src/<resource>/:*-schemas.ts(Zod),*-query.ts(pure filter builders),*-repository.ts(MongoDB),*-service.ts(paging, mapping),*-responses.ts(OpenAPI response schemas, checked against the mappers in unit tests) and*-routes.ts(register<Resource>Routes: the CE routes and the locks of the PRO ones). - Zod schemas live here because typings has no runtime dependencies; typings declares the matching types in
src/api/. Errors use{ error: { code, message, details? } }withErrorCode. - Shared query pieces in
src/api/:rangedQuery(now, shape)for ranged queries (relative grammar resolved at parse time) andoptionalRangeQuery(now, shape)when the bounds are optional,pageQuery()for keyset pages on an index ending in_id,indexOrderedPage()when the index does not order by_id, andrankedPage()withassertRankedRange()(src/api/ranked.ts) for metric sorts ranked in memory at the cursor'sasOf. Calendar math in a time zone uses date-fns and@date-fns/tz. src/stats/stats-mode.ts:StatsModeReaderreads the writer'sstats_detailforGET /info.src/analytics/answers from the rollup collections only:analytics-planner.tspicks the granularity, source collection and bucket grid,analytics-counters.tsfolds the documents in process with the definitions of the catalogue,AnalyticsCachekeeps the folds of completed documents andAnalyticsFeatureGaterejects PRO metrics, dimensions and node scopes on CE.src/status/freshness.tsmarks active rooms and participantsstalewith the backend clock, from the typingsfreshnessWindows().src/index.tsexports what an extending backend builds on: the startup, tokens and registry, the generic query, cursor, response and freshness pieces, and the list pieces that entity details extend.- Exact identifiers (
RM_,PA_,EG_,IN_,TR_) are matched withENTITY_ID_PATTERNS,isEntityId()andentityIdKind()from typings. - Configuration variables are new
DASHBOARD_*, orDATABASE_*for database connection settings; legacy names keep their 3.9 meaning (src/config/variables.ts, unit-tested). The README lists them all. scripts/dev.ts(exported as@openvidu-dashboard/backend/dev) serves./dashboard.sh dev:loadDevEnv()(the environment, then.env, thendev.env;scripts/dev-preload.tsfortsx watch --import) andcheckDevConfig()(scripts/dev-check.ts).dev.envholds the openvidu-local-deployment defaults; never givesrc/defaults for required variables, since a deployment must fail when they are missing.
Rules
- Repositories own the queries. Every list, detail and time-series query is backed by an index and asserted with
expectIndexBacked(test/support/query-plan.ts: no COLLSCAN above 1 000 documents, boundedtotalDocsExamined).
Tests
-
Unit tests: Vitest (
pnpm test). -
Integration tests:
test/integration/, Vitest projectsintegrationandintegration-plans(the*query-plansuites, run after the rest so their data generation does not skew the latency budgets).test/support/starts a replica set with Testcontainers onopenvidu/mongodb:8.0.29-r1(the officialmongo:8.0refuses Linux kernels 6.19 and newer), or usesDASHBOARD_TEST_MONGO_URI;DASHBOARD_TEST_MONGO_IMAGEoverrides the image. Through pnpm without Docker the suites report themselves skipped;./dashboard.sh test-integrationfails instead. -
They also need
openssl(test CA of the TLS case) and build the package to rundist/server.jsas a process.test/support/boot.tsstarts the dashboard in-process on a fresh database with a controllable clock. -
test/support/is exported to the suites of extending packages as@openvidu-dashboard/backend/testing(source only, never indist), and the MongoDB global setup as@openvidu-dashboard/backend/testing/global-mongo. -
Query-plan suites generate data with
dashboard-ce/tools/data-generatorand report the p95 of their budget. Design figures come from scenario M over 7 days on a MongoDB with room for it, run alone:DASHBOARD_TEST_MONGO_URI=<uri> ROOMS_PLAN_SCENARIO=M ROOMS_PLAN_DAYS=7 ROOMS_PLAN_REPORT=<file> \ pnpm --filter @openvidu-dashboard/backend exec vitest run --project integration-plans \ test/integration/rooms-query-plan.test.tsThe other suites take the prefixes
PARTICIPANTS_PLAN_,EGRESS_PLAN_,INGRESS_PLAN_,OVERVIEW_PLAN_andANALYTICS_PLAN_.DASHBOARD_TEST_LATENCY_BUDGETS=report(set in CI) turns p95 overruns into warnings; plan assertions fail either way.