# Customer Project Git Workflow

> Branching model, upstream sync, and deployment guide for customer projects built from the Pharmacy System Starter.

---

## Overview

Customer projects use a **three-branch model** that preserves the starter's git history, enabling clean merges in both directions:

```
starter/master ──────────────────────────────► (starter repo)
                  │
                  ▼
upstream ─────────────────────────────────────► (clean mirror of starter)
                  │
                  ▼
develop ──────── feature/* ── bugfix/* ──────► (staging / dev work)
                  │
                  ▼
main ─────────────────────────────────────────► (production)
```

| Branch     | Purpose                               | Deploy target | Direct commits? |
|------------|---------------------------------------|---------------|-----------------|
| `main`     | Production releases                   | Production    | No — PR only    |
| `develop`  | Active development & staging          | Staging       | No — PR only    |
| `upstream` | Clean tracking of the starter repo    | None          | Never           |

---

## Initialising a New Customer Project

### Prerequisites

1. **Fork** `pharmacy-system-starter` on Bitbucket (Repository > Fork). This creates a linked copy under the `mtcmedia` workspace (e.g. `mtcmedia/pharmacy-clientname`) with full git history preserved
2. Ensure SSH keys are configured for Bitbucket access

> **Why fork?** Bitbucket forks maintain a native relationship between the repos. This means cross-repo pull requests (for contributing fixes back to the starter) work out of the box, and you can see divergence in the Bitbucket UI.

### Setup Steps

```bash
# 1. Fork pharmacy-system-starter on Bitbucket
#    (Repository page > Fork > name it e.g. pharmacy-clientname)

# 2. Clone the fork
git clone git@bitbucket.org:mtcmedia/pharmacy-clientname.git ~/Code/pharmacy-clientname

# 3. Run the init script from inside the clone
cd ~/Code/pharmacy-clientname
./init-customer-project.sh

# 4. Set up Bitbucket branch permissions (see below)

# 5. Configure Envoyer for deployments (see below)

# 6. Create .env and run setup
cp .env.example .env
# Edit .env with customer details
sh setup.sh
```

The init script will:
- Add the starter repo as a `starter` remote
- Create `main`, `develop`, and `upstream` branches
- Record the starter origin in a `.starter-version` file
- Push all branches to the fork

---

## Bitbucket Repository Settings

### Default Branch

Set **`main`** as the default branch:

> Repository settings > Repository details > Main branch > `main`

### Branch Permissions

> Repository settings > Branch permissions > Add a branch permission

Set up the following rules:

#### 1. Protect `main` (production)

| Setting                           | Value                                  |
|-----------------------------------|----------------------------------------|
| Branch                            | `main`                                 |
| Write access                      | No one (or leads only)                 |
| Merge via pull request            | Checked                                |
| Minimum approvals                 | 1                                      |
| Merge checks — No incomplete tasks| Checked                                |
| Allow deleting this branch        | Unchecked                              |

#### 2. Protect `develop` (staging)

| Setting                           | Value                                  |
|-----------------------------------|----------------------------------------|
| Branch                            | `develop`                              |
| Write access                      | No one (or leads only)                 |
| Merge via pull request            | Checked                                |
| Minimum approvals                 | 1 (optional for smaller teams)         |
| Allow deleting this branch        | Unchecked                              |

#### 3. Lock `upstream` (starter tracking)

| Setting                           | Value                                  |
|-----------------------------------|----------------------------------------|
| Branch                            | `upstream`                             |
| Write access                      | Project lead only                      |
| Merge via pull request            | Not required (lead pushes directly)    |
| Allow deleting this branch        | Unchecked                              |

> **Why lock upstream?** This branch must only contain commits from the starter repo. If customer code gets committed here, future upstream merges will conflict unpredictably. Only the project lead should update it.

### Merge Strategy

> Repository settings > Merge strategies

Recommended defaults:
- **Default merge strategy**: Merge commit (preserves history, makes upstream merges cleaner)
- Allow: Merge commit, Squash
- Disallow: Fast-forward (prevents losing merge context)

---

## Day-to-Day Development Workflow

Development follows the same branching conventions as the starter's [internal workflow](./git_workflow_internal.md), but targeting `develop` instead of `master`:

```bash
# Start a new feature
git checkout develop
git pull origin develop
git checkout -b feature/your-feature-name
git push -u origin feature/your-feature-name

# Work, commit, push (stage specific files, not everything)
git add src/Feature.php tests/FeatureTest.php
git commit -m "feat: implement X feature"
git push

# When done — create a PR into develop on Bitbucket
```

