vuer_oss Data Model (Sequelize)

The system-of-record schema for FaceKom lives in vuer_oss. It is defined with Sequelize over PostgreSQL (pg/pg-hstore). There are 61 model files in server/db/model/, each a (sequelize, DataTypes) => Model factory. A single aggregator file, server/db/models.js, requires all 61, wires every association centrally, and returns the model registry. This is the single-models-file pattern — see the gotcha below.

Scope verified against the devel branch (origin/HEAD -> origin/devel). Working tree is checked out on update/customization/instacash-2026-05-27; all reads here used git show devel:<path>. Sibling: vuer_oss, INDEX.

Related siblings: vuer_oss · architecture-overview · vuer_css (the customer-side node; shares codebase shape but OSS owns the DB).


1. ORM, versions, drivers (from manifests)

AspectValueSource
ORMSequelize — forked: "sequelize": "npm:@techteamer/sequelize@^6.30.1"package.json
Resolved fork version@techteamer/sequelize 6.32.2yarn.lock (sequelize@npm:@techteamer/sequelize@^6.30.1version "6.32.2")
CLIsequelize-cli@^6.6.0package.json
Programmatic migrationsumzug@^3.8.2 (used by bin/db/migrate-data; server/db/migrationHelpers.js)package.json
Primary DB driverpg@^8.0.2 + pg-hstore@^2.3.2PostgreSQLpackage.json
Session storeconnect-session-sequelize@^8.0.3 (persists Express sessions in the DB Session table)package.json
Other dialects (README opt-in)OracleDB / MySQL (mysql2) / MSSQL (tedious) — alternates documented; Postgres is the shipped defaultREADME.md, vuer_oss

sequelize is the @techteamer/sequelize fork, not upstream npm. The import is require('sequelize') everywhere, but it resolves to the fork (package.json aliases the package name). Pinned range ^6.30.1, actually resolved 6.32.2. Treat behavior as Sequelize v6, with fork patches.

Connection (server/db/sequelize.js, 117 lines)

  • Builds one shared Sequelize instance from config.db. If db.database is set → new Sequelize(database, username, password, options); else backward-compat new Sequelize(db.url, options) (sequelize.js:27-33).
  • Default pool max: 100, merged with config.get('db.options') (sequelize.js:17-23).
  • SQL logging only when NODE_ENV === 'dev'logger.channels.sql.info (sequelize.js:5).
  • Global hooks: beforeFind / beforeCount strip undefined keys from where (a v6 behavior shim — undefined is no longer coerced to null; sequelize.js:36-58).
  • A 5 s setInterval publishes pool stats to serviceContainer.diagnostic.sequelizeStats and logs POOL WARNING/ERROR at >0.4 / >0.6 usage (sequelize.js:60-95).
  • SIGUSR1/SIGUSR2 dump/force-release pooled connections (debug; sequelize.js:100-115).
  • Module exports the singleton sequelize.

Model definition pattern (per file)

