Skip to content

Jsondb - #67

Open
z9security wants to merge 86 commits into
bytedreamer:developfrom
z9security:jsondb
Open

Jsondb#67
z9security wants to merge 86 commits into
bytedreamer:developfrom
z9security:jsondb

Conversation

@z9security

Copy link
Copy Markdown

Migrates the Aporta database to use JSON clobs for all datatypes, and have ids not assigned by sqlite, but able to be auto-assigned in code, or assigned from the outside

z9security and others added 30 commits February 4, 2026 06:25
Replace traditional relational columns with JSON document storage pattern.
Each table now stores data as JSON blobs with SQLite handling ID generation.

Changes:
- Add JsonDocumentRepository<T> base class for JSON serialization
- Consolidate 11 migrations into single _0000_InitialCreate with JSON schema
- Convert all 9 repositories to use JSON document storage
- Add JSON indexes for credential number and assignment lookups
- Remove old Aporta.sqlite file from repo
- Delete unused BaseRepository.cs

All 72 tests pass with the new storage model.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow IDs to be assigned by code instead of auto-increment, enabling
sync from upstream systems where IDs are pre-assigned.

Changes:
- Remove AUTOINCREMENT from schema (except event table)
- Add optional explicitId parameter to Insert method
- Add Upsert method for insert-or-update by ID
- EventRepository overrides Insert to always use AUTOINCREMENT
- Add tests for explicit IDs and upsert functionality

In production, either auto-assign (Aporta standalone) or explicit
(upstream sync) mode is used, not mixed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Standalone tool to migrate from column-based schema (v0-10) to JSON
document storage. Supports upgrading from any old schema version.

Features:
- Embeds old migrations to bring DB up to v10 first
- Transforms all tables to JSON format
- Creates backup before migration
- Dry-run mode for preview
- Automatic rollback on error

Usage:
  dotnet Aporta.Migration.dll <database-path> [--dry-run]

Tests cover:
- Full migration from v10
- Partial migration from v5 (applies missing migrations)
- Dry-run mode
- Already-migrated database (no-op)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- JSON schema uses version 100 (old column-based schema was 0-10)
- App refuses to start with old schema, directs user to migration tool
- Migration tool sets version to 100 after migrating

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Aporta now listens as a Z9/Open panel for host connections. The service
handles identification handshake, DbChange, and DevActionReq messages
with dummy responses as a foundation for data mapping.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Uses SpCoreProtoUtil.ToBigInteger() for proper card number conversion,
auto-creates Person for each credential, falls back to card number as
name when Cred.Name is blank, and skips credentials with no card number.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Panel now makes the outbound TCP connection to the Z9/Open Community
host instead of listening. Upstream host is configured via command line
args --z9OpenCommunityHost and --z9OpenCommunityPort (default 9723).
Service only starts when --z9OpenCommunityHost is provided. Also
updates Z9.Protobuf.Community from 1.0.0 to 1.0.2.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Read Logging:File:Path from configuration instead of hardcoding
/var/log/aporta.log, which requires root permissions. Development
defaults to relative "aporta.log" in working directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Send IDENTIFICATION first (initiating side sends before reading)
- Use IoControllerCommunity DevMod instead of IoControllerZ9Spcore
- Set SupportsIdentificationPassword/Upstream to true
- Make panel Id configurable via --z9OpenCommunityId arg

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added TCP/IP connection support for OSDP readers:
- Bus.cs: Added ConnectionType enum (Serial/Tcp), TcpHost, TcpPort properties
- OSDPDriver.cs: Handle TCP connections using TcpClientOsdpConnection

Added automatic OSDP driver configuration from Z9 Dev messages:
- Z9OpenCommunityProtocolService.cs: Process Dev messages to extract OSDP
  CredReader configurations, fires OsdpConfigurationReceived event
- StartupWorker.cs: Subscribe to OsdpConfigurationReceived, automatically
  enable OSDP driver extension, add TCP bus and device

Updated Z9.Protobuf.Community to 1.0.3 for community proto field number fixes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- OSDPDriver: Add NotifyEndpointOnlineStatus() to raise OnlineStatusChanged
  events when OSDP devices come online/offline