### Releasing to Production

```bash
# Create a PR from develop → main on Bitbucket
# After review and approval, merge it
# Envoyer deploys main automatically
```

---

## Pulling Starter Updates (Upstream Sync)

When the starter repo receives updates (bug fixes, new features, security patches), pull them into the customer project:

### Step 1: Update the `upstream` branch

```bash
# Fetch latest from the starter
git fetch starter

# Switch to upstream and fast-forward
git checkout upstream
git merge starter/master

# Push the updated upstream branch
git push origin upstream
```

> This should always be a **fast-forward** merge. If it isn't, something was committed to `upstream` that shouldn't have been — investigate before continuing.

### Step 2: Merge into `develop`

```bash
# Switch to develop
git checkout develop
git pull origin develop

# Merge the updated upstream
git merge upstream
```

Resolve any conflicts. These will typically occur in files the customer project has customised (routes, config, templates). After resolving:

```bash
git push origin develop
```

Or, for traceability, create a PR: `upstream → develop`.

### Step 3: Test and release

Test the merged changes on staging. When ready, merge `develop → main` via PR as normal.

---

## Contributing Back to the Starter

When a customer project produces a fix or improvement that benefits all projects, contribute it back. Because customer projects are **Bitbucket forks**, cross-repo PRs are natively supported.

### Option A: Fork PR (preferred)

Since the customer repo is a fork of the starter, Bitbucket supports PRs back to the parent repo directly:

1. Create a feature branch in the customer project with the fix/improvement
2. Push it to the customer repo (`origin`)
3. On Bitbucket, create a **Pull Request** and select `mtcmedia/pharmacy-system-starter:master` as the destination
4. Review and merge as normal

> This is the simplest approach and works because the fork relationship gives Bitbucket the shared history needed to compute a clean diff.

### Option B: Cherry-pick (for isolated fixes when the branch has customer-specific changes mixed in)

```bash
# In the starter repo (or a clone of it)
cd ~/Code/pharmacy-system-starter

# Add the customer project as a temporary remote
git remote add clientname git@bitbucket.org:mtcmedia/pharmacy-clientname.git
git fetch clientname

# Cherry-pick the specific commit(s)
git checkout -b improvement/description-of-fix
git cherry-pick <commit-sha>

# Push and create a PR into master on the starter
git push -u origin improvement/description-of-fix
```

### Option C: Patch file (fallback)

```bash
# In the customer project, generate a patch
git format-patch upstream..feature/the-fix --stdout > fix-description.patch

# In the starter repo, apply it
cd ~/Code/pharmacy-system-starter
git checkout -b improvement/description-of-fix
git am < /path/to/fix-description.patch
git push -u origin improvement/description-of-fix
```

---

## Envoyer Deployment Setup