Every server/db/model/*.js exports (sequelize, DataTypes) => { const M = sequelize.define('<name>', { ...attributes }, { indexes, [tableName] }); ... return M }. Models define attributes, indexes, instance/class methods, getters/setters and hooks — but NOT associations (those are centralized in models.js). Common conventions seen across models:

  • M.getModelDescription() — human label (e.g. Room → 'Videochat rooms', Setting → 'Settings, for example: hologram detection limits').
  • M.prototype.toFrontendSync() — serializer (epoch-second timestamps) used to ship rows to the UI.
  • JSON columns stored as TEXT with get/set that JSON.parse/stringify and, where encryption is enabled, transparently decrypt/encrypt (e.g. room.data, customer.data, flow.metadata, setting.value).
  • Conditional indexes: several models skip FK indexes on MySQL (if (sequelize.dialect.name !== 'mysql')) to avoid duplicate indexes (flow.js:17, encryption.js:6).

2. The single-models-file (server/db/models.js, 408 lines)

All associations live in one 408-line file, not in the model files. server/db/models.js requires every one of the 61 model factories, calls each with (sequelize, DataTypes), then declares every hasMany / belongsTo / addScope for the whole schema in its body, and returns the model registry object. The individual server/db/model/*.js files contain attributes + methods only and have no knowledge of their relationships. To understand any entity's graph you must read models.js, not the model file.

How it is wired:

  • Loaded via require('../../db/models')(sequelize) and assigned to serviceContainer.dbModels in three places:
    • server/bootstrap/connection/db.js:13 (the normal boot path — setupDb()),
    • server/backgroundProcess/workers/report.worker.js:30,
    • server/service/ImportService.js:263 (assigns to serviceContainer.importDbModels, against a second connection this.originConnection — used to read a legacy/import DB with the same schema).
  • The factory returns a flat object of all 61 models (keys like Room, SelfServiceRoom, Customer, Flow, …). Verified: all 61 model files are required, and all 61 are returned (1:1, no orphans).
  • Named scopes are defined here too, e.g. Flow.withTasks/withCustomer/withRoom/withUsers, FlowProto.withTasks/withTranslations/withActivityLog, Document.withFile, FaceComparison.withRecognitions, CustomerDataChange.withUser, SelfServiceRoom.withCustomer, User.withCerts, Cert.withUser (models.js:119-331).

User is frequently associated .unscoped() (e.g. all Flow.belongsTo(User.unscoped(), { as: ... }), FlowActivity, UserActivity, ClientErrorLog). User has a defaultScope (see §5) that hides disabled users (where: { isEnabled: true } only — no sensitive-field exclusion); .unscoped() bypasses it so audit/flow joins still resolve disabled operators.


3. Entities / tables (61)

Each model define()s a name; Sequelize derives the table name from that name (v6 default pluralization — no global freezeTableName/underscored was found in server/db/**, config/**, or .sequelize-config.js). The only explicit tableName override is session.jstableName: 'Session'.

Three different identifiers per entity — the file name, the models.js const, and the sequelize.define(...) name often diverge. Examples where they differ: feedback.js defines feedbackAnswer; cert.jscerts; setting.jssettings; backgroundProcess.jsbackgroundProcesses; backgroundProcessLog.jsbackgroundProcessLogs; customerdatachange.jscustomerDataChange; customerhistory.jscustomerHistory; customervalidation.jscustomerValidation; flowProtoActivity.jsflowprotoactivity; passwordhistory.jspasswordHistory; systemDocument.jssystemdocument; totpKey.jstotpKeys; userActivity.jsuserActivities; webAuthnCredential.jswebAuthnCredentials. When mapping a DB table, go by the define() name (column 2 below), not the filename.

File (server/db/model/)define() namemodels.js constDomain area
room.jsroomRoomVideochat room (system core)
selfserviceroom.jsselfServiceRoomSelfServiceRoomSelf-service (unattended) session
customer.jscustomerCustomerEnd-user being identified
user.jsuserUserOperator/admin account
cert.jscertsCertUser signing certificate
activity.jsactivityActivityRoom/self-service activity log
customerhistory.jscustomerHistoryCustomerHistoryCustomer change history
customervalidation.jscustomerValidationCustomerValidationCustomer data validation record
customerdatachange.jscustomerDataChangeCustomerDataChangeCustomer data-change audit
attachment.jsattachmentAttachmentStored file/screenshot blob ref
mediafile.jsmediafileMediaFileRecorded/converted media file
encryption.jsencryptionEncryptionPer-record AES key metadata
recognitionattempt.jsrecognitionattemptRecognitionAttemptFace-recognition attempt
document.jsdocumentDocumentDocument record
documentVersion.jsdocumentVersionDocumentVersionDocument version
download.jsdownloadDownloadExport/download artifact
feedback.jsfeedbackAnswerFeedbackCustomer feedback answer
openhourstandard.jsopenhourstandardOpenHourStandardWeekly opening hours (7 rows)
openhourexception.jsopenhourexceptionOpenHourExceptionOpening-hour exception/holiday
emaillog.jsemaillogEmailLogSent-email log
smslog.jssmslogSmsLogSent-SMS log
auditlog.jsauditlogAuditLogAdmin/security audit log
callbackrequest.jscallbackrequestCallbackRequestCustomer callback request
callbackRequestActivity.jscallbackRequestActivityCallbackRequestActivityCallback request activity
communicationlog.jscommunicationlogCommunicationLogComms log (room/self-service)
clienterrorlog.jsclienterrorlogClientErrorLogBrowser/client error log
shortener.jsshortenerShortenerURL shortener entries
timestampToken.jstimestampTokenTimestampTokenRFC3161 trusted-timestamp token
setting.jssettingsSettingKey/value system settings
oneTimeLogin.jsoneTimeLoginOneTimeLoginOne-time login token
job.jsjobJobBackground/identification job
backgroundProcess.jsbackgroundProcessesBackgroundProcessLong-running process record
backgroundProcessLog.jsbackgroundProcessLogsBackgroundProcessLogBackground-process log line
flow.jsflowFlowKYC flow instance
flowproto.jsflowProtoFlowProtoFlow definition/prototype
task.jstaskTaskFlow task instance
taskproto.jstaskProtoTaskProtoTask definition/prototype
flowactivity.jsflowactivityFlowActivityFlow activity log
flowscope.jsflowScopeFlowScopeFlow scope
flowresult.jsflowResultFlowResultFlow result
flowTranslation.jsflowTranslationFlowTranslationFlow proto translation
flowProtoActivity.jsflowprotoactivityFlowProtoActivityFlow-proto edit activity
faceRecognition.jsfaceRecognitionFaceRecognitionFace-recognition result
faceComparison.jsfaceComparisonFaceComparisonFace-comparison (1:1) result
storage.jsstorageStorageStorage-engine placement record
emrtdInfo.jsemrtdInfoEmrtdInfoeMRTD (passport chip) data
passwordhistory.jspasswordHistoryPasswordHistoryUser password history
userActivity.jsuserActivitiesUserActivityUser activity audit
systemDocument.jssystemdocumentSystemDocumentSystem document
webAuthnCredential.jswebAuthnCredentialsWebAuthnCredentialWebAuthn/FIDO2 credential
totpKey.jstotpKeysTotpKeyTOTP secret
integrationLog.jsintegrationLogIntegrationLogEncrypted external-integration log
janusevent.jsjanuseventJanusEventJanus/WebRTC event log
session.jsSession (tableName: 'Session')SessionExpress login session
partner.jspartnerPartnerPartner
partnerService.jspartnerServicePartnerServicePartner service
partnerServiceRequest.jspartnerServiceRequestPartnerServiceRequestPartner service request
importedCustomer.jsimportedCustomerImportedCustomerMigrated/imported customer
importedRoom.jsimportedRoomImportedRoomMigrated/imported room
importedFlow.jsimportedFlowImportedFlowMigrated/imported flow
importedFlowTranslation.jsimportedFlowTranslationImportedFlowTranslationImported flow translation

feedback.js → table-name feedbackAnswer is the sharpest filename/table mismatch; the registry key stays Feedback. Searching the DB for a feedback table will fail.


4. Key relationships (all from models.js)

System-of-record hubs

  • Customer is the central party. Customer hasMany Room, SelfServiceRoom, CustomerHistory, CallbackRequest, EmailLog, SmsLog, Document, Encryption, Download, ClientErrorLog, PartnerServiceRequest (models.js:74-336).
  • Room belongsTo Customer and belongsTo User; User hasMany Room. Room hasMany Activity, Feedback, CommunicationLog, ClientErrorLog, Encryption, Document, MediaFile, EmrtdInfo, Storage (models.js:74-323).
  • SelfServiceRoom belongsTo Customer; mirrors Room’s hasMany set (Activity, Feedback, CommunicationLog, ClientErrorLog, Encryption, Document, MediaFile, EmrtdInfo, Storage). Scope withCustomer (models.js:80-331).
  • User hasMany Room, EmailLog, SmsLog, Cert, Download, ClientErrorLog, PasswordHistory, WebAuthnCredential, TotpKey; Cert belongsTo User (models.js:74-343).

Activity / audit

  • Activity belongsTo Room, SelfServiceRoom, User, Customer, plus a second Customer alias encryptionCustomer (models.js:81-85).
  • AuditLog belongsTo User and belongsTo User as 'targetUser' (models.js:94-95).
  • UserActivity belongsTo User.unscoped(), User.unscoped() as 'targetUser', Customer (models.js:327-329).
  • CustomerDataChange belongsTo Customer, Room, SelfServiceRoom, User + scope withUser (models.js:115-119).

Flow engine (proto vs instance)

  • Definition side: FlowProto hasMany TaskProto(as tasks), FlowScope(as scopes), FlowResult(as results), FlowTranslation(as translations), FlowProtoActivity(as activities); FlowProto belongsTo User.unscoped() (fk editingBy); TaskProto belongsTo FlowProto (models.js:200-223).
  • Instance side: Flow belongsTo FlowProto, Customer, Room, SelfServiceRoom, Flow(as parentFlow), and four User.unscoped() roles createdBy/startedBy/updatedBy/finishedBy; Flow hasMany Task. Task belongsTo Flow (constraints:false), TaskProto, User.unscoped()(as updatedBy) (models.js:173-198).
  • FlowActivity belongsTo User.unscoped(), Flow, Task, Room, SelfServiceRoom. FlowTranslation belongsTo FlowProto. FlowProtoActivity belongsTo FlowProto, User.unscoped(). Document belongsTo Flow (models.js:225-236).

Biometrics

  • FaceRecognition belongsTo Attachment(as sourceAttachment), Attachment(as resultAttachment), Room, SelfServiceRoom, Customer, User (models.js:291-296).
  • FaceComparison belongsTo FaceRecognition(as recognitionFrom), FaceRecognition(as recognitionTo), Room, SelfServiceRoom, Customer, User; scope withRecognitions (models.js:298-309).
  • RecognitionAttempt belongsTo Attachment, User, Room, SelfServiceRoom, Customer (models.js:243-247).
  • EmrtdInfo belongsTo Customer, Room, SelfServiceRoom (models.js:319-323).

Crypto / media / storage

  • Encryption is referenced from Customer/Room/SelfServiceRoom/ImportedRoom/ImportedCustomer (hasMany) and joined by Attachment/MediaFile/IntegrationLog/Document(withFile scope) (belongsTo) (models.js:138-241).
  • Attachment belongsTo TimestampToken, Encryption; MediaFile belongsTo TimestampToken, Encryption, Room, ImportedRoom, SelfServiceRoom (models.js:126-171).
  • Storage belongsTo Room, SelfServiceRoom, Attachment, Flow; Room/SelfServiceRoom/Flow hasMany Storage (models.js:311-317).
  • Document belongsTo Customer, Room, SelfServiceRoom, Attachment, Flow + scope withFile (includes Attachment → Encryption). DocumentVersion belongsTo Document, Attachment (models.js:142-158).

Background processing

  • BackgroundProcess belongsTo a wide fan-out: User, Customer, Room, SelfServiceRoom, Flow, Task, Attachment, Document, MediaFile, Partner, PartnerService, PartnerServiceRequest, Cert, Download, EmrtdInfo, ImportedRoom; BackgroundProcess hasMany BackgroundProcessLog (models.js:263-280).

Partner

  • Partner hasMany PartnerService; PartnerService belongsTo Partner, hasMany PartnerServiceRequest; PartnerServiceRequest belongsTo PartnerService, Customer; Customer hasMany PartnerServiceRequest (models.js:282-287).

Imported (data migration)

  • ImportedRoom belongsTo ImportedCustomer, hasMany Encryption; ImportedCustomer hasMany Encryption, ImportedRoom; ImportedFlow belongsTo ImportedCustomer, ImportedRoom (models.js:333-339).

Misc

  • IntegrationLog belongsTo Customer, Encryption, Room, SelfServiceRoom (models.js:238-241).
  • OneTimeLogin belongsTo User; Job belongsTo User (models.js:249-251).
  • Feedback belongsTo Customer, Room, SelfServiceRoom (models.js:86-88).
  • EmailLog/SmsLog/CallbackRequest/CommunicationLog/ClientErrorLog all hang off Customer and/or Room/SelfServiceRoom (models.js:89-136).

5. Notable attribute details (sampled)

  • room (room.js): status (default 'waiting'; validated against allStatuses = waiting|incall|closed|deleted|archived), closedAt, roomCodec (default vp8; vp8|vp9|h264), roomCodecContainer (mkv|mp4|webm), closedInitiator (operator|customer|supervisor|admin), convertState (queued|processing|done|errored), deleteReason STRING(255), data TEXT (transparent JSON + optional AES via cryptos.data), encryptionKey STRING(44). Indexes [userId,status], [customerId,status], [status]. Hooks: beforeSave ensures an encryption key when crypto enabled; afterSave emits room:updated. Methods close(), isDeletable(), isEncrypted(), toFrontendSync(), toCustomerSync().
  • customer (customer.js): ip STRING(45), userAgent TEXT, locale (default config.locales.default), token, data TEXT (transparent JSON + crypto, calls updatePortalData), key STRING(44), deleteReason STRING(255), and searchField1searchField9+ (hashed/searchable surrogate columns — populated by bin/db/customer-index.js re-indexing). Requires customization/portal/PortalData and ua-parser-js.
  • selfServiceRoom (selfserviceroom.js): status, serviceProgress, data (transparent JSON/crypto), closedAt, expireAt, roomCodec, roomCodecContainer, convertState, deleteReason, encryptionKey.
  • flow (flow.js): status (created|in-progress|on-hold|finished|aborted, default created), finishedTaskCount, startedAt/finishedAt/lastUpdatedAt, result, name (validated against config.flow.flows), version (default 1), taskCount (NOT NULL), isArchived, cleared, metadata TEXT (JSON). Index on result and [roomId,name,status] (+ FK indexes off-MySQL).
  • user (user.js): username, email, phone, rights, data, searchField1searchField8, isEnabled, firstName, lastName, password, passwordExpiry. defaultScope is { where: { isEnabled: true } } only — it hides disabled users and does not exclude any sensitive fields (user.js:157-161). Additional named scopes come from customization/user/UserScopes.getScopes(). This defaultScope is why User.unscoped() is pervasive in associations.
  • encryption (encryption.js): algorithm (NOT NULL), version INT (default 1), key STRING(44) (getter resolves actual key via cryptos.data.getActualKey), aad TEXT, chunkSize/chunkCount INT, dataIsArchived BOOL. FK indexes on customerId/roomId/selfServiceRoomId (skipped on MySQL).
  • settings (setting.js): key (unique, NOT NULL), value TEXT (transparent JSON). Stores e.g. hologram/face-comparison thresholds (cf. bin/self_service_settings_db_checker).
  • Session (session.js): sid STRING(36) PK, expires DATE, data TEXT, tableName: 'Session'. Copied from connect-session-sequelize’s internal model so that syncOnStart creates it; file header warns to keep it in sync with the upstream module.

Non-DB "models" exist too. server/model/ holds 12 plain domain classes (OperatorRoomData, RoomSettings, ReplayData, ScreenshotLog, CustomerEnvData, CustomerRoomData, GirinfoCheckData, SelfServiceChecksData, SelfServiceOperatorRoomData[V2], SelfServiceReplayData, SelfServiceRoomData) — these are not Sequelize tables; server/db/helpers.js:3-6 requires several of them. Don't confuse server/model/ (domain objects) with server/db/model/ (the 61 ORM entities).


6. Migrations

Models and migrations are separate trees, both under version control.

  • Two migration directories (db/):
    • db/migrate/ — the main migration set, 127 .js files (git ls-tree devel:db/migrate | grep '\.js$' | wc -l; the dir holds only .js migrations). Naming is YYYYMMDDHHMMSS-<desc>.js. Range observed (valid timestamps only): 20170625…20260110150200-index-feedback-indexes.js. One filename is malformed: 201090911093344-add-meta-to-otl.js has a 15-digit prefix (201090911093344), not a valid 14-digit YYYYMMDDHHMMSS — it sorts above 20170625… but is not the real lower bound. It is still counted in the 127. Path set by .sequelizercmigrations-path: db/migrate.
    • db/beforeMigrate/ — a pre-migration set (≈25 files, index/search-field setup) run first via a separate rc, .sequelizercBeforemigrations-path: db/beforeMigrate.
  • Config for both: .sequelizerc and .sequelizercBefore both point config.sequelize-config.js and models-pathserver/db/model. .sequelize-config.js reads db.{database|url, username, password, options.dialect} from config, throws Sequelize misconfiguration error! unless exactly one of db.database/db.url is set, and requires db.options.dialect when using db.database.
  • Boot-time execution order (server/bootstrap/connection/db.js:16-28, only when setupDb(initDb=true) — i.e. server.js only, with db.syncOnStart true):
    1. sequelize db:migrate --options-path=.sequelizercBefore (run db/beforeMigrate/),
    2. ./bin/db/sync (sequelize.sync()),
    3. sequelize db:migrate (run db/migrate/),
    4. dbHelpers.checkStandardDays() (seed the 7 OpenHourStandard rows). If db.syncOnStart is false, only checkStandardDays() runs.
  • Umzug (umzug@^3.8.2) backs programmatic data migrations: server/db/migrationHelpers.js and bin/db/migrate-data (storage in db/beforeMigrate); bin/db/migrate-rdbms.js migrates between two RDBMS URLs running sequelize db:migrate with .sequelizercBefore then default. (See vuer_oss §“bin/db”.)

Only server.js migrates/syncs the DB. setupDb runs migrations solely when called with initDb=true, which happens only from server.js. The other daemons (media.js, convert.js, cron.js, background.js, storage.js, integrationLog.js) connect read/write against an already-migrated schema. With db.syncOnStart true, boot mutates schema (runs sequelize.sync() + both migration sets).


7. Verified gotchas (data model)

Single models file. Associations + scopes for all 61 entities are centralized in server/db/models.js (408 lines), not in the per-entity files. The model files are attributes/methods only. Edit/read associations there.

Forked ORM. sequelize resolves to @techteamer/sequelize@6.32.2 (range ^6.30.1), not upstream sequelize. Behavior is Sequelize v6 + fork patches; server/db/sequelize.js adds a where-undefined-stripping shim because v6 stopped coercing undefinednull.

Filename ≠ table name. Go by the sequelize.define(...) name (often pluralized/camelCased) — e.g. feedback.jsfeedbackAnswer, cert.jscerts, setting.jssettings. Only Session sets an explicit tableName. No global freezeTableName/underscored is configured, so Sequelize default pluralization applies.

Transparent at-rest encryption is baked into model getters/setters (room.data, customer.data, flow.metadata, setting.value, encryption.key) via serviceContainer.service.cryptos.data and CryptoService.isEnabledFor([...]). Reading these columns raw in SQL yields ciphertext when encryption is on; the Encryption table + encryptionKey/key STRING(44) columns hold per-record key material.

User.unscoped() everywhere in associations bypasses User.defaultScope ({ where: { isEnabled: true } } — disabled-user filter only, no field exclusion) so audit/flow/activity joins still surface disabled operators.

A second model graph for imports. ImportService builds require('../db/models')(originConnection) against a separate legacy DB connection (serviceContainer.importDbModels) — same 61-entity schema, different connection.


Unverified / gaps

  • Read in full: server/db/models.js, server/db/sequelize.js, server/bootstrap/connection/db.js, .sequelizerc, .sequelizercBefore, .sequelize-config.js, and the model files room.js, customer.js(head), selfserviceroom.js(headers), flow.js, user.js(headers), setting.js, session.js, encryption.js, auditlog.js(headers). The remaining ~50 model files were enumerated for define() name + tableName (via grep) but not read line-by-line — their full column lists, validators, hooks and methods were not transcribed.
  • Exact DB column types/lengths beyond the sampled models are not enumerated here; authoritative source is each server/db/model/*.js plus the 127 db/migrate/ files (not all read).
  • Precise count of db/beforeMigrate/ (listed ≈25; not exhaustively counted) — the directory listing shown was truncated by the tool; only db/migrate/ was counted exactly (127).
  • Default vs. partner-overridden schema: customization/* branches may add/alter models and migrations (see customization-architecture); this doc reflects devel core only.

Sources

Read via git show devel:<path> / git ls-tree devel:<path> on /Users/levander/coding/facekom/vuer_oss:

  • server/db/models.js (408 lines, full), server/db/sequelize.js (117 lines, full), server/db/helpers.js (head), server/db/migrationHelpers.js (counted).
  • server/db/model/git ls-tree (61 files); read: room.js, customer.js (head), selfserviceroom.js (headers), flow.js, user.js (headers), setting.js, session.js, encryption.js, auditlog.js (headers); grepped define() name + tableName across all 61.
  • server/model/git ls-tree (12 non-DB domain models).
  • server/bootstrap/connection/db.js (full), server/backgroundProcess/workers/report.worker.js:30 (grep), server/service/ImportService.js:263 (grep).
  • .sequelizerc, .sequelizercBefore, .sequelize-config.js (full).
  • db/git ls-tree of db, db/migrate (127 .js), db/beforeMigrate (sample).
  • package.json (sequelize/pg/umzug/connect-session-sequelize deps), yarn.lock (@techteamer/sequelize resolved 6.32.2).
  • Cross-checked against existing vuer_oss doc; independently verified each claim against source.