- OSDPDriver: Add try-catch in PanelOnConnectionStatusChanged to prevent
  silent async exceptions
- ExtensionService: Forward OnlineStatusChanged events from drivers
- Z9OpenCommunityProtocolService: Add endpoint-to-config mapping and
  SendCredReaderOnlineEvent() to send EVT messages to Z9
- StartupWorker: Disable OSDP extension in Z9 Open Community mode until
  config is received from the host, subscribe to OnlineStatusChanged

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix host/port parsing in Z9OpenCommunityProtocolService to correctly
  handle serialPortAddress that already contains port (e.g., "localhost:9843")
- Add constructor to OnlineStatusChangedEventArgs for endpoint notifications
- Add --cleanDatabase CLI argument to delete database on startup for testing
- Reorder startup to disable OSDP extension BEFORE ExtensionService.Startup()
  to prevent loading stale configuration
- Use direct database access to disable OSDP since ExtensionService isn't
  started yet when we need to clear the config
- Add debug logging to OSDPDriver for troubleshooting device online flow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SendAccessEvent method to Z9OpenCommunityProtocolService for sending
  access granted/denied events back to Z9
- Add OnAccessCredentialReceived handler in StartupWorker to forward card
  reads from OSDP readers to Z9 as access denied events (unknown credential)
- Fix OSDPDriver endpoint ID parsing for TCP connections where the port name
  contains a colon (e.g., "localhost:9843"). The previous Split(":")[0] logic
  broke when the port name itself contained colons.
- Add ParseEndpointId helper method to properly extract port name and OSDP
  address from endpoint IDs regardless of connection type

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Encode credentials from Z9 as bit strings using BinaryFormatter.Encode()
- Decode card reads using BinaryFormatter.Decode() to extract credNum
- Store DataFormat, DataLayout, CredTemplate from Z9 downloads
- Update SendAccessEvent to include decoded credNum on EvtCredRef
- Add conditional Z9.Protobuf project reference for z9main development

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace in-memory dictionaries with database storage for Z9 Open
protobuf types. Add ProtoJsonRepository base class using Google.Protobuf
JsonFormatter/JsonParser for serialization with proper oneof extension
handling.

New tables: cred_template, data_layout, data_format, priv, sched, hol,
hol_cal, hol_type. All types now persist across restarts.

Also fixes migration system bug that used version as array index.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enable Aporta to grant access when a known credential is swiped:

AccessService.cs:
- Add AccessDecisionMade event for external systems to subscribe
- Add 35-bit credential decoding fallback to match raw card reads
  against credentials stored as decimal numbers
- Allow access decisions without door strike (for community controllers)

