Add readme
This commit is contained in:
168
README.md
Normal file
168
README.md
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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](https://www.avconnect.it) 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
|
||||||
|
- **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 |
|
||||||
|
| 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
|
||||||
|
├── models/ # Thin wrappers re-exporting DB models
|
||||||
|
├── 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
|
||||||
|
│ ├── admins.py # Admin user management
|
||||||
|
│ ├── credentials.py # AVConnect credential management
|
||||||
|
│ └── stats.py # Access log / statistics
|
||||||
|
├── services/
|
||||||
|
│ ├── avconnect.py # AVConnect session management and macro execution
|
||||||
|
│ └── gates.py # Gate open orchestration
|
||||||
|
└── 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 |
|
||||||
|
|
||||||
|
### 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 |
|
||||||
|
|
||||||
|
### Admin — Statistics (manager+)
|
||||||
|
|
||||||
|
| Method | Endpoint | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/api/admin/stats` | Retrieve the last 500 access log entries |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
All settings are read from environment variables.
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `SECRET_KEY` | Random 32 bytes | JWT signing key and Fernet encryption key. **Set this explicitly in production.** |
|
||||||
|
| `ADMIN_USERNAME` | `admin` | Username for the initial admin account |
|
||||||
|
| `ADMIN_PASSWORD` | *(none)* | Password for the initial admin account. If unset, no seed account is created. |
|
||||||
|
| `APP_PORT` | `8000` | HTTP port the server listens on |
|
||||||
|
| `DATABASE_URL` | `sqlite:///data/gates.db` | SQLAlchemy database URL |
|
||||||
|
| `MOCK_AVCONNECT` | `false` | Set to `true` to skip real AVConnect calls (always returns success — useful for development) |
|
||||||
|
|
||||||
|
## Running with Docker Compose
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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` with the initial admin credentials `admin` / `changeme`. Change `ADMIN_PASSWORD` and set a strong `SECRET_KEY` before deploying.
|
||||||
|
|
||||||
|
The `./data` directory is mounted into the container so the SQLite database persists across restarts.
|
||||||
|
|
||||||
|
## Running Locally
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
export SECRET_KEY="change-me"
|
||||||
|
export ADMIN_USERNAME="admin"
|
||||||
|
export ADMIN_PASSWORD="changeme"
|
||||||
|
|
||||||
|
uvicorn src.main:app --reload --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:
|
||||||
|
|
||||||
|
1. Authenticates with AVConnect using the stored credentials (session is cached in the database)
|
||||||
|
2. Executes the configured macro for the gate
|
||||||
|
|
||||||
|
Credentials (password) are stored encrypted in the database using Fernet symmetric encryption derived from `SECRET_KEY`.
|
||||||
|
|
||||||
|
## Roles
|
||||||
|
|
||||||
|
| Role | Permissions |
|
||||||
|
|---|---|
|
||||||
|
| `admin` | Full access — all endpoints including gate/user/credential management |
|
||||||
|
| `manager` | Gate open, keypass management, statistics — cannot manage admin users, AVConnect credentials, or create/delete gates |
|
||||||
Reference in New Issue
Block a user