← Back to Selected work
Software Engineering

Anviz Cloud Sync

An access-control clock that only spoke over the local network now syncs to the cloud at zero monthly cost. Records can be checked from anywhere, and every correction is kept in an auditable history.

Role
Developer (end to end)
When
2026
Stack
Python · Supabase · PostgreSQL · Vue 3 · Tailwind CSS · Binary protocols
Dashboard records table with the edit history of one record open below its row

Names, codes, reasons and device details in the screenshots have been replaced with fictitious ones. The dashboard itself is in Spanish, so its screenshots are too.

The problem

The clock’s data could only be seen from a PC on the same network. An Anviz GC150 device kept the punches in its own memory, and the only way to read them was CrossChex Standard, a desktop program on that same network.

  • No remote access: nobody could check the records off-site.
  • No traceability: there was no way to correct a record while noting who changed it and why.
  • No backup: the data depended on a single device and a local database.
  • Cost ruled out: the vendor’s cloud option (CrossChex Cloud) is a paid subscription, and the goal was to add no fixed costs.

The solution

A Python agent bridges the local network and the cloud without opening any inbound port. The clock listens on the LAN, the agent connects to it and pushes the data over HTTPS to Supabase. The web dashboard only talks to Supabase, never to the clock.

Architecture: the clock and the agent on the local network, Supabase in the cloud and the dashboard in the browser

Changes going the other way go through a queue: the dashboard writes a request, and the agent applies it to the clock on its next run and records the result.

The key decision is that the clock is the raw record and Supabase is the official version. They can differ on purpose, and every difference is explained by the history.

Technical challenges

Every decision was checked against the real device or the production database, not just on paper.

ChallengeWhat was doneHow it was verified
Binary protocol with no SDKA dependency-free TCP client in Python: frames, CRC16, commands and parsers163 of 163 records identical to the CrossChex database; 9 people’s records rebuilt byte for byte
Never lose dataThe clock’s “new” flags are cleared only after upload; a unique key prevents duplicatesRecord-by-record reconciliation: 0 left un-uploaded
Correct without losing the originalThe device time never changes and is the key; the official time is editable; deletes are softA full re-download neither revives nor overwrites edited or deleted records
Security with no server of my ownRow Level Security, column permissions and Postgres triggersFrom the browser, the database rejected hard deletes, changes to the original time, a forged author and an empty reason
Protected access PINs3072-bit RSA-OAEP-SHA256: the browser encrypts, only the agent decryptsA new PIN written to the clock and used on the device, leading zero intact
Clock running at the wrong timeThe agent corrects drifts over 30 seconds on every cycleA one-hour drift was caught by cross-checking punches against schedules, and fixed while keeping the original time

A trigger writes the history, so it can’t be forged from the browser: the author comes from the session, not from what the page sends.

The product

The dashboard has three screens, dark theme by default and light theme one click away.

  • Records: quick ranges, per-column filters, a summary row and CSV export that matches what’s on screen. Manual entry, editing, deletion and restore, each with a required reason. Clicking a row opens its history.
  • People: add, edit and remove people on the clock from the web, with the PIN encrypted in the browser.
  • Changes: one board with everything that was modified, who did it and what is still waiting to be applied on the clock.
  • Device status: last sync, records not yet uploaded, memory usage and the command ready to copy.

Stack and results

The system runs at zero monthly cost, with the clock’s whole history in the cloud. Today the agent runs on demand; the next step is to leave it on an always-on machine.

LayerTechnology
AgentPython, TCP sockets, requests, cryptography
Data and accessSupabase: Postgres, Auth, RLS, triggers
DashboardVue 3, Vite, Pinia, Vue Router
UIshadcn-vue, Tailwind CSS v4, TanStack Table, Day.js, PapaParse
DevelopmentAI-assisted with Claude Code