Z9OpenCommunityProtocolService.cs:
- Only set EvtSubCode for denied events (granted events don't need one)

StartupWorker.cs:
- Auto-create Door entities when OSDP readers come online
- Subscribe to AccessDecisionMade event to forward decisions
- Add retry logic for endpoint lookup during door creation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Z9CredRepository to store full Z9 Cred proto with privilege bindings
- Add migration _0002_AddZ9CredTable for z9_cred table
- Implement HasAccessPrivilege() in AccessService to check privilege bindings
- Store Z9 Cred proto when processing credentials from Z9 server
- Check for PrivType.Door or precision access bindings before granting access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Includes schedule utilities for evaluating time-based access restrictions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Check Z9 Cred status before granting access:
- Disabled credential -> ACCESS_DENIED_INACTIVE
- Not yet effective (future date) -> ACCESS_DENIED_NOT_EFFECTIVE
- Expired (past date) -> ACCESS_DENIED_EXPIRED
- No privilege bindings -> ACCESS_DENIED_NO_PRIV

Add corresponding EventReason enum values and map to EvtSubCode
for proper event reporting to Z9 host.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… checking

Upgrade NuGet package to 1.0.6, fix protobuf API usage for DoorAccessPriv
(use Elements collection) and SchedElement (use SchedDays/Start/Stop),
add DoorUnid to OsdpReaderConfig for door-to-reader mapping, implement
schedule restriction checking for access privileges, and simplify csproj
references by removing conditional local Z9.Protobuf paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lookup

1.0.7 adds the missing privUnid field to CredPrivBinding, enabling proper
privilege resolution for schedule-restricted access bindings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Process Z9 Actuator Dev objects to extract door strike output config,
match actuators to readers via shared door (logicalParentUnid), and
wire DoorStrikeEndpointId when the OSDP output endpoint comes online.
Handle DevActionReq DOOR_MOMENTARY_UNLOCK from the Z9 host. Filter
OnlineStatusChanged to only process reader endpoints (not outputs)
to prevent duplicate door creation. Fix OpenDoor to fire strike
asynchronously so the access processing task completes immediately,
preventing the deduplication check from dropping subsequent card reads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Subscribe to OSDP state changes and send DoorUnlocked/DoorLocked events
when the strike output changes, and DoorOpened/DoorClosed events when
the door contact input changes. Process Door and Sensor dev objects from
Z9 to wire door contact inputs alongside existing strike outputs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire REX sensor from Z9 as OSDP input endpoint on door, send
EXIT_REQUESTED event on REX press, and fire door strike if
activateStrikeOnRex is enabled. Upgrade Z9.Protobuf.Community to
1.0.8 for DoorConfig proto support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract strikeTime from community proto DoorConfig and use it for
door strike pulse duration instead of hardcoded 3 seconds. Defaults
to 3000ms when not configured. Upgrade Z9.Protobuf.Community to 1.0.9.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Track per-door strike state and send DoorForced/DoorNotForced events
to Z9 when the door contact opens while the strike is not energized.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a credential has extDoorTime=true, use the door's extendedStrikeTime
instead of the normal strikeTime for access grant strike duration.

Also remove unnecessary IsOpen check from OSDPDriver.AddUpdateDevice -
devices should be registered in the panel regardless of connection state,
as the reader may come online later.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
z9security and others added 26 commits February 9, 2026 11:13
Introduces DevStateRecord-based state tracking using z9/open proto types,
replacing the need for ad-hoc state queries. DevStateService is wired into
InputService, OutputService, StartupWorker (door aspects), and the SpCore
protocol service (batch/continuous DevStateRecord forwarding). Adds Flex
REST API endpoint at flex/devStateRecord/list for read-only state queries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…to Flex API

Events cleanup: Delete EventsController, EventService, and EventServiceTests —
Monitoring.razor already uses FlexApi exclusively. Move EventType enum to
EventData.cs and delete Event.cs.

Credentials migration: Enhance FlexCredController with Save override (auto-assign
unid, ensure default CredTemplate, SignalR notify), Delete override, and Enroll
endpoint. Add FlexPostAsync/SaveCredAsync/DeleteCredAsync/EnrollCredAsync to
FlexApiService. Rewrite Credentials.razor to use Flex API exclusively.

Delete CredentialsController, PeopleController, CredentialService, PeopleService.
Remove service registrations from Startup.cs and paths from Paths.cs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sensors.razor, Actuators.razor, and Monitoring.razor were hybrid — listing
via Flex but create/delete/available/state via legacy REST controllers.
Now all three pages use Flex API exclusively, continuing the pre-fork
alignment started with the Credentials migration.

- Rewrite FlexSensorController and FlexActuatorController with full
  endpoints: list (enabled-only filter), save/assign, delete, available
  pool, and state get/set
- Add 9 FlexApiService client methods for sensor/actuator CRUD and state
- Strip InputService/OutputService to event-handler-only singletons
  (retain hardware→SignalR state relay)
- Delete InputsController, OutputsController, Input.cs, Output.cs
- Update Doors.razor to use FlexApi for available actuators

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Doors.razor now uses FlexApiService exclusively for list/create/delete
and available readers. FlexDoorController gains custom List (top-level
doors only), POST create, Delete (via DoorConfigurationService), and
available/readers + available/endpoints routes. DoorsController is
slimmed to read-only GETs for integration test compatibility. Virtual
driver Configuration.razor also migrated from IDoorCalls to FlexApiService.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Launch Aporta as a process and exercise the Flex API through the typed
Kiota FlexClient, catching swagger-vs-implementation drift at the
deserialization layer. Tests cover auth (401, valid, bad creds), all 13
list endpoints, CRUD for schedule and holiday type, pagination, and
session termination.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix three issues preventing DevStateRecords from reaching SpCoreDriver:
- SendAllDevStateRecords skipped empty responses, deadlocking batch polling
- Door contact/REX sensors used wrong door unid (LogicalParentUnid vs config)
- Concurrent protobuf access between batch serialization and UpdateAspect

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Persist a CONTROLLER_STARTUP event to z9_evt on application startup
(before connecting to the host), then send it when the host identifies.
References the top-level IoControllerCommunity device. Unit tests updated
with CompleteIdentification helper that consumes the startup event.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Send MOMENTARY_UNLOCK event when a host-initiated DevActionReq triggers
a door momentary unlock, providing an audit trail distinct from REX-
triggered unlocks. Update README completed/TODO sections accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Z9/Flex Community swagger defines paths without a /flex/ prefix
(e.g., /cred/list, /door/list). This removes the prefix from all
controller routes, updates FlexAuthFilter to use namespace-based
controller detection instead of path-based, and updates all client
URL references accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Send TAMPER/TAMPER_NORMAL events with DevAspectState tracking when an OSDP
reader reports a tamper state change, and CRED_READER_POWER_CYCLE when a
reader reports it has power-cycled. Bump Z9.Protobuf.Community to 1.0.12
for the new TamperState enum.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…luation

Evaluates all schedules once per minute (aligned to minute boundary) using
SchedEvaluator.InSched, tracks active/inactive state, and reports transitions
as SCHED_ACTIVE (127) / SCHED_INACTIVE (128) events. Events are persisted to
z9_evt and sent over the wire when connected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Populate EvtDevRef and EvtCredRef in InsertAccessEvt so monitoring
  page shows device and credential columns for access events
- Add EvtCode 17 "Card Read" to FlexEvtCodeHelper
- Revert auto-credential creation on badge swipe; swipes now only
  produce RAW_CRED_READ events
- Add enroll-from-read flow: raw reads API endpoint, enroll-from-read
  controller endpoint, and updated Credentials.razor enrollment UI
  to select from raw card reads instead of unassigned credentials
- Update Selenium tests to verify new enrollment dropdown and
  monitoring page device/credential assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hand-maintained FlexEvtCodeHelper with Messages.GetEvtCodeText()
and Messages.GetEvtSubCodeText() from Z9.Protobuf.Community 1.0.13.
Display strings now match the commercial Z9 product. FlexMapper populates
EvtCodeText/EvtSubCodeText on FlexEvt during conversion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace silent auto-authentication with a visible login form. FlexApiService
gains LoginAsync/Logout/IsAuthenticated; App.razor gates on auth state and
restores sessions from sessionStorage across page reloads. Selenium tests
log in through the UI and capture a login screen screenshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ide Unid assignment

Credentials page: rename Person to Credential labels, add Door Access column showing
assigned doors with schedule names, add Edit Access modal for managing door access
privileges with schedule selection. Add Schedules page for creating/editing schedules
with time intervals and day-of-week selection.

Fix server-side Unid auto-assignment in FlexCrudControllerBase so new records created
via web UI get unique IDs (previously defaulted to 0, causing database collisions).

Selenium tests cover the full flow: create schedule, edit credential access to use it,
verify Access Denied when schedule is not active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create, edit, and delete binary card formats (DataFormat + DataLayout)
from a new Card Formats page under Configuration > Access. Each format
defines min/max bits and a list of binary elements (static, parity, or
field). Selenium test validates creating a Standard 26-Bit format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds the Holidays configuration page for creating, editing, and deleting
holidays with repeat and schedule preservation options. Exposes the
Holidays checkbox on schedule time intervals so they can match during
holidays. Includes Selenium tests verifying the holiday-aware access
control flow: schedule without holidays causes denial on a holiday day,
enabling holidays on the schedule restores access.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses <clear /> to override any developer-local NuGet sources,
ensuring all packages resolve from nuget.org only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the local project reference to z9flex-community with a NuGet
PackageReference (v1.0.1). Also remove NuGet.Config which contained a
local package source that is no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Picks up SpCoreHostConnection with optional password support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
z9security and others added 3 commits March 20, 2026 13:44
Sets SpCoreDevUse to IoControllerSecondary in identification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds exponential backoff for SpCoreHostConnection reconnects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant