diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dd3317d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +All notable changes to InboxIntel are documented here. Format follows +[Keep a Changelog](https://keepachangelog.com/); versions follow +[Semantic Versioning](https://semver.org/). See [docs/WORKFLOW.md](docs/WORKFLOW.md). + +## [Unreleased] +### Added +- Formal Git workflow & environment strategy (`docs/WORKFLOW.md`). +- Staging environment overlay (`docker-compose.staging.yml`) — production-shaped + Linux containers on Windows, isolated ports/volumes. +- Version-controlled Git hooks (`scripts/git-hooks/`) + installer + (`scripts/install-hooks.ps1`): pre-commit secret/format checks, pre-push + build+test gate. +- `VERSION` file as the single source of truth for the release number. + +## [0.1.0] — scaffold +### Added +- .NET 8 Clean Architecture backend (Domain/Application/Infrastructure/Api) + React/Vite SPA. +- Docker Compose stack (Postgres 16, API, frontend, optional nginx proxy). +- Gitea Actions CI (backend build+test, frontend build) on `main`/`develop` + PRs. +- Security hardening: encrypted OAuth tokens, EF global query filters (IDOR), + loopback binds, non-root containers, SSRF egress guard. +- One-command deploy scripts (`deploy/up.ps1`, `deploy/up.sh`). + +[Unreleased]: https://your-gitea-host/InboxIntel/compare/v0.1.0...HEAD diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md new file mode 100644 index 0000000..de116fc --- /dev/null +++ b/docs/WORKFLOW.md @@ -0,0 +1,188 @@ +# InboxIntel — Git Workflow & Environment Strategy + +The single source of truth for how we branch, commit, version, and promote code +across environments. Optimised for a **solo developer on Windows 11 with a future +Linux production server**. Kept deliberately lightweight — every rule here earns +its place. + +--- + +## 1. Branch strategy + +A trimmed **GitHub Flow + a long-lived `develop`** model. Two permanent branches, +short-lived branches off `develop`. + +| Branch | Lives for | Purpose | Deploys to | +|-----------------|-----------|------------------------------------------------------|------------| +| `main` | forever | Always releasable. Every commit is tagged & shippable | production | +| `develop` | forever | Integration branch. What staging runs | staging | +| `feature/*` | hours–days| One feature or refactor | dev (local)| +| `fix/*` | hours | Non-urgent bug fix | dev (local)| +| `hotfix/*` | minutes–hrs| Urgent prod fix, branched from `main` | prod (fast)| +| `release/x.y.0` | optional | Only if a release needs stabilisation before tagging | staging | + +**Why this shape (not full GitFlow):** a solo dev doesn't need GitFlow's ceremony +(separate release managers, parallel release trains). But keeping `develop` +separate from `main` gives one thing that pure trunk-based can't: a **staging +environment that always mirrors `develop`** while `main` stays clean and +tag-perfect for production. `release/*` exists only when you want to freeze +features and stabilise — skip it for routine work. + +### Normal flow + +``` +main ──────●────────────────────●────────── (tagged: v1.2.0, v1.3.0) + \ / +develop ──●──●──●──●──●──●──●──●──────────── (staging) + \ / \ / +feature/x ●─● \ / +fix/y ●───● +``` + +1. `git switch develop && git pull` +2. `git switch -c feature/sender-policy` +3. Commit in small conventional commits. +4. Push, open a PR **into `develop`** (Gitea). CI must be green. +5. Squash-merge. Delete the branch. +6. When `develop` is ready to ship → PR `develop → main`, tag, deploy. + +--- + +## 2. Commit conventions — Conventional Commits + +Format: `type(scope): short imperative summary` + +**Types:** `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `ci`, `perf`, +`build`, `style`, `security`. + +Rules: +- Summary ≤ 72 chars, imperative mood ("add", not "added"). +- One logical change per commit. +- Body explains **why**, not what (the diff shows what). +- Breaking change → add `!` (`feat!:`) and a `BREAKING CHANGE:` footer. + +Examples (matching this repo's history): +``` +feat(ui): F1+F2 — component primitives + rebuilt app shell +fix(security): systemic IDOR safeguard via EF global query filters +ci: add Gitea Actions build + test pipeline +``` + +Why: conventional commits drive **automatic semver bumps** and a generated +CHANGELOG, and make `git log` scannable. `feat` → minor, `fix` → patch, +`BREAKING CHANGE` → major. + +--- + +## 3. Pull request / merge flow (Gitea) + +Even solo, PRs are worth it: they run CI, give a diff review checkpoint, and build +a paper trail. + +- **Target:** `feature/*` and `fix/*` → `develop`. `develop`/`hotfix/*` → `main`. +- **Gate:** the `CI` workflow (backend build+test, frontend build) must pass. +- **Merge style:** **squash-merge** feature branches (one clean commit on + `develop`). **Merge commit** for `develop → main` (preserves the integration + history and makes the release boundary visible). +- **Branch protection (Gitea → Settings → Branches):** protect `main` and + `develop`; require status checks to pass; disallow force-push. + +--- + +## 4. Versioning — Semantic Versioning (`MAJOR.MINOR.PATCH`) + +- **MAJOR** — breaking API/behaviour change. +- **MINOR** — backward-compatible feature. +- **PATCH** — backward-compatible fix. + +The current version lives in [`VERSION`](../VERSION) and is the one place bumped +per release. Pre-1.0 while scaffolding: stay on `0.x` (minor = features, patch = +fixes; anything may change). + +--- + +## 5. Tagging & releases + +Tags are cut **only on `main`**, annotated, prefixed `v`: + +```bash +git switch main && git pull +# bump VERSION + CHANGELOG in a release commit, then: +git tag -a v1.3.0 -m "v1.3.0 — sender policy + staging overlay" +git push origin main --tags +``` + +- Tag == the exact commit deployed to production == the rollback target. +- The tag message summarises the release; details live in `CHANGELOG.md`. + +--- + +## 6. Hotfix process + +For a bug already in production: + +```bash +git switch main && git pull +git switch -c hotfix/oauth-callback-500 +# fix + test +git commit -m "fix(security): guard null OAuth state on callback" +# PR hotfix/* -> main, CI green, merge +git switch main && git pull +git tag -a v1.3.1 -m "v1.3.1 hotfix — OAuth callback" && git push origin main --tags +# deploy the tag, THEN back-merge so develop doesn't lose the fix: +git switch develop && git merge main && git push +``` + +The **back-merge to `develop`** is the step people forget — without it the next +release silently reintroduces the bug. + +--- + +## 7. Environments + +| Env | Host | Runtime | Config source | Purpose | +|-------------|-------------------------|--------------------------------------|--------------------------|--------------------| +| Development | Windows 11 (native) | `dotnet run` + `vite` (hot reload) | `appsettings.Development.json` + user-secrets | fast iteration, debugging | +| Staging | Windows 11 (Docker) | Linux containers, `ASPNETCORE_ENVIRONMENT=Production` | `deploy/.env.staging` + `docker-compose.staging.yml` | production rehearsal | +| Production | Linux server (Docker) | identical Linux containers | `deploy/.env` on the server | live | + +**Parity principle:** dev is fast (native, Windows) and *not* production-shaped — +that's fine, it's for inner-loop speed. **Staging is the parity gate**: it runs the +*same Linux images* Docker builds for production, so "works in staging" genuinely +predicts "works in prod". The only staging↔prod differences are the dev banner, +capped sync, ports, and volume namespace — see `docker-compose.staging.yml`. + +### Commands + +```powershell +# DEV (native, hot reload) — two terminals +dotnet run --project src/InboxIntel.Api # http://localhost:5080 +cd frontend; npm run dev # http://localhost:5173 + +# STAGING (production-shaped, on Windows via Docker) +./deploy/up.ps1 -Staging # http://localhost:18081 +./deploy/down.ps1 -Staging + +# PRODUCTION-shaped run locally (smoke test the real config) +./deploy/up.ps1 # http://localhost:8081 +``` + +Dev and staging use **different ports and different volumes**, so they can run at +the same time and never share a database. + +--- + +## 8. Git hooks + +Installed via `core.hooksPath` (run once per clone): + +```powershell +./scripts/install-hooks.ps1 +``` + +- **pre-commit** (fast): blocks committed `.env`/secrets, verifies `dotnet format`. +- **pre-push** (thorough): `dotnet build -c Release` + `dotnet test` + frontend + build — the same gate CI runs, caught before the push. + +Emergency bypass: `--no-verify`. CI still enforces the gate server-side, so a +bypassed push can still be rejected by branch protection.