Door & Gate Access

Core Platform
door_access_auto_messagesDoor & Gate Access

Manages the Door & Gate Access automated per-user messaging rules — facility-level rules that automatically set or clear a user's mobile-app message based on their synced membership status, person type, or tags (e.g. show "Your membership is suspended — contact the front desk" to everyone whose status is Suspended).

Manual per-user messages (set via door_access_manage_users) and decoupled/suppressed users are never overwritten by automation.

Actions:

  • get — the current config: { enabled, rules: [{ id, enabled, match: { field membershipStatus|type|tag, values[] }, message: { title, text, severity info|warning|critical, link } }] }
  • update — save the config (config object, full replace — call get first and send back the whole modified document). Saving immediately queues a BACKGROUND sweep that re-evaluates every User Access row at the facility; the response confirms { sweep: { status: 'queued' } }.
  • sweep_status — progress of that background sweep: { status queued|running|done|error, startedAt, finishedAt, usersScanned, usersUpdated, startedBy, error }. Poll this after an update to confirm the sweep finished.

Parameters

NameTypeDescription
action*"get" | "update" | "sweep_status"`get` = read config; `update` = save config + queue re-evaluation sweep; `sweep_status` = background sweep progress.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
configobjectupdate: the full config { enabled, rules: [{ id, enabled, match: { field, values }, message: { title, text, severity, link } }] }. Full replace — get the current config first.
door_access_configure_doorDoor & Gate Access

Configures a Door & Gate Access (DGA) door controller: per-door rule/geofence overrides plus device-side settings. Only the fields you supply are changed; everything else is left untouched.

Configurable fields:

  • accessRulesOverride — per-door access rules object overriding the facility defaults. Pass null to clear and fall back to facility rules.
  • geofenceOverride — per-door geofence override (enabled, center {lat,lng}, radiusMeters, accuracyBufferMeters...). Pass null to clear.
  • icon — door | door-sliding | door-double | garage | gate-barrier | pedestrian | security | office | delivery | locker
  • holdTimeSeconds — relay hold time on unlock, 1-30 seconds
  • maintenanceMode — off | force-open (relay latched open) | force-closed (locked; only admin override unlock works)
  • doorLocation — free-text physical location label, max 64 chars; empty string clears
  • playNotificationSoundOnRelayToggle — boolean; whether the controller chirps when the relay toggles
  • autoUnlockSchedule — weekly schedule that latches the relay open during configured windows: { enabled, windows: { monday: [{ from: "09:00", to: "17:00" }], ... } } in the facility's timezone. Cross-midnight windows are split automatically. Pass null to clear.

When device-side fields change, the tool also pushes the matching Balena env vars and an MQTT refresh so the controller picks up the new config immediately (best-effort; a Balena outage will not fail the save — note that an autoUnlockSchedule change triggers a container restart on the controller).

SAFETY: maintenanceMode force-open latches the door physically open and autoUnlockSchedule keeps it unlocked during the windows. The AI assistant MUST confirm with the user before applying these unless explicitly requested.

Workflow: get the doorId (and current settings) from door_access_doors first.

Parameters

NameTypeDescription
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
doorId*stringDoor controller ID (balena UUID). Get it from door_access_doors (action list).
accessRulesOverrideobjectnullPer-door access rules override. null clears the override.
geofenceOverrideobjectnullPer-door geofence override. null clears the override.
icon"door" | "door-sliding" | "door-double" | "garage" | "gate-barrier" | "pedestrian" | "security" | "office" | "delivery" | "locker"Icon shown in the admin list and the mobile app.
holdTimeSecondsintegerRelay hold time on unlock, in seconds.
maintenanceMode"off" | "force-open" | "force-closed"Maintenance override. force-open latches the relay open; force-closed blocks member unlocks.
doorLocationstringnullPhysical location label (max 64 chars). Empty string or null clears.
playNotificationSoundOnRelayTogglebooleanWhether the controller plays a chirp when the relay toggles.
autoUnlockScheduleobjectnullWeekly auto-unlock schedule { enabled, windows: { day: [{from,to}] } } (HH:MM, facility timezone). null clears.
door_access_control_doorDoor & Gate Access

