# meowtrace — DevOps & Deployment Notes (DEVOPS.md)

> ↩ **Back to canonical entry:** [SPEC.md](./SPEC.md)
> This doc holds deployment, hosting, and infrastructure notes for the **meowtrace
> product**. Keep it linked from SPEC.md's document table; no orphaned docs.
>
> **Not here:** the standalone Markdown viewer tool has its own spec + deployment
> record in [VIEWER-APP.md](./VIEWER-APP.md) (separate from the product). API endpoint
> reference lives in [API.md](./API.md).

**Last updated:** 2026-07-19

---

## Local Environment (host)

| Tool | Version / State | Purpose |
|---|---|---|
| Chrome | 150.0.7871.128 | Frontend preview / rendering |
| nginx | installed, active, boot-enabled | Serve locally-hosted environments (HTTP 200 on localhost) |
| Node | v24.18.0 | Runtime (backend + Vite frontend) |
| PostgreSQL | 18.4 (apt), service active + boot-enabled | Data store — `geo_ranges` (§6). Local dev DB `meowtrace`, role `meowtrace` on 127.0.0.1:5432 |

_Note: nginx binary lives in `sbin` (off PATH); the service runs regardless._

## Reference Assets & Frontend Base

The purchased **Minimal v5.4.0** MUI kit ($69, one-time license — see [SPEC.md §5.1](./SPEC.md#51-components)) is the frontend base.

**Layout:**

| Path | Role |
|---|---|
| `projects/meowtrace/reference/Minimal_v5.4.0/` | **Reference only** — untouched extracted archive. Not built/deployed. Keeps design source (`.fig`, fonts) + all six TS variants for lookup. |
| `projects/meowtrace/src/frontend/` | **Actual source** — duplicated from the **`vite-ts`** variant (React + Vite + React Router, MUI 5; **no Next.js**). This is what we adapt and build. |

**Provenance of the duplication:**
- Extracted `Minimal_v5.4.0.zip` → `reference/` (stripped macOS junk: `__MACOSX`, `.DS_Store`).
- Reference contains: `Minimal_Design_v5.4.0/` (Figma `.fig` + `font.zip`) and `Minimal_TypeScript_v5.4.0/` with six variants: `cra-ts`, `next-ts`, `simple-cra-ts`, `simple-next-ts`, `simple-vite-ts`, `vite-ts`.
- **Chosen variant: `vite-ts`** — React + Vite + React Router (routed SPA, dashboard
  scaffold, auth/invoice/pricing/account sections). **No Next.js** (reduced-complexity
  decision, 2026-07-20). Copied whole into `src/frontend/`. *(Earlier `next-ts` base was
  swapped out per this decision.)*
- Duplicate freely from other variants/design assets in `reference/` into `src/frontend/` as needed; record any such copy here.

> **Rule:** `reference/` is read-only source-of-truth for the kit; never build from it. All edits happen in `src/frontend/`.

## Hosting / Deployment Target
_(TBD — Vercel? self-hosted? evaluate against stack chosen in [SPEC.md](./SPEC.md#5-architecture))_

## Domains & DNS
- **meowtrace.com** — acquired. DNS / registrar config: _(TBD)_

## CI/CD
_(TBD)_

## Environments
| Env | URL | Notes |
|---|---|---|
| local | _(TBD, e.g. localhost via nginx)_ | preview |
| staging | _(TBD)_ | |
| production | meowtrace.com | |

## Staging Services (live)

| Service | URL | Web root | vhost | Notes |
|---|---|---|---|---|
| Docs site | https://docs.staging.meowtrace.com | `/var/www/docs.staging.meowtrace.com/` | `sites-available/docs.staging.meowtrace.com` | Serves `projects/meowtrace/docs/*.md` with autoindex; `.md` served as `text/markdown` + `Access-Control-Allow-Origin: *` (CORS) so the viewer can fetch them. LE SSL, HTTP→HTTPS 301, expires 2026-10-17. |
| MD Viewer | https://viewer.staging.meowtrace.com | — | — | See [VIEWER-APP.md](./VIEWER-APP.md). |
| **API** | https://api.staging.meowtrace.com | — (reverse proxy) | `sites-available/api.staging.meowtrace.com` | **Reverse-proxies → Fastify `127.0.0.1:8080`** (systemd `meowtrace-api`). The Lookup API ([API.md](./API.md)). LE SSL, HTTP→HTTPS 301, expires 2026-10-18. Root `/` = 404 by design; use `/v1`, `/v1/lookup/:ip`. |
| **User Portal** | https://app.staging.meowtrace.com | `/var/www/app.staging.meowtrace.com/` | `sites-available/app.staging.meowtrace.com` | Static SPA root (`try_files … /index.html` for client routing). **Placeholder until Phase 5**; swap in the Vite build later. LE SSL. |
| **Admin Portal** | https://admin.staging.meowtrace.com | `/var/www/admin.staging.meowtrace.com/` | `sites-available/admin.staging.meowtrace.com` | Static SPA root. **Placeholder until Phase 5.** LE SSL. |
| **Marketing (www)** | https://www.staging.meowtrace.com | `/var/www/www.staging.meowtrace.com/` | `sites-available/www.staging.meowtrace.com` | Static site root. **Placeholder until Phase 5.** LE SSL. |

> **DNS:** `api` / `app` / `admin` / `www` `.staging.meowtrace.com` all resolve to the
> host (52.74.243.182). Existing `docs` + `viewer` vhosts were preserved (merge, not clobber).

### Staging subdomain routing (Phase 6 groundwork)

```
api.staging   → nginx (443, LE) → proxy_pass → 127.0.0.1:8080  (Fastify, systemd meowtrace-api)
app.staging   → nginx (443, LE) → /var/www/app.staging.…    (static SPA, Phase 5)
admin.staging → nginx (443, LE) → /var/www/admin.staging.…  (static SPA, Phase 5)
www.staging   → nginx (443, LE) → /var/www/www.staging.…    (static site, Phase 5)
```

### API service (systemd)

```bash
sudo systemctl status meowtrace-api     # unit: /etc/systemd/system/meowtrace-api.service
sudo journalctl -u meowtrace-api -f     # logs
sudo systemctl restart meowtrace-api    # after a backend code change
```

- **Runs:** `node --import tsx/esm src/server.ts` from `src/backend/` as user `ubuntu`,
  enabled at boot, `Restart=on-failure`.
- **Gotcha (learned):** nvm's Node is **not** on systemd's PATH — the unit sets an explicit
  `PATH` + absolute node, and uses `--import tsx/esm` (the `tsx` bin is not a directly
  loadable module). Env (incl. `MEOWTRACE_DSN` with the real password) lives in
  `/etc/meowtrace-api.env` (mode 600, root-only) — **never** the masked `***` literal.

### Redeploy docs (push updated markdown)
```bash
sudo cp projects/meowtrace/docs/*.md /var/www/docs.staging.meowtrace.com/
# static files only — no nginx reload needed
```

### Browse a doc rendered
`https://viewer.staging.meowtrace.com/?url=https://docs.staging.meowtrace.com/SPEC.md`

## Secrets & Config
- **`/etc/meowtrace-api.env`** (mode 600, root-only) — holds `MEOWTRACE_DSN` (real DB
  password), `PORT`, `HOST` for the API systemd service. Not in the repo. **Never** use
  the masked `***` placeholder as an actual password (it fails auth as a literal).
- _(TBD — API keys for geolocation providers, Stripe keys, etc. Never commit secrets.)_

## Backend & Data (Phase 1)

- **Stack:** PostgreSQL + TypeScript (Node) — see [SPEC.md §5](./SPEC.md#51-components).
- **Backend source:** `src/backend/` (Node + TS, `pg` driver). Scripts: `npm run import`,
  `npm run lookup`, `npm run benchmark` (via `tsx`).
- **Local DB:** `postgresql://meowtrace:***@127.0.0.1:5432/meowtrace` (dev password local-only;
  override with `MEOWTRACE_DSN`). Never commit real credentials.
- **Schema:** owned by the importer's atomic swap; reference DDL in `scripts/schema.sql`.
- **Import (Phase 1 verified):**
  ```bash
  cd src/backend && npm install
  npm run import -- --file /path/to/data.csv --dataset-version ip2location-2026-07
  npm run lookup -- 1.2.3.4        # IP -> country/region/city
  ```
- **Lookup API (Phase 2 verified):** Fastify server (`src/backend/src/server.ts`).
  ```bash
  cd src/backend
  MEOWTRACE_DSN='postgresql://meowtrace:<pw>@127.0.0.1:5432/meowtrace' PORT=8080 npm run serve
  curl http://127.0.0.1:8080/v1/lookup/1.2.3.4
  curl -XPOST http://127.0.0.1:8080/v1/lookup -H 'content-type: application/json' \
       -d '{"ips":["1.2.3.4","8.8.8.8"]}'
  ```
  Endpoints + error codes: [API.md](./API.md). **Never hardcode the DB password** —
  supply via `MEOWTRACE_DSN` (a masked `***` in a DSN will fail auth as a literal).

## Deployment Rules
- **Rule 1:** Always seek explicit approval before deploying builds. (See workspace `TOOLS.md`.)

---

## Changelog
- **2026-07-19** — DevOps notes initialized alongside project scaffold.
- **2026-07-19** — Docs moved into `docs/`; exposed live at `docs.staging.meowtrace.com` (nginx autoindex + CORS, Let's Encrypt SSL).
- **2026-07-20** — **Minimal v5.4.0 kit imported.** Extracted `Minimal_v5.4.0.zip` → `reference/` (read-only); duplicated a variant → `src/frontend/` as the frontend base. Provenance + layout recorded above.
- **2026-07-20** — **Stack ratified + Phase 1 built.** Frontend base swapped `next-ts` →
  **`vite-ts`** (React+Vite, no Next.js). **PostgreSQL 18.4** installed (apt, active); dev
  DB/role `meowtrace` created. Backend scaffolded at `src/backend/` (Node+TS): TS importer
  (COPY+atomic swap), lookup module+CLI, benchmark — all verified against the 306-row sample.
