6fe9f1820c
Admin screen shows the machine fingerprint to send for a licence key, installs a pasted key, and lists connected stations. A persistent banner warns all users during the grace period. The browser sends the station heartbeat rather than the bridge, because the bridge deliberately has no dependency on Django; it already talks to both. Two tabs on one station share a slot, and a station reconnecting at the limit reclaims its own slot so a brief drop cannot lock it out behind its own expiring registration. license_tool.py is the only thing that can sign a licence - the application can only verify. The private key it generates is gitignored and must never ship: if it leaks every licence becomes forgeable, and it cannot be rotated without reissuing to every customer, since the public key is compiled into shipped binaries. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>