diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 7b0e28aba..b1661da65 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,39 +1,378 @@ -## Prepare Release (`prepare-relese.yml`) +# GitHub Workflows -- manually +This document provides an overview of all GitHub Actions workflows in this repository. For the complete release process documentation, see [RELEASE.md](https://github.com/fiskaltrust/team-middleware/blob/main/middleware/RELEASE.md). -## CI (`-build.yml`) +--- -- on push - - paths: `/**` -- manually -- from `/run ci` comment +## Slash Commands -## Package (`package.yml`) +All slash commands are dispatched via [`slash-commands.yml`](slash-commands.yml) when commenting on a Pull Request. -- manually -- from `/package ` comment +### `/run` Command (`command-run.yml`) -## Queue Acceptance Tests (`queue-acceptance-tests.yml`) +Triggers CI builds or acceptance tests. -- on push - - branch: `main` - - tags-ignore: `queue/**/v*` -- manually -- from `/run queue acceptance-tests` comment +| Usage | Description | +|-----------------------------------------|--------------------------------| +| `/run ci` | Run CI build for a component | +| `/run build` | Alias for `ci` | +| `/run queue acceptance-tests` | Run all queue acceptance tests | +| `/run queue acceptance-tests ` | Run specific acceptance test | -## Enforce All Status Checks -- on pull_request update -- from `/check` comment +**Components:** `queue`, `scu-at`, `scu-de`, `scu-es`, `scu-it` -## Version +### `/package` Command (`command-package.yml`) -## Release (`release.yml`) +Builds a package without deploying. -- on push - - tags: `/**/v*` +``` +/package +``` -## Deploy (`deploy.yml`) +**Example:** `/package queue SQLite` -- manually (via Package) -- from `/deploy ` comment +### `/deploy` Command (`command-package.yml`) + +Builds a package and deploys to sandbox. + +``` +/deploy +``` + +**Example:** `/deploy scu-de SwissbitCloudV2` + +**Behavior:** +1. Builds the package with version based on branch (`-ci` or `-rc`) +2. Updates comment with approval link (πŸ‘€) +3. On approval, deploys to sandbox +4. Updates comment with success (πŸŽ‰) or failure (πŸ˜•) + +### `/release` Command (`command-release.yml`) + +Creates a version tag and GitHub release. Only works on release branches. + +``` +/release +``` + +**Example:** `/release queue SQLite` + +**Behavior:** +1. Creates tag using `nbgv tag` +2. Pushes tag to repository +3. Creates GitHub release with appropriate release notes +4. Updates comment with link to release + +### `/version` Command (`command-version.yml`) + +Removes the `-rc` prerelease suffix from the version. Only works on release branches. + +``` +/version +``` + +**Behavior:** Updates `version.json` to full release version (e.g., `1.3.68-rc` β†’ `1.3.68`) + +### `/merge` Command (`command-merge.yml`) + +Merges a release PR with special conflict handling. Only works on release branches. + +``` +/merge +``` + +**Behavior:** +1. Resolves `version.json` conflicts in favor of `main` branch +2. Verifies all status checks pass +3. Merges the PR + +--- + +## Build Workflows + +CI workflows that run on push to component directories and can be triggered manually or via `/run`. + +| Workflow | Trigger Paths | Manual Trigger | +|--------------------|---------------|------------------| +| `queue-build.yml` | `queue/**` | `/run queue ci` | +| `scu-at-build.yml` | `scu-at/**` | `/run scu-at ci` | +| `scu-de-build.yml` | `scu-de/**` | `/run scu-de ci` | +| `scu-es-build.yml` | `scu-es/**` | `/run scu-es ci` | +| `scu-it-build.yml` | `scu-it/**` | `/run scu-it ci` | +| `scu-be-build.yml` | `scu-be/**` | `/run scu-be ci` | + +### Queue Acceptance Tests (`queue-acceptance-tests.yml`) + +**Triggers:** +- Push to `main` branch +- Tag ignore: `queue/**/v*` +- Manual: `/run queue acceptance-tests` + +**Options:** +- Run all tests: `/run queue acceptance-tests` +- Run specific test: `/run queue acceptance-tests SQLite` + +--- + +## Package Workflows + +### Package (`package.yml`) + +Reusable workflow for building and packaging components. + +**Inputs:** +- `pattern`: Project pattern to match +- `directory`: Source directory +- `commit`: Optional commit ref +- `deploySandbox`: Deploy to sandbox after packaging + +**Called by:** `command-package.yml`, `release.yml`, individual package workflows + +### Component Package Workflows + +Pre-configured package workflows for each component: + +- `queue-package.yml` +- `scu-at-package.yml` +- `scu-de-package.yml` +- `scu-es-package.yml` +- `scu-it-package.yml` +- `scu-be-package.yml` + +--- + +## Release Workflows + +### Prepare Release (`prepare-release.yml`) + +**Trigger:** Manual (workflow dispatch) + +**Purpose:** Creates a release branch with RC version. + +**Actions:** +1. Creates `release/vX.Y` branch from `main` +2. Sets release branch version to `-rc` +3. Bumps `main` to next version with `-ci` +4. Creates PR from release branch to `main` + +### Release (`release.yml`) + +**Trigger:** GitHub release published with tag matching `//v*` + +**Purpose:** Deploys a tagged release to production. + +**Actions:** +1. Validates tag format +2. Runs component-specific tests +3. Packages the component +4. Deploys to sandbox (for verification) +5. Deploys to production + +### Deploy (`deploy.yml`) + +Reusable workflow for deploying packages to an environment. + +**Inputs:** +- `package`: Package name to deploy +- `environment`: Target environment (`sandbox` or `production`) + +**Deployments:** +- v1 Packages (Azure Storage) +- v2 Packages (Azure Storage) + +--- + +## Utility Workflows + +### Enforce All Checks (`enforce-all-checks.yml`) + +**Triggers:** +- Pull request updates + +**Purpose:** Waits for all status checks to complete. + +### Check Labels (`check-labels.yml`) + +Validates that PRs have required labels. + +### Check Linked Issue (`check-linked-issue.yml`) + +Validates that PRs are linked to issues. + +### CLA (`cla.yml`) + +Contributor License Agreement checking. + +### Manual Merging (`manual-merging.yml`) + +Makes sure that release PRs can not be merged manually. + +### Remove No Issue Label (`remove-no-issue-label.yml`) + +Automatically removes `no-issue` label when an issue is linked. + +### Smoketests (`smoketests.yml`) + +Runs smoke tests for release verification. + +## Workflow Dependencies + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ SLASH COMMANDS β”‚ +β”‚ β”‚ +β”‚ Triggered by: issue_comment on pull requests β”‚ +β”‚ Dispatched via: slash-commands.yml β”‚ +β”‚ β”‚ +β”‚ /run ──► command-run.yml ──► queue-build.yml β”‚ +β”‚ queue-acceptance-tests.yml β”‚ +β”‚ scu-at-build.yml β”‚ +β”‚ scu-de-build.yml β”‚ +β”‚ scu-es-build.yml β”‚ +β”‚ scu-it-build.yml β”‚ +β”‚ β”‚ +β”‚ /package ──► command-package.yml ──► package.yml β”‚ +β”‚ /deploy ──► command-package.yml ──► package.yml ──► deploy.yml β”‚ +β”‚ β”‚ +β”‚ /release ──► command-release.yml β”‚ +β”‚ /version ──► command-version.yml β”‚ +β”‚ /merge ──► command-merge.yml β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ BUILD WORKFLOWS β”‚ +β”‚ β”‚ +β”‚ Triggered by: pull_request, workflow_dispatch, workflow_call β”‚ +β”‚ Called by: command-run.yml, release.yml β”‚ +β”‚ β”‚ +β”‚ queue-build.yml (paths: queue/**) β”‚ +β”‚ queue-acceptance-tests.yml (paths: queue/**, branches: main, release/v*) β”‚ +β”‚ scu-at-build.yml (paths: scu-at/**) β”‚ +β”‚ scu-de-build.yml (paths: scu-de/**) β”‚ +β”‚ scu-es-build.yml (paths: scu-es/**) β”‚ +β”‚ scu-it-build.yml (paths: scu-it/**) β”‚ +β”‚ scu-be-build.yml (paths: scu-be/**) β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PACKAGE WORKFLOWS β”‚ +β”‚ β”‚ +β”‚ Triggered by: workflow_dispatch, workflow_call β”‚ +β”‚ Called by: command-package.yml, release.yml β”‚ +β”‚ β”‚ +β”‚ queue-package.yml ───────┐ β”‚ +β”‚ scu-at-package.yml ─────── β”‚ +β”‚ scu-de-package.yml ──────┼──► package.yml ──► deploy.yml (optional) β”‚ +β”‚ scu-es-package.yml ─────── β”‚ +β”‚ scu-it-package.yml ─────── β”‚ +β”‚ scu-be-package.yml β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ RELEASE WORKFLOW β”‚ +β”‚ β”‚ +β”‚ Triggered by: GitHub release published (tag: //v*) β”‚ +β”‚ β”‚ +β”‚ release.yml β”‚ +β”‚ β”‚ β”‚ +β”‚ β”œβ”€β”€β–Ί queue-build.yml ────────┐ β”‚ +β”‚ β”œβ”€β”€β–Ί scu-at-build.yml ──────── β”‚ +β”‚ β”œβ”€β”€β–Ί scu-de-build.yml ───────┼──► queue-acceptance-tests.yml β”‚ +β”‚ β”œβ”€β”€β–Ί scu-es-build.yml ──────── β”‚ β”‚ +β”‚ └──► scu-it-build.yml β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β–Ό β”‚ +β”‚ package.yml β”‚ +β”‚ β”‚ β”‚ +β”‚ β–Ό β”‚ +β”‚ deploy.yml (sandbox) β”‚ +β”‚ β”‚ β”‚ +β”‚ β–Ό β”‚ +β”‚ deploy.yml (production) β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ STANDALONE WORKFLOWS β”‚ +β”‚ β”‚ +β”‚ Triggered by: workflow_dispatch, repository_dispatch β”‚ +β”‚ β”‚ +β”‚ prepare-release.yml - Creates release branches β”‚ +β”‚ command-release.yml - Creates tags and GitHub releases β”‚ +β”‚ command-version.yml - Updates version.json β”‚ +β”‚ command-merge.yml - Merges release PRs β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +> | Trigger types | description | +> |---|---| +> | [workflow_call](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflow_call) | Called by another workflow | +> | [workflow_dispatch](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflow_dispatch) | Manual trigger through the github ui | +> | [repository_dispatch](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#repository_dispatch) | Triggered by a slash command | + + +### Composite Actions + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ COMPOSITE ACTIONS β”‚ +β”‚ β”‚ +β”‚ Located in: .github/actions/ β”‚ +β”‚ β”‚ +β”‚ build - Restores and builds .NET projects β”‚ +β”‚ test - Runs tests and uploads results β”‚ +β”‚ sign - Signs DLLs with Azure Key Vault β”‚ +β”‚ package - Creates v1 (NuGet) and v2 (zip) packages β”‚ +β”‚ deploy-v1-packages - Deploys NuGet packages to Azure Storage β”‚ +β”‚ deploy-v2-packages - Deploys zip packages to Azure Storage β”‚ +β”‚ check-linked-issue - Validates PR has linked issue β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ WORKFLOW β†’ ACTION USAGE β”‚ +β”‚ β”‚ +β”‚ Build Workflows: β”‚ +β”‚ β”‚ +β”‚ queue-build.yml ─────────────► build, test β”‚ +β”‚ queue-acceptance-tests.yml ──► test β”‚ +β”‚ scu-at-build.yml ────────────► build, test β”‚ +β”‚ scu-de-build.yml ────────────► build, test β”‚ +β”‚ scu-es-build.yml ────────────► build, test β”‚ +β”‚ scu-it-build.yml ────────────► build, test β”‚ +β”‚ scu-be-build.yml ────────────► build, test β”‚ +β”‚ β”‚ +β”‚ Package/Deploy Workflows: β”‚ +β”‚ β”‚ +β”‚ package.yml ─────────────────► build, sign, package β”‚ +β”‚ deploy.yml ──────────────────► deploy-v1-packages, deploy-v2-packages β”‚ +β”‚ β”‚ +β”‚ Utility Workflows: β”‚ +β”‚ β”‚ +β”‚ check-linked-issue.yml ──────► check-linked-issue β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Workflow Call Summary + +| Caller Workflow | Calls | +|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `slash-commands.yml` | Dispatches: `command-run`, `command-package`, `command-release`, `command-version`, `command-merge` | +| `command-run.yml` | `queue-build.yml`, `queue-acceptance-tests.yml`, `scu-at-build.yml`, `scu-de-build.yml`, `scu-es-build.yml`, `scu-it-build.yml` | +| `command-package.yml` | `package.yml`, `deploy.yml` | +| `command-release.yml` | _(standalone - creates tags/releases)_ | +| `command-version.yml` | _(standalone - updates version.json)_ | +| `command-merge.yml` | _(standalone - merges PRs)_ | +| `queue-package.yml` | `package.yml` | +| `scu-at-package.yml` | `package.yml` | +| `scu-de-package.yml` | `package.yml` | +| `scu-es-package.yml` | `package.yml` | +| `scu-it-package.yml` | `package.yml` | +| `scu-be-package.yml` | `package.yml` | +| `package.yml` | `deploy.yml` (when `deploySandbox: true`) | +| `release.yml` | `queue-build.yml`, `scu-at-build.yml`, `scu-de-build.yml`, `scu-es-build.yml`, `scu-it-build.yml`, `queue-acceptance-tests.yml`, `package.yml`, `deploy.yml` | +| `prepare-release.yml` | _(standalone - creates release branches)_ | diff --git a/.github/workflows/enforce-all-checks.yml b/.github/workflows/enforce-all-checks.yml index 2b853b64b..495f8aefb 100644 --- a/.github/workflows/enforce-all-checks.yml +++ b/.github/workflows/enforce-all-checks.yml @@ -1,11 +1,9 @@ name: Summary on: pull_request: - repository_dispatch: - types: [check-command] concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.client_payload.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: diff --git a/.github/workflows/slash-commands.yml b/.github/workflows/slash-commands.yml index 2704e8cdc..04b69872f 100644 --- a/.github/workflows/slash-commands.yml +++ b/.github/workflows/slash-commands.yml @@ -26,5 +26,4 @@ jobs: deploy release version - check merge diff --git a/rfcs/0000-template.md b/rfcs/0000-template.md index 0adc7687e..d4d4bd917 100644 --- a/rfcs/0000-template.md +++ b/rfcs/0000-template.md @@ -6,84 +6,84 @@ # Summary -One paragraph explanation of the feature. +> One paragraph explanation of the feature. # Motivation -Why are we doing this? What use cases does it support? What is the expected outcome? +> Why are we doing this? What use cases does it support? What is the expected outcome? # Guide-level explanation -Explain the proposal as if it was already included in the middleware and you were teaching it to a PosCreator. That generally means: - -- Introducing new named concepts. -- Explaining the feature, ideally through simple examples of solutions to concrete problems. -- Explaining how users should *think* about the feature, and how it should impact the way they use the middleware. It should explain the impact as concretely as possible. -- If applicable, provide sample error messages, deprecation warnings, or migration guidance. -- If applicable, explain how this feature compares to similar existing features, and in what situations the user would use each one. +> Explain the proposal as if it was already included in the middleware and you were teaching it to a PosCreator. That generally means: +> +> - Introducing new named concepts. +> - Explaining the feature, ideally through simple examples of solutions to concrete problems. +> - Explaining how users should *think* about the feature, and how it should impact the way they use the middleware. It should explain the impact as concretely as possible. +> - If applicable, provide sample error messages, deprecation warnings, or migration guidance. +> - If applicable, explain how this feature compares to similar existing features, and in what situations the user would use each one. # Reference-level explanation -This is the technical portion of the RFC. -Try to capture the broad implementation strategy, -and then focus in on the tricky details so that: - -- Its interaction with other features is clear. -- It is reasonably clear how the feature would be implemented. -- Corner cases are dissected by example. -- Discuss how this impacts the ability to read, understand, and maintain middleware code. - Code is read and modified far more often than written; will the proposed feature make code easier to maintain? - -When necessary, this section should return to the examples given in the previous section and explain the implementation details that make them work. - -When writing this section be mindful of the following: -- **RFCs should be scoped:** Try to avoid creating RFCs for huge design spaces that span many features. - Try to pick a specific feature slice and describe it in as much detail as possible. - Feel free to create multiple RFCs if you need multiple features. -- **RFCs should avoid ambiguity:** Two developers implementing the same RFC should come up with nearly identical implementations. -- **RFCs should be "implementable":** Merged RFCs should only depend on features from other merged RFCs and existing features. - It is ok to create multiple dependent RFCs, but they should either be merged at the same time or have a clear merge order that ensures the "implementable" rule is respected. +> This is the technical portion of the RFC. +> Try to capture the broad implementation strategy, +> and then focus in on the tricky details so that: +> +> - Its interaction with other features is clear. +> - It is reasonably clear how the feature would be implemented. +> - Corner cases are dissected by example. +> - Discuss how this impacts the ability to read, understand, and maintain middleware code. +> Code is read and modified far more often than written; will the proposed feature make code easier to maintain? +> +> When necessary, this section should return to the examples given in the previous section and explain the implementation details that make them work. +> +> When writing this section be mindful of the following: +> - **RFCs should be scoped:** Try to avoid creating RFCs for huge design spaces that span many features. +> Try to pick a specific feature slice and describe it in as much detail as possible. +> Feel free to create multiple RFCs if you need multiple features. +> - **RFCs should avoid ambiguity:** Two developers implementing the same RFC should come up with nearly identical implementations. +> - **RFCs should be "implementable":** Merged RFCs should only depend on features from other merged RFCs and existing features. +> It is ok to create multiple dependent RFCs, but they should either be merged at the same time or have a clear merge order that ensures the "implementable" rule is respected. # Drawbacks -Why should we *not* do this? +> Why should we *not* do this? # Rationale and alternatives -- Why is this design the best in the space of possible designs? -- What other designs have been considered and what is the rationale for not choosing them? -- What objections immediately spring to mind? How have you addressed them? -- What is the impact of not doing this? +> - Why is this design the best in the space of possible designs? +> - What other designs have been considered and what is the rationale for not choosing them? +> - What objections immediately spring to mind? How have you addressed them? +> - What is the impact of not doing this? # \[Optional\] Prior art -Discuss prior art, both the good and the bad, in relation to this proposal. -A few examples of what this can include are: - -- Does this feature exist in other markets and what experience have their community had? -- Does this feature exist in other PosSystems and what experience have their community had? -- Papers: Are there any published papers or great posts that discuss this? - If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. - -This section is intended to encourage you as an author to think about the lessons from other markets and projects, provide readers of your RFC with a fuller picture. -If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or not. - -Note that while precedent set by other projects and markets is some motivation, it does not on its own motivate an RFC. +> Discuss prior art, both the good and the bad, in relation to this proposal. +> A few examples of what this can include are: +> +> - Does this feature exist in other markets and what experience have their community had? +> - Does this feature exist in other PosSystems and what experience have their community had? +> - Papers: Are there any published papers or great posts that discuss this? +> If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. +> +> This section is intended to encourage you as an author to think about the lessons from other markets and projects, provide readers of your RFC with a fuller picture. +> If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or not. +> +> Note that while precedent set by other projects and markets is some motivation, it does not on its own motivate an RFC. # Unresolved questions -- What parts of the design do you expect to resolve through the RFC process before this gets merged? -- What parts of the design do you expect to resolve through the implementation of this feature before before the feature PR is merged? -- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? +> - What parts of the design do you expect to resolve through the RFC process before this gets merged? +> - What parts of the design do you expect to resolve through the implementation of this feature before before the feature PR is merged? +> - What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? # \[Optional\] Future possibilities -Think about what the natural extension and evolution of your proposal would be and how it would affect the middleware and ecosystem as a whole in a holistic way. -Try to use this section as a tool to more fully consider all possible interactions with the project in your proposal. -Also consider how this all fits into the roadmap for the project and of the relevant sub-team. - -This is also a good place to "dump ideas", if they are out of scope for the RFC you are writing but otherwise related. - -Note that having something written down in the future-possibilities section is not a reason to accept the current or a future RFC; -such notes should be in the section on motivation or rationale in this or subsequent RFCs. -The section merely provides additional information. \ No newline at end of file +> Think about what the natural extension and evolution of your proposal would be and how it would affect the middleware and ecosystem as a whole in a holistic way. +> Try to use this section as a tool to more fully consider all possible interactions with the project in your proposal. +> Also consider how this all fits into the roadmap for the project and of the relevant sub-team. +> +> This is also a good place to "dump ideas", if they are out of scope for the RFC you are writing but otherwise related. +> +> Note that having something written down in the future-possibilities section is not a reason to accept the current or a future RFC; +> such notes should be in the section on motivation or rationale in this or subsequent RFCs. +> The section merely provides additional information. \ No newline at end of file diff --git a/rfcs/0441-release-lifecycle.md b/rfcs/0441-release-lifecycle.md new file mode 100644 index 000000000..4845effc0 --- /dev/null +++ b/rfcs/0441-release-lifecycle.md @@ -0,0 +1,235 @@ +- Feature Name: `release_lifecycle` +- Start Date: 2025-05-08 +- RFC PR: [fiskaltrust/middleware#441](https://github.com/fiskaltrust/middleware/pull/441) +- Tracking Issue: [fiskaltrust/engineering#777](https://github.com/fiskaltrust/engineering/issues/777) + +# Summary + +This RFC proposes to change the middleware release process from developers pushing release out to the market teams pulling them in. +This is done by splitting it into two phases. +First, the **deployment phase** handled by the developers where the middleware is built and deployed to the servers but not yet publicly available. +And second, the **release phase** handled by the market teams where the release visibility is managed and the release is made public. + +# Motivation + +The current release process is lacking a few things which this RFC aims to solve. + +* The possibility to End2End test a release before it being made public. +* The possibility to release something for internal testing that should not be made public. +* The possibility to release versions certain customers only. +* The possibility of prerelease versions that are not automatically used in production. +* The possibility for the market teams to greenlight releases. +* The possibility for broken releases to be "unreleased". + +# Guide-level explanation + +The middleware release process is split up into two main phases. + +1. Deployment +2. Release + +The **deployment phase** is performed in the middleware github repository using issues, milestones, releases, actions, etc. +At the end of the deployment phase all middleware artifacts that are to be released are deployed to the respective targets. +(This includes nuget and zip packages, the release notes documents, etc..) +Most of the artifacts are not yet listed or downloadable anywhere. +The middleware development team is responsible for handling this part of the release process. + +The **release phase** is performed in the portal admin interface. +It's purpose is to manage the publishing (releasing) of the artifacts that were deployed in the previous phase. +At the beginning of this phase the release (collection of artifacts related to a middleware version) is deployed on the servers but unlisted and not downloadable. +In the admin release console in the portal the release can be reviewed, approved, and published. +A release can have complex visibility states for different environments (sandbox, production and the different markets). +A staggered rollout and rollbacks are possible. +At the end of the release phase the artifacts are listed and downloadable on all servers. +The customer success teams are responsible for handling this part of the release process. + +## Deployment Phase + +### Versioning Scheme + +The middleware versions use [SemVer v2](https://semver.org/spec/v2.0.0.html) for its version structure conventions and a modified version of [0ver](https://0ver.org) (called "1ver") for its semantic conventions. + +Two prerelease identifiers are allowed: +| identifier | description | environments | +|------------|------------------------------------------------------------------------------------------------------|---------------------| +| `-ci.X` | "continuous integration" is used for dev releases used for internal testing of features. | sandbox | +| `-rc.X` | "release candidate" are used for testing of whole releases and external testing as well as hotfixes. | production, sandbox | + +### Artifacts + +| artifact | target | notes | published in this stage | +|------------------|------------------------------------|-----------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------| +| github tag | middleware github repo | Every released version has a tag that can be used to link the version to a commit | βœ… | +| github release | middleware github repo | This contains the autogenerated github release notes for this package | βœ… | +| release notes | release notes repository | | βœ… (With a disclaimer that the version will become available soon) | +| byodc | github container registry | | βœ… | +| cloudcashbox | cloudcashbox instances | | ❌ (The cloudcashbox does not support the release phase it is released manually by the development team) | +| android launcher | google play store | | ❌ (The android launcher does not support the release phase it is released manually by the development team) | +| nuget package | public devops nuget feed/nuget.org | | ❌ | +| nuget package | sandbox packages v1 server | | ❌ | +| nuget package | production packages v1 server | | ❌ | +| zip package | sandbox packages v2 server | | ❌ | + +## Release Phase + +### States + +The following states describe the lifecycle of a release within the portal release console. + +| State | Direction | Description | +|-----------|-----------|---------------------------------------------------------| +| Unlisted | ⬇ | Artifacts are deployed and downloadable but not listed. | +| Published | ↕ | Artifacts are deployed, listed, and downloadable. | +| Yanked | πŸ”’ | Artifacts are deployed and downloadable but not listed. | + +An _Unlisted_ release can be set to _Published_ or _Yanked_. +A _Published_ release can be set to _Unlisted_ or _Yanked_. +The state of a _Yanked_ release can not be changed anymore. + +### Environments + +The release state is managed separately for sandbox and production. +In sandbox the default state is _Published_. +In production the default state is _Unlisted_. + +A release can be overwritten to _Published_ for specific markets or accounts. +A release can only be _Yanked_ everywhere at once. + +### Prerelease Versions + +PreRelease versions only visible if you have checked the "Show prereleases" checkmark in the portal version selection interface. +They are not selected by default when creating new component in the portal and they are not used by automatic processes such as templates. + +### Version Tracability + +Every deployed version has a related tag in the middleware repository. +Every public version should have a release notes post at `https://docs.fiskaltrust.cloud/changelog/middleware/`. + +When showing the version of a package we can link directly to the github repository or release notes of said release. + +### Admins + +Admins have access to the Release Console in the portal where the release states can be managed. +The release state of all packages is overwritten to _Published_ for all admin accounts. + +### Release Console + +The Release Console is reachable through the market production portals. (Because sandbox releases are always _Public_ by default there's no need to manage those separately) +There's no separate for the different markets but the same console with the same state that's loaded in all markets. + +In the Release Console a table lists all deployed versions with their states in production as well as overrides and possibility to yank a release. + +The releases are grouped by version in the table. +The release can be published for whole group or separatley for for single packages (when it's not the same for all packages a `-` is shown in the group checkbox). +Overrides for markets and accounts can be set. +The release can be yanked through a separate confirmation dialog. It's then yanked in sandbox _and_ production. + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ v vX.Y.Z [-] Public [...] β”‚ β”‚ +β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ +β”‚ β”‚ [...] β”‚ β”‚ +β”‚ β”‚ fiskaltrust.Middleware.Queue.XXX [x] Public β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”‚ β”‚ +β”‚ β”‚ [...] β”‚ β”‚ +β”‚ β”‚ fiskaltrust.Middleware.Queue.YYY [-] Public Markets: at β”‚ β”‚ +β”‚ β”‚ Accounts: a@b.c, d@e.f β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€[...] β”‚ β”‚ +β”‚ β”‚ fiskaltrust.Middleware.SCU.DE.XXX [ ] Public β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ Set Market Overrides β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ Set Account Overridesβ”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ Yank release β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ > vX.Y.W [x] Public [...] β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Legend: + v vX.Y.Z - Expanded version group (showing packages) + > vX.Y.W - Collapsed version group + [-] Public - Mixed state (some packages public, some not) + [x] Public - Published + [ ] Public - Not published + [...] - Context menu (Set Market/Account Overrides, Yank release) +``` +(this is just a ui mockup to demonstrate the functionality ux and layout will be designed properly when implementing the RFC) + +# Reference-level explanation + +## Deployment Process + +The process of the **deployment phase** is described in [`RELEASE.md`](../RELEASE.md). + +## Storage + +## API + +## Release Console + +## Packages Servers + +> This is the technical portion of the RFC. +> Try to capture the broad implementation strategy, +> and then focus in on the tricky details so that: +> +> - Its interaction with other features is clear. +> - It is reasonably clear how the feature would be implemented. +> - Corner cases are dissected by example. +> - Discuss how this impacts the ability to read, understand, and maintain middleware code. +> Code is read and modified far more often than written; will the proposed feature make code easier to maintain? +> +> When necessary, this section should return to the examples given in the previous section and explain the implementation details that make them work. +> +> When writing this section be mindful of the following: +> - **RFCs should be scoped:** Try to avoid creating RFCs for huge design spaces that span many features. +> Try to pick a specific feature slice and describe it in as much detail as possible. +> Feel free to create multiple RFCs if you need multiple features. +> - **RFCs should avoid ambiguity:** Two developers implementing the same RFC should come up with nearly identical implementations. +> - **RFCs should be "implementable":** Merged RFCs should only depend on features from other merged RFCs and existing features. +> It is ok to create multiple dependent RFCs, but they should either be merged at the same time or have a clear merge order that ensures the "implementable" rule is respected. + +# Drawbacks + +The Relese Console increases the complexity of the release process and the number of people wo need to get involved. + +This increases the error surface of the packages servers. + +> Why should we *not* do this? + +# Rationale and alternatives + +> - Why is this design the best in the space of possible designs? +> - What other designs have been considered and what is the rationale for not choosing them? +> - What objections immediately spring to mind? How have you addressed them? +> - What is the impact of not doing this? + +# Unresolved questions + +> - What parts of the design do you expect to resolve through the RFC process before this gets merged? +> - What parts of the design do you expect to resolve through the implementation of this feature before before the feature PR is merged? +> - What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? + +# \[Optional\] Future possibilities + +## Versioning Scheme + +TODO: Check where 1.3 version stuff is hardcoded. + +> Think about what the natural extension and evolution of your proposal would be and how it would affect the middleware and ecosystem as a whole in a holistic way. +> Try to use this section as a tool to more fully consider all possible interactions with the project in your proposal. +> Also consider how this all fits into the roadmap for the project and of the relevant sub-team. +> +> This is also a good place to "dump ideas", if they are out of scope for the RFC you are writing but otherwise related. +> +> Note that having something written down in the future-possibilities section is not a reason to accept the current or a future RFC; +> such notes should be in the section on motivation or rationale in this or subsequent RFCs. +> The section merely provides additional information. diff --git a/rfcs/assets/0441-release-lifecycle-ui-mockup.svg b/rfcs/assets/0441-release-lifecycle-ui-mockup.svg new file mode 100644 index 000000000..1ad20ffdf --- /dev/null +++ b/rfcs/assets/0441-release-lifecycle-ui-mockup.svg @@ -0,0 +1,5 @@ +

