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