Physically actions a Door & Gate Access (DGA) door controller: admin override unlock, or an identify beep to locate the device on-site.

This is the DGA module (Performance Hub managed door controllers), NOT the GymMaster partner integration — for partner-integration doors use facility_control_door instead.

Actions:

  • unlock — admin override unlock. Briefly toggles the relay using the door's configured hold time (the door auto-relocks). Writes an admin-override audit row to the Access Logs attributed to the acting user. Always works, even when the door is in force-closed maintenance mode (this is the admin escape hatch). Requires a reason for the audit trail.
  • identify — plays a short locator beep pattern (3 beeps, ~2 seconds) on the door controller so someone on-site can find it. Diagnostic only; no audit row.

SAFETY: unlocking a door is a physical security action. The AI assistant MUST confirm with the user before unlocking unless the user explicitly and unambiguously asked to unlock that specific door.

Workflow: if you don't know the doorId, call door_access_doors with action list first — do NOT guess door IDs.

Returns (unlock): commandId, the audit eventId, holdTimeSeconds used, and whether force-closed maintenance mode was bypassed. The command is dispatched fire-and-forget; device confirmation is not awaited.

Parameters

NameTypeDescription
action*"unlock" | "identify"`unlock` = admin override unlock (auto-relocks); `identify` = locator beep.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
doorId*stringDoor controller ID (balena UUID). Get it from door_access_doors (action list).
reasonstringReason for the unlock, stored in the audit log. REQUIRED for unlock. If the user did not state one, generate a professional reason from the conversation context.
door_access_doorsDoor & Gate Access

Read-only tool for the Door & Gate Access (DGA) module: lists the door controllers at a facility and fetches a single door's live device status.

This is the DGA module (mobile-app door unlocking managed in Performance Hub), NOT the GymMaster partner integration — for partner-integration doors use facility_control_door instead.

Actions:

  • list — every door controller at the facility with: doorId, doorName, doorLocation, icon, live online state (heartbeat-derived), maintenanceMode, holdTimeSeconds, auto-unlock schedule + live scheduled-unlock state, whether the door has rule/geofence overrides, and the fully-merged effective access rules and geofence.
  • device_status — Balena + heartbeat snapshot for one door (requires doorId): update status, IP address, network source, WiFi SSID, hardware make/model/serial, OS/supervisor/application versions, uptime, CPU usage/temperature, memory usage. Returns data: null when no telemetry is available.

Use this tool when:

  • The user asks which doors exist at a facility, whether a door is online, or what rules/geofence apply to a door
  • You need a doorId before calling door_access_control_door or door_access_configure_door
  • Troubleshooting an offline or misbehaving door controller (device_status)

Note: adding/decommissioning door controllers is done via Device Management, not this module.

Parameters

NameTypeDescription
action*"list" | "device_status"`list` = all doors at the facility; `device_status` = telemetry snapshot for one door.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
doorIdstringDoor controller ID (balena UUID). Required for device_status. Get it from the list action.
door_access_eventsDoor & Gate Access

Read-only tool for the Door & Gate Access (DGA) module's Access Logs — the audit trail of every unlock attempt at a facility.

Returns door-access events newest-first: member unlocks from the mobile app, denied attempts (with the denial reason — rule mismatch, outside hours, geofence, access disabled, etc.), admin override unlocks performed from Performance Hub or via MCP, and command outcome states (dispatched / confirmed / failed / timed out).