v vX.Y.Z

-

. . .

fiskaltrust.Middleware.Queue.XXX

. . .

fiskaltrust.Middleware.SCU.DE.XXX

. . .

fiskaltrust.Middleware.Queue.YYY

. . .

> vX.Y.Z

. . .

Public for Markets: at

Publci for Accounts: a@b.c, d@e.f

. . .

Set Market Overrides


Set Account Overrides


Yank release

Public

x

Public

Public

Public

x

Public

diff --git a/rfcs/assets/0441-release-lifecycle-ui-mockup.tldr b/rfcs/assets/0441-release-lifecycle-ui-mockup.tldr new file mode 100644 index 000000000..31a9883e2 --- /dev/null +++ b/rfcs/assets/0441-release-lifecycle-ui-mockup.tldr @@ -0,0 +1 @@ +{"tldrawFileFormatVersion":1,"schema":{"schemaVersion":2,"sequences":{"com.tldraw.store":4,"com.tldraw.asset":1,"com.tldraw.camera":1,"com.tldraw.document":2,"com.tldraw.instance":25,"com.tldraw.instance_page_state":5,"com.tldraw.page":1,"com.tldraw.instance_presence":6,"com.tldraw.pointer":1,"com.tldraw.shape":4,"com.tldraw.asset.bookmark":2,"com.tldraw.asset.image":5,"com.tldraw.asset.video":5,"com.tldraw.shape.group":0,"com.tldraw.shape.text":3,"com.tldraw.shape.bookmark":2,"com.tldraw.shape.draw":2,"com.tldraw.shape.geo":10,"com.tldraw.shape.note":9,"com.tldraw.shape.line":5,"com.tldraw.shape.frame":1,"com.tldraw.shape.arrow":6,"com.tldraw.shape.highlight":1,"com.tldraw.shape.embed":4,"com.tldraw.shape.image":5,"com.tldraw.shape.video":3,"com.tldraw.binding.arrow":1}},"records":[{"id":"pointer:pointer","typeName":"pointer","x":-27.658002148437504,"y":46,"lastActivityTimestamp":1747297745236,"meta":{}},{"x":413,"y":141,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:XkQtMPyiG6Dz6bNIdQF5j","type":"geo","props":{"w":56,"h":56,"geo":"rectangle","color":"grey","labelColor":"black","fill":"none","dash":"draw","size":"s","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"-"}]}]}},"parentId":"page:page","index":"a52nw","typeName":"shape"},{"x":412,"y":469,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:lAz34OhhZ_YMlS3houpHV","type":"geo","props":{"w":56,"h":56,"geo":"rectangle","color":"grey","labelColor":"black","fill":"none","dash":"draw","size":"s","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"x"}]}]}},"parentId":"page:page","index":"ak0uG","typeName":"shape"},{"x":476.3419978515625,"y":392,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:PH1JBQhAjGj8t1qifhsmQ","type":"text","props":{"color":"black","size":"s","w":54.734375,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Public"}]}]}},"parentId":"page:page","index":"aj7Zq","typeName":"shape"},{"x":31.34199785156261,"y":114,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:-jcpR8Ip_kb47FtSy9OVf","type":"geo","props":{"w":953.6580021484374,"h":461,"geo":"rectangle","color":"light-blue","labelColor":"black","fill":"none","dash":"draw","size":"m","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph"}]}},"parentId":"page:page","index":"a1","typeName":"shape"},{"x":140.6580021484375,"y":0,"z":1,"meta":{},"id":"camera:page:page","typeName":"camera"},{"x":722.3419978515625,"y":429,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:zcrrdczYQuunIxYTyNDw5","type":"text","props":{"color":"grey","size":"s","w":205.453125,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Set Market Overrides"}]},{"type":"paragraph","attrs":{"dir":"auto"}},{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Set Account Overrides"}]},{"type":"paragraph","attrs":{"dir":"auto"}},{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Yank release"}]}]}},"parentId":"page:page","index":"ac37G","typeName":"shape"},{"x":477.3419978515625,"y":253,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:VKCj8fe4aLsG_-w0UutIV","type":"text","props":{"color":"black","size":"s","w":54.734375,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Public"}]}]}},"parentId":"page:page","index":"af9ss","typeName":"shape"},{"x":711.3419978515625,"y":370,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:m__Qxu07bOy8xVfJfHdby","type":"geo","props":{"w":242,"h":191,"geo":"rectangle","color":"grey","labelColor":"black","fill":"solid","dash":"draw","size":"s","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph"}]}},"parentId":"page:page","index":"aaC0g","typeName":"shape"},{"x":478.3419978515625,"y":319,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:YcGM-S6udlzyjPx80_Hnz","type":"text","props":{"color":"black","size":"s","w":54.734375,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Public"}]}]}},"parentId":"page:page","index":"ah4Tw","typeName":"shape"},{"editingShapeId":null,"croppingShapeId":null,"selectedShapeIds":[],"hoveredShapeId":null,"erasingShapeIds":[],"hintingShapeIds":[],"focusedGroupId":null,"meta":{},"id":"instance_page_state:page:page","pageId":"page:page","typeName":"instance_page_state"},{"x":71,"y":386,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:yFj1mrtMKb8FW7wOudORe","type":"text","props":{"color":"black","size":"s","w":318.875,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"fiskaltrust.Middleware.SCU.DE.XXX"}]}]}},"parentId":"page:page","index":"aF4UG","typeName":"shape"},{"x":911,"y":149,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:v8fjlKWUXVeybLp3jkgVW","type":"text","props":{"color":"black","size":"s","w":29.5625,"font":"draw","textAlign":"start","autoSize":true,"scale":1.2916666666666667,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":". . ."}]}]}},"parentId":"page:page","index":"a8BkM","typeName":"shape"},{"x":63.341997851562496,"y":214,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:I1pfswR9odtZ_OUT4kVjD","type":"geo","props":{"w":889,"h":1,"geo":"rectangle","color":"grey","labelColor":"black","fill":"none","dash":"draw","size":"s","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph"}]}},"parentId":"page:page","index":"aR8Gp","typeName":"shape"},{"x":72,"y":155,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:ZwmXd3IwBR-O6Ae5_y94m","type":"text","props":{"color":"black","size":"m","w":89.046875,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"v vX.Y.Z"}]}]}},"parentId":"page:page","index":"a36yB","typeName":"shape"},{"x":62,"y":479,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:I13155yz_yOlJNVaUeFnL","type":"text","props":{"color":"black","size":"m","w":91.5625,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"> vX.Y.Z"}]}]}},"parentId":"page:page","index":"aTBcC","typeName":"shape"},{"x":908,"y":308,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:ctLFKgqxSxNn031-jBVKG","type":"text","props":{"color":"black","size":"s","w":29.5625,"font":"draw","textAlign":"start","autoSize":true,"scale":1.2916666666666667,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":". . ."}]}]}},"parentId":"page:page","index":"aKB6P","typeName":"shape"},{"x":909,"y":371,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:cJNA_23NHdn2pXbfY0iis","type":"text","props":{"color":"black","size":"s","w":29.5625,"font":"draw","textAlign":"start","autoSize":true,"scale":1.2916666666666667,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":". . ."}]}]}},"parentId":"page:page","index":"aQAhG","typeName":"shape"},{"x":482.3419978515625,"y":487,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:VUdd1Wi2ioX4aq8EMswlQ","type":"text","props":{"color":"black","size":"s","w":54.734375,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Public"}]}]}},"parentId":"page:page","index":"alAKI","typeName":"shape"},{"x":63,"y":255,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:kkeH_z-PwoUpp6r53X9_1","type":"text","props":{"color":"black","size":"s","w":317.203125,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"fiskaltrust.Middleware.Queue.XXX"}]}]}},"parentId":"page:page","index":"a9055","typeName":"shape"},{"x":411,"y":237,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:Ku9xD2JjVdapSYlUygOh4","type":"geo","props":{"w":56,"h":56,"geo":"rectangle","color":"grey","labelColor":"black","fill":"none","dash":"draw","size":"s","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"x"}]}]}},"parentId":"page:page","index":"ae2YW","typeName":"shape"},{"x":905,"y":487,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:Pey8c_-f6WLL0K4xREF-m","type":"text","props":{"color":"black","size":"s","w":29.5625,"font":"draw","textAlign":"start","autoSize":true,"scale":1.2916666666666667,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":". . ."}]}]}},"parentId":"page:page","index":"aY2HF","typeName":"shape"},{"x":410,"y":306,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:f7ecKJsQEgUOZkiC9wOkx","type":"geo","props":{"w":56,"h":56,"geo":"rectangle","color":"grey","labelColor":"black","fill":"none","dash":"draw","size":"s","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":" "}]}]}},"parentId":"page:page","index":"ag65e","typeName":"shape"},{"x":906,"y":379,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:L14dY1pX3K-inlNojcqZu","type":"text","props":{"color":"black","size":"s","w":29.5625,"font":"draw","textAlign":"start","autoSize":true,"scale":1.2916666666666667,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":". . ."}]}]}},"parentId":"page:page","index":"ab6uV","typeName":"shape"},{"x":42.999999999999886,"y":460,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:7jw7lZ_VIWPhJl5DAc6f1","type":"geo","props":{"w":929.0000000000001,"h":80,"geo":"rectangle","color":"black","labelColor":"black","fill":"none","dash":"draw","size":"m","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"}}]}},"parentId":"page:page","index":"aS5WQ","typeName":"shape"},{"x":483.3419978515625,"y":159,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:4sySsz_kjmNQoJ4RwwPAn","type":"text","props":{"color":"black","size":"s","w":54.734375,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Public"}]}]}},"parentId":"page:page","index":"ad2Fa","typeName":"shape"},{"meta":{},"id":"page:page","name":"Page 1","index":"a1","typeName":"page"},{"gridSize":10,"name":"","meta":{},"id":"document:document","typeName":"document"},{"followingUserId":null,"opacityForNextShape":1,"stylesForNextShape":{"tldraw:geo":"rectangle","tldraw:color":"black","tldraw:arrowheadEnd":"none","tldraw:arrowKind":"elbow","tldraw:size":"s","tldraw:fill":"solid"},"brush":null,"scribbles":[],"cursor":{"type":"default","rotation":0},"isFocusMode":false,"exportBackground":true,"isDebugMode":false,"isToolLocked":false,"screenBounds":{"x":0,"y":0,"w":1696,"h":1028},"insets":[false,false,false,false],"zoomBrush":null,"isGridMode":false,"isPenMode":false,"chatMessage":"","isChatting":false,"highlightedUserIds":[],"isFocused":true,"devicePixelRatio":1,"isCoarsePointer":false,"isHoveringCanvas":false,"openMenus":[],"isChangingStyle":false,"isReadonly":false,"meta":{},"duplicateProps":null,"id":"instance:instance","currentPageId":"page:page","typeName":"instance"},{"x":912,"y":228,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:O7qyR_9O6wsKTBcX88R5G","type":"text","props":{"color":"black","size":"s","w":29.5625,"font":"draw","textAlign":"start","autoSize":true,"scale":1.2916666666666667,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":". . ."}]}]}},"parentId":"page:page","index":"aE5wC","typeName":"shape"},{"x":44.999999999999886,"y":125,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:pBbh6IMd0FVtYKnaeMixh","type":"geo","props":{"w":929.0000000000001,"h":313,"geo":"rectangle","color":"black","labelColor":"black","fill":"none","dash":"draw","size":"m","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"}}]}},"parentId":"page:page","index":"a23k7","typeName":"shape"},{"x":411,"y":372,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:ROUYB6EnlVi5MoXUW9u5M","type":"geo","props":{"w":56,"h":56,"geo":"rectangle","color":"grey","labelColor":"black","fill":"none","dash":"draw","size":"s","font":"draw","align":"middle","verticalAlign":"middle","growY":0,"url":"","scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":" "}]}]}},"parentId":"page:page","index":"ai5D1","typeName":"shape"},{"x":69,"y":316,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:5XLhkWaWgOvAuw5xSAkA5","type":"text","props":{"color":"black","size":"s","w":315.015625,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"fiskaltrust.Middleware.Queue.YYY"}]}]}},"parentId":"page:page","index":"aL95i","typeName":"shape"},{"x":567.3419978515625,"y":300,"rotation":0,"isLocked":false,"opacity":1,"meta":{},"id":"shape:GmcumSdsfIRHz6PFIWXeK","type":"text","props":{"color":"grey","size":"s","w":302.65625,"font":"draw","textAlign":"start","autoSize":true,"scale":1,"richText":{"type":"doc","content":[{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Public for Markets: at"}]},{"type":"paragraph","attrs":{"dir":"auto"},"content":[{"type":"text","text":"Publci for Accounts: a@b.c, d@e.f"}]}]}},"parentId":"page:page","index":"aZB5h","typeName":"shape"}]}