diff --git a/20260607-2FA-email-mobile-auth-flow.md b/20260607-2FA-email-mobile-auth-flow.md index f864888..933bdde 100644 --- a/20260607-2FA-email-mobile-auth-flow.md +++ b/20260607-2FA-email-mobile-auth-flow.md @@ -51,7 +51,7 @@ _Date: 2026-06-07 — FR §9 (email) + FR §10 (registration, 2FA, mobile) — * - [§9 — Email addresses & agent config](#9-email-addresses-agent-config) - [§9.1 Prerequisites](#91-prerequisites) - [§9.2 Register addresses (free — DNS, not “buy mailboxes”)](#92-register-addresses-free-dns-not-buy-mailboxes) - - [§9.3 Forward / duplicate to Gmail (info@ → foxxspambox0@gmail.com)](#93-forward-duplicate-to-gmail-info-foxxspambox0gmailcom) + - [§9.3 Forward / duplicate to Gmail (info@ → bestcastr@gmail.com)](#93-forward-duplicate-to-gmail-info-foxxspambox0gmailcom) - [§9.4 Recommended prod layout for this project](#94-recommended-prod-layout-for-this-project) - [§9.5 Outbound mail from BE (verification emails)](#95-outbound-mail-from-be-verification-emails) - [§10 — Registration, 2FA, mobile auth](#10-registration-2fa-mobile-auth) @@ -128,7 +128,7 @@ You do **not** need to buy Google Workspace or Microsoft 365 mailboxes. You **do | 3 | **Inbound path** | MX records → free forwarder **or** self-hosted Postfix alias on FE/BE. | | 4 | **Outbound path (BE)** | SMTP relay for verification/reset mail (see §9.5) — can be Gmail SMTP, SendGrid free tier, or local Postfix with SPF alignment. | | 5 | **TLS on web** | Already have `https://apps.f0xx.org` — verification links use same vhost. | -| 6 | **Gmail destination** | e.g. `foxxspambox0@gmail.com` — receives forwarded + BCC copies. | +| 6 | **Gmail destination** | e.g. `bestcastr@gmail.com` — receives forwarded + BCC copies. | **Deliverability minimum (avoid spam folder):** @@ -147,7 +147,7 @@ Start with `p=none`; tighten after monitoring. #### Option A — **Cloudflare Email Routing** (recommended if DNS is on Cloudflare) 1. Cloudflare dashboard → **Email** → **Email Routing** → enable for `apps.f0xx.org`. -2. Add **destination address** `foxxspambox0@gmail.com` (verify Gmail link once). +2. Add **destination address** `bestcastr@gmail.com` (verify Gmail link once). 3. Create **Custom addresses**: - `info@apps.f0xx.org` → forward to Gmail - `admin@apps.f0xx.org` → forward to Gmail @@ -161,7 +161,7 @@ Start with `p=none`; tighten after monitoring. 1. Sign up at [improvmx.com](https://improvmx.com) (free tier: limited aliases). 2. Add domain `apps.f0xx.org` → set MX to ImprovMX hosts (they show exact records). -3. Create aliases `info`, `admin`, `root` → `foxxspambox0@gmail.com`. +3. Create aliases `info`, `admin`, `root` → `bestcastr@gmail.com`. 4. Add SPF include for ImprovMX. #### Option C — **Self-hosted alias** (Gentoo FE or Alpine BE) @@ -170,16 +170,16 @@ If you already run Postfix on FE: ```text /etc/postfix/virtual: -info@apps.f0xx.org foxxspambox0@gmail.com -admin@apps.f0xx.org foxxspambox0@gmail.com -root@apps.f0xx.org foxxspambox0@gmail.com +info@apps.f0xx.org bestcastr@gmail.com +admin@apps.f0xx.org bestcastr@gmail.com +root@apps.f0xx.org bestcastr@gmail.com ``` Then `postmap /etc/postfix/virtual && systemctl reload postfix`. Requires **MX** pointing to FE public IP and port **25** reachable (often blocked on residential; OK on HVM with firewall rule). **Do first:** pick **A or B** unless you explicitly want to operate SMTP on FE. -### §9.3 Forward / duplicate to Gmail (info@ → foxxspambox0@gmail.com) +### §9.3 Forward / duplicate to Gmail (info@ → bestcastr@gmail.com) | Method | Inbox copy | Send-as From | IMAP on apps domain | |--------|------------|--------------|---------------------| @@ -201,9 +201,9 @@ No IMAP/POP3 server on `apps.f0xx.org` is required for this FR. ```text Inbound (public): - info@apps.f0xx.org ──forward──► foxxspambox0@gmail.com - admin@apps.f0xx.org ──forward──► foxxspambox0@gmail.com - root@apps.f0xx.org ──forward──► foxxspambox0@gmail.com (same inbox or +tag) + info@apps.f0xx.org ──forward──► bestcastr@gmail.com + admin@apps.f0xx.org ──forward──► bestcastr@gmail.com + root@apps.f0xx.org ──forward──► bestcastr@gmail.com (same inbox or +tag) Outbound (BE PHP): From: Android Cast Issues @@ -438,7 +438,7 @@ Hub landing contact form (`landing-pages.inc.php`) should eventually use **`info |---|----------|------------------| | Q1 | Require WebAuthn for alpha or TOTP-only? | **TOTP required**; WebAuthn optional P4 | | Q2 | Allow registration on prod immediately or invite-only? | **Open register** with captcha; `viewer` role | -| Q3 | Single Gmail inbox for all aliases? | Yes for now (`foxxspambox0@gmail.com`) | +| Q3 | Single Gmail inbox for all aliases? | Yes for now (`bestcastr@gmail.com`) | | Q4 | Separate `noreply@` for outbound? | Yes — no forward needed; SPF only | --- diff --git a/DEVELOPER_SETUP.md b/DEVELOPER_SETUP.md index 8c766a7..5a5c343 100644 --- a/DEVELOPER_SETUP.md +++ b/DEVELOPER_SETUP.md @@ -1,8 +1,13 @@ # Developer setup — org `ac` -**Clean machine?** Start with [docs/FRESH_ENV_CLONE.md](docs/FRESH_ENV_CLONE.md) and run `ac-scripts/fresh-clone-dev-env.sh`. +**Clean machine?** Start with [docs/FRESH_ENV_CLONE.md](docs/FRESH_ENV_CLONE.md) (`~/repos/ac`). -Canonical entry point: **`ac-workspace`** (submodule manifest). +```bash +mkdir -p ~/repos/ac && cd ~/repos/ac +git clone --branch next --single-branch git://f0xx.org/ac/ac-workspace . +git submodule update --init --recursive +echo 'source "$(git rev-parse --show-toplevel)/ac-be-public-assets/ac-bash.env"' >> ~/.bashrc +``` ```bash git clone git://f0xx.org/ac/ac-workspace diff --git a/README.md b/README.md index 3aa2ea1..1e53d5b 100644 --- a/README.md +++ b/README.md @@ -11,5 +11,7 @@ AndroidCast documentation (extracted from monolith `docs/`). | Doc | Purpose | |-----|---------| | [DEVELOPER_SETUP.md](DEVELOPER_SETUP.md) | Repo map, lab paths | -| [docs/FRESH_ENV_CLONE.md](docs/FRESH_ENV_CLONE.md) | Clean laptop — clone all `ac/*` repos | +| [docs/FRESH_ENV_CLONE.md](docs/FRESH_ENV_CLONE.md) | Clean laptop — `~/repos/ac` clone workflow | +| [docs/CURSOR_SECONDARY_LAPTOP.md](docs/CURSOR_SECONDARY_LAPTOP.md) | Agent history handoff between laptops | +| [docs/HELP_REQUEST_20260623.md](docs/HELP_REQUEST_20260623.md) | Updated dev checklist (email, clone) | | [docs/SECRETS_AND_RECOVERY.md](docs/SECRETS_AND_RECOVERY.md) | Passwords, tokens, VPN/RSSH recovery | diff --git a/docs/CURSOR_SECONDARY_LAPTOP.md b/docs/CURSOR_SECONDARY_LAPTOP.md new file mode 100644 index 0000000..75d9d58 --- /dev/null +++ b/docs/CURSOR_SECONDARY_LAPTOP.md @@ -0,0 +1,54 @@ +# Cursor IDE — second laptop / agent handoff + +Cursor does not ship a single “export entire IDE” button. Use this checklist to move **code + rules + agent chat history** to another machine. + +## 1. Code (required) + +On the **new** laptop, follow [FRESH_ENV_CLONE.md](FRESH_ENV_CLONE.md) (`~/repos/ac`). + +## 2. Workspace rules (recommended) + +Copy from the old machine: + +| Source | Destination on new laptop | +|--------|---------------------------| +| `~/repos/ac/.cursor/rules/` (if present) | same under workspace | +| `~/repos/ac/AGENTS.md` | workspace root | + +Or re-clone — rules live in `ac-docs` / monolith exports when committed. + +## 3. Agent conversation history + +Cursor stores transcripts per project, e.g.: + +`~/.cursor/projects//agent-transcripts/*.jsonl` + +**Handoff archive** (run on the **old** laptop from repo root): + +```bash +cd ~/repos/ac +tar czvf ~/ac-cursor-handoff-$(date +%Y%m%d).tar.gz \ + .cursor/rules 2>/dev/null \ + AGENTS.md 2>/dev/null \ + -C "$HOME/.cursor/projects" \ + $(ls -1d "$HOME/.cursor/projects"/*androidcast* 2>/dev/null | xargs -I{} basename {}) +``` + +Copy the `.tar.gz` to the new laptop and extract: + +```bash +mkdir -p ~/.cursor/projects +tar xzvf ac-cursor-handoff-YYYYMMDD.tar.gz -C ~ +``` + +Open **`~/repos/ac`** in Cursor on the new machine — past chats appear under that project when the slug matches. + +## 4. What is *not* portable + +- Local Cursor login / API keys (re-sign-in) +- Uncommitted work (commit or stash before switch) +- Cluster secrets (`secrets.lab.env` on NFS — not in git) + +## 5. Scripted helper + +`ac-scripts/export-cursor-handoff.sh` — builds the tarball paths above. diff --git a/docs/FRESH_ENV_CLONE.md b/docs/FRESH_ENV_CLONE.md index cf43aa4..24bd972 100644 --- a/docs/FRESH_ENV_CLONE.md +++ b/docs/FRESH_ENV_CLONE.md @@ -1,90 +1,77 @@ # Fresh developer machine — clone guide -Use this on a **clean laptop** (no legacy `android_cast` monolith checkout). -Canonical layout: org **`ac`** on `git://f0xx.org/ac/*`, branch **`next`**. +Use on a **clean laptop**. Canonical org: **`ac`** on `git://f0xx.org/ac/*`, branch **`next`**. -## One command (recommended) - -From any empty directory (requires `git` and reachability to `git://f0xx.org`): +## Standard layout (`~/repos/ac`) ```bash -# Bootstrap: shallow clone ac-scripts only, then run the full workspace clone -git clone --branch next --single-branch --depth 1 \ - git://f0xx.org/ac/ac-scripts /tmp/ac-scripts-bootstrap -sh /tmp/ac-scripts-bootstrap/fresh-clone-dev-env.sh -``` +mkdir -p ~/repos/ac && cd ~/repos/ac -Default target: `~/src/androidcast-ac/` (override with `-d /path`). +git clone --branch next --single-branch git://f0xx.org/ac/ac-workspace . -The script: - -1. Clones **`ac-workspace`** (submodule manifest). -2. Runs `git submodule update --init --recursive` on **`next`**. -3. Verifies every submodule path exists and prints a SHA summary. -4. Exits non-zero if any submodule is missing or unreachable. - -## Manual steps (review / teach) - -```bash -export AC_GIT_BASE=git://f0xx.org/ac -export AC_BRANCH=next -export TARGET=~/src/androidcast-ac - -mkdir -p "$(dirname "$TARGET")" -git clone --branch "$AC_BRANCH" --single-branch \ - "${AC_GIT_BASE}/ac-workspace" "$TARGET" -cd "$TARGET" git submodule sync --recursive git submodule update --init --recursive -# Sanity: expect 32 submodule directories + ac-workspace root -find . -maxdepth 1 -type d -name 'ac-*' | wc -l +echo 'source "$(git rev-parse --show-toplevel)/ac-be-public-assets/ac-bash.env"' >> ~/.bashrc +source ~/.bashrc +``` -# Spot-check remotes (each submodule should be git://f0xx.org/ac/) -git submodule foreach --quiet 'echo $name $(git rev-parse --short HEAD) $(git remote get-url origin)' +You now have every `ac-*` submodule under one directory. Docs: `ac-docs/` (start with [DEVELOPER_SETUP.md](../DEVELOPER_SETUP.md)). + +## Stay up to date + +From `~/repos/ac`: + +```bash +git pull --rebase origin next +git submodule sync --recursive +git submodule update --init --recursive +``` + +Or, after sourcing `ac-bash.env`: **`ac-pull`** + +When child repos change on the server, the workspace root commit updates submodule SHAs — always pull **root first**, then submodule update. + +## One-command bootstrap (alternative) + +```bash +git clone --branch next --single-branch --depth 1 \ + git://f0xx.org/ac/ac-scripts /tmp/ac-scripts-bootstrap +sh /tmp/ac-scripts-bootstrap/fresh-clone-dev-env.sh -d ~/repos/ac ``` ## What you get -| Path under workspace | Role | -|----------------------|------| +| Path | Role | +|------|------| | `ac-mobile-android/` | Android app | -| `ac-deploy/` | Lab cluster (`sim/cluster0/`), compose scripts | -| `ac-docs/` | Documentation (this file) | -| `ac-scripts/` | `fresh-clone-dev-env.sh`, CI helpers | -| `ac-platform-*` | DB, PHP, web, edge nginx snippets | -| `ac-ms-*`, `ac-be-*` | Backend microservices and consoles | +| `ac-deploy/` | Lab cluster (`sim/cluster0/`) | +| `ac-docs/` | Documentation | +| `ac-be-public-assets/` | Shared `ac-bash.env` (non-secret) | +| `ac-platform-*`, `ac-ms-*`, `ac-be-*` | Backend stack | -**Do not** clone legacy `git://f0xx.org/android_cast` for new work — it is frozen read-only. +**Do not** clone legacy `git://f0xx.org/android_cast` for new work. ## After clone | Task | Where | |------|--------| | Repo map, lab URLs | [DEVELOPER_SETUP.md](../DEVELOPER_SETUP.md) | -| Passwords / tokens / VPN recovery | [SECRETS_AND_RECOVERY.md](SECRETS_AND_RECOVERY.md) | +| Secrets / recovery | [SECRETS_AND_RECOVERY.md](SECRETS_AND_RECOVERY.md) | +| Cursor + second laptop | [CURSOR_SECONDARY_LAPTOP.md](CURSOR_SECONDARY_LAPTOP.md) | | Android build | `cd ac-mobile-android && ./gradlew :app:assembleDebug` | -| Unit tests | `./gradlew :app:testDebugUnitTest` | -| Lab cluster (optional) | `ac-deploy/sim/cluster0/DEPLOY.md` | -## Lab vs production URLs +## Lab vs production -| Environment | Issues API | Gitea browse | -|-------------|------------|--------------| -| Production (current) | `https://apps.f0xx.org/app/androidcast_project/issues/` | prod BE Gitea | -| Lab cluster (cast01) | `https://acl0.f0xx.org/...` (after FE `ac-fe.conf`) | `.../git/ac/` | - -Mobile defaults target **production** until you point a debug build at lab (`BackendEndpoints` / settings). - -## Version note (post-migration) - -After migration completes, **app and backend minor versions will bump**. Older mobile builds were not publicly released; lab/prod may **reject** clients below the new minimum. Rebuild from `ac-mobile-android` on `next` after pulling. +| Environment | Issues API | +|-------------|------------| +| Production | `https://apps.f0xx.org/app/androidcast_project/issues/` | +| Lab cluster | `https://acl0.f0xx.org/...` (after FE `ac-fe.conf`) | ## Troubleshooting | Symptom | Fix | |---------|-----| -| `git://f0xx.org` unreachable | VPN/LAN to git host; try from cluster or PO network | -| Submodule empty dir | `git submodule update --init --recursive` in workspace root | +| `git://f0xx.org` unreachable | VPN/LAN to git host | +| Empty submodule dir | `git submodule update --init --recursive` | | Wrong branch | `git checkout next && git submodule foreach git checkout next` | -| SSH instead of git | Not required for read-only clone; push uses `git://` on FE | diff --git a/docs/HELP_REQUEST_20260623.md b/docs/HELP_REQUEST_20260623.md new file mode 100644 index 0000000..1613e63 --- /dev/null +++ b/docs/HELP_REQUEST_20260623.md @@ -0,0 +1,36 @@ +# Developer help request — updated 2026-06-23 + +Supersedes `tmp/20260608_help_request.md` for **email inbox** and **clone workflow**. +Original PDF still valid for DNS/MX items not listed here. + +## Done / updated by agent + +| Item | Status | +|------|--------| +| Gmail destination | **`bestcastr@gmail.com`** (replaces foxxspambox0@gmail.com) | +| alpine-be msmtp | `bestcastr@gmail.com` + app password in `/etc/androidcast/msmtp.secret` | +| Lab cluster mail | cast01: `deploy-mailrelay.sh` (msmtp), PHP `sendmail` transport | +| Dev clone path | `~/repos/ac` ← `git clone git://f0xx.org/ac/ac-workspace .` | +| `ac-be-public-assets` | `ac-bash.env` for shared non-secret env | + +## Your verification (after agent test send) + +1. Check **`bestcastr@gmail.com`** inbox for: + - msmtp CLI smoke from cast01 (`Lab mail relay` or similar subject from verify script) + - Optional: registration mail after you test `/issues/register` +2. Reply: **“mail received”** or paste failure (Gmail spam, delay, etc.) + +## Still on you (unchanged from 20260608) + +| Task | Notes | +|------|--------| +| **2.1 DNS** | MX/SPF/DKIM/DMARC — apex `f0xx.org` if `apps.f0xx.org` is CNAME | +| **ImprovMX** | Activate aliases `info@` / `admin@` / `root@` → **bestcastr@gmail.com** (hoster.by partial) | +| **FE acl0** | Install `ac-fe.conf` on monstro — see `ac-platform-edge/fe/INSTALL.md` | +| **Inbound** | Confirm forwarded mail to bestcastr@gmail.com after ImprovMX live | + +## References + +- [20260607-2FA-email-mobile-auth-flow.md](../20260607-2FA-email-mobile-auth-flow.md) +- [FRESH_ENV_CLONE.md](FRESH_ENV_CLONE.md) +- [SECRETS_AND_RECOVERY.md](SECRETS_AND_RECOVERY.md)