Door epic phases 4-5: inbound access-log ingest + universal API-call buttons
Phase 4 (migration 053): pull entry/denied events into door_access_log and match each card to a member, via two transports sharing one ingest core. Poll: a CRON_SECRET-guarded /api/cron/door-ingest reads each opted-in native-HeatSync connection's ?z log through the existing hardened executor and parses it (firmware-characterized, best-effort ring buffer). Webhook: /api/door/inbound/[connection] accepts pushed event JSON authenticated by a per-connection bearer secret from the vault. Both dedupe on (connection_id, dedupe_key) so re-polls and retries are no-ops. Adds an inbound config panel to /door/manage. Phase 5 (migration 054): admins define api_buttons that fire a configured HTTP call (full verbs + headers + body) when an authorized member presses them, through the same hardened egress (now shared between callDoor and the new callApi). Each button carries a required_permission (default the new apicall.invoke code); members see only buttons they may press. Builder at /door/buttons with a door-template preset; members press from /doors. Every press is recorded in api_call_log with secrets redacted. Both subsystems are inert until an admin enables inbound on a connection or creates a button. 624 unit + 50 integration tests; migrations applied top-to-bottom in schema.sql; types and docs updated.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { requireDoorManagerPage } from '@/lib/door-guard'
|
||||
import { listApiButtons, listSecretTitles, listApiCallLog } from '@/lib/actions'
|
||||
import { PERMISSIONS } from '@/lib/permissions-catalog'
|
||||
import { ApiButtonsClient } from './api-buttons-client'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export default async function ApiButtonsPage() {
|
||||
await requireDoorManagerPage()
|
||||
|
||||
const [buttons, secrets, log] = await Promise.all([
|
||||
listApiButtons(),
|
||||
listSecretTitles(),
|
||||
listApiCallLog(),
|
||||
])
|
||||
|
||||
return (
|
||||
<ApiButtonsClient
|
||||
initial={'data' in buttons ? (buttons.data as unknown[]) : []}
|
||||
secrets={'data' in secrets ? (secrets.data as { id: string; title: string }[]) : []}
|
||||
log={'data' in log ? (log.data as unknown[]) : []}
|
||||
permissions={PERMISSIONS.map(p => ({ code: p.code, label: p.label }))}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user