Each event includes the doorId, who attempted it (personID — a User Access userId for members, or the admin's email for admin overrides), the state/outcome, timestamps, and request metadata (source, geolocation result, user agent).

Parameters:

  • from / to — unix-seconds time window (optional)
  • limit — max events to return (default 100, capped at 500)
  • The response includes lastEvaluatedKey when more pages exist; narrow the time window to page through history.

Use this tool when:

  • The user asks who unlocked a door, when, or why an unlock was denied
  • Auditing admin override unlocks
  • Investigating door activity over a time period

Parameters

NameTypeDescription
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
fromintegerWindow start (unix seconds). Optional.
tointegerWindow end (unix seconds). Optional.
limitintegerMaximum events to return (default 100, max 500).
door_access_invitationsDoor & Gate Access

Bulk Door & Gate Access mobile-app invitations: emails users a link to install and sign in to the app. Two-step preview -> send flow.

(For a single user, use door_access_manage_users with action resend_invite instead.)

Actions:

  • preview — computes the candidate recipients WITHOUT sending anything. Base pool: every non-deleted user with an email who has never used the app. By default it is narrowed to users who currently have access and have never been invited; widen with:
    • includeAlreadyInvited: true — also re-send to previously-invited users
    • includeNoAccess: true — also include users without effective access
      Returns counts, a sample, and the full candidate userIds list for the send step.
  • send — emails the invitation to the supplied userIds (max 50 per call; batch a longer preview list across multiple calls). Each user is re-validated at send time — rows that vanished, lost their email, or logged in since the preview are skipped, not failed. Returns per-user outcomes (sent / failed / skipped) and a summary.

SAFETY: send emails real users. ALWAYS run preview first, show the user the recipient count, and get their confirmation before calling send.

Parameters

NameTypeDescription
action*"preview" | "send"`preview` = dry-run candidate computation; `send` = email the invitations.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
includeAlreadyInvitedbooleanpreview: also include users who already received an invitation (re-send).
includeNoAccessbooleanpreview: also include users who do not currently have effective access.
userIdsarraysend: the recipients (from the preview), max 50 per call.
door_access_manage_usersDoor & Gate Access

Write tool for the Door & Gate Access (DGA) module's User Access list — creates, edits, and removes the people who can use the Door & Gate Access mobile app at a facility, and manages their grants, sync coupling, sessions, and invitations.

Use door_access_users (read tool) first to find userIds and inspect current state.

Actions:

  • create — manually add a person (user object; at least one of mobilePhone/email required; phone is normalised to E.164). sendInvite: true also emails the app invitation. Returns 409 with the existing user when phone/email already exists at the facility.
  • bulk_create — import up to 200 people in one call (users array, same fields as create plus optional accessEnabled and grants). Per-row outcomes are reported individually (created / duplicate / error).
  • update — partial edit of any user fields (userId + user object). Pass null to clear an optional field. Includes accessEnabled (the access kill switch), autoMessageSuppressed, and the per-user appMessage.
  • delete — soft-delete a user (userId). Access logs are preserved. Confirm with the user before deleting.
  • set_grants — REPLACE the user's personal grants (userId + grants: { facilityWide, doors[], groups[], accessHours? }). Grants work alongside facility rules — a user may unlock when either matches.
  • decouple — freeze the row against partner/CCTV sync updates (admin takes manual control).
  • recouple — re-attach the row to sync updates.
  • logout — revoke all of the user's mobile-app sessions (refresh tokens, matched by their phone/email).
  • resend_invite — force-send the app invitation email (requires the user to have an email on file).

User object fields (create / bulk_create rows / update): firstName, lastName, mobilePhone, email, type, membershipStatus, tags[], customTags[], notes, accessEnabled, autoMessageSuppressed, appMessage ({ enabled, title, text, severity info|warning|critical, link {url,label}, startsAt, endsAt }).

Parameters

NameTypeDescription
action*"create" | "bulk_create" | "update" | "delete" | "set_grants" | "decouple" | "recouple" | "logout" | "resend_invite"The operation to perform.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
userIdstringUser Access row ID. Required for update, delete, set_grants, decouple, recouple, logout, resend_invite.
userobjectUser fields for create / update (firstName, lastName, mobilePhone, email, type, membershipStatus, tags, customTags, notes, accessEnabled, autoMessageSuppressed, appMessage).
usersarraybulk_create rows (max 200). Same fields as user, plus optional grants { facilityWide, doors[], groups[] }.
sendInvitebooleancreate / bulk_create: also send the app invitation email to users with an email address.
grantsobjectset_grants: REPLACES the grants — { facilityWide: boolean, doors: string[], groups: string[], accessHours?: object }.
door_access_scopesDoor & Gate Access

Manages Door & Gate Access "Access Scopes" (door groups) at a facility — named sets of doors that can carry their own access rules and geofence overrides, and that users can be granted access to via door_access_manage_users (set_grants with groups).

A door can belong to multiple scopes. At unlock time the evaluator merges rules in priority order: door override > scope override > facility defaults.

Actions:

  • list — all scopes at the facility (name, description, doorIds, whether they carry rule/geofence overrides)
  • get — one scope by groupId
  • create — new scope. name required (max 120 chars); optional description (max 2000), doorIds[] (from door_access_doors), accessRulesOverride, geofenceOverride
  • update — partial edit (groupId + any of the same fields). doorIds REPLACES the door list when supplied.
  • delete — soft-delete a scope (groupId). Users granted access via this scope lose that grant path. Confirm with the user before deleting.

Parameters

NameTypeDescription
action*"list" | "get" | "create" | "update" | "delete"The operation to perform.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
groupIdstringScope (door group) ID. Required for get, update, delete.
namestringScope name (required for create, max 120 chars).
descriptionstringnullOptional description (max 2000 chars). null/empty clears.
doorIdsarraynullDoor controller IDs in this scope. REPLACES the list when supplied; null empties it.
accessRulesOverrideobjectnullScope-level access rules override. null clears.
geofenceOverrideobjectnullScope-level geofence override. null clears.
door_access_settingsDoor & Gate Access

Reads and writes the facility-level Door & Gate Access settings (the module's Settings tab), and dry-runs geofence evaluations.

Actions:

  • get_rules — the facility's effective rules document:
    • memberTypeRules / tags — who can access (matched against User Access type/status/tags)
    • accessHours — operating-hours windows per day
    • geofence — { enabled, center {lat,lng}, centerOverridden, radiusMeters, accuracyBufferMeters, requireAccuracyBetterThan }
    • appLock — facility-enforced mobile-app re-authentication { enforced, graceSeconds (0-3600), allowedMethods [biometric|pin] }
    • supportContacts — { mode: default|on|off } controls whether the app shows the club's support email/phone
    • appMessage — facility-wide app announcement { enabled, title, text, severity info|warning|critical, link {url,label}, startsAt, endsAt (unix seconds) }
  • update_rules — saves the rules document (rules object). This is a FULL replace of memberTypeRules / tags / accessHours / geofence — always call get_rules first, modify the result, and send the whole document back. Changing these affects who can open doors facility-wide; confirm significant changes with the user.
  • test_geofence — dry-run a geofence evaluation for a coordinate (lat, lng, optional accuracyMeters and doorId to include that door's override). Returns the effective geofence and the pass/fail result — nothing is modified.

Sync settings live in door_access_sync; automated per-user messages in door_access_auto_messages.

Parameters

NameTypeDescription
action*"get_rules" | "update_rules" | "test_geofence"The operation to perform.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
rulesobjectupdate_rules: the full rules document (memberTypeRules, tags, accessHours, geofence, appLock, supportContacts, appMessage). Get it with get_rules first and send the whole modified document.
latnumbertest_geofence: latitude of the test pin.
lngnumbertest_geofence: longitude of the test pin.
accuracyMetersnumbertest_geofence: reported GPS accuracy in metres (optional).
doorIdstringtest_geofence: evaluate against this door's geofence override instead of just the facility default (optional).
door_access_syncDoor & Gate Access

Manages Door & Gate Access User Access syncing — pulling people in from the facility's partner integrations (member-management systems) and CCTV — plus the partner-synced bulk-delete flow and the sync troubleshooting log.

Actions:

  • partners — the partner integrations at the facility (partnerId, name, enabled, how many User Access rows each has synced)
  • get_config — the sync config: { partner: { enabled, requireIdentifier email|phone|both|either, partners: per-partner opt-out map }, cctv: { enabled, requireIdentifier } }, plus lastRunAt / lastRunCounts
  • update_config — save the admin-controlled sync config fields (config object, same shape; lastRunAt/lastRunCounts are engine-written and ignored)
  • run — run an on-demand sync now (also runs nightly). Synchronously sweeps every enabled source and returns per-source counts (processed / created / updated / skipped)
  • log — recent sync outcomes newest-first with the reason a member did or didn't sync (limit default 100, max 500)
  • bulk_delete_preview — dry-run of deleting partner-synced users (optionally scoped to one partnerId). Returns the affected count, a sample, and a confirmToken. Nothing is modified.
  • bulk_delete — execute the soft-delete. Requires the confirmToken from the preview; if the user set changed since the preview the call is rejected (409) and you must re-preview. Access logs are preserved, but admin customisations on the deleted rows (grants, custom tags, notes) are lost.

SAFETY: bulk_delete removes potentially thousands of users' app access. ALWAYS run bulk_delete_preview first, show the user the count, and get their explicit confirmation before calling bulk_delete.

Parameters

NameTypeDescription
action*"partners" | "get_config" | "update_config" | "run" | "log" | "bulk_delete_preview" | "bulk_delete"The operation to perform.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
configobjectupdate_config: the sync config { partner: { enabled, requireIdentifier, partners }, cctv: { enabled, requireIdentifier } }.
partnerIdstringbulk_delete_preview / bulk_delete: limit to one partner. Omit to target all partner-synced users.
confirmTokenstringbulk_delete: the token returned by bulk_delete_preview. REQUIRED.
limitintegerlog: max entries to return (default 100, max 500).
door_access_usersDoor & Gate Access

Read-only tool for the Door & Gate Access (DGA) module's User Access list — the people who can sign in to the Door & Gate Access mobile app at a facility.

Actions:

  • list — all (non-deleted) User Access rows at the facility, each with a computed hasAccess flag (would they pass the effective access rules / grants). Supports filters:
    • search — free text across name, phone, email, tags
    • source — all | manual | partner | cctv (where the row came from)
    • accessEnabled — any | true | false (the per-user kill switch)
    • hasGrants — any | true | false (has personal grants)
    • hasAccess — any | true | false (computed effective access)
  • get — one User Access row by userId (full detail: identity, tags, grants, sync linkage, invitation status, app sessions, per-user app message).
  • people_config — the distinct person types, membership statuses, and tags present at the facility (useful for building access rules that match real data).

Use this tool when:

  • The user asks who can unlock doors, whether a specific person has access, or why someone does/doesn't have access
  • You need a userId before calling door_access_manage_users
  • Building or reviewing access rules and you need the real type/status/tag values (people_config)

Parameters

NameTypeDescription
action*"list" | "get" | "people_config"`list` = filtered user list; `get` = single user; `people_config` = distinct types/statuses/tags.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
userIdstringUser Access row ID. Required for the get action.
searchstringlist filter: free-text search across name, phone, email, and tags.
source"all" | "manual" | "partner" | "cctv"list filter: where the row came from. Default all.
accessEnabled"any" | "true" | "false"list filter: per-user access kill switch state. Default any.
hasGrants"any" | "true" | "false"list filter: whether the user has personal grants. Default any.
hasAccess"any" | "true" | "false"list filter: computed effective access (rule match or grant). Default any.
hideExcludedbooleanlist filter (legacy): hide synced users with no effective access; the response then includes a hidden { count, sample } envelope. Prefer the hasAccess filter.