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.
| Option | Pros | Cons |
|---|---|---|
| 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 stage | Once 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 team | Hard 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 cadence | Requires 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 setsGOPRIVATE=github.com/viettechno/vietgara-proto,GONOSUMDBand 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-protoin 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.
| Branch | Purpose | Rules |
|---|---|---|
| master | The primary branch, always in a deployable state | Branch-protected (Section 8); only mergeable via an approved Pull Request + passing CI |
| feature/ | Develops a specific feature/bugfix | Created 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 production | Created 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 ratiofix(inventory): fix incorrect stock calculation on concurrent stock-outdocs(api-spec): update the create-insurance-claim endpointrefactor(license): extract the entitlement cache out of the main handler| Type | Meaning | Version Impact (semantic-release) |
|---|---|---|
| feat | Adds a new feature | Bumps MINOR |
| fix | Fixes a bug | Bumps PATCH |
| docs | Documentation-only change | No version bump |
| refactor | Restructuring, no behavior change | No version bump |
| test | Adding/modifying tests | No version bump |
| chore | Chores (dependency updates, CI config) | No version bump |
| BREAKING CHANGE (in the footer) | A backward-incompatible change | Bumps 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 TicketCloses 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 submitting5.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 bygit describe. Computing the version automatically with semantic-release from Conventional Commits, and Artifact Registry tags such asbilling-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).
7. Link to GitOps (Deployment)
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.