Skip to content
prod 352bb92
Browse

2 · Server sync — capture server changes

Objective — capture changes made on the server (admin-panel uploads, installer output, config) back into git before the next deploy silently wipes them — and do it without ever committing secrets.

A deployed app has two sources of truth that can drift apart: git (your code) and the server (files written after deploy — a logo uploaded through the admin panel, files the web installer generated, an admin config change). Your deploy pipeline clears and replaces the release directory on every deploy — so anything written outside the shared directories that git doesn’t know about gets erased on the next deploy.

The deploy keeps a small set of shared directories (notably storage/ and the .env file) that are symlinked into each release and survive every deploy — that’s why an uploaded logo under storage/app/public and the storage/installed marker persist on the server without ever being committed. Server sync is for the durable files that land outside those shared dirs (or for assets you want versioned in git): it pulls them back into git first, so the next deploy preserves them instead of destroying them — while leaving per-env state (storage/installed, public/storage, .env) on the server where it belongs.

Read Zaj-PROJECT.md before syncing. Use the environment matrix for the target row’s SSH alias, deploy path, branch/source, and DB/runtime facts. If you discover a changed SSH alias, deploy path, hosting account, runtime version, DB engine/collation, or capture scope, update Zaj-PROJECT.md before committing the sync.

Before reporting “SSH credentials missing,” inspect the operator’s existing machine config and reuse a matching alias instead of creating duplicate SSH entries:

Terminal window
grep -nE '^Host |HostName|User|Port|IdentityFile' ~/.ssh/config 2>/dev/null
SSH_ALIAS="<target-alias-from-Zaj-PROJECT>"
PHPBIN="<versioned-php-path-if-known-or-php>"
ssh -o BatchMode=yes -o ConnectTimeout=8 "$SSH_ALIAS" "pwd && $PHPBIN -v | head -1"
# Expected: exit 0; alias/host/user/port match the selected environment row
flowchart LR
A["Server writes file<br/>upload · installer · config"] --> B["Capture into git<br/>commit on production"]
B --> C["Review file list<br/>no secrets"]
C --> D["Merge to develop<br/>safe to deploy"]

The risk runs the other way too: server files can include .env, private keys, or logs with personal data. Capturing those into git would leak secrets — so every sync is review-first, never auto-merge.

For the command-only card, see the Server sync capture runbook.

Not every server change needs syncing. Match what changed against the table so you only capture real, durable files — and never sweep secrets in by accident.

  1. Match the change against the capture table.

    Change typeExampleCapture?
    Admin-panel uploadsLogo, favicon, images✅ Yes
    Web installer output (real files)Generated config, seeded assets✅ Yes
    Composer install on serverPackage installed on the server⚠️ Re-scan vendor first — see caution below
    Admin-panel configSMTP, payment keys⚠️ Maybe — .env.example updates only
    Installer marker (storage/installed)Proof the installer ran🔴 No — per-env runtime state, gitignored
    Per-env symlinks (public/storage, public/packages)storage:link output🔴 No — recreated per environment, gitignored
    .env, *.key, *.pem, logs with PIIServer secrets🔴 No — secrets, never captured
    • ✅ You’ve confirmed the change is a real, durable file worth keeping in git — not a per-env marker, symlink, or secret.

Two ways to capture: the GitHub Action does it for you (preferred), or you do it by hand over SSH. Either way, the server’s new files land as a commit on the production branch.

  1. Preferred — trigger the ServerSync GitHub Action. From the repository’s Actions tab, run the capture workflow (e.g. capture-production.yml) for the right environment. It SSHes in, captures the shared directories, and commits to production for you.

    • ✅ The workflow run finishes and a capture commit appears on production.
  2. Manual fallback — capture over SSH, screening for secrets first. Use this only if the Action isn’t available.

    Terminal window
    ssh [SSH_PRODUCTION_ALIAS]
    cd [DEPLOY_PATH]
    git status
    # Review the list. Three classes must NEVER be staged — abort the add if any appear:
    # secrets: .env *.key *.pem credentials logs-with-PII
    # per-env: storage/installed public/storage public/packages
    # untrusted: vendor/ (re-scan + composer reinstall first — see caution above)
    # Add ONLY the durable asset files you intend to capture (never a blanket `git add .`):
    git add [specific upload/asset paths]
    git status # re-confirm: no secret, no marker, no symlink, no vendor/ staged
    git commit -m "🔄 ⬛ T5 ServerSync-Upload: Capture [description]"
    git push origin production
    # Expected: only the intended asset files are committed and pushed on production
    • ✅ The captured files are committed on production; no secret, installer marker, per-env symlink, or unscanned vendor/ file is staged.

This is the human gate. A sync commit can include deletions caused by config drift, not just safe additions — so a person reads the file list before it merges anywhere.

  1. Pull the capture locally and inspect the file list.

    Terminal window
    git checkout production && git pull origin production
    git log --oneline -3
    git show --stat HEAD
    # Expected: the capture commit, and a file list of exactly what changed
    • ✅ Every captured file is an intentional ADDED/MODIFIED asset — no surprise DELETED files, no secrets.

If you see DELETED files you didn’t expect, that’s drift between the deploy config’s clear_paths and the sync workflow’s GIT_ONLY_PATHS — fix the symmetry before trusting another sync, rather than committing the deletions.

Once reviewed, fold the capture into develop so your everyday branch carries the server’s truth and the next ship doesn’t reintroduce the drift.

  1. Merge production into develop and push.

    Terminal window
    git checkout develop && git merge production && git push origin develop
    # Expected: develop now contains the captured server files
    • develop carries the captured changes; you can resume normal development and ship when ready.

Do not mark this step done until every box below is checked.

  • 👤 Worth capturing — the change is a durable server file (upload / installer output / config), not noise.
  • 🤖 No secrets staged — no .env, *.key, *.pem, logs, or credentials in the commit.
  • 🤖 No per-env state staged — no storage/installed marker, public/storage, or public/packages symlinks captured (they stay on the server, gitignored).
  • 🤖 No unscanned vendor/ — if the server ran composer install, vendor/ was re-scanned + composer reinstalled before any of it entered git.
  • 🤖 Committed on production — captured via the GitHub Action or manual SSH, with a T5 ServerSync message.
  • 👤 File list reviewed — inspected git show --stat; no unexpected DELETED files; not auto-merged.
  • 🤖 Merged to developproduction folded back into develop and pushed.