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, tags, or whether the app has any doors to show.

Manual per-user messages (set via door_access_manage_users) and decoupled/suppressed users are never overwritten by automation.
This tool changes messages only; it never changes regular rules, permanent grants, or Access Time Windows.

Actions:

  • get — the current config: { enabled, rules: [{ id, enabled, match: { field membershipStatus|type|tag|doorVisibility, values[] }, message: { title, text, severity info|warning|critical, link } }] }. For doorVisibility use none (no doors visible) or some (at least one visible door).
  • 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: safety, geofence, and device-side settings. Door authorization is configured centrally with Access Policies. Only the fields you supply are changed; everything else is left untouched.

Configurable fields:

  • blockAllAccess — explicit door kill switch. When true it denies member access before Access Policies, permanent grants, and all time windows.
  • 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, autoUnlockSchedule keeps it unlocked during its windows, and blockAllAccess removes every member authorization path. The AI assistant MUST confirm before applying these unless explicitly requested. Read the current door first.

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).
blockAllAccessbooleanExplicit member-access kill switch, evaluated before every allow path.
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. This is the explicit admin escape hatch and bypasses member authorization, including force-closed maintenance and blockAllAccess. Requires a reason.
  • 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 with live status, maintenanceMode, explicit blockAllAccess, Access Scope groupIds, whether it has rule/geofence/time-window overrides, fully merged effective rules, effectiveTimeWindowAccess, facility timezone, and device settings.
  • 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 by default. Set view to no_visit_recorded to return elapsed user-specific one-time windows with no successful unlock. That opt-in view is separate from actual door activity and excludes weekly windows and policy schedules.

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.
view"door_events" | "no_visit_recorded"Door events by default, or elapsed one-time windows with no successful visit.
fromintegerWindow start (unix seconds). Optional.
tointegerWindow end (unix seconds). Optional.
limitintegerMaximum events to return (default 100, max 500).
cursorstringPagination cursor returned by the no-visit view.
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 any potential regular, permanent-grant, or enforce-mode time-window access. A valid future window counts as potential 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 permanent grants). Time-window grants are intentionally not accepted in bulk; add them with set_time_window_grants. Per-row outcomes are reported individually.
  • update — partial edit of any user fields (userId + user object). Pass null to clear an optional field. Includes accessEnabled, autoMessageSuppressed, per-user appMessage, and optional timeWindowGrants.
  • delete — soft-delete a user (userId). Access logs are preserved. Confirm with the user before deleting.
  • set_grants — REPLACE the user's permanent grants (userId + grants: { facilityWide, doors[], groups[], accessHours? }).
  • set_time_window_grants — REPLACE only admin-owned additive time-window grants (userId + timeWindowGrants[]). Existing permanent grants and partner-owned windows remain untouched. Empty [] explicitly clears admin windows.
  • decouple — freeze the row against partner/CCTV sync updates and clear all partner-owned source windows (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).

Before replacing grants: use door_access_users get and effective_access first, present the doors and time bounds gained/lost, and obtain confirmation unless the user explicitly requested that exact replacement.

User object fields (create / update): firstName, lastName, mobilePhone, email, type, membershipStatus, tags[], customTags[], notes, accessEnabled, autoMessageSuppressed, appMessage, timeWindowGrants[].

Parameters

NameTypeDescription
action*"create" | "bulk_create" | "update" | "delete" | "set_grants" | "set_time_window_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, set_time_window_grants, decouple, recouple, logout, resend_invite.
userobjectUser fields for create / update (including optional additive timeWindowGrants).
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 }.
timeWindowGrantsarrayset_time_window_grants: REPLACES admin-owned scoped time windows. [] explicitly clears them.
door_access_scopesDoor & Gate Access

Manages Door & Gate Access "Access Scopes" (door groups) at a facility — named sets of doors that Access Policies can target, that can carry geofence overrides, and that users can be granted via door_access_manage_users.

A door can belong to multiple scopes. Access Policy exclusions take precedence over policy targets.

Actions:

  • list — all scopes at the facility (name, description, doorIds, and geofence override state)
  • get — one scope by groupId
  • create — new scope. name required; optional description, doorIds[], 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.

For updates that replace doorIds, read the scope and affected policies first, show the access impact, and confirm unless the user explicitly requested the exact change.

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.
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_policies / update_policies — read or atomically replace the versioned Access Policies document. A policy combines audience (who), targets (where), and an anytime or scheduled window set (when). Always preserve and submit the current revision.
  • create_policy / update_policy / duplicate_policy / delete_policy — make one revision-checked policy change without replacing unrelated policies.
  • policy_impact — count current users and doors affected by one policy before editing or deleting it.
  • get_rules — reads the shared facility settings document used for non-policy controls:
    • geofence — { enabled, center {lat,lng}, centerOverridden, radiusMeters, accuracyBufferMeters, requireAccuracyBetterThan }
    • accessTimeWindowGrace — facility-wide early/late access minutes applied to every policy, user, and integration window
    • 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 those non-policy settings. Always call get_rules first and return the complete document; authorization fields are preserved server-side and access must be changed with Access Policies.
  • 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" | "get_policies" | "update_policies" | "create_policy" | "update_policy" | "duplicate_policy" | "delete_policy" | "policy_impact" | "test_geofence"The operation to perform.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
rulesobjectupdate_rules: the full settings document. Authorization is managed through Access Policies and preserved server-side.
accessPolicyConfigobjectupdate_policies: complete Access Policy configuration returned by get_policies.
policyobjectcreate_policy/update_policy: complete Access Policy object.
revisionintegerPolicy CRUD: current Access Policy revision returned by get_policies.
policyIdstringpolicy_impact: stable policy ID.
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 — partner integrations, synced user counts, and each partner's source time-window mapping
  • get_config — sync config, including per-partner timeWindowAccess: { mappings, freshness } and nested appInvitations eligibility/rules
  • update_config — update admin-controlled sync config while preserving omitted fields. Source mappings translate partner scopeKey values to facilityWide/doors/groups. Enabled advanced invitation rules replace the simple recipient mode and choose synced recipients by membershipStatus/type/tag/source/partnerId without requiring current door access; automatic invitations always require email, exclude disabled/conflicted users, send once, and never grant access.
  • 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. For update_config, call get_config first, preserve unrelated partner/source/invitation settings, show mapping/freshness/invitation changes, and confirm material authorization changes.

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: partial sync config patch. Omitted settings are preserved. Read get_config first.
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, each with computed hasAccess (could pass an Access Policy, permanent grant, or time window now or in the future) and source-window freshness. 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, including admin timeWindowGrants, integration sourceTimeWindows, and freshness.
  • effective_access — current per-door decision plus configured authorization paths: allowedNow, deterministic allowedVia/deniedReason, block/maintenance state, active/next time-window availability, scopes, and source freshness. Use this before any grant replacement.
  • people_config — the distinct person types, membership statuses, and tags present at the facility (useful for building Access Policy audiences 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 Policies and you need the real type/status/tag values (people_config)

Parameters

NameTypeDescription
action*"list" | "get" | "effective_access" | "people_config"`list` = filtered user list; `get` = single user; `effective_access` = per-door current/future attribution; `people_config` = distinct types/statuses/tags.
facilityIdstringFacility ID. Falls back to the currently selected facility when omitted.
userIdstringUser Access row ID. Required for get and effective_access.
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 (policy 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.