# Production start — day 1

Do these steps in order. Full reference: [CNPERP_HETZNER_CLOUD_DEPLOYMENT.md](../CNPERP_HETZNER_CLOUD_DEPLOYMENT.md)

## Step 1 — Create the Hetzner server (10 min)

1. [Hetzner Cloud Console](https://console.hetzner.cloud/) → **Add Server**
2. **Ubuntu 24.04**
3. **CPX31** (4 vCPU, 8 GB) — recommended
4. Location: **Helsinki** or **Falkenstein**
5. Add your **SSH public key**
6. **Enable backups**
7. Create firewall: allow **22, 80, 443** only
8. Note the **IPv4 address** (e.g. `95.217.x.x`)

## Step 2 — DNS (5 min + propagation)

**Interim:** only the ERP hostname is required.

| Type | Name | Value |
|------|------|--------|
| A | `erp` | Your server IPv4 |

Optional later: `@` and `www` → same IP (Caddy redirects apex to `erp.*`).

## Step 3 — Push latest code to GitHub

From your dev PC (PowerShell):

```powershell
cd c:\dev\cnperp-dimensions
git add deploy/ app/  # production + security files
git commit -m "chore: production bootstrap and security hardening for Hetzner"
git push origin main
```

## Step 4 — Bootstrap from Windows

```powershell
cd c:\dev\cnperp-dimensions
copy deploy\hetzner\production.local.example.ps1 deploy\hetzner\production.local.ps1
notepad deploy\hetzner\production.local.ps1
# Fill: ServerIp, DbPassword
```

**Private GitHub repo** — if clone fails with *Invalid username or token*, either:

1. Create a new [GitHub PAT](https://github.com/settings/tokens) (read access to `cnperpdimensions`) and set `$GitHubToken` in `production.local.ps1`, then run the script again, **or**
2. Upload code from your PC (no token):

```powershell
.\deploy\hetzner\Start-HetznerProduction.ps1 -UseLocalCode
```

You will be prompted for your SSH key passphrase several times (or run `ssh-add` once first).

Save the **LICENSE_ADMIN_SECRET** printed at the end.

## Step 5 — First setup in browser

1. Wait for DNS (check: `ping erp.cnpsolutions.co.bw` → your server IP)
2. Open **https://erp.cnpsolutions.co.bw/setup**
3. Complete company setup with a valid license key
4. Open **https://erp.cnpsolutions.co.bw/** → CNP Solutions **landing page**
5. From there use **ERP Login** → `/static/login.html` or **Setup** → `/setup`

## Step 6 — Enable in-app updates (if server was deployed via SCP/tarball)

If **Settings → Software Updates** shows “Git is not installed” or cannot pull:

```powershell
cd c:\dev\cnperp-dimensions\deploy\hetzner
# Optional: set $GitHubToken in production.local.ps1 for a private repo
.\Setup-GitUpdatesOnProduction.ps1
```

This initializes git in `/opt/cnperp`, configures `cnperp` user credentials, and allows passwordless `systemctl restart cnperp` for `deploy/auto_update.sh`.

## Step 7 — Smoke test

- [ ] Login works (username/password, no branch dropdown)
- [ ] Session bar shows user + branch
- [ ] Settings → Software Updates → Check for updates
- [ ] `/docs` returns 404

## Platform admin (God Mode)

Operator-only portal — **not linked** from the marketing site.

1. Set in `/opt/cnperp/.env`:
   - `PLATFORM_ADMIN_SECRET=` (long random string), or reuse `LICENSE_ADMIN_SECRET`
2. Open: **https://erp.cnpsolutions.co.bw/platform-admin**
3. Sign in with that secret — manage all companies, licenses, passwords, impersonate users, and trigger git updates.
4. Use the **Help** tab (or top-bar **? Help**) for call-center playbooks, licensing model, and troubleshooting scripts.

Platform JWTs cannot call tenant APIs; tenant tokens cannot call `/api/v1/platform/*`.

**Full operator handbook** (support login `cnpadmin`, customer cloud login, licensing, branch transfers):  
→ [CNP_OPERATIONS_AND_SUPPORT.md](../CNP_OPERATIONS_AND_SUPPORT.md)

## CNP field-support login (inside customer ERP)

For fixing a tenant on-site or online — use the **normal login page**, not God Mode:

1. Type **company code** + **branch code** (Verify optional)
2. Username: `cnpadmin` / Password: `cnpadmin90210` (change via `CNP_SUPPORT_PASSWORD` in production)
3. Full super_admin in that company/branch — create users, transfer branches, fix data

See [CNP_OPERATIONS_AND_SUPPORT.md](../CNP_OPERATIONS_AND_SUPPORT.md) §2 for step-by-step instructions.

## If something fails

```bash
ssh root@YOUR_IP
journalctl -u cnperp -n 80 --no-pager
journalctl -u caddy -n 30 --no-pager
```
