CI/CD and Deployment: How We Ship Without Drama

Our pragmatic deployment pipeline — GitHub Actions, a VPS, and boring releases. What we automate, what we keep manual, and why the best deploy is the one nobody notices.

CI/CD and Deployment: How We Ship Without Drama

The best deploy is the one nobody notices. No downtime window, no "it works on my machine", no 2 AM rollback. That's the standard we hold every SrcTeam project to, and it doesn't require a fancy platform — just a pipeline that's boring on purpose.

The pipeline in one paragraph

Push to master → GitHub Actions runs the build → artifacts are synced to the VPS over SSH → post-deploy steps run (migrations, cache rebuild) → the app process restarts. Total time: about two minutes, fully unattended.

What we automate

  • Tests and linting on every pull request — broken code never reaches master.
  • The build — frontend assets compiled, dependencies installed, on a clean runner.
  • The syncrsync with --delete, so removed files don't linger on the server.
  • Post-deploy stepsoptimize:clear, migrate --force, and cache rebuilds, run in order.
  • The restart — the SSR process is bounced so the new build is live immediately.

A minimal workflow looks like this:

name: deploy
on:
  push:
    branches: [master]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - run: |
          rsync -az --delete --exclude '.env' \
            ./dist/ deploy@server:/var/www/app/
      - run: ssh deploy@server 'php artisan migrate --force && php artisan optimize'

What stays manual

Automation is a tool, not a religion. Three things are deliberately human:

  • Secrets.env never enters the repository. It lives on the server, excluded from every sync.
  • Risky migrations — a migration that rewrites a large table gets a review and a maintenance window, not an automatic run.
  • The rollback plangit revert + push is the fastest way back, and it's rehearsed, not improvised.

Why a VPS instead of a managed PaaS

Managed platforms are convenient until they aren't — vendor lock-in, surprise pricing, and a ceiling on what you can tune. A plain VPS with SSH, rsync, and a process manager covers 90% of real-world apps with full control and predictable cost. Docker is an option when isolation matters, but for many projects it's unnecessary complexity: a systemd unit and a synced directory are enough.

Rules we keep

  • Deploy from master only — no ad-hoc server edits.
  • Small, descriptive commits; the changelog is the git log.
  • A health check after every deploy — the pipeline isn't done until the site answers.
  • If a deploy breaks, revert first, debug second.

A good pipeline doesn't make shipping exciting. It makes shipping safe — and that's exactly the point. When deploying is boring, your team spends its energy on the product, not on firefighting.