Three new doors, all wire-contract ports of the shared @otm/account-panel factories (this backbone is plain Node — the Next factories can't mount): - GET /api/auth/operator-magic — OTM 'Log in as admin'. HS256 verify against OPERATOR_SHARED_SECRET (alg allowlist, constant-time, action-claim rejected for flow separation), single-use jti via OperatorMagicConsumed (+ who/when audit), 1-HOUR session with cookie Max-Age derived from the payload, 🔑 support-session banner in the app, every failure a 302 reason redirect. - GET /api/auth/otm-sso — the OTM /account tile. Stricter sso-ticket verify (exp mandatory, audience compared), email-then-role actor mapping, safeNext. - 💡 suggestion jot chip — files a Gitea issue (shared attribution footer, 8k cap, 10s timeout); on any failure the jot is kept as a note instead. Success also leaves a '#N — …' note so she has her own record. - Footer version chip + one-tap self-update (HMAC-signed OTM proxy with explicit field picking — foreign JSON can never reach the _setSession/_redirect control keys), owner-gated, 10-min sessionStorage cache on the check. Hardening that rode along: session key now derived from OPERATOR_SHARED_SECRET (managed boot REFUSES the old derivable DATABASE_URL fallback), 1MB JSON body cap, login.html prototype-lookup fix. NOTE: server.mjs previously contained a literal NUL byte that made git treat it as binary — this commit re-encodes it as an escape (behavior identical) and adds .gitattributes so source diffs can never go blind again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SmybqyQmZWfcqA1vMP4jbQ
139 lines
7.4 KiB
Markdown
139 lines
7.4 KiB
Markdown
# Bonna Moon Studio — access notes
|
|
|
|
Status as of 2026-08-06: **provisioned and live** at
|
|
https://bonnamoonstudio.poweredbyotm.com (`site` template v0.11.0, container
|
|
`site-bonnamoonstudio` on anvil). The repo now holds the studio-backbone
|
|
**vision, Phase 1 designs, and a working local prototype** — see
|
|
[VISION.md](VISION.md) and [prototype/README.md](prototype/README.md). The
|
|
`site` instance's code still lives in the platform monorepo, not here (see "The
|
|
plan" below); this repo is the backbone's home. Local branch is now `main`,
|
|
tracking `gitea/main`.
|
|
|
|
The long-term product vision — a custom "studio backbone" app in the FMB mold
|
|
(glaze recipes, firing log, inventory, accounting, market scanner, kiln control) —
|
|
is captured in [VISION.md](VISION.md). The `site` instance is the storefront layer.
|
|
|
|
**The backbone is LIVE (2026-08-06): https://bms.poweredbyotm.com** — template
|
|
`bms-backbone-next` (otm-admin 0.111.0), container `bms-backbone-bms` on anvil,
|
|
built from this repo's `app/` (Postgres + Prisma port of the prototype, OTM
|
|
owner-seed auth). Deploy sequence: bump `app/lib/version.mjs` **and
|
|
`app/package.json`** + push here → the push webhook now AUTO-BUILDS the image
|
|
(`autoBuildOnly`, otm-admin 0.111.1) → deploying it stays a manual click on
|
|
OTM `/instances` (or `redeploy_service` via the MCP).
|
|
Bonna's laptop data was migrated; `prototype/` is now legacy reference (the
|
|
laptop `.command` still works but the hosted notebook is the daily driver).
|
|
|
|
## v0.4.0 — OTM integrations (what needs which env)
|
|
|
|
All three are provision-injected via the template's flags; a hand-provision
|
|
that misses one degrades silently, so here's the lookup:
|
|
|
|
| Feature | Env it needs | Symptom when unset |
|
|
|---|---|---|
|
|
| OTM "Log in as admin" (`GET /api/auth/operator-magic`) + OTM account SSO (`GET /api/auth/otm-sso`) | `OPERATOR_SHARED_SECRET`; SSO also `OTM_SSO_SECRET` + `OTM_SSO_AUDIENCE` | `/login?reason=not_enabled` |
|
|
| Suggestion jots → Gitea issues (the 💡 chip) | `GITEA_URL` + `GITEA_TOKEN` + `GITEA_REPO` | jot saved as a note tagged `suggestion` instead (`fallback: true`) — never lost |
|
|
| Self-update (footer ✨ chip) | `OTM_API_BASE` + `OTM_SERVICE_ID` + `OPERATOR_SHARED_SECRET` | footer shows no update chip; API answers 503 `not_configured` |
|
|
|
|
Session-signing note: the cookie key is derived from `OPERATOR_SHARED_SECRET`
|
|
(domain-separated HMAC) unless an explicit `SESSION_SECRET` is set; a managed
|
|
instance (`OTM_MANAGED=true`) with neither refuses to boot. OTM sign-ins are
|
|
recorded in `OperatorMagicConsumed` (jti + who + when); operator sessions last
|
|
1h and show a 🔑 support-session banner.
|
|
|
|
## The repo
|
|
|
|
- Gitea: `https://git.poweredbyotm.com/bonna61/Bonna-Moon-Studio.git`
|
|
- Remote name here is **`gitea`** (not `origin`) — matches the FMB convention.
|
|
- Local branch is `master`; FMB and the platform both use **`main`**. Rename before
|
|
the first commit, or let `git checkout main` create the tracking branch after the
|
|
remote has one.
|
|
|
|
```sh
|
|
cd "/Users/bonnamoon/Projects/Bonna Moon Studio"
|
|
git fetch gitea && git checkout main # once the remote has content
|
|
```
|
|
|
|
**Auth: macOS keychain.** There is no `~/.gitconfig` and no `~/.git-credentials` on
|
|
this machine; `credential.helper=osxkeychain` is set at the git *system* level. A
|
|
`git ls-remote gitea` completes with no prompt, so pushes and fetches over
|
|
`https://git.poweredbyotm.com` just work. Nothing needs a token in the URL.
|
|
|
|
Commit identity is set **locally** in this repo (there's no global fallback — commits
|
|
would fail without it):
|
|
|
|
```
|
|
user.name = Bonna
|
|
user.email = bonna@fullmoonbakehouse.com
|
|
```
|
|
|
|
### The other Gitea address — ⚠️ TWO instances now, NAS is legacy
|
|
|
|
**Corrected 2026-08-06 (the hard way):** `git.poweredbyotm.com` and the home NAS
|
|
are **separate Gitea instances**. They diverged at some point; an earlier version
|
|
of this file claimed they were one instance with three addresses. They are not.
|
|
|
|
| Address | What it is |
|
|
|---|---|
|
|
| `https://git.poweredbyotm.com` | **Production Gitea. Use this, always.** Keychain auth. Holds this repo, `tonym/platform` (the real one — admin 0.111.0-era), `bonna61/Moonbase`, etc. |
|
|
| `http://192.168.0.5:3022` / `http://167.237.9.184:3022` | **Legacy home-NAS Gitea (LAN / public IP of the same box). Being retired** — Tony confirmed 2026-08-06. Its `tonym/platform` is frozen at ~0.80.0; pushing there deploys nothing. A stray bms commit (`e2ea2b3`) landed there before the divergence was discovered. |
|
|
|
|
Do not push platform work to the NAS. If a doc, remote URL, or memory points at
|
|
`192.168.0.5:3022` / `167.237.9.184:3022`, treat it as stale until verified.
|
|
|
|
The sibling repos (`moonbase`, `moon-household-budget`, `otm-platform`) embed an
|
|
access token directly in their remote URL against `192.168.0.5:3022`. Those tokens
|
|
are **only** recorded in those URLs — the `~/Projects/CLAUDE.md` that
|
|
[moonbase/docs/git-deploy-guide.md](../moonbase/docs/git-deploy-guide.md) refers to
|
|
does not exist on this machine. Read one back with:
|
|
|
|
```sh
|
|
git -C /Users/bonnamoon/Projects/moonbase remote get-url origin
|
|
```
|
|
|
|
Never commit a token.
|
|
|
|
## Hosts
|
|
|
|
- **`anvil`** = `debian@51.81.80.250` — OVH VPS, **production, live**. Serves
|
|
`*.poweredbyotm.com` with real Let's Encrypt certs. Wildcard `*` A-record, so any
|
|
new `<slug>.poweredbyotm.com` resolves with zero DNS work. Host user is `debian`,
|
|
not `tonym`. Can't reach the home LAN — its builds use `167.237.9.184:3022`.
|
|
- **`forge`** = `tonym@192.168.0.83` — Unraid VM, staging, `*.local` hostnames with a
|
|
local CA. Needs the home LAN.
|
|
- OTM Admin: **https://admin.poweredbyotm.com** (anvil) — provisioning, template
|
|
builds, per-service ops, logs.
|
|
|
|
A connected MCP server exposes the same control plane read/write (`platform_status`,
|
|
`list_instances`, `list_templates`, `onboard`, deploy + log tools). Call
|
|
`platform_status` or `list_instances` first for an overview. It points at **live
|
|
production** — treat `onboard`, deploys, and restarts as real-world actions.
|
|
|
|
Platform source: `/Users/bonnamoon/Projects/platform` (and `otm-platform`). Its
|
|
`CLAUDE.md` is the authority on deploys, the CI-gated auto-deploy webhook, and the
|
|
long list of anvil-vs-forge gotchas.
|
|
|
|
## The plan (executed 2026-08-06)
|
|
|
|
One app with public pages **plus** an `/admin` back office — the **`site`** template
|
|
("Web — hosting + site + account", v0.11.0), same as `home`, `overthemoon`, and
|
|
`vvts`. Public site plus the drag-and-drop CMS page editor from `@otm/account-panel`.
|
|
|
|
Provisioned via `onboard`: customer **Bonna Moon Studio**, app/service slug
|
|
`bonnamoonstudio`, industry `universal`, owner **bonna@bonnamoonstudio.com**.
|
|
Live at **https://bonnamoonstudio.poweredbyotm.com** (admin at `/admin`). The
|
|
seeded owner password was captured and handed to Bonna at provisioning time; it is
|
|
deliberately not recorded anywhere in this repo.
|
|
|
|
What it is: Bonna's **art studio** — ceramics, carved wood, and sterling
|
|
silver/ceramic jewelry. The prior site at bonnamoonstudio.com (shop temporarily
|
|
closed during the studio rebuild) has the source content: product lines, collector
|
|
testimonials, newsletter signup. That domain still points at the old site; cutover
|
|
is a future DNS step.
|
|
|
|
Remaining notes:
|
|
|
|
- **The `site` template does not use this repo.** Its code lives in the platform
|
|
monorepo at `apps/site`; per-instance content lives in that instance's Postgres, not
|
|
in git. This repo staying empty is expected. Giving it real code means authoring a
|
|
new platform template and build chain — days, not minutes.
|