Docs: refresh every README against the current code
Verified each documented command, path, port and env var against what the code actually does, and corrected the drift. Phone App. Was still titled Car Control. The navigation description was also stale: the app moved to a RootShell bottom nav (Garage, Charging, Settings, and Users for admins), so the Settings gear and admin action the dashboard bullet described no longer exist. Adds the Charging screen, noting its public tab is placeholder data and only the Home tab's OCPP control is real, and rebuilds the lib/ tree, which had lost i18n.dart, theme.dart, widgets/ and three screens. Web App. Node 18+ was wrong. The installed Vite is 8.1.2, whose engines field is ^20.19.0 || >=22.12.0 - Node 18 is EOL and cannot build this. API Server. The config table gained OCPP_REQUIRE_TLS, OCPP_PUBLIC_URL, PB_BOOTSTRAP and DRIVERVAULT_SUPERADMIN_*, plus a note that PLUGINS_FILE and the panel-written .env resolve against the working directory (a volume, in Docker). Plugins. Per-tenant credentials sat under "not yet implemented", but /api/integrations/* has done exactly that for both built-ins for a while. Narrowed the roadmap item to the genuinely missing generic version. New Docker/README.md and Docker AIO/README.md: the root README's component table linked those directories as documentation but neither had any. The root README now points at them. All 8 markdown files pass a relative-link check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
01d82ebda9
commit
a0eb5e4e9d
@@ -258,10 +258,19 @@ Copy `.env.example` to `.env` and fill in. Summary:
|
|||||||
| `WEBAPP_URL` | `http://localhost:8090` | probed by `/api/status` |
|
| `WEBAPP_URL` | `http://localhost:8090` | probed by `/api/status` |
|
||||||
| `AUTH_USERS_COLLECTION` | `users` | PocketBase auth collection |
|
| `AUTH_USERS_COLLECTION` | `users` | PocketBase auth collection |
|
||||||
| `PLUGINS_FILE` | `plugins.json` | plugin state store |
|
| `PLUGINS_FILE` | `plugins.json` | plugin state store |
|
||||||
|
| `OCPP_REQUIRE_TLS` | `true` | reject chargers that did not connect over TLS |
|
||||||
|
| `OCPP_PUBLIC_URL` | — | canonical `ws(s)://` base to point chargers at |
|
||||||
|
| `PB_BOOTSTRAP` | `true` | run the on-boot schema create/reconcile |
|
||||||
|
| `DRIVERVAULT_SUPERADMIN_EMAIL` / `_PASSWORD` / `_NAME` | — / — / `Administrator` | first `superadmin`, created on boot when absent |
|
||||||
|
|
||||||
`PB_URL`, `PB_ADMIN_EMAIL`, `PB_ADMIN_PASSWORD`, `PORT` and `CORS_ORIGINS` are
|
`PB_URL`, `PB_ADMIN_EMAIL`, `PB_ADMIN_PASSWORD`, `PORT` and `CORS_ORIGINS` are
|
||||||
still honoured for older deployments; the modern names win when both are set.
|
still honoured for older deployments; the modern names win when both are set.
|
||||||
|
|
||||||
|
Two paths are resolved **relative to the working directory**: `PLUGINS_FILE` and
|
||||||
|
the `.env` the panel rewrites when a superadmin retargets PocketBase. In Docker
|
||||||
|
the working directory is `/data`, a volume, so both survive a container
|
||||||
|
recreate — see [`Dockerfile`](Dockerfile) and [`../Docker`](../Docker).
|
||||||
|
|
||||||
`CORS_ALLOW_ORIGINS` only matters for **browser** clients (the web app). Native
|
`CORS_ALLOW_ORIGINS` only matters for **browser** clients (the web app). Native
|
||||||
mobile apps are not subject to CORS.
|
mobile apps are not subject to CORS.
|
||||||
|
|
||||||
|
|||||||
@@ -303,8 +303,14 @@ The contract is shaped for these; see [`doc.go`](doc.go):
|
|||||||
- **Invocation API** — an endpoint to call `Invoke` from clients, with a normalized
|
- **Invocation API** — an endpoint to call `Invoke` from clients, with a normalized
|
||||||
request/response envelope and a provider→internal mapper.
|
request/response envelope and a provider→internal mapper.
|
||||||
- **Resilience** — retry/backoff, circuit breaker, per-plugin latency/error metrics.
|
- **Resilience** — retry/backoff, circuit breaker, per-plugin latency/error metrics.
|
||||||
- **Per-tenant credentials** — config keyed by org/user so users connect their own accounts.
|
- **Per-tenant credentials _for arbitrary plugins_** — the two built-in connectors
|
||||||
- **Audit logging** of plugin access.
|
already have them, through the hand-written `/api/integrations/toyota` and
|
||||||
|
`/api/integrations/anker-solix` routes and their **superadmin → org admin →
|
||||||
|
user** config cascade. What is missing is the generic version: per-org/per-user
|
||||||
|
config keyed off `ConfigFields`, so a newly registered plugin gets the same
|
||||||
|
treatment without new endpoints.
|
||||||
|
- **Audit logging** of plugin access. (Charger *control* commands are already
|
||||||
|
audited to the `control_audit` collection; this is the wider plugin case.)
|
||||||
|
|
||||||
Until the invocation API lands, `Invoke` is dormant — plugins are discoverable,
|
Until the invocation API lands, `Invoke` is dormant — plugins are discoverable,
|
||||||
configurable, and health-checked, but not yet callable over HTTP.
|
configurable, and health-checked, but not yet callable over HTTP.
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# DriverVault — Docker AIO (all-in-one image)
|
||||||
|
|
||||||
|
**PocketBase + API Server + Web App in a single container**, supervised by
|
||||||
|
`supervisord` with nginx serving the SPA and proxying `/api/` to the API Server
|
||||||
|
on localhost. One image, one volume set, no compose network — the simplest way
|
||||||
|
to stand DriverVault up on a single host.
|
||||||
|
|
||||||
|
Prefer the three-container stack in [`../Docker`](../Docker) when you want to
|
||||||
|
scale, upgrade or restart the pieces independently.
|
||||||
|
|
||||||
|
```
|
||||||
|
:80 nginx ─► SPA, and /api/ ─► API Server on 127.0.0.1:8080 ─► PocketBase on :8070
|
||||||
|
```
|
||||||
|
|
||||||
|
| File | Use |
|
||||||
|
|---|---|
|
||||||
|
| `Dockerfile` | the all-in-one image (build context must be the **repo root**) |
|
||||||
|
| `docker-compose.yml` | **builds from source** — for development and local testing |
|
||||||
|
| `docker-compose.prod.yml` | **pulls the prebuilt image** from the registry |
|
||||||
|
| `.env.example` / `.env.prod.example` | copy to `.env` for the matching compose file |
|
||||||
|
|
||||||
|
## Run it
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd "Docker AIO"
|
||||||
|
cp .env.example .env # then edit — PB_ADMIN_* have no safe defaults
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Production, from the registry:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.prod.example .env # then edit
|
||||||
|
docker compose -f docker-compose.prod.yml pull
|
||||||
|
docker compose -f docker-compose.prod.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Then: web app on `http://host:8090/`, the API Server's superadmin panel on
|
||||||
|
`http://host:8080/`, PocketBase admin on `http://host:8070/_/`.
|
||||||
|
|
||||||
|
Note the port mapping: inside the container the web app is on **80**, published
|
||||||
|
as `WEB_PORT` (8090 by default) to line up with the other deployment.
|
||||||
|
|
||||||
|
## Building by hand
|
||||||
|
|
||||||
|
The build context **must be the repo root** so the Dockerfile can reach both
|
||||||
|
`API Server/` and `Web App/`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -f "Docker AIO/Dockerfile" -t drivervault-aio .
|
||||||
|
```
|
||||||
|
|
||||||
|
Build args: `VITE_API_BASE` (leave empty so the bundle uses same-origin `/api`)
|
||||||
|
and `PB_VERSION` (pin PocketBase, or leave empty to fetch the latest release at
|
||||||
|
build time).
|
||||||
|
|
||||||
|
## First boot
|
||||||
|
|
||||||
|
Identical to the multi-container stack, and idempotent:
|
||||||
|
|
||||||
|
1. PocketBase upserts its superuser from `PB_ADMIN_EMAIL` / `PB_ADMIN_PASSWORD`.
|
||||||
|
2. The API Server waits for PocketBase to report healthy, then creates any
|
||||||
|
missing collections, reconciles existing ones, and creates the first app
|
||||||
|
`superadmin` from `DRIVERVAULT_SUPERADMIN_EMAIL` / `_PASSWORD`. Set
|
||||||
|
`PB_BOOTSTRAP=false` to skip once the database is established.
|
||||||
|
|
||||||
|
## Volumes
|
||||||
|
|
||||||
|
| Volume | Holds |
|
||||||
|
|---|---|
|
||||||
|
| `/pb/pb_data` | the PocketBase SQLite database and uploaded files |
|
||||||
|
| `/data` | the API Server's `plugins.json`, and the `.env` the panel rewrites when a superadmin retargets the PocketBase connection |
|
||||||
|
|
||||||
|
Both default to Docker-managed named volumes; set `PB_DATA` / `API_DATA` to
|
||||||
|
absolute host paths in the prod file for bind mounts.
|
||||||
|
|
||||||
|
## Charger control (OCPP)
|
||||||
|
|
||||||
|
Chargers in own/proxy mode dial in to `/ocpp/{serial}` on the **API Server port
|
||||||
|
(8080)** — not through nginx — authenticating with a per-charger control token
|
||||||
|
in an OCPP Basic-auth header. Because a plaintext `ws://` would expose that
|
||||||
|
token, `OCPP_REQUIRE_TLS` defaults to `true`.
|
||||||
|
|
||||||
|
This image serves plain HTTP, so charger control needs TLS terminated in front
|
||||||
|
of it, with `OCPP_PUBLIC_URL` set to the public `wss://` base. Only drop
|
||||||
|
`OCPP_REQUIRE_TLS` on a trusted network.
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- Everything runs as **root** in one container, and a crash of `supervisord`
|
||||||
|
takes all three services down together. That is the trade for the simplicity.
|
||||||
|
- Logs from all three processes are interleaved on the container's stdout/stderr
|
||||||
|
(`docker logs drivervault-aio`).
|
||||||
|
- `PB_VERSION` empty means the image pulls whatever PocketBase release is latest
|
||||||
|
**at build time**, so two builds of the same source can differ. Pin it for
|
||||||
|
reproducibility.
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# DriverVault — Docker (multi-container stack)
|
||||||
|
|
||||||
|
Three containers — **PocketBase**, **API Server**, **Web App** — on one compose
|
||||||
|
network. This is the deployment to use unless you specifically want everything
|
||||||
|
in a single image; for that see [`../Docker AIO`](../Docker%20AIO).
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser ─► Web App BFF (:8090) ──/api/*──► API Server (:8080) ─► PocketBase (:8070)
|
||||||
|
```
|
||||||
|
|
||||||
|
Only the Web App port is meant to be public. The API Server and the PocketBase
|
||||||
|
admin UI are published for convenience and, in the prod file, bound to
|
||||||
|
`127.0.0.1` by default.
|
||||||
|
|
||||||
|
| File | Use |
|
||||||
|
|---|---|
|
||||||
|
| `docker-compose.yml` | **builds from source** in this repo — for development and local testing |
|
||||||
|
| `docker-compose.prod.yml` | **pulls prebuilt images** from the registry — for deployment |
|
||||||
|
| `.env.example` / `.env.prod.example` | copy to `.env` for the matching compose file |
|
||||||
|
| `pocketbase/` | the PocketBase image (official release binary on alpine) |
|
||||||
|
|
||||||
|
## Run it
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd Docker
|
||||||
|
cp .env.example .env # then edit — PB_ADMIN_* have no safe defaults
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Production, from the registry:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.prod.example .env # then edit
|
||||||
|
docker compose -f docker-compose.prod.yml pull
|
||||||
|
docker compose -f docker-compose.prod.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Then: web app on `http://host:8090/`, the API Server's superadmin panel on
|
||||||
|
`http://host:8080/`, PocketBase admin on `http://host:8070/_/`.
|
||||||
|
|
||||||
|
## First boot
|
||||||
|
|
||||||
|
Both steps are idempotent, so restarts and upgrades are safe:
|
||||||
|
|
||||||
|
1. **PocketBase** upserts its superuser from `PB_ADMIN_EMAIL` / `PB_ADMIN_PASSWORD`.
|
||||||
|
This is the only way to create the first superuser — the REST API cannot
|
||||||
|
bootstrap it. The API Server then authenticates with the same credentials.
|
||||||
|
2. **The API Server** creates any missing collections and reconciles existing
|
||||||
|
ones, then creates the first app `superadmin` from
|
||||||
|
`DRIVERVAULT_SUPERADMIN_EMAIL` / `_PASSWORD` if no such user exists. Set
|
||||||
|
`PB_BOOTSTRAP=false` to skip once the database is established.
|
||||||
|
|
||||||
|
No manual `setup-pocketbase.mjs` step is needed here — the server runs the same
|
||||||
|
schema reconcile itself.
|
||||||
|
|
||||||
|
## Volumes
|
||||||
|
|
||||||
|
| Volume | Holds |
|
||||||
|
|---|---|
|
||||||
|
| `pb_data` | the PocketBase SQLite database and uploaded files |
|
||||||
|
| `api_data` | the API Server's `plugins.json`, and the `.env` the panel rewrites when a superadmin retargets the PocketBase connection |
|
||||||
|
|
||||||
|
Both default to Docker-managed named volumes. In the prod file, set `PB_DATA` /
|
||||||
|
`API_DATA` to absolute host paths for bind mounts instead.
|
||||||
|
|
||||||
|
> The API Server container runs as an unprivileged user, and a **named** volume
|
||||||
|
> inherits that ownership from the image. A **bind mount** does not — the host
|
||||||
|
> directory's ownership wins, so `chown` it to the container's `app` user (or
|
||||||
|
> `chmod` it writable) before setting `API_DATA` to a host path, otherwise the
|
||||||
|
> server cannot write `plugins.json`.
|
||||||
|
|
||||||
|
## Charger control (OCPP)
|
||||||
|
|
||||||
|
Chargers in own/proxy mode dial in to `/ocpp/{serial}` **on the API Server
|
||||||
|
port**, authenticating with a per-charger control token in an OCPP Basic-auth
|
||||||
|
header. A plaintext `ws://` would put that token on the wire in the clear, so
|
||||||
|
`OCPP_REQUIRE_TLS` defaults to `true` and non-TLS connections are rejected.
|
||||||
|
|
||||||
|
This stack serves plain HTTP, so to actually use charger control you need to
|
||||||
|
terminate TLS in a reverse proxy in front of it and set `OCPP_PUBLIC_URL` to the
|
||||||
|
public `wss://` base (behind a proxy, deriving it from request headers is
|
||||||
|
unreliable). `OCPP_REQUIRE_TLS=false` is for trusted networks only. You will
|
||||||
|
also need `API_BIND` set so the proxy can reach the port.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `docker-compose.yml` builds the API Server and Web App from `../API Server`
|
||||||
|
and `../Web App`, so run it from this directory with the repo checked out.
|
||||||
|
- The Web App's Vue bundle is built with an empty `VITE_API_BASE`, so the
|
||||||
|
browser uses same-origin `/api` and the BFF proxies it — no CORS in play.
|
||||||
|
- `CORS_ALLOW_ORIGINS` therefore only matters if a browser calls the API Server
|
||||||
|
directly. Native mobile apps are not subject to CORS at all.
|
||||||
+31
-15
@@ -1,6 +1,6 @@
|
|||||||
# Car Control — Phone App (Flutter)
|
# DriverVault — Phone App (Flutter)
|
||||||
|
|
||||||
A Flutter client for the Car Control maintenance tracker. Talks **only** to the
|
A Flutter client for the DriverVault maintenance tracker. Talks **only** to the
|
||||||
API Server (same contract and auth as the web app — a PocketBase token relayed by
|
API Server (same contract and auth as the web app — a PocketBase token relayed by
|
||||||
the server, not a JWT the server mints). At full feature parity with the web app
|
the server, not a JWT the server mints). At full feature parity with the web app
|
||||||
(data export/import is the only deliberate omission).
|
(data export/import is the only deliberate omission).
|
||||||
@@ -11,12 +11,16 @@ deprecated.
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
Once signed in, `RootShell` hosts the app behind a persistent **bottom
|
||||||
|
navigation bar** — Garage, Charging, Settings, and Users for admins — in an
|
||||||
|
`IndexedStack`, so each section keeps its state as you switch tabs.
|
||||||
|
|
||||||
- **Login** — email/password against `/api/auth/login`, password show/hide, and a
|
- **Login** — email/password against `/api/auth/login`, password show/hide, and a
|
||||||
collapsible **Server settings** section to override the API base URL on-device.
|
collapsible **Server settings** section to override the API base URL on-device.
|
||||||
- **Biometric / face sign-in + app lock** — see the dedicated section below.
|
- **Biometric / face sign-in + app lock** — see the dedicated section below.
|
||||||
- **Dashboard** — car list with next-due status badges (date + km, worst-of),
|
- **Garage (dashboard)** — car list with next-due status badges (date + km,
|
||||||
a "shared" chip on cars owned by someone else, pull-to-refresh, **Add car**
|
worst-of), a "shared" chip on cars owned by someone else, pull-to-refresh and
|
||||||
FAB, Settings gear, and an admin action (admins only).
|
an **Add car** FAB.
|
||||||
- **Car detail** — all spec fields (incl. VIN and transmission / differential /
|
- **Car detail** — all spec fields (incl. VIN and transmission / differential /
|
||||||
brake / coolant specs), a **share** sheet (owner only), quick odometer update,
|
brake / coolant specs), a **share** sheet (owner only), quick odometer update,
|
||||||
edit car, and delete car (type-to-confirm; cascades). Actions are gated by the
|
edit car, and delete car (type-to-confirm; cascades). Actions are gated by the
|
||||||
@@ -45,13 +49,20 @@ deprecated.
|
|||||||
workshop visit, refill, document and part (PDF or image, up to 10MB). Picked
|
workshop visit, refill, document and part (PDF or image, up to 10MB). Picked
|
||||||
with `file_picker`, fetched back through the API Server — never a public URL —
|
with `file_picker`, fetched back through the API Server — never a public URL —
|
||||||
and opened with the phone's own viewer via `open_filex`.
|
and opened with the phone's own viewer via `open_filex`.
|
||||||
|
- **Charging** — mirrors the web `Charging.vue`, split into two tabs. **Public**
|
||||||
|
is a discovery map with a demo session and nearby stations: presentational
|
||||||
|
placeholders, because there is no public-charging API yet (same as the web).
|
||||||
|
**Home** carries the one real piece — an OCPP control card that drives your
|
||||||
|
own charger through the Anker Solix control endpoints, once you pick Own/Proxy
|
||||||
|
CSMS under Settings → Integrations.
|
||||||
- **Settings** — account (name / email verification / password), appearance
|
- **Settings** — account (name / email verification / password), appearance
|
||||||
(theme + dark mode, **language**, **region**, date format, **currency**, font
|
(theme + dark mode, **language**, **region**, date format, **currency**, font
|
||||||
size), profile (avatar via `image_picker`, bio), **Security** (biometric
|
size), profile (avatar via `image_picker`, bio), **integrations** (Toyota,
|
||||||
toggle), and the account-deletion state machine. Auth relays PocketBase's own
|
Anker Solix), **Security** (biometric toggle), and the account-deletion state
|
||||||
stateless tokens, so there is no per-device session list to show or revoke.
|
machine. Auth relays PocketBase's own stateless tokens, so there is no
|
||||||
- **Admin** — user management screen (list / create / role / reset password /
|
per-device session list to show or revoke.
|
||||||
delete), gated by the admin role.
|
- **Users (admin)** — user management tab (list / create / role / reset password
|
||||||
|
/ delete), shown only for the admin role.
|
||||||
|
|
||||||
Sharing/ownership: `Car.access` drives `isOwner` / `canWrite` / `isReadOnly`
|
Sharing/ownership: `Car.access` drives `isOwner` / `canWrite` / `isReadOnly`
|
||||||
getters that gate the UI, mirroring the server's access checks.
|
getters that gate the UI, mirroring the server's access checks.
|
||||||
@@ -134,15 +145,20 @@ Notes:
|
|||||||
```
|
```
|
||||||
lib/
|
lib/
|
||||||
├── config.dart # default API base URL (kDefaultApiBase)
|
├── config.dart # default API base URL (kDefaultApiBase)
|
||||||
├── models.dart # Car (+ access getters), ServiceRecord, Part, AuthUser, UserProfile, Session
|
├── models.dart # Car (+ access getters), the record types, integrations, profile
|
||||||
├── api.dart # ApiClient — the only thing that calls the API Server
|
├── api.dart # ApiClient — the only thing that calls the API Server
|
||||||
├── auth.dart # AuthService (token persistence, app-lock flag, ChangeNotifier)
|
├── auth.dart # AuthService (token persistence, app-lock flag, ChangeNotifier)
|
||||||
├── biometric.dart # BiometricAuth — local_auth + secure storage; biometricAuth singleton
|
├── biometric.dart # BiometricAuth — local_auth + secure storage; biometricAuth singleton
|
||||||
├── app_settings.dart # AppSettings (theme/locale/date/font), persisted; drives MaterialApp
|
├── app_settings.dart # AppSettings (theme/locale/date/font), persisted; drives MaterialApp
|
||||||
|
├── i18n.dart # translation lookup — t("key"); en/pl/da with en fallback
|
||||||
|
├── theme.dart # shared colours/tones (status badges, charging tiles)
|
||||||
├── format.dart # date/km formatting + next-service status (worst-of date/km)
|
├── format.dart # date/km formatting + next-service status (worst-of date/km)
|
||||||
├── main.dart # app root; routes Login / Lock / Dashboard; lifecycle-based re-lock
|
├── main.dart # app root; routes Login / Lock / RootShell; lifecycle re-lock
|
||||||
|
├── widgets/
|
||||||
|
│ └── attachment_field.dart # pick / view / clear a record's attached file
|
||||||
└── screens/
|
└── screens/
|
||||||
├── login_screen.dart dashboard_screen.dart car_detail_screen.dart
|
├── root_shell.dart # bottom-nav shell: Garage, Charging, Settings, Users
|
||||||
├── car_form_sheet.dart settings_screen.dart admin_users_screen.dart
|
├── login_screen.dart lock_screen.dart dashboard_screen.dart
|
||||||
└── lock_screen.dart
|
├── car_detail_screen.dart car_form_sheet.dart record_form_sheets.dart
|
||||||
|
└── charging_screen.dart settings_screen.dart admin_users_screen.dart
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ nothing talks to PocketBase directly.
|
|||||||
| **Database** | PocketBase | ✅ running, schema + seed done | — |
|
| **Database** | PocketBase | ✅ running, schema + seed done | — |
|
||||||
| **Web App** | Vue 3 + Vite + Tailwind v4 | ✅ full feature set (below) | [Web App/README.md](Web%20App/README.md) |
|
| **Web App** | Vue 3 + Vite + Tailwind v4 | ✅ full feature set (below) | [Web App/README.md](Web%20App/README.md) |
|
||||||
| **Phone App** | Flutter (Android) | ✅ web parity + biometric login | [Phone App/README.md](Phone%20App/README.md) |
|
| **Phone App** | Flutter (Android) | ✅ web parity + biometric login | [Phone App/README.md](Phone%20App/README.md) |
|
||||||
| **Docker** | Compose (server / all-in-one) | ✅ deployment configs | [Docker](Docker) · [Docker AIO](Docker%20AIO) |
|
| **Docker** | Compose (multi-container / all-in-one) | ✅ deployment configs | [Docker/README.md](Docker/README.md) · [Docker AIO/README.md](Docker%20AIO/README.md) |
|
||||||
| **Car Agent Device** | ESP32 + SIM7600 (LILYGO TTGO) | 🚧 firmware in progress | [Car Agent Device](Car%20Agent%20Device) |
|
| **Car Agent Device** | ESP32 + SIM7600 (LILYGO TTGO) | 🚧 firmware in progress | [Car Agent Device](Car%20Agent%20Device) |
|
||||||
| **Home Assistant Plugin** | — | ⬜ later | — |
|
| **Home Assistant Plugin** | — | ⬜ later | — |
|
||||||
|
|
||||||
@@ -113,8 +113,10 @@ Bring up the stack in this order — each app's README has the details:
|
|||||||
3. **[Phone App](Phone%20App/README.md)** — `flutter build apk` /
|
3. **[Phone App](Phone%20App/README.md)** — `flutter build apk` /
|
||||||
`flutter run` with `--dart-define=API_BASE=http://<server-ip>:8080/api`.
|
`flutter run` with `--dart-define=API_BASE=http://<server-ip>:8080/api`.
|
||||||
|
|
||||||
Or bring the whole stack up with **Docker** — see [Docker](Docker) (server +
|
Or skip all of that and bring the whole stack up with **Docker**, which runs the
|
||||||
web) and [Docker AIO](Docker%20AIO) (single all-in-one image).
|
schema setup itself — see [Docker](Docker/README.md) (PocketBase + API Server +
|
||||||
|
Web App as three containers) or [Docker AIO](Docker%20AIO/README.md) (all three
|
||||||
|
in a single image).
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -38,7 +38,9 @@ web/ Vue 3 + Vite + Tailwind v4 source
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Node 18+ and Go 1.26+
|
- **Node 20.19+ or 22.12+** (Vite 8's floor — Node 18 is end-of-life and will not
|
||||||
|
build) and **Go 1.26+** (the `go.mod` directive). The Docker image builds on
|
||||||
|
`node:22-alpine`.
|
||||||
- A running **API Server** (see `../API Server`)
|
- A running **API Server** (see `../API Server`)
|
||||||
|
|
||||||
## Develop
|
## Develop
|
||||||
|
|||||||
Reference in New Issue
Block a user