Skip to content

GIT STRATEGY

VietGara — Multi-Tenant SaaS Platform for Auto Garage Management & Maintenance

Version 1.7 — October 10, 2026 · Cloud: Google Cloud Platform (GCP) · Backend: Go

1. Introduction

This document defines the source code management (Git) strategy for the entire VietGara ecosystem: repository structure, branching model, commit conventions, Pull Request process, versioning, and how it links to the GitOps CI/CD pipeline described in Deployment Architecture.

2. Repository Structure: Monorepo vs. Polyrepo

This is an important decision affecting the entire development workflow, analyzed in the same format (options — pros/cons — decision) as the Architecture Decision Records document.

OptionProsCons
Monorepo (a single repo for the entire Go backend)Easy to share common domain code while still a Modular Monolith (ADR-001, Phase 1); atomic commits for changes spanning multiple modules at once; a single CI pipeline is easy to manage in the early stageOnce split into true microservices (Phase 2+), a more efficient build tool (Bazel/Turborepo) is needed to avoid rebuilding everything for a single line change
Polyrepo (one repo per service)Clear boundaries, independent access/CI per service, suits a model where each service has its own dedicated teamHard to share common code (requires separate versioned packages), cross-service changes require multiple coordinated PRs, adds complexity during the Modular Monolith stage
Hybrid (Monorepo for Go backend + Polyrepo for each other platform)Captures Monorepo’s benefits while the backend is still a Modular Monolith, while keeping Owner Web/mobile apps/infrastructure independent since they differ in technology and release cadenceRequires clear conventions to avoid confusion about what lives in which repo

Decision: use the Hybrid model. Concrete repository structure:

vietgara-backend (Go monorepo: the entire Modular Monolith Phase 1,
split into a multi-module Go workspace as services start splitting from Phase 15)
vietgara-owner-web (React + TypeScript — garage owners and staff)
vietgara-admin-web (React + TypeScript — VietGara platform administrators)
vietgara-owner-app (Flutter — garage owners, Phase 2)
vietgara-admin-app (Flutter — VietGara platform administrators, Phase 2)
vietgara-customer-app (Flutter — customers, Phase 2)
vietgara-technician-app (Flutter — technicians, offline-first, Phase 2)
vietgara-flutter-core (Dart package vietgara_core shared by the Flutter apps; public;
apps pin a release tag — Coding Standards 4.1a)
vietgara-proto (shared .proto definitions + generated Go/gateway code and OpenAPI document;
the backend imports it as a Go module, the owner web and admin web generate types from the OpenAPI file)
vietgara-infra (Terraform - Infrastructure Architecture)
vietgara-gitops-config (Helm charts + ArgoCD config - Deployment Architecture, contains NO application code)
vietgara-web-ui (React/TypeScript design system kit: tokens, Tailwind theme, components; source-only,
tagged vX.Y.Z and pinned by vietgara-owner-web and vietgara-admin-web — Coding Standards 3.6)
vietgara-e2e (Playwright end-to-end tests that drive vietgara-owner-web and vietgara-admin-web against a running backend)
viettechno-website (company homepage and product landing pages, static Astro site; company-wide, not VietGara-only; published on merge to master — ADR-013)
vietgara-help (user guide for garage owners and staff, Astro Starlight; published on merge to master — ADR-013)
vietgara-testdata (public, disposable test credentials only, pinned by tag without deploy keys; shared test dataset in YAML + JSON Schema + Go/TypeScript loaders; pinned by tag by the
backend blackbox suite and vietgara-e2e)

As the backend gradually splits into true microservices (from Phase 15, the integration services from Phase 16, per ADR-001), individual services can be split out of vietgara-backend into their own repos — this decision is based on: the service having its own dedicated team AND a high enough independent change frequency that sharing a repo would bottleneck CI.

2.1. Private repositories

vietgara-proto is planned to become private (vietgara-testdata is public: it holds disposable test credentials only, and consumers pin its tags without a key). Another repository’s CI reads a private repository through a read-only deploy key:

  • one key pair per private repository: the public key is added to that repository as a read-only deploy key, and the private key is stored as a repository secret in every consumer (PROTO_DEPLOY_KEY). The organization is on GitHub Free, where organization secrets are not available to private repositories, so the secrets are set per repository;
  • CI checks out the pinned tag with actions/checkout (ssh-key); for a Go module it sets GOPRIVATE=github.com/viettechno/vietgara-proto, GONOSUMDB and a git rewrite limited to that one repository, so every other module still comes from the Go proxy;
  • container builds that download a private Go module use a BuildKit SSH mount (RUN --mount=type=ssh) fed by the same key, never a key copied into an image layer;
  • developers use their own GitHub access (SSH key or credential helper) for the same commands;
  • artefacts that other repositories commit stay committed (for example the OpenAPI document behind the web apps’ API types), so the web repositories need no access to vietgara-proto in CI.

2.2. Database migrations and the migration freeze

While no non-test tenant exists, database migrations are edited in place and make db-reset rebuilds a database (Database Design Section 1.1); from the first real tenant migrations are forward-only.

3. Branching Model

Trunk-Based Development with short-lived feature branches is applied — fitting the continuous CI/CD and GitOps strategy already chosen (Deployment Architecture, Section 3), avoiding long-lived branches that cause large merge conflicts.