[Laravel Envoyer](https://envoyer.io) handles zero-downtime deployments from the Bitbucket repository.

### Creating a Project in Envoyer

1. **New Project** in Envoyer
2. **Type**: Other
3. **Provider**: Bitbucket
4. **Repository**: `mtcmedia/pharmacy-clientname`
5. **Branch**: `main` for production

For staging, create a **second Envoyer project** pointing at the same repo but deploying the `develop` branch.

### Server Configuration (Production — Main Domain)

For the main production site where the domain's document root is `public_html`:

1. In Envoyer, click **Configure** under manual configuration
2. Fill in server details:
   - **Name**: production (or a meaningful label)
   - **Hostname**: clientname.co.uk
   - **Port**: 22
   - **Connect As**: cPanel username
   - **PHP Version**: 8.4
   - **Receives Code Deployments**: ticked
   - **Project Path**: `/home/username/clientname.co.uk` (or wherever Envoyer should deploy releases)
3. Press **Save** and follow instructions to add the SSH key to `authorized_keys`
4. **Replace `public_html` with a symlink** to Envoyer's `current` link:

```bash
# SSH into the server
cd /home/username

# Back up and remove the existing document root
mv public_html public_html_backup

# Symlink to Envoyer's current release
ln -s /home/username/clientname.co.uk/current public_html
```

> This is the key trick — Apache/cPanel still serves from `public_html`, but it now points to whichever release Envoyer has activated. Zero-downtime deployments just update the `current` symlink.

### Server Configuration (Demo / Subdomain)

For demo or staging sites on a subdomain (e.g. `demo.clientname.mtcdevserver8.com`):

1. **Create the subdomain in cPanel**:
   - Domain: `demo.clientname.mtcdevserver8.com`
   - Document root: `demo.clientname.mtcdevserver8.com/public`

2. **Create a new project in Envoyer**:
   - Type: Other
   - Provider: Bitbucket
   - Repository: `mtcmedia/pharmacy-clientname`
   - Branch: the branch to deploy (e.g. `develop` or a feature branch)

3. **Configure the server** (click "Configure" under manual configuration):
   - Name: dev8 (or a meaningful label)
   - Hostname: clientname.mtcdevserver8.com
   - Port: 22
   - Connect As: cPanel username
   - PHP Version: 8.4
   - Receives Code Deployments: ticked
   - Project Path: `/home/username/demo.clientname.mtcdevserver8.com`
   - Press **Save** and add the SSH key to `authorized_keys`

4. **Set up linked directories/files** in the Deployment Hooks section (see below)

5. **Copy deployment hooks** from the parent/production project, edit as needed, and ensure they're set to run on the correct server

6. **Configure `.env`** via Envoyer's "Manage Environment":
   - Use staging database credentials
   - Set `APP_ENV=staging`, `APP_DEBUG=true`
   - Set SSL/Vite dev server variables if needed

7. **Run the first deployment** from Envoyer

### Deployment Hook (after install)

Add the following as an **"After" activation hook** in Envoyer:

```
cd {{release}}
sh deploy.sh --envoyer
```

The `--envoyer` flag tells `deploy.sh` to skip steps that Envoyer handles (Composer install, cron setup). The script still runs:
- Cache clearing and rebuilding
- Database migrations
- Frontend asset build (`npm install && npm run build`)
- Media manager asset publishing

### Environment Variables

In Envoyer's project settings, configure the `.env` via **Manage Environment**. This is managed by Envoyer and symlinked into each release — it won't be in the git repo.

Key variables to set:

```dotenv
APP_ENV=production
APP_DOMAIN=www.clientname.co.uk
APP_KEY=<generate with php artisan key:generate --show>

DB_DATABASE=clientname_live
DB_USERNAME=clientname_user
DB_PASSWORD=<secure password>
```

### Deployment Triggers

- **Auto-deploy on push to `main`**: Enable in Envoyer project settings. Envoyer provides a webhook URL — add it in Bitbucket under Repository settings > Webhooks.
- **Staging auto-deploy on push to `develop`**: Same process for the staging Envoyer project.

### Linked Directories & Files

In Envoyer's "Linked" settings, ensure these persist across releases:

| Type      | Path              | Reason                           |
|-----------|-------------------|----------------------------------|
| Directory | `storage`         | Logs, cache, sessions, uploads   |
| Directory | `uploads`         | Customer media uploads           |
| File      | `.env`            | Environment config               |

> `storage/` is gitignored — Envoyer's shared directory and symlink handles persistence. The `scripts/ensure-storage.php` Composer hook creates the directory structure on fresh installs (CI, local dev).

---

## Quick Reference

### Remotes

| Remote    | Points to                          | Used for                          |
|-----------|------------------------------------|------------------------------------|
| `origin`  | Customer fork on Bitbucket         | All development work               |
| `starter` | `pharmacy-system-starter` repo     | Pulling updates & contributing back|

### Common Commands

```bash
# Pull starter updates into upstream
git fetch starter && git checkout upstream && git merge starter/master && git push origin upstream

# Merge upstream into develop
git checkout develop && git merge upstream && git push origin develop

# Check which starter commits haven't been merged yet
git log develop..upstream --oneline
```

### Troubleshooting

**"upstream" merge isn't a fast-forward:**
Someone committed directly to the `upstream` branch. Reset it:
```bash
git checkout upstream
git reset --hard starter/master
git push --force-with-lease origin upstream
```

**Lost the `starter` remote:**
```bash
git remote add starter git@bitbucket.org:mtcmedia/pharmacy-system-starter.git
git config remote.starter.fetch "+refs/heads/master:refs/remotes/starter/master"
git fetch starter
```

**Merge conflicts during upstream sync:**
This is expected as the customer project diverges. Focus on:
- `routes/` — customer-specific routes
- `config/` — customer-specific config
- `resources/views/` — customised templates
- `sites/` — site-specific overrides

The `sites/` directory and any customer-specific modules should rarely conflict since they don't exist in the starter.
