Lagomare Gates
A web-based gate access management and control system. Authorized users can remotely open physical car and pedestrian gates via a mobile-friendly PWA. An admin dashboard provides full management of gates, access codes, and users.
Features
- Keypass authentication — users authenticate with an access code; each keypass can have a per-gate allowlist and an optional expiration date
- Remote gate control — integrates with AVConnect to trigger gate macros
- Role-based admin panel — two roles (
admin,manager) with different permission levels - Access audit log — every open attempt is logged with timestamp, keypass, gate, IP, and result; filterable and paginated
- Keypass QR codes — generate a scannable QR code for each keypass; scanning opens the PWA and logs in automatically
- Keypass code options — choose character set (alphanumeric, alpha, numeric, or a 4-word passphrase) and length when auto-generating codes
- Telegram notifications — optional push notifications to a Telegram group whenever a gate is opened
- Progressive Web App — installable on mobile devices with offline caching
Tech Stack
| Layer | Technology |
|---|---|
| Backend | FastAPI + Uvicorn |
| ORM | SQLAlchemy |
| Database | SQLite |
| Auth | JWT (HS256) + bcrypt |
| Credential storage | Fernet symmetric encryption |
| Gate integration | AVConnect HTTP API |
| Notifications | Telegram Bot API |
| QR generation | qrcode + Pillow |
| Frontend | Vanilla JS PWA |
Project Structure
src/
├── main.py # App entry point, startup, static file serving
├── core/
│ ├── auth.py # JWT creation/verification, password hashing
│ ├── config.py # Settings loaded from environment variables
│ ├── database.py # SQLAlchemy models and DB initialization
│ ├── dependencies.py # FastAPI dependency injection (auth guards)
│ └── schemas.py # Pydantic request/response schemas
├── routers/
│ ├── auth.py # POST /api/auth/admin, POST /api/auth/keypass
│ ├── gates.py # User-facing gate list and open endpoints
│ ├── keypasses.py # Admin keypass CRUD + QR code generation
│ ├── admins.py # Admin user management
│ ├── credentials.py # AVConnect credential management
│ ├── stats.py # Access log / statistics (paginated, filtered)
│ └── telegram.py # Telegram notification configuration
├── services/
│ ├── avconnect.py # AVConnect session management and macro execution
│ ├── gates.py # Gate open orchestration
│ └── telegram.py # Telegram Bot API client
└── static/ # Frontend PWA (index.html, admin.html, JS, CSS)
data/
└── gates.db # SQLite database (auto-created on first run)
API Endpoints
Authentication
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/admin |
Admin login — returns JWT |
| POST | /api/auth/keypass |
Keypass login — returns JWT |
User (keypass token required)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/gates |
List gates accessible to the authenticated keypass |
| POST | /api/gates/{gate_id}/open |
Open a gate |
Admin — Gates (manager+)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/gates |
List all gates |
| POST | /api/admin/gates |
Create a gate (admin only) |
| PUT | /api/admin/gates/{gate_id} |
Update a gate (admin only) |
| DELETE | /api/admin/gates/{gate_id} |
Delete a gate (admin only) |
| POST | /api/admin/gates/{gate_id}/open |
Manually open a gate |
Admin — Keypasses (manager+)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/keypasses |
List all keypasses |
| POST | /api/admin/keypasses |
Create a keypass |
| PATCH | /api/admin/keypasses/{kp_id} |
Update a keypass |
| DELETE | /api/admin/keypasses/{kp_id} |
Revoke a keypass |
| GET | /api/admin/keypasses/{kp_id}/qr |
Download QR code PNG for a keypass |
Admin — Users (admin only)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/admins |
List admin users |
| POST | /api/admin/admins |
Create an admin user |
| DELETE | /api/admin/admins/{username} |
Delete an admin user |
| PATCH | /api/admin/admins/{username}/password |
Change password |
Admin — AVConnect Credentials (admin only)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/credentials |
View stored credentials |
| PUT | /api/admin/credentials |
Create or update credentials |
| GET | /api/admin/credentials/mock |
Get mock mode status |
| PUT | /api/admin/credentials/mock |
Enable or disable mock mode |
Admin — Statistics (manager+)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/stats |
Paginated, filtered access log |
Query parameters: gate_id, keypass_code (partial match), success (bool), date_from, date_to, page (default 1), page_size (default 50, max 200).
Admin — Telegram Notifications (admin only)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/telegram |
Get current Telegram configuration |
| PUT | /api/admin/telegram |
Save bot token and chat ID |
| POST | /api/admin/telegram/test |
Send a test message |
Configuration
All settings are read from environment variables (centralised in src/core/config.py).
Security
| Variable | Default | Description |
|---|---|---|
SECRET_KEY |
(required) | JWT signing key and Fernet encryption key. The application will refuse to start if this is not set. Use a long random string (openssl rand -hex 32). |
Admin seed account
| Variable | Default | Description |
|---|---|---|
ADMIN_USERNAME |
admin |
Username for the initial admin account created on first run. |
ADMIN_PASSWORD |
(none) | Password for the initial admin account. If unset, no seed account is created. Minimum 12 characters. |
Server
| Variable | Default | Description |
|---|---|---|
APP_PORT |
8000 |
HTTP port the server listens on. |
Database
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite:///data/gates.db |
SQLAlchemy database URL. |
Network / reverse proxy
| Variable | Default | Description |
|---|---|---|
CORS_ORIGINS |
(empty — no cross-origin requests) | Comma-separated list of allowed CORS origins, e.g. https://gates.example.com. |
TRUSTED_PROXY_IPS |
127.0.0.1 |
Comma-separated list of reverse-proxy IPs whose X-Forwarded-For header is trusted for client IP resolution. |
Logging
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL |
INFO |
Logging verbosity. One of DEBUG, INFO, WARNING, ERROR, CRITICAL. |
LOG_FILE |
/var/log/lagomaregates.log |
Path to the rotating log file (10 MB, 5 backups). Set to an empty string to disable file logging. |
Running with Docker Compose
# Copy and edit the compose file to set your SECRET_KEY
docker compose up -d
The default docker-compose.yml starts the service on port 8000. Set a strong SECRET_KEY and, optionally, ADMIN_USERNAME / ADMIN_PASSWORD before deploying.
The ./data directory is mounted into the container so the SQLite database persists across restarts.
Running Locally
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
export SECRET_KEY="$(openssl rand -hex 32)"
export ADMIN_USERNAME="admin"
export ADMIN_PASSWORD="changeme-at-least-12"
uvicorn src.main:app --port 8000
The application is then available at:
- User interface —
http://localhost:8000/ - Admin dashboard —
http://localhost:8000/admin
AVConnect Integration
Gates are controlled through the AVConnect platform. Each gate is mapped to an AVConnect macro ID. When a gate open request is received, the service:
- Authenticates with AVConnect using the stored credentials (session is cached in the database)
- Executes the configured macro for the gate
Credentials (password) are stored encrypted in the database using Fernet symmetric encryption derived from SECRET_KEY.
Mock mode — when enabled via the admin dashboard, gate open requests always succeed without contacting AVConnect. Useful for testing.
Keypass QR Codes
Each active keypass has a QR button in the admin panel. Clicking it generates a PNG QR code that encodes the URL:
https://<your-domain>/?k=<KEYPASS_CODE>
Scanning the code with a phone opens the web app and logs in automatically. If the keypass is expired or revoked, the user is shown an error on the login screen.
Telegram Notifications
Configure a Telegram bot to receive a message in a group or chat every time a gate is opened:
- Create a bot via @BotFather and copy the token
- Add the bot to your group and obtain the chat ID (e.g. using @userinfobot)
- Open Admin → Notifications, enter the token and chat ID, and click Save
- Use Send test message to verify the setup
Notifications are sent in a background thread and never block the gate open response. Failures are logged as warnings and do not affect gate operation.
Roles
| Role | Permissions |
|---|---|
admin |
Full access — all endpoints including gate/user/credential/notification management |
manager |
Gate open, keypass management, statistics — cannot manage admin users, AVConnect credentials, gate configuration, or Telegram settings |