Co-authored-by: orchestrator-agent <20+orchestrator-agent@code.cubecraftcreations.com>
This commit was merged in pull request #130.
This commit is contained in:
+11
-4
@@ -8,6 +8,7 @@
|
||||
# mkdir -p deploy/secrets && chmod 700 deploy/secrets
|
||||
# head -c 32 /dev/urandom | base64 > deploy/secrets/secret_key
|
||||
# printf '%s\n' '<Authentik client secret>' > deploy/secrets/oidc_client_secret
|
||||
# printf '%s\n' '<Google OAuth client secret>' > deploy/secrets/google_client_secret
|
||||
# sudo chown 10001:10001 deploy/secrets/* && sudo chmod 600 deploy/secrets/*
|
||||
#
|
||||
# SearXNG's secret key is the exception: compose reads it itself, so it
|
||||
@@ -54,6 +55,14 @@ MEALQUEST_OIDC_CLIENT_ID=mealquest
|
||||
# Comma-separated Authentik groups whose members may sign in.
|
||||
MEALQUEST_OIDC_ALLOWED_GROUPS=mealquest-admin
|
||||
|
||||
# --- Google Calendar (Push to Calendar) ------------------------------------
|
||||
|
||||
# Client ID of the Google OAuth web client (deploy/RUNBOOK.md "Google
|
||||
# Calendar OAuth client"). Required: the service will not start without it
|
||||
# and the client secret file. Its authorized redirect URI is
|
||||
# <MEALQUEST_PUBLIC_URL origin>/api/v1/integrations/google/callback.
|
||||
MEALQUEST_GOOGLE_CLIENT_ID=<client id>.apps.googleusercontent.com
|
||||
|
||||
# Optional session lifetimes. A session ends after IDLE unused and always MAX
|
||||
# after sign-in; MAX must be at least IDLE. Defaults: 720h and 4320h.
|
||||
MEALQUEST_SESSION_IDLE=720h
|
||||
@@ -67,6 +76,8 @@ MEALQUEST_SESSION_MAX=4320h
|
||||
# Base64 of 32 random bytes; encrypts secrets at rest (AES-256-GCM).
|
||||
# MEALQUEST_OIDC_CLIENT_SECRET_FILE=/run/secrets/oidc_client_secret
|
||||
# The Authentik provider's client secret.
|
||||
# MEALQUEST_GOOGLE_CLIENT_SECRET_FILE=/run/secrets/google_client_secret
|
||||
# The Google OAuth web client's secret.
|
||||
# MEALQUEST_SEARXNG_URL=http://searxng:8080
|
||||
# The SearXNG recipe-search sidecar on the compose network. The Settings
|
||||
# screen pre-fills it as the SearXNG URL until one is saved; the saved
|
||||
@@ -81,7 +92,3 @@ MEALQUEST_SESSION_MAX=4320h
|
||||
# MEALQUEST_VAPID_PUBLIC_KEY=<base64url VAPID public key>
|
||||
# MEALQUEST_VAPID_PRIVATE_KEY_FILE=/run/secrets/vapid_private_key
|
||||
# MEALQUEST_VAPID_SUBJECT=mailto:<owner address>
|
||||
#
|
||||
# Google Calendar OAuth web client (Feature 16).
|
||||
# MEALQUEST_GOOGLE_CLIENT_ID=<client id>.apps.googleusercontent.com
|
||||
# MEALQUEST_GOOGLE_CLIENT_SECRET_FILE=/run/secrets/google_client_secret
|
||||
|
||||
+56
-2
@@ -33,6 +33,8 @@ On office-srvr (10.60.1.14), as recorded on 2026-10-05:
|
||||
Elsewhere:
|
||||
|
||||
- Admin access to Authentik at <https://auth.cubecraftlabs.com>.
|
||||
- Owner access to the Google Cloud project that holds MealQuest's OAuth
|
||||
client (see "Google Calendar OAuth client").
|
||||
- SSH access to the Traefik host 10.60.1.33.
|
||||
- Cloudflare access for the `cubecraftlabs.com` zone, and admin access to
|
||||
both Pi-holes (10.60.1.101 `dns.ccl`, 10.60.1.85 `dns2.ccl`).
|
||||
@@ -129,6 +131,7 @@ Values in use:
|
||||
| `MEALQUEST_OIDC_ISSUER` | `https://auth.cubecraftlabs.com/application/o/mealquest/` |
|
||||
| `MEALQUEST_OIDC_CLIENT_ID` | `i6zraqmWsF552b8nmte070LXz0SI5pRdArBxFxeq` (not a secret) |
|
||||
| `MEALQUEST_OIDC_ALLOWED_GROUPS` | `mealquest-admin` |
|
||||
| `MEALQUEST_GOOGLE_CLIENT_ID` | Client ID of the Google OAuth web client (not a secret; see "Google Calendar OAuth client") |
|
||||
| `MEALQUEST_SESSION_IDLE` / `MEALQUEST_SESSION_MAX` | `720h` / `4320h` |
|
||||
|
||||
`MEALQUEST_HTTP_ADDR`, `MEALQUEST_DATA_DIR` and the `*_FILE` variables are
|
||||
@@ -146,6 +149,7 @@ service refuses to start.
|
||||
| --- | --- | --- |
|
||||
| `secret_key` | base64 of 32 random bytes; encrypts stored secrets (AES-256-GCM) | `/run/secrets/secret_key` |
|
||||
| `oidc_client_secret` | Client Secret of the Authentik provider `mealquest` | `/run/secrets/oidc_client_secret` |
|
||||
| `google_client_secret` | Client secret of the Google OAuth web client | `/run/secrets/google_client_secret` |
|
||||
| `litestream_key` | dedicated SSH private key for the NAS (see "Backups") | `/etc/litestream/sftp_key` |
|
||||
| `searxng.env` | `SEARXNG_SECRET=<64 hex characters>`; SearXNG's secret key | not mounted; compose passes it as an environment variable |
|
||||
|
||||
@@ -156,11 +160,12 @@ it (as `env_file`), so it is owned by `overseer`, mode 0600.
|
||||
mkdir -p deploy/secrets && chmod 700 deploy/secrets
|
||||
head -c 32 /dev/urandom | base64 > deploy/secrets/secret_key
|
||||
printf '%s\n' '<Authentik client secret>' > deploy/secrets/oidc_client_secret
|
||||
printf '%s\n' '<Google OAuth client secret>' > deploy/secrets/google_client_secret
|
||||
# litestream_key: see "Backups" > "Database — Litestream"
|
||||
sudo chown 10001:10001 deploy/secrets/secret_key deploy/secrets/oidc_client_secret deploy/secrets/litestream_key
|
||||
sudo chown 10001:10001 deploy/secrets/secret_key deploy/secrets/oidc_client_secret deploy/secrets/google_client_secret deploy/secrets/litestream_key
|
||||
sudo chmod 600 deploy/secrets/*
|
||||
(umask 077; printf 'SEARXNG_SECRET=%s\n' "$(openssl rand -hex 32)" > deploy/secrets/searxng.env)
|
||||
sudo ls -la deploy/secrets # three files mealquest mealquest, searxng.env overseer overseer; all -rw-------
|
||||
sudo ls -la deploy/secrets # four files mealquest mealquest, searxng.env overseer overseer; all -rw-------
|
||||
```
|
||||
|
||||
The `mealquest` host user (uid/gid 10001) is created in "Media — nightly
|
||||
@@ -238,6 +243,38 @@ On 2026-10-05 discovery returned 200 with issuer
|
||||
`https://auth.cubecraftlabs.com/application/o/mealquest/` and
|
||||
`id_token_signing_alg_values_supported: ["RS256"]`.
|
||||
|
||||
## Google Calendar OAuth client
|
||||
|
||||
Push to Calendar connects the household's Google account with a Google
|
||||
OAuth web client. MealQuest calls Google's OAuth and Calendar REST
|
||||
endpoints directly. **The service will not start without
|
||||
`MEALQUEST_GOOGLE_CLIENT_ID` and `deploy/secrets/google_client_secret`**,
|
||||
so create the client before deploying a release that contains Feature 16.
|
||||
|
||||
In the Google Cloud console, in the project that holds MealQuest:
|
||||
|
||||
| Object | Setting |
|
||||
| --- | --- |
|
||||
| API | Google Calendar API enabled |
|
||||
| OAuth consent screen | User type External; app name MealQuest; publishing status **In production** (a client left in Testing gets refresh tokens that expire after 7 days, so Push to Calendar would stop working a week after connecting) |
|
||||
| Scopes | `https://www.googleapis.com/auth/calendar.events` and `https://www.googleapis.com/auth/calendar.calendarlist.readonly` |
|
||||
| Credentials | OAuth client ID, application type **Web application**, name `mealquest` |
|
||||
| Authorized redirect URI | `https://mealquest.cubecraftlabs.com/api/v1/integrations/google/callback` (exactly; it is `MEALQUEST_PUBLIC_URL`'s origin plus that path) |
|
||||
| Client ID | in `deploy/.env` as `MEALQUEST_GOOGLE_CLIENT_ID` (not a secret) |
|
||||
| Client secret | in `deploy/secrets/google_client_secret` only |
|
||||
|
||||
The app is unverified, so Google shows an "unverified app" warning on the
|
||||
consent screen; choose to continue. That is expected for a single-household
|
||||
deployment.
|
||||
|
||||
To connect, a signed-in household member opens
|
||||
`https://mealquest.cubecraftlabs.com/api/v1/integrations/google/connect`
|
||||
(the Settings screen links there once it ships). MealQuest asks for offline
|
||||
access with consent always prompted, and lands back on
|
||||
`/settings/calendar` once the refresh token is stored. Disconnecting
|
||||
(`DELETE /api/v1/integrations/google`) revokes the token at Google and
|
||||
forgets it.
|
||||
|
||||
## Reverse proxy (Traefik)
|
||||
|
||||
MealQuest is published at <https://mealquest.cubecraftlabs.com> by the
|
||||
@@ -1313,6 +1350,23 @@ Sign in at <https://mealquest.cubecraftlabs.com> to confirm; sign-ins
|
||||
fail between regenerating the secret in Authentik and recreating the
|
||||
service.
|
||||
|
||||
### Google OAuth client secret (`deploy/secrets/google_client_secret`)
|
||||
|
||||
In the Google Cloud console, open the OAuth client `mealquest`, add a new
|
||||
client secret, write it to the file (same owner and mode as above) and
|
||||
recreate the service:
|
||||
|
||||
```sh
|
||||
printf '%s\n' '<new Google OAuth client secret>' | sudo tee deploy/secrets/google_client_secret >/dev/null
|
||||
sudo chown 10001:10001 deploy/secrets/google_client_secret
|
||||
sudo chmod 600 deploy/secrets/google_client_secret
|
||||
docker compose -f deploy/compose.yaml up -d --force-recreate mealquest
|
||||
```
|
||||
|
||||
Then disable and delete the old secret in the console. A new client secret
|
||||
leaves the household's stored refresh token valid, so nothing needs
|
||||
reconnecting.
|
||||
|
||||
### LLM API key
|
||||
|
||||
Stored encrypted in the database, not in `deploy/`. In the app, open
|
||||
|
||||
@@ -32,10 +32,12 @@ services:
|
||||
MEALQUEST_DATA_DIR: /data
|
||||
MEALQUEST_SECRET_KEY_FILE: /run/secrets/secret_key
|
||||
MEALQUEST_OIDC_CLIENT_SECRET_FILE: /run/secrets/oidc_client_secret
|
||||
MEALQUEST_GOOGLE_CLIENT_SECRET_FILE: /run/secrets/google_client_secret
|
||||
MEALQUEST_SEARXNG_URL: http://searxng:8080
|
||||
secrets:
|
||||
- secret_key
|
||||
- oidc_client_secret
|
||||
- google_client_secret
|
||||
volumes:
|
||||
- mealquest-data:/data
|
||||
ports:
|
||||
@@ -128,6 +130,8 @@ secrets:
|
||||
file: ./secrets/secret_key
|
||||
oidc_client_secret:
|
||||
file: ./secrets/oidc_client_secret
|
||||
google_client_secret:
|
||||
file: ./secrets/google_client_secret
|
||||
|
||||
volumes:
|
||||
mealquest-data:
|
||||
|
||||
Reference in New Issue
Block a user