# Deploy-on-VPS: the cron-based VPS deploy

**Since 2026-07-30 21:10 BST**, the VPS no longer receives paramiko file copies from
fvcms-deploy.mjs. Instead, each VPS site is a working git clone of its GitHub repo,
and a single cron line on the VPS iterates a JSON registry to snap each site to
`origin/main`.

## The 3 pieces

| File | Lives on | Purpose |
|---|---|---|
| `git-deploy-all.py` | `/usr/local/bin/` on each VPS | The deploy script. Iterates sites.json, fetches each vendor, resets the site |
| `sites.example.json` | `/etc/freshvibe/sites.json` on each VPS | The registry of sites + their vendors. Add a site = add a JSON line |
| `freshvibe-deploy.cron` | `/etc/cron.d/` on each VPS | One line: every 2 min, run the script. Add a new VPS = add this cron |

## Adding a new site

1. On the VPS: `git clone <repo> <path>` (e.g. `git clone https://github.com/avidtech6/freshcards.git /var/www/freshvibeapps/clients/freshcards`)
2. Edit `/etc/freshvibe/sites.json`, add:
   ```json
   "freshcards": {
     "path": "/var/www/freshvibeapps/clients/freshcards",
     "vendors": [
       {"name": "freshcards-bundle", "repo": "https://github.com/avidtech6/freshcards.git", "ref": "main"}
     ]
   }
   ```
3. Done. Within 2 min, the cron deploys the first time. From then on, every push to GitHub auto-deploys.

No cron edit. No script edit. Just the JSON.

## Multi-vendor per site

A site can vendor from multiple repos. For example, a future site that vendors both
freshvibe-cms AND FvRE:

```json
"future-school": {
  "path": "/var/www/freshvibeapps/clients/future-school",
  "vendors": [
    {
      "name": "site-code",
      "repo": "https://github.com/avidtech6/future-school.git",
      "ref": "main"
    },
    {
      "name": "fv-cms",
      "repo": "https://github.com/avidtech6/freshvibe-cms.git",
      "ref": "v0.8.0",
      "subpath": "runtime/"
    },
    {
      "name": "fv-re",
      "repo": "https://github.com/avidtech6/fv-reconstruction-engine.git",
      "ref": "v1.5.0",
      "subpath": "fv-re/"
    }
  ]
}
```

The script fetches each vendor at its pinned ref, then deploys them in order. The
`subpath` field is reserved for future per-vendor subpaths (currently the whole
vendor repo is reset into the site root).

## When does the deploy NOT work?

- **Repo is private and VPS has no credentials**: The fetch will fail. Add the
  VPS's SSH key as a collaborator on the GitHub repo, or use a deploy token.
- **Repo URL wrong**: The script logs `ERROR fetching <repo>`. Check sites.json.
- **Working tree has local changes**: `git reset --hard` will nuke them. The
  site path is meant to be a clean clone, not a working dir for editing.

## Verifying it works

```bash
# On the VPS:
/usr/local/bin/git-deploy-all.py 2>&1
# Should show: summary: N sites, deployed=0, skipped=0, no-change=N, error=0

# After a push to GitHub, wait 2 min, then:
tail -20 /var/log/freshvibe-deploy.log
# Should show: <site>/<vendor>: deployed <old-sha> -> <new-sha>
```

## The shape of the cron

```
*/2 * * * * root /usr/local/bin/git-deploy-all.py >> /var/log/freshvibe-deploy.log 2>&1
```

One line. Same on every VPS. Add more VPSes, copy the same cron line, no per-VPS
scripting.

## What happens to fvcms-deploy.mjs?

`fvcms-deploy.mjs` (in the parent dir) still does:
1. Verify the freshvibe-cms source is clean
2. Run fvcms-update-local to push CMS into the consumer site
3. Commit + push the consumer site to GitHub
4. Print a reminder that the VPS cron will deploy within 2 min

It does NOT do paramiko file copies anymore. That's gone.
