added doc
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
# CannaManage — now LIVE & public, auth blocker fixed (2026-06-22)
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
`https://cannamanage.plate-software.de` is **live in production** over HTTPS. The
|
||||||
|
9-day systemic missing-token auth blocker (flagged 2026-06-13 / 2026-06-18) is
|
||||||
|
**fixed and verified end-to-end through the public chain**. Push→deploy→tunnel
|
||||||
|
now mirrors inspectflow. End of alpha.
|
||||||
|
|
||||||
|
## What shipped (2 commits on main)
|
||||||
|
- **a686957** `feat(deploy): public hosting + fix systemic auth-token bug`
|
||||||
|
- **83b46c8** `harden(deploy): db internal-only + robust container-loopback frontend verify`
|
||||||
|
|
||||||
|
### 1. The auth fix (the important one)
|
||||||
|
Root cause (unchanged from prior notes): the frontend used a **static
|
||||||
|
`next.config.mjs` rewrites()** to proxy `/api/backend/*` → backend, which cannot
|
||||||
|
inject the user's bearer token, so every authenticated server call hit the API
|
||||||
|
unauthenticated and the UI silently fell back to mock data.
|
||||||
|
|
||||||
|
Fix — replaced the static rewrite with a **server-side catch-all Route Handler**:
|
||||||
|
- `cannamanage-frontend/src/app/api/backend/[...path]/route.ts` (new) — reads the
|
||||||
|
NextAuth session via `auth()`, injects `Authorization: Bearer <accessToken>`,
|
||||||
|
streams request/response bodies (`duplex: "half"`) for uploads/downloads,
|
||||||
|
strips hop-by-hop headers, GET/POST/PUT/PATCH/DELETE.
|
||||||
|
- `src/lib/auth.ts` — `session()` callback now exposes `session.accessToken`.
|
||||||
|
- `src/types/next-auth.d.ts` — added `accessToken?: string` to `Session`.
|
||||||
|
- `next.config.mjs` — removed the static `rewrites()`.
|
||||||
|
|
||||||
|
**Why `auth()` not `getToken()`**: `getToken()` autodetects the `__Secure-`
|
||||||
|
cookie prefix, which breaks across the public-HTTPS → internal-HTTP proxy
|
||||||
|
boundary. `auth()` resolves the session reliably behind the frp/Apache chain.
|
||||||
|
|
||||||
|
**Accepted tradeoff**: `accessToken` is now readable at `/api/auth/session`
|
||||||
|
(client-visible). Fine for alpha; revisit if we want it httpOnly-only.
|
||||||
|
|
||||||
|
### 2. Public hosting wiring (mirrors inspectflow)
|
||||||
|
Chain: browser →HTTPS→ IONOS Apache (82.165.206.45, LE TLS) →ProxyPass→
|
||||||
|
VPS frps (85.214.154.199:**30010**) →frp tunnel→ TrueNAS frpc → frontend:3000.
|
||||||
|
The frontend proxies `/api/backend/*` to `backend:8080` server-side, so **only
|
||||||
|
the frontend port is tunnelled** (no Caddy needed, unlike inspectflow).
|
||||||
|
|
||||||
|
- `docker-compose.truenas.yml` — public `NEXTAUTH_URL`/`AUTH_URL`, `AUTH_TRUST_HOST`,
|
||||||
|
rotated prod secrets, `BACKEND_URL=http://backend:8080`, **db internal-only**
|
||||||
|
(`ports: !override []`), backend remapped 8081→8080 (host 8080 taken by searxng).
|
||||||
|
- `.gitea/workflows/deploy.yml` — injects `AUTH_SECRET`/`JWT_SECRET`/`DB_PASSWORD`
|
||||||
|
from Gitea repo secrets; new **"reconcile DB role password"** step (ALTER USER —
|
||||||
|
POSTGRES_PASSWORD only applies on first volume init, the persistent
|
||||||
|
`cannamanage_pgdata` volume kept the old password); **hardened frontend verify**
|
||||||
|
(probes container loopback via bundled `node`, not host wget — fixes a transient
|
||||||
|
false-failure when polling mid-recreate).
|
||||||
|
- frpc.toml on TrueNAS: added `cannamanage` proxy localPort 3000 → remotePort 30010.
|
||||||
|
- IONOS: Let's Encrypt cert via acme.sh + `:443` vhost ProxyPass → VPS:30010.
|
||||||
|
|
||||||
|
## Port map (NO collision with inspectflow — explicitly verified)
|
||||||
|
| layer | inspectflow | cannamanage |
|
||||||
|
|---|---|---|
|
||||||
|
| VPS frps remotePort | 30009 | **30010** |
|
||||||
|
| TrueNAS host publish | 8090→80 (caddy) | 3000 (frontend), 8081→8080 (backend) |
|
||||||
|
| db / internal | internal-only | **internal-only** (5432/tcp, no host bind) |
|
||||||
|
|
||||||
|
## Verified live (end-to-end, public HTTPS)
|
||||||
|
- `GET /` → 307 → `/login` (correct NextAuth redirect), valid LE TLS.
|
||||||
|
- Login `admin@test.de` → 302; session = role ADMIN, accessToken present.
|
||||||
|
- **`GET /api/backend/members` → HTTP 200** through the full public chain. ✅
|
||||||
|
- db: no host listener on :5432 after hardened deploy. ✅
|
||||||
|
- Deploy run #59 (deploy.yml) = success with hardened verify. ✅
|
||||||
|
|
||||||
|
## Flags / follow-ups for Work Lumen
|
||||||
|
1. **PII / GDPR**: this is a German cannabis-club app (KCanG) now public. Members
|
||||||
|
table is empty today, but before real data lands we need: backups (deploy/backup.sh
|
||||||
|
exists — wire a cron), retention enforcement, and a documented restore drill.
|
||||||
|
2. **Secret rotation**: prod secrets live only in Gitea repo secrets + the running
|
||||||
|
containers. They are NOT in git (verified). Document them in a vault; rotating
|
||||||
|
`JWT_SECRET` invalidates all tokens, `AUTH_SECRET` all sessions, `DB_PASSWORD`
|
||||||
|
needs the ALTER USER reconcile (already automated in deploy.yml).
|
||||||
|
3. **accessToken client-exposure** tradeoff (see above) — revisit post-alpha.
|
||||||
|
4. **ci.yml is red** (separate workflow): backend `mvn test` + frontend `pnpm lint`
|
||||||
|
fail in CI but pass locally; local type-check shows only TEST-file errors
|
||||||
|
(missing vitest globals / stale assertions). deploy.yml does NOT depend on ci.yml
|
||||||
|
(tests are a local-only gate per its header — nested-DinD can't volume-mount).
|
||||||
|
Worth fixing ci.yml separately so the badge is honest.
|
||||||
|
5. **HTTP→apex redirect cosmetic quirk**: `http://cannamanage…` 301s to apex
|
||||||
|
`plate-software.de` (Apache `*:80` vs `plate-software.de:80` vhost ordering) —
|
||||||
|
same as inspectflow, harmless since the site is HTTPS, but tidy it if it bugs you.
|
||||||
|
6. acme.sh default CA was ZeroSSL and stalled (retryafter=86400). Switched the box
|
||||||
|
default to **Let's Encrypt** (`--set-default-ca --server letsencrypt`) — matches
|
||||||
|
inspectflow. Auto-renew cron inherits this now.
|
||||||
|
|
||||||
|
## Test creds (alpha)
|
||||||
|
`admin@test.de` / `Test1234!` (hash was reset during smoke testing).
|
||||||
Reference in New Issue
Block a user