Development guide · v1

How we ship Setcon software

A practical walkthrough of our Git Flow process — the same on every Setcon repository, from the controller HMI to the cloud EMS platform. From your first pull on Monday morning to tagging a release. New to collaborative dev? Start at the top and follow it through.

The big picture

Three layers of branches. Everyone agrees on which layer their work belongs in.

main dev feature/* v0.3 v0.4 v0.5 feature/dispatch-opt fix/login-loop feature/alarms-ui release PR release PR
Three lanes. Features land on dev. Periodically dev is promoted to main with a tag.
Branch
main
What's running in the field. Updated only by release PRs from dev. Tagged per version.
Branch
dev
The integration line. Where features land after review and before they hit production.
Branch
feature/<topic>
Your working branch. Branch off dev, merge back into dev via PR.

Why this way?

Our software runs in places where breakage is expensive — on customer controllers in the field, on cloud EMS servers that customers depend on, on industrial panels that are hard to reach. We can't just push to a single line and hope. We need an integration playground separate from what's deployed to production. Hence two protected lines: main for what's running, dev for what's next.

The model applies whether you're working on:

  • Controller code — the CODESYS / Node.js firmware that runs on customer-deployed energy controllers
  • Cloud platforms — the EMS, monitoring, or customer-facing services hosted on Setcon servers
  • Internal tools — commissioning utilities, diagnostic tools, brand assets, anything else under version control
The mental shift

You're not "pushing code to the project." You're proposing changes via PRs. Code only becomes real once a teammate has reviewed it and CI has confirmed it works. This is the safety net that makes shipping to production survivable — whether production is a remote controller or a cloud server.

Before you start

One-time setup. Each row links to a detailed guide in the Setup guides section below.

WhatWhySetup
GitHub account So you can be added to the setcon-za org and own your PRs. Create account →
Org membership Without it, you can't see the repo. Ask the project lead. Get invited →
Git + Git Bash The command-line client that talks to GitHub. Git Bash gives you a Unix-style terminal on Windows. Install Git →
Git identity Stamps your name + email on each commit so reviewers know who did what. Configure →
GitHub auth (PAT) A personal access token so Git can push on your behalf. Stored once via Credential Manager. Set up auth →
Node.js 20+ Required to run the HMI locally and let CI mirror your machine. Install Node →
Clone the repo Brings the project onto your local disk so you can work on it. Clone →
Claude Code Your AI pair-programmer. Reads project context from CLAUDE.md and helps you build. Install Claude →
Estimated time

About 45 minutes for a clean machine. Most of it is waiting on installers. Do it once and you're set.

First-time setup

The actual sequence we walk new teammates through — sitting next to them at their machine. Each step has a checkpoint; pause and verify before moving on.

Commands shown in PowerShell (Windows default). They all work in Git Bash too, with slightly different path syntax (/c/Users/<you> instead of C:\Users\<you>).

  1. Pre-flight: what's already installed?

    Open PowerShell (Win + R → type powershell → Enter):

    git --version       # expect git version 2.x
    node --version      # expect v20.x or later

    If either says "not recognized", install it before going further:

    Re-run the checks above before continuing.

  2. Configure your git identity

    So every commit you make is stamped with your name and links to your GitHub profile:

    git config --global user.name "Your Full Name"
    git config --global user.email "your-github-email@example.com"

    Use the email associated with your GitHub account. Verify:

    git config --global --list

    Should show user.name=... and user.email=... among the output.

  3. Generate a Personal Access Token (PAT)

    GitHub's password replacement for command-line operations. Created once, stored by Windows Credential Manager after first use.

    1. Sign in to GitHub in any browser
    2. Visit github.com/settings/tokensPersonal access tokens (classic)Generate new token (classic)
    3. Fill in:
      • Note: setcon-<your-laptop>
      • Expiration: 90 days
      • Scopes: tick repo (full control of private repos)
    4. Click Generate tokencopy it immediately (GitHub only shows it once)
    5. Paste it somewhere temporary (Notepad is fine) until step 4 below
    If you lose the token

    Don't panic — just regenerate. The old one is invalidated automatically. Tokens are disposable.

  4. Pick a projects folder and clone the repo

    Decide where you'll keep Setcon projects. Common choice: C:\Users\<you>\projects\.

    # Create the folder if it doesn't exist
    mkdir C:\Users\<you>\projects -Force
    cd C:\Users\<you>\projects
    
    # Clone (replace <repo> with the actual repo name)
    git clone https://github.com/setcon-za/<repo>.git
    cd <repo>
    git checkout dev

    The clone triggers an authentication prompt — a Windows dialog pops up. Pick the Token option, enter your GitHub username, paste the PAT as the password. Credential Manager remembers it after that.

    Verify:

    git status            # expect "On branch dev"
    git log --oneline -5  # expect a list of recent commits
  5. Install dependencies

    npm install

    Pulls down node_modules for every workspace. Takes 1–2 minutes. Expect output like "added 200+ packages, 0 vulnerabilities".

  6. Smoke-test by running the project

    Each repo has its own dev / build commands. For the controller HMI:

    npm run dev -w packages/frontend

    Vite starts and prints Local: http://localhost:5173/. Open that URL in your browser — you should see the HMI render with the dark theme. If yes, your environment is fully working.

    Press Ctrl+C in PowerShell to stop the server.

    Port already in use?

    If 5173 is busy (someone else on the same machine, or a previous session that didn't exit cleanly), Vite automatically picks 5174. That's normal — just visit the URL it prints.

  7. Open the workflow guide

    In File Explorer, navigate to your cloned repo → docs\workflow-guide.html → double-click. Opens in your default browser.

    Skim the Daily workflow section — that's the loop you'll run for every change going forward.

  8. Your "Hello PR"

    The single best way to internalise the workflow: do it once with a tiny, real change. Suggestions:

    • Fix a typo you spot in any doc
    • Add your name to a CONTRIBUTORS.md
    • Tighten an unclear comment in code you read

    Then follow the standard PR loop:

    git checkout dev
    git pull
    git checkout -b fix/<short-description>
    # make your change in an editor, save
    git add <the-file>
    git commit -m "fix: <short-description>"
    git push -u origin fix/<short-description>

    Open the PR via the URL git prints. A teammate reviews + approves. You squash-merge + delete the branch. Pull dev locally.

    You're now a contributor. From here, every change follows that same loop.

Per-repo, not per-machine

Steps 4–7 above apply to each repo you'll work on (controller, EMS platform, etc). Clone the repo, install dependencies, smoke-test. Your git identity + PAT from steps 2–3 are global and don't need to be redone.

Daily workflow

The loop you'll repeat hundreds of times. Five moves.

1. Sync git pull on dev 2. Branch feature/your-topic 3. Commit + push small, focused 4. Open PR base = dev 5. Review + merge CI green → squash next task
The PR-driven loop. Same five steps regardless of branch type.
  1. Sync with the latest dev

    Pulls down anything teammates have merged since you last worked.

    # Morning ritual — never skip this
    git checkout dev
    git pull

    Why: branching off a stale dev means you'll probably hit merge conflicts later. 30 seconds now saves 30 minutes on Friday afternoon.

  2. Branch off dev with a descriptive name

    Pick a prefix matching the kind of change you're making.

    PrefixWhenExample
    feature/New functionalityfeature/dispatch-optimisation
    fix/Bug fixfix/login-redirect-loop
    refactor/Restructure, no behaviour changerefactor/extract-shared-charts
    chore/Tooling, deps, configchore/upgrade-vite-7
    docs/Documentation onlydocs/add-onboarding-guide
    git checkout -b feature/<your-topic>

    Your terminal prompt should change to show the new branch in parentheses.

    Git Bash terminal showing checkout dev, pull, checkout -b feature branch, add file, and git status with the new file staged
    FIG 1Real terminal: sync dev, branch off, stage a new file
  3. Code, commit, push — small chunks

    Commit every time you finish a coherent slice of work. Don't wait until the whole feature is done. One concept per commit.

    # Stage just the files you intend to commit
    git add path/to/changed-file.ts
    
    # Commit with a conventional message
    git commit -m "feat: Add <short description of what this adds>"
    
    # First push needs -u to set up tracking; after that just `git push`
    git push -u origin feature/<your-topic>
    Conventional commits

    Subject ≤ 70 chars. Start with one of: feat:, fix:, chore:, refactor:, docs:, ci:, test:, perf:. Imperative mood ("Add", not "Added"). Body explains why, not what.

    Git Bash terminal showing git commit followed by git push -u origin, with the new branch created on GitHub and the URL to create a pull request printed at the end
    FIG 2After push: GitHub prints the PR creation URL you click next
  4. Open a PR targeting dev

    Once your feature is in a reviewable state, push your final commits and open the pull request. The push output prints a URL — click it.

    git push
    # → https://github.com/setcon-za/<repo>/pull/new/feature/<your-topic>

    On the PR form, confirm base = dev and fill in:

    • Title: same conventional format (e.g. feat: Add <short description>)
    • What changed — 1–2 sentences
    • Why — the user-facing reason
    • How to verify — steps to test locally
    • Screenshots for any UI change

    Click Create pull request.

    GitHub Comparing changes page showing base = dev, compare = feature branch, the title field, and the description with What changed / Why / How to verify sections
    FIG 3The PR creation form — confirm base = dev before clicking create
  5. Wait for CI + review, address feedback, merge

    Within ~30 seconds, the project's CI checks kick off (typically a build + tests; each repo defines its own in .github/workflows/). While they run, a teammate picks up the review.

    • CI running   Yellow dot — build / tests in progress
    • CI passed   Green check — all checks satisfied
    • CI failed   Red x — fix the issue, push again, CI re-runs

    The merge box on the PR is your status dashboard. Here's what it looks like right after the PR opens — review block, CI still queued, the merge button greyed out:

    GitHub PR merge box showing Review required (red X), Some checks haven't completed yet (yellow dot with queued build), Merging is blocked, the bypass checkbox, and the greyed-out Squash and merge button
    FIG 4Composite status: review block + CI queued + merge greyed out

    ~17 seconds later the build finishes. The CI section turns green but the review requirement still blocks — protection working exactly as designed:

    GitHub PR merge box showing Review required still blocking, All checks have passed with green tick and Successful in 17s, Merging is still blocked
    FIG 5CI green ≠ merge unlocked. Review requirement still blocks.

    Once you have an approval (or, while working solo, you tick the bypass option), the squash-merge button activates. Confirm the squash message and merge. GitHub immediately shows the merged state:

    GitHub PR conversation showing the merged commit and a purple Pull request successfully merged and closed banner with a Delete branch button
    FIG 6Merged. Click Delete branch to clean up the remote.

    Then locally:

    git checkout dev
    git pull
    git branch -D feature/<your-topic>

    Your dev fast-forwards to the squashed merge commit, and your local feature branch is gone. The new commit is visible at the top of git log alongside every other merged PR:

    Git Bash terminal showing checkout dev, pull fast-forwarding to the new merge, branch deletion, clean working tree, and a git log oneline showing the last 5 commits in conventional-commit format
    FIG 7Back on a clean dev. The history reads like a changelog.

    You're back at the start of the loop. Time for the next task.

Code review

The single most important part of a team workflow. Two angles — the author and the reviewer.

As the author
Make it easy to review
  • Keep PRs < 400 lines
  • Write a clear description with screenshots
  • Self-review your diff before requesting review
  • Respond to comments as new commits — don't force-push
As the reviewer
Review like you mean it
  • Does the code do what the description says?
  • Does it follow this project's conventions (CLAUDE.md + docs/)?
  • Are types / inputs tight? No unjustified any / unchecked inputs?
  • Did any affected docs stay accurate?
  • For UI changes: does it work at the target form factor (panel / desktop / mobile)?

How to leave a review on GitHub

  1. Open the PR → Files changed tab
  2. Hover the gutter on any line → click the + icon → leave a comment
  3. For "change this to that" feedback, use a suggestion block (the ± icon) — the author can apply it with one click
  4. When done, click Review changes at the top right
  5. Choose: Approve, Comment (questions only, no block), or Request changes (block until addressed)
Don't sit on PRs

Aim to review within 24 hours. If a PR sits open longer than that, merge conflicts pile up and momentum dies. If you can't review fully, leave a quick comment so the author knows you've seen it.

Merge conflicts

What happens when two PRs touch the same lines. Sounds scary the first time. It's fine.

The scenario

You and a teammate both edited the same file on different branches. They merged first. Your PR now shows a red banner: "This branch has conflicts that must be resolved."

Resolving locally

# 1. Switch to your branch and pull the latest dev into it
git checkout feature/your-thing
git fetch origin
git merge origin/dev

# 2. Git tells you which files conflict — open them in your editor
#    You'll see <<<<<<< HEAD ... ======= ... >>>>>>> origin/dev
#    markers around the conflicting regions.

# 3. Edit each conflict to keep the correct final code. Delete the markers.

# 4. Stage the resolved files and finish the merge
git add path/to/resolved-file
git commit -m "chore: Resolve merge with dev"

# 5. Push — the PR auto-updates and CI re-runs
git push
Long branches need maintenance

If your feature branch lives for more than a day or two, periodically pull dev into it (steps 1–2 above) before conflicts pile up. Resolving one day of drift is easy. A week of drift is painful.

Working with Claude Code

Claude Code is an AI pair-programmer that lives in your terminal. It reads the repo, edits files, runs builds, and commits — like another developer on your team.

You on feature branch Claude Code reads CLAUDE.md edits files runs builds + commits Your repo local working tree + branch state "Add X feature" edits + commits you review the diff before opening a PR
Claude operates inside your branch. You stay in control of what gets pushed.

The rules of engagement

  • Open Claude Code from your feature/<topic> branch. Claude commits to whatever branch you're on. Never run it from dev or main directly.
  • Claude reads CLAUDE.md automatically. That file is the project-wide context — domain glossary, file map, conventions. Keep it accurate.
  • Review every diff before pushing. Claude is fast and usually right, but it doesn't know everything. git diff before git push is your safety net.
  • If Claude proposes something against convention, push back. The convention wins. Tell Claude what's wrong and ask it to retry.

Good things to ask Claude for

Boilerplate
New module scaffold
"Add a new module / screen / endpoint at <path> following the same pattern as <existing file>."
Refactor
Extract shared logic
"This logic appears in three places — extract it into a shared utility / component."
Investigate
Trace a behavior
"Where does X get decided? Trace the call path from user action to final state."
Doc
Update CLAUDE.md
"I added a new concept <name>. Update the domain glossary and any docs that reference the affected area."
Multiple devs, multiple Claudes

Each developer runs their own Claude session on their own feature branch. They never collide because each branch is isolated until PR time. The review + CI pipeline catches anything Claude got wrong on any branch.

Releases

The rare moment when dev gets promoted to main and a customer-deployable version is born.

When to release

  • A logical group of features is complete on dev
  • Integration testing passed
  • A customer deployment is planned (or you want a clean checkpoint)

The release process

  1. Confirm dev is shippable

    Pull the latest dev, run a clean build, do a smoke test of the project locally.

    git checkout dev
    git pull
    # Then run the project's build + local smoke test
    # (each repo has its own commands — see its README)
  2. Open the release PR: dev → main

    On GitHub, set base = main, compare = dev. Title: Release v0.4 — <theme>. Description is the changelog — group commits by feat:, fix:, refactor:, etc.

  3. Get approval + merge

    Use Merge commit here, not Squash — preserves the dev history on main so an engineer can later trace which feature PR added what.

  4. Tag the merge commit

    git checkout main
    git pull
    git tag -a v0.4-<theme> -m "Release v0.4 — short summary"
    git push --tags

    On GitHub: Releases → Draft a new release → pick the tag → write release notes → publish.

  5. Deploy the tag to production

    Deploy the tagged version to whatever production target this repo serves — customer controller hardware, cloud server, internal panel, etc. The tag name is your reference point: if a bug is reported later, check out that tag to reproduce the exact deployed state.

Hotfixes (the rare exception)

Production (a customer controller, a cloud service, etc.) is on v0.4 and a critical bug surfaces. You can't wait for the next normal release cycle. Branch off main, fix, ship, then back-port to dev.

main dev hotfix/* v0.4 v0.4.1 hotfix/<fix> back-merge to dev
Hotfix branches off main, lands back on main + dev.
# 1. Branch off main (NOT dev)
git checkout main
git pull
git checkout -b hotfix/<short-description>

# 2. Fix the bug, commit
git commit -m "fix: <what the fix does>"

# 3. Push and open a PR targeting main (not dev)
git push -u origin hotfix/<short-description>

After the PR merges to main:

  • Tag the new release (e.g. v0.4.1)
  • Also open a PR merging main back into dev so the fix doesn't get lost when dev next releases
  • Deploy v0.4.1 to the affected customer
When NOT to hotfix

If the bug isn't actively burning a customer, just fix it as a normal fix/ branch off dev and let it ride the next release. Hotfixes bypass the integration testing on dev; only worth that risk for genuine emergencies.

Setup guides

One-time setup steps, each as a collapsible block. Work through them in order on a new machine.

Create a GitHub account
  1. Go to github.com/signup
  2. Use your Setcon work email if you have one — easier to manage org membership
  3. Pick a username that's recognisable to teammates (your real name or a clear handle)
  4. Enable 2-factor authentication — this is required for any org with a security policy, and we'll enforce it on setcon-za
Get added to the setcon-za GitHub org

Ask the project lead (currently Jaco) to invite you:

  1. Send them your GitHub username
  2. They'll go to setcon-za org → People → Invite member
  3. You'll receive an email with an invite link — click it and accept
  4. Once in the org, you'll be added to the repos relevant to your work (controller, EMS platform, etc.) with at least Write access
If you can't see a repo

Visit github.com/setcon-za after accepting the invite. If a repo you expect to see is missing or returns 404, your access wasn't granted — ask the lead.

Install Git + Git Bash (Windows)
  1. Download from git-scm.com/download/win
  2. Run the installer. Recommended settings:
    • Default editor: pick whatever you'll edit commit messages in (VS Code, Notepad++, vim)
    • Branch name: "Override the default to main"
    • PATH: "Git from the command line and 3rd-party software" (default)
    • HTTPS: "Use the OpenSSL library" (default)
    • Credential helper: "Git Credential Manager" — this is what lets you authenticate to GitHub without typing a password every push
    • Everything else: defaults
  3. After install, open Git Bash (it's a new entry in your start menu)
  4. Verify: git --version should print something like git version 2.45.1.windows.1
Configure your Git identity

Stamps your name + email on every commit you make. Use the email associated with your GitHub account — that's what links commits to your GitHub profile.

git config --global user.name "Your Name"
git config --global user.email "you@example.com"

Verify with:

git config --global --list
Wrong email?

If your first commit shows up under a placeholder like Jacoj@solareff.local, you forgot this step. Set it now — it'll apply to all future commits. (Old commits stay under the old identity; not worth fixing unless they're public.)

Set up GitHub authentication (Personal Access Token)

For pushing to GitHub from the command line. Git Credential Manager (installed with Git for Windows) handles storing it — you only enter the token once.

  1. Go to github.com/settings/tokensPersonal access tokens (classic) → Generate new token
  2. Name it something like setcon-laptop (one token per machine is the usual approach)
  3. Expiration: 90 days (you'll re-generate periodically)
  4. Scopes: tick repo (full control of private repos)
  5. Click Generate token and copy the value (you only see it once)
  6. The next time you git push a Git Bash window will pop up asking for credentials — enter your GitHub username and paste the token as the password. Credential Manager remembers it.
Alternative: SSH keys

If you prefer SSH over HTTPS+PAT, follow GitHub's SSH key setup guide — slightly more setup but no token expiry. For a brand-new developer, PAT is faster to get going.

Install Node.js 20+
  1. Download the LTS version from nodejs.org — currently Node 20 or 22 (either works)
  2. Run the installer with default options
  3. Open Git Bash and verify:
    node --version   # should print v20.x.x or v22.x.x
    npm --version    # should print 10.x.x
Clone a repository

Brings any Setcon project onto your local disk. Repeat for each repo you'll work on (e.g. setcon-controller, ems-platform, etc.).

  1. Open Git Bash. cd to wherever you keep your projects:
    cd "/c/Users/you/projects"
  2. Clone the repo (replace <repo> with the actual repo name):
    git clone https://github.com/setcon-za/<repo>.git
    cd <repo>
  3. The first git clone triggers the auth prompt — enter your GitHub username + the PAT you generated earlier
  4. Switch to dev (the integration branch) before you start work:
    git checkout dev
  5. Follow the project's README.md for project-specific install + run instructions (every Setcon repo has one at the root). Typical pattern for Node projects:
    npm install
    npm run dev
First time per repo

The cadence applies per-repo, not per-machine. Every new repo you join needs its own clone + dependency install.

Install Claude Code

Claude Code is a CLI that brings the Claude AI into your local dev loop. It reads your files, edits them, and commits to your branch.

  1. Sign up for an Anthropic account at console.anthropic.com
  2. Install Claude Code from docs.anthropic.com/en/docs/claude-code — follow the platform-specific install steps for Windows
  3. Authenticate when prompted (sign in via browser)
  4. Open Git Bash and cd into whichever Setcon repo you'll work in
  5. Make sure you're on a feature branch (not dev or main):
    git checkout -b feature/my-first-task
  6. Launch Claude Code:
    claude
  7. Claude will read CLAUDE.md automatically and be ready for your first prompt
Suggested first prompt

"Read CLAUDE.md and tell me back in 5 bullet points what this project does and what conventions you'll follow."

This verifies Claude is loading the project context correctly before you start asking for real changes.

(Optional) Install the GitHub CLI

Lets you open PRs from the terminal instead of clicking through the GitHub web UI. Convenient but not required.

  1. Install from cli.github.com
  2. Authenticate:
    gh auth login
    Pick GitHub.com → HTTPS → "Yes, authenticate Git" → "Login with web browser" and follow the prompts.
  3. Now you can do gh pr create --base dev to open a PR without leaving the terminal.

Abbreviations

A quick reference for all the abbreviations used in this guide — useful if you are reading this for the first time.

AbbreviationStands forWhat it means in context
PRPull RequestA proposed change submitted on GitHub for review before merging into a branch.
CIContinuous IntegrationAutomated checks (build + tests) that run on every PR to catch problems early.
PATPersonal Access TokenA GitHub-generated password replacement used to authenticate Git from the command line.
HMIHuman Machine InterfaceThe on-site operator screen on a Setcon controller — what the customer sees and touches.
EMSEnergy Management SystemThe Setcon cloud platform for monitoring and controlling energy assets remotely.
LTSLong Term SupportA stable, long-supported release of software (e.g. Node.js LTS). Recommended over cutting-edge versions for reliability.
CLICommand-Line InterfaceA text-based terminal tool — Git, npm, and Claude Code are all CLI tools.
HTTPSHyperText Transfer Protocol SecureThe secure web protocol used to connect to GitHub. Used when cloning with a PAT.
SSHSecure ShellAn alternative to HTTPS for authenticating to GitHub using a cryptographic key pair.
2FATwo-Factor AuthenticationA login security method requiring a second form of verification (e.g. an app code) in addition to your password.
npmNode Package ManagerThe tool used to install JavaScript dependencies for a project (npm install, npm run dev).
AIArtificial IntelligenceRefers to Claude Code — the AI pair-programmer used in the Setcon workflow.
VS CodeVisual Studio CodeA popular free code editor by Microsoft. Recommended for editing files in Setcon projects.
URLUniform Resource LocatorA web address — e.g. the link GitHub prints after a push to create a PR.
WIPWork In ProgressA branch or PR that is not yet ready for review. Prefix the PR title with [WIP] to signal this.

Quick reference

Print this page or pin the section. The 10 commands that cover 95% of your day.

WhatCommand
Sync devgit checkout dev && git pull
Start a new taskgit checkout -b feature/<topic>
Stage changesgit add <file>
Commitgit commit -m "feat: ..."
Push (first time on branch)git push -u origin <branch>
Push (subsequent)git push
See branch stategit status
See recent commitsgit log --oneline -10
Pull dev into your branchgit fetch && git merge origin/dev
Delete a merged branch locallygit branch -D <branch>

Conventional commit prefixes

feat:A new feature
fix:A bug fix
refactor:Restructure without behaviour change
chore:Tooling, deps, config
docs:Documentation only
ci:CI / GitHub Actions changes
test:Tests added or updated
perf:Performance improvement

Where to look for help

Each Setcon repo follows the same convention — look in these files of whichever project you're in:

Project context, domain glossary, conventionsCLAUDE.md
This workflow (full prose)CONTRIBUTING.md
Project-specific design docsdocs/
Visual / reference assetsreference/
This guide (web version)docs/workflow-guide.html

If a doc you need isn't there, write it — that's a valid PR.