Civiqapp architecture

Automated draft releases

A successful merged pull request to main can create a reviewable Android draft release. The pipeline separates untrusted change text, read-only note generation, and the only write-capable publication step so a release is traceable without making it automatic publication.

Release flow from successful main validation through merged pull request detection, read-only Claude note generation, VERSION commit, annotated tag, draft release, and manual rebuild
Automatic release and manual rebuild paths. All write operations happen after validation and provenance checks; the GitHub release remains a draft for human review.

Version source and transitions

VERSION is the single newline-terminated source of Flutter build name and build number, in MAJOR.MINOR.PATCH+BUILD form. Release Make targets validate it and pass both parts to Flutter without changing tracked files. The version utility rejects malformed, negative, overflowing, or multi-line values before a workflow uses them.

PathSelectionResult
AutomaticMerged PR labeled release:minorIncrement MINOR and BUILD; reset PATCH to zero.
AutomaticAny other merged PRIncrement PATCH and BUILD.
Manual rebuildworkflow_dispatchPreserve MAJOR.MINOR.PATCH; increment BUILD only.

BUILD is a positive, globally increasing value that becomes the Android versionCode and iOS CFBundleVersion, so it is never reset. Semantic releases use immutable annotated tags named vMAJOR.MINOR.PATCH: an automatic release with build name 0.1.2 and build number 42 carries tag v0.1.2, and a rebuild increments only the build number (0.1.2+43) to replace the draft assets without moving that tag.

Automatic flow

  1. Flutter-Analyze-Test-Build validates formatting, analysis, tests, and the documentation site. On a main push it resolves the merged pull request and builds versioned signed Android APK and AAB artifacts; a direct push validates without producing a release build.
  2. Automated Draft Release runs only after that workflow succeeds for a main push. Its gate resolves the PR associated with the exact workflow-run SHA and skips direct pushes and prior release VERSION commits.
  3. The prepare job independently calculates the expected version, downloads artifacts from that exact CI run, and verifies names, metadata, and SHA-256 digests before preserving only verified inputs.
  4. A separate read-only Claude job receives bounded PR metadata. It uses schema-constrained output, a single permitted file read, and CLAUDE_CODE_OAUTH_TOKEN; it cannot commit, tag, publish, or receive publication credentials. The validator requires developer Markdown headed with the exact release version and non-empty, plain store text of at most 500 Unicode characters with no control characters.
  5. The write-capable publish job revalidates notes and artifact provenance, commits only VERSION, creates or verifies the annotated tag, creates or resumes a compatible draft release, and uploads exactly the verified APK and AAB.

The workflow is serialized rather than canceled mid-transaction, and queued runs are never dropped so closely spaced merges each receive a release. Release provenance records the source SHA, PR, workflow run, selected version, and artifact digests; reruns resume only compatible commits, tags, draft releases, and assets. The draft is intentionally left unpublished for a human to inspect the notes and binaries.

Manual rebuild flow

Run Automated Draft Release with workflow_dispatch only when an existing semantic tag and compatible draft release already exist. The rebuild path reads main, computes one BUILD increment, verifies the tag/release contract, creates signed Android artifacts, and records their hashes. Its publish job revalidates the complete transaction, makes (or recognizes on a rerun) the one-file VERSION commit, confirms that the semantic tag never moved, then deterministically replaces the draft's APK and AAB. It refuses published, missing, duplicated, unexpected, or provenance-mismatched assets.

Operator setup

Configure these repository secrets before expecting a main release build to succeed. Names are shown deliberately; values must never be committed, copied into workflow logs, or placed in documentation.

SecretUsed for
CLAUDE_CODE_OAUTH_TOKENClaude subscription authentication in the isolated read-only release-notes job. Generate locally with claude setup-token, then store the displayed token as this repository secret.
CIVIQ_RELEASE_API_HOSTRelease API-host input used to generate the untracked HTTPS runtime configuration.
ANDROID_KEYSTORE_BASE64Base64-encoded Android release keystore provisioned only in the runner temporary directory.
ANDROID_STORE_PASSWORDAndroid keystore password.
ANDROID_KEY_ALIASAndroid signing-key alias.
ANDROID_KEY_PASSWORDAndroid signing-key password.

Install the Claude GitHub App for the repository before using the subscription token. Keep Claude's job at contents: read and pull-requests: read; only publication jobs receive contents: write. The token is generated with claude setup-token; do not use Claude bare mode for this OAuth credential.

Branch protection and token policy

The publication jobs use the ephemeral GITHUB_TOKEN and require contents: write. Repository and branch-protection settings must explicitly permit the GitHub Actions bot to create the one-file VERSION commit on main; normal required checks and review rules still apply. Tag and release creation also require that the repository policy permits the job token's write permission. The workflow never substitutes a personal access token, force-pushes, or bypasses protection.

Fail closed: missing secrets, an unavailable write permission, branch protection rejection, a changed main ref, invalid release notes, a moved tag, incompatible draft state, or an artifact/hash mismatch stops the affected job. It does not create an unsigned release, publish a draft, mutate a tag, or fall back to another credential. Correct the repository configuration or state, then rerun only after verifying the failure cause.

Failure recovery and review

FailureSafe operator action
Validation or Android prerequisites failFix the failing validation or configure every required secret, then allow a new merged-PR run or explicitly start the appropriate rebuild. Do not treat an unconfigured build as a release.
VERSION commit is rejectedAuthorize the GitHub Actions bot for the required one-file commit through repository policy. Do not provide an alternate bypass credential; rerun after the rule is corrected.
Concurrent main change or incompatible tag/draftInspect the recorded SHA, tag target, provenance marker, and assets. Preserve immutable tags; resolve the competing release deliberately rather than forcing an update.
Manual rebuild fails after stagingVerify the draft remains compatible and rerun the same workflow run where supported. Convergent checks recognize its prior one-file rebuild commit and avoid a second BUILD increment.

Before publishing a draft, reviewers should confirm the tag target and VERSION commit, developer and ≤500-character store notes, Android APK/AAB names and checksums, and the release provenance marker. Publishing is a separate human decision.

Documentation process: the project documentation skill was unavailable while this page was added. The house documentation standard was applied directly; this constraint is recorded in the release-automation subtask metadata.