BranchPurposeRules
masterThe primary branch, always in a deployable stateBranch-protected (Section 8); only mergeable via an approved Pull Request + passing CI
feature/-Develops a specific feature/bugfixCreated from master, lives at most ~3-5 working days, merged back to master via a PR then deleted
release/Used only to freeze scope before a major release (e.g. launching a new Phase)Only accepts cherry-picked bugfixes, no new features
hotfix/Emergency fix on productionCreated from master or the current production tag, merged immediately upon approval, not waiting for the normal release cycle
%%{init: {'gitGraph': {'mainBranchName': 'master'}}}%%
gitGraph
  commit
  branch feature/VG-101
  commit
  commit
  checkout master
  merge feature/VG-101
  branch feature/VG-102
  commit
  checkout master
  commit
  merge feature/VG-102
  branch hotfix/VG-205
  commit
  checkout master
  merge hotfix/VG-205
  commit

Feature branches are merged via PR and deleted right after the merge. The trunk branch of every repository is named master. Refactoring work uses refactor/<topic> branches, for example refactor/split-web-admin.

4. Commit Message Convention (Conventional Commits)

Conventional Commits is applied to auto-generate CHANGELOG.md and to determine the type of change (new feature/bugfix) for automated semantic versioning; it is not enforced for now.

<type>(<scope>): <short description, present tense>
[body - optional, explains the reason for the change]
[footer - optional: BREAKING CHANGE, Closes VG-123]
Examples:
feat(billing): add insurance allocation logic based on coverage ratio
fix(inventory): fix incorrect stock calculation on concurrent stock-out
docs(api-spec): update the create-insurance-claim endpoint
refactor(license): extract the entitlement cache out of the main handler
TypeMeaningVersion Impact (semantic-release)
featAdds a new featureBumps MINOR
fixFixes a bugBumps PATCH
docsDocumentation-only changeNo version bump
refactorRestructuring, no behavior changeNo version bump
testAdding/modifying testsNo version bump
choreChores (dependency updates, CI config)No version bump
BREAKING CHANGE (in the footer)A backward-incompatible changeBumps MAJOR
  • Every commit should include the ticket ID (e.g. VG-101) in the scope or footer to trace back to the original requirement.

5. Pull Request Process

5.1. Requirements Before Merging

  • At least 1 approval from someone other than the author (2 approvals for changes within the finance-services group: Billing, Payment, E-Invoice — high risk per Risk Assessment RISK-TECH-01).
  • All CI checks pass: lint, unit tests, coverage, security scan (see Coding Standards, Sections 2.7/3.7/4.5).
  • No unresolved review conversations/comments remain.

5.2. PR Description Template

## Description
[Summary of the change and why]
## Related Ticket
Closes VG-XXX
## Type of Change
[ ] feat [ ] fix [ ] refactor [ ] docs [ ] chore
## Checklist
[ ] Unit tests added for new/changed logic
[ ] Relevant documentation updated (API Spec / README) if needed
[ ] No secrets/sensitive data logged
[ ] Self-reviewed the diff before submitting

5.3. Merge Strategy

  • Use Squash Merge for feature/* into master — keeps master’s history clean, with each commit on master representing one complete unit of change, making the CHANGELOG easy to read.
  • Use a Merge Commit (no squash) when merging release/* to preserve the detailed history of individual patches within a major release.

6. Versioning & Tagging

  • Semantic Versioning (MAJOR.MINOR.PATCH) is applied to each independent service/application. Today a release is cut by pushing a v* tag by hand; the CI workflow builds the image and pushes it to GHCR tagged by git describe. Computing the version automatically with semantic-release from Conventional Commits, and Artifact Registry tags such as billing-v1.4.0, are the target for production (Deployment Architecture, Section 3).
  • A Git tag (e.g. billing-v1.4.0) matches the image tag in Artifact Registry (Deployment Architecture, Section 3), ensuring traceability: a version running in production maps to exactly one specific commit.
  • The vietgara-proto repo is versioned per .proto package (vietgara.billing.v1, vietgara.billing.v2, etc.) — breaking changes must bump the package version rather than modifying the old version directly (per NFR-MT-04’s support for two parallel API versions).

This is the production target (Deployment Architecture, Section 3); the vietgara-gitops-config repository does not exist yet. Staging is a single VM running Docker Compose from vietgara-infra/staging, deployed with make deploy from GHCR image tags (Deployment Guide). Per Deployment Architecture Section 3, ArgoCD will sync Kubernetes configuration from the vietgara-gitops-config repo — fully separate from the code repos (vietgara-backend, vietgara-owner-web, vietgara-admin-web, etc.). Release flow:

sequenceDiagram
  participant Dev as Code repo (e.g. vietgara-backend)
  participant CI as GitHub Actions
  participant AR as Artifact Registry
  participant Cfg as vietgara-gitops-config
  participant Argo as ArgoCD
  Dev->>CI: PR merged to master
  CI->>AR: build, scan, push image (tag = git SHA)
  CI->>Cfg: PR updating the image tag in Helm values
  Note over Cfg: dev auto-merges, production requires approval
  Argo->>Cfg: detect change
  Argo->>Argo: sync the cluster

A contract change is merged in vietgara-proto first (tagged), then the backend bumps the module version and the owner web and admin web regenerate their API types in their own PRs.

8. Branch Protection Rules

  • master: direct pushes and force-pushes are forbidden; a PR + approval + passing CI is required; the branch must be up-to-date with master before merging to avoid hidden conflicts.
  • Deletion of master/release/* branches is forbidden for anyone other than a repo Admin.
  • Commit signing is encouraged for sensitive repos (vietgara-infra, vietgara-gitops-config) to ensure traceability of infrastructure changes.

9. Conflict Resolution & Rebase Policy

  • feature/* branches should rebase onto master frequently (rather than merging master into the feature branch) to keep a linear, easy-to-review history.
  • Never rebase a branch that another person has already pulled and continued building on (only rebase a personal branch not yet shared) to avoid rewriting a teammate’s history.
  • Complex conflicts spanning multiple modules should be resolved via direct discussion between the two authors rather than being resolved unilaterally based on individual judgment, especially for code within finance-services.