diff --git a/.dockerignore b/.dockerignore index 8d11b9a7..dabdd975 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,7 @@ .git .github .gitignore +.venv chopsticks docs diff --git a/.github/workflows/_job-docs-deploy.yml b/.github/workflows/_job-docs-deploy.yml new file mode 100644 index 00000000..5f2dda72 --- /dev/null +++ b/.github/workflows/_job-docs-deploy.yml @@ -0,0 +1,62 @@ +name: Deploy docs + +on: + workflow_call: + inputs: + version: + description: "Documentation version to deploy (e.g., '0.5', 'dev')" + required: true + type: string + alias: + description: "Version alias (e.g., 'latest', 'dev')" + required: false + type: string + set_default: + description: "Set this version as the default landing page" + required: false + type: boolean + default: false + +permissions: + contents: write # for mike to push to gh-pages + +jobs: + docs-deploy: + name: Deploy docs (${{ inputs.version }}) + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + persist-credentials: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install dependencies + run: pip install mkdocs-materialx mike + + - name: Configure git user + # Using the official GitHub Actions bot identity (user ID 41898282). + # This shows the bot avatar on gh-pages commits. + # See: https://api.github.com/users/github-actions%5Bbot%5D + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Fetch gh-pages branch + run: git fetch origin gh-pages --depth=1 || true + + - name: Deploy docs + run: | + if [ -n "${{ inputs.alias }}" ] && [ "${{ inputs.alias }}" != "${{ inputs.version }}" ]; then + mike deploy --push --update-aliases ${{ inputs.version }} ${{ inputs.alias }} + else + mike deploy --push ${{ inputs.version }} + fi + + - name: Set default version + if: inputs.set_default + run: mike set-default --push ${{ inputs.alias || inputs.version }} diff --git a/.github/workflows/merge-to-dev.yml b/.github/workflows/merge-to-dev.yml index b2563ed8..72577751 100644 --- a/.github/workflows/merge-to-dev.yml +++ b/.github/workflows/merge-to-dev.yml @@ -29,3 +29,10 @@ jobs: permissions: contents: read packages: write + + docs-deploy: + uses: ./.github/workflows/_job-docs-deploy.yml + with: + version: dev + permissions: + contents: write diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e5c0633..b18995b8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,3 +39,13 @@ jobs: changelog_body: ${{ needs.prepare.outputs.changelog_body }} permissions: contents: write + + docs-deploy: + needs: [prepare] + uses: ./.github/workflows/_job-docs-deploy.yml + with: + version: ${{ needs.prepare.outputs.version }} + alias: latest + set_default: true + permissions: + contents: write diff --git a/.gitignore b/.gitignore index f218b1d9..6c0b7674 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ static/ # locally installed binaries /bin +# python virtual environment +/.venv + # asset hub node metadata required for subxt compilation /metadata.scale diff --git a/Makefile b/Makefile index bf99a54e..65b0c8c4 100644 --- a/Makefile +++ b/Makefile @@ -145,3 +145,17 @@ generate-coverage-report: # Generate test coverage report as lcov.info open-coverage-report: # Generate and open test coverage report PATH="${PWD}/bin:${PATH}" cargo llvm-cov nextest -p kalatori --open + +###################### +### Documentation ### +###################### + +install-mkdocs: # Install mkdocs with material theme and mike into local .venv + python3 -m venv .venv + .venv/bin/pip install mkdocs-materialx mike + +docs-serve: # Serve documentation locally with live reload + .venv/bin/mkdocs serve --livereload -o + +docs-build: # Build documentation locally + .venv/bin/mkdocs build diff --git a/docs/DATABASE.md b/docs/DATABASE.md deleted file mode 100644 index 00bac1d3..00000000 --- a/docs/DATABASE.md +++ /dev/null @@ -1,37 +0,0 @@ -Plan is to update the database scheme in a way that it will support the requirements we have as for the API specs and additional improvements of the deamon. - -## Tables -### Orders (`orders`) -- order - String: order identifier provided by the frontend -- payment_status - Enum: (pending|paid|timed_out). -- withdrawal_status - Enum: (waiting|failed|completed|forced|none). -- amount - u128: Order amount -- currency - String: Currency ticker ("DOT"|"USDC"|...). -- callback: String: Callback url for frontend order status update -- payment_account: [u8; 32]: Derived address for this order. -- recipient: [u8; 32]: Address that will receive the payout once the order is fulfilled. -- message: String|null: Optional parameter for failed orders. -- payment_page: String|null: Optional parameter for the frontend to redirect to a payment page. -- redirect_url: String|null: Optional parameter for the frontend to redirect once the order is repaid. -- death: u32: Expiry timestamp for the order. - -### Transactions (`transactions`) -- transaction_id - unique id generated by us to allow linking transaction to order -- order - String: order id to link transaction to order -- chain - String: identifier for the chain where transaction occurred -- block_number - Integer: Block number where the transaction is recorded. -- position_in_block - Integer: Position of the transaction within the block. -- timestamp - Timestamp: Timestamp of the transaction. -- transaction_bytes - String: Raw transaction data. -- sender - String: Address sending the transaction. -- recipient - String: Address receiving the transaction. -- amount - Float: transaction amount -- currency: String: Transaction currency -- type - Enum: Transaction type (payment|withdrawal) to distinguish between internal (withdrawal) and external (payment) transactions -- status - Enum: Transaction status (pending|finalized|failed). - -### Instance Metadata (`instance_info`) -- instance_id - String: instance id randomly generated, happy-octopus or similar shit -- version - String: daemon version (storing it just for consistency with ServerInfo struct) -- debug - String: Debug toggle -- kalatori_remark: String: Environment specific something, can be used for whatever diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..3067a673 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,310 @@ +# Configuration + +Kalatori is configured through JSON files and/or environment variables. Environment variables take precedence over file values. + +## Quick Start + +```bash +# Copy example configs +make copy-configs +``` + +### For Development / Testing + +The example configs work out of the box for local development and API testing without real transfers. Just copy them and run the daemon: + +```bash +make setup +make run +``` + +!!! note + The payment page (front-end) requires a valid Reown project ID to work correctly. Without it, wallet connection will fail. Get one for free at [cloud.reown.com](https://cloud.reown.com/) and set it in `shop.json` → `reown_project_id`. + +### For Real Transfers + +When handling real money, you **must** configure the following: + +| What | Where | How to Get | +|------|-------|------------| +| Seed phrase | `secrets.json` → `seed` | Generate a unique BIP39 mnemonic — the example seed is publicly known and must not be used for real funds | +| Recipient address | `payments.json` → `recipient` | Your own wallet address for used chain (Polygon by default) | +| Reown project ID | `shop.json` → `reown_project_id` | Register at [cloud.reown.com](https://cloud.reown.com/) (free) | +| Etherscan API key | `etherscan_client.json` → `api_key` | Register at [polygonscan.com/apis](https://polygonscan.com/apis) (free, required for Polygon) | +| Webhook URL | `shop.json` → `invoices_webhook_url` | Your e-commerce platform's endpoint, or use [webhook.site](https://webhook.site) for testing | + +### For Production + +On top of the above, for a production deployment you should also: + +- **Generate a new API secret key** (`secrets.json` → `api_secret_key`) — use a strong random value, e.g.: `openssl rand -base64 32` +- **Set your public URL** (`payments.json` → `payment_url_base`) — the externally accessible URL of your Kalatori instance +- **Set your shop name and logo** (`shop.json` → `shop_name`, `logo_url`) — displayed on the payment page + +## Config Files + +All files are loaded from the `configs/` directory (override with `KALATORI_CONFIG_DIR_PATH` env var). Every file is optional on the filesystem — you can provide all values via environment variables instead. + +### secrets.json + +Sensitive credentials. Both fields are required. + +```json +{ + "seed": "your twelve or twenty four word mnemonic phrase here", + "api_secret_key": "your-api-secret-key" +} +``` + +| Field | Required | Description | +|-------|----------|-------------| +| `seed` | Yes | BIP39 mnemonic phrase (12 or 24 words). Used to deterministically derive unique payment accounts for each invoice. The same seed always produces the same accounts, so it's safe to restart the daemon without losing track of payments. | +| `api_secret_key` | Yes | Secret key for webhook HMAC signature verification. Must match the key configured in your e-commerce platform. | + +**Where to get values:** + +- **seed**: Generate a BIP39 mnemonic using any trusted tool. For production, use an offline generator or a hardware wallet. Never reuse a seed phrase that holds personal funds. +- **api_secret_key**: Generate a random string, e.g.: `openssl rand -base64 32` + +!!! warning "Security" + Both values are automatically removed from environment variables after loading to prevent accidental exposure. They are stored in memory using `SecretString` which zeroes memory on drop. + +### payments.json + +Payment routing and invoice settings. + +```json +{ + "recipient": { + "PolkadotAssetHub": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "Polygon": "0x0E3Ca7fD040144900AdaA5f9B8917f3933A4F5e9" + }, + "payment_url_base": "https://pay.example.com" +} +``` + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `recipient` | Yes | — | Wallet addresses where paid invoices are swept to, one per chain. At minimum, the address for the default chain must be set. | +| `payment_url_base` | Yes | — | Public URL of your Kalatori instance. Used to generate payment page links. | +| `invoice_lifetime_millis` | No | `86400000` (24h) | How long an invoice stays active before expiring, in milliseconds. | +| `default_chain` | No | `Polygon` | Which chain to use when creating invoices without specifying a chain. | +| `default_asset_id` | No | Per-chain built-in | Default asset for each chain. PolkadotAssetHub: `1337`, Polygon: `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` (native USDC). | +| `slippage_params` | No | All zeros | Per-asset underpay/overpay tolerance. See [Slippage Parameters](#slippage-parameters). | + +**Where to get values:** + +- **recipient (Polygon)**: Your Ethereum/Polygon wallet address in 0x format. Get from MetaMask, Ledger, etc. +- **recipient (PolkadotAssetHub)**: Your Polkadot wallet address in ss58 format (prefix 0). Get from Polkadot.js, Nova Wallet, Ledger, etc. Note: the front-end payment page does not support Polkadot Asset Hub yet. + +### shop.json + +Shop metadata and webhook integration for the payment page. + +```json +{ + "invoices_webhook_url": "https://mystore.com/webhooks/kalatori", + "shop_name": "My Store", + "logo_url": "https://mystore.com/logo.png", + "reown_project_id": "da9b8666eec49849ccb28bca96afdefa" +} +``` + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `invoices_webhook_url` | Yes | — | URL where Kalatori sends invoice status updates (paid, expired, etc.). | +| `shop_name` | Yes | — | Display name shown on the payment page. | +| `reown_project_id` | Yes | — | Reown (formerly WalletConnect) project ID for wallet connection on the payment page. | +| `logo_url` | No | `null` | URL to shop logo image displayed on the payment page. | +| `signature_max_age_secs` | No | `300` (5 min) | Maximum age of webhook HMAC signature before rejection. Prevents replay attacks. | + +**Where to get values:** + +- **reown_project_id**: Register at [cloud.reown.com](https://cloud.reown.com/), create a project, and copy the Project ID. Free tier is available. +- **invoices_webhook_url**: Your e-commerce platform's endpoint that will receive invoice status notifications. + +### chains.json + +Blockchain RPC endpoints and monitored assets. Fully optional — defaults are provided for all chains. + +```json +{ + "chains": { + "PolkadotAssetHub": { + "endpoints": ["wss://asset-hub-polkadot-rpc.n.dwellir.com"], + "allow_insecure_endpoints": false + }, + "Polygon": { + "endpoints": ["wss://polygon-bor-rpc.publicnode.com"], + "allow_insecure_endpoints": false + } + } +} +``` + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `chains.[ChainType].endpoints` | No | Built-in public RPCs | WebSocket RPC endpoints. Multiple endpoints enable automatic failover. | +| `chains.[ChainType].assets` | No | Default USDC per chain | Asset IDs to monitor. Cannot be overridden via env vars — only via JSON. | +| `chains.[ChainType].allow_insecure_endpoints` | No | `false` | Allow `ws://` and `http://` endpoints. Set to `true` only for local development. | + +Default endpoints: + +- **PolkadotAssetHub**: `wss://asset-hub-polkadot-rpc.n.dwellir.com`, `wss://polkadot-asset-hub-rpc.polkadot.io` +- **Polygon**: `wss://polygon-bor-rpc.publicnode.com`, `wss://polygon.drpc.org` + +### etherscan_client.json + +Required for Polygon chain support. Not needed if you only use Polkadot Asset Hub. + +```json +{ + "api_key": "YOUR_POLYGONSCAN_API_KEY" +} +``` + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `api_key` | Yes (for Polygon) | — | API key for Polygonscan, used to track token transfers. | +| `requests_per_second` | No | `3` | Rate limit for API calls. Free tier allows 3 req/s. | + +**Where to get values:** + +- **api_key**: Register at [polygonscan.com/apis](https://polygonscan.com/apis), create an API key in your account settings. Free tier is sufficient. + +### web_server.json + +HTTP server binding. Fully optional. + +```json +{ + "host": "0.0.0.0", + "port": 8080 +} +``` + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `host` | No | `0.0.0.0` | IP address to bind to. Use `127.0.0.1` to restrict to localhost. | +| `port` | No | `8080` | TCP port for the HTTP server. | + +### database.json + +SQLite database settings. Fully optional. + +```json +{ + "dir": "database", + "temporary": false +} +``` + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `dir` | No | `./database` | Directory where `kalatori_db.sqlite` is stored. | +| `temporary` | No | `false` | Use in-memory database (data lost on shutdown). Useful for testing only. | + +### logger.json + +Logging configuration. Fully optional. + +```json +{ + "directives": "kalatori=trace,info", + "loki_url": null +} +``` + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `directives` | No | `kalatori=trace,info` | [Tracing filter directives](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html) controlling log verbosity. | +| `loki_url` | No | `null` | Grafana Loki URL for centralized log aggregation. If `null`, logs go to stdout only. | + +## Environment Variables + +Flat config fields can be set via environment variables. Fields with nested structure (like `recipient`, `chains`, `slippage_params`, `assets`) should be configured via JSON files. The pattern is: + +``` +{PREFIX}_{CONFIG}_{FIELD} +``` + +where `PREFIX` defaults to `KALATORI`. + +### Examples + +```bash +# Secrets +export KALATORI_SECRETS_SEED="your mnemonic phrase here" +export KALATORI_SECRETS_API_SECRET_KEY="your-secret-key" + +# Payments (flat fields only — recipient and slippage_params should be set via JSON) +export KALATORI_PAYMENTS_PAYMENT_URL_BASE="https://pay.example.com" +export KALATORI_PAYMENTS_INVOICE_LIFETIME_MILLIS=86400000 +export KALATORI_PAYMENTS_DEFAULT_CHAIN=Polygon + +# Shop +export KALATORI_SHOP_SHOP_NAME="My Store" +export KALATORI_SHOP_INVOICES_WEBHOOK_URL="https://mystore.com/webhooks" +export KALATORI_SHOP_REOWN_PROJECT_ID="da9b8666eec49849ccb28bca96afdefa" + +# Web server +export KALATORI_WEB_SERVER_HOST=0.0.0.0 +export KALATORI_WEB_SERVER_PORT=8080 + +# Database +export KALATORI_DATABASE_DIR=/var/lib/kalatori + +# Etherscan +export KALATORI_ETHERSCAN_CLIENT_API_KEY="your-api-key" + +# Logger +export KALATORI_LOGGER_DIRECTIVES="kalatori=debug,info" +export KALATORI_LOGGER_LOKI_URL="http://localhost:3100" +``` + +!!! note + Fields with nested structure (`recipient`, `slippage_params`, `chains`) should be configured via JSON files rather than environment variables. + +### Special Variables + +| Variable | Description | +|----------|-------------| +| `KALATORI_APP_ENV_PREFIX` | Change the prefix from `KALATORI` to a custom value. All other env vars must then use the new prefix. | +| `KALATORI_CONFIG_DIR_PATH` | Override the config files directory (default: `configs`). | + +### Priority + +Environment variables override JSON file values. Built-in defaults apply when neither is set. + +``` +Environment variable > JSON file > Built-in default +``` + +## Slippage Parameters + +Slippage parameters control how the daemon handles payments that don't exactly match the invoice amount. Configured per asset in `payments.json`: + +```json +{ + "slippage_params": { + "Polygon": { + "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359": { + "underpayment_tolerance": "0.05", + "overpayment_tolerance": "0.10" + } + } + } +} +``` + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `underpayment_tolerance` | `0` | Maximum amount below the invoice that is still accepted as paid. `0` means exact amount required. | +| `overpayment_tolerance` | `0` | Maximum excess above the invoice before triggering a partial refund. `0` means any overpayment triggers refund. | + +## Supported Chains + +| Chain | Address Format | Default Asset | +|-------|---------------|---------------| +| `PolkadotAssetHub` | ss58 (prefix 0), e.g. `5Grwva...` | `1337` (USDC) | +| `Polygon` | 0x hex (ERC-20), e.g. `0x0E3C...` | `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` (native USDC) | diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..4c9c577d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,9 @@ +# Kalatori Documentation + +Kalatori is a self-hosted, non-custodial blockchain payment gateway daemon for processing crypto payments on Polygon and Polkadot's Asset Hub parachain. + +## Sections + +- **[Configuration](configuration.md)** — Config files, environment variables, and setup guide +- **[Policies](policies/git.md)** — Git, CI, release, and workflow policies +- **Dev** — Architecture, error handling, logging conventions *(coming soon)* diff --git a/docs/policies/ci.md b/docs/policies/ci.md new file mode 100644 index 00000000..dc683ee1 --- /dev/null +++ b/docs/policies/ci.md @@ -0,0 +1,99 @@ +# CI Policies + +1. Quality gates that must pass before merging into `dev`: + - Commit message format validation (conventional commits) + - Branch name format validation + - Code formatting checks + - Linting + - Compilation / type checking + - Unit tests + - Integration / end-to-end tests + - Dependency audit (license compliance, security advisories) + +2. Additional quality gates before merging into `main` (on top of all `dev` checks): + - Source branch validation (only `dev` and `hotfix-*`) + - Version validation (see point 3) + - Changelog validation (see point 4) + +3. Version is read from the project manifest (e.g., `Cargo.toml`, `package.json`). Before merge into `main`, the version must: + - Be valid semver. + - Not already exist as a git tag. + - Increment major, minor, or patch over the latest existing tag. + - If no tags exist yet, be `0.1.0` or `1.0.0`. + +4. `CHANGELOG.md` must contain a section heading matching the version being released (e.g., `## [0.8.2]`). Changelog is semi-automatic: + - Generated via tooling (e.g., `git-cliff`). + - Reviewed and edited by a human before committing. + +5. On merge into `main`, CI runs tests (with coverage) and integration tests. Release is a separate step triggered by a tag push: + - The project owner manually creates a signed `vX.Y.Z` tag on the merge commit. + - On tag push, CI runs tests, builds release artifacts with the release version. + - CI extracts the relevant changelog section. + - CI creates a GitHub release with changelog as release notes and artifacts attached. + - Release artifacts may also be tagged as `latest` if the artifact type supports it (e.g., Docker images). + +6. On merge into `dev`, CI automatically: + - Runs tests (with coverage) and integration tests. + - Builds artifacts with version `dev-${COMMIT_SHA}` (full commit hash). + - Each artifact must be able to report this exact version at runtime (e.g., `--version` flag, `/health` endpoint, embedded metadata). + - Dev artifacts use a separate image name (e.g., `kalatori-dev`) and are also tagged as `latest`. + +7. Projects should pin their build toolchain versions to ensure reproducible builds across local development, CI, and Docker environments. Examples: + - **Rust**: `rust-toolchain.toml` + - **Node.js**: `.node-version` or `.nvmrc` + - **Python**: `.python-version` + - **Ruby**: `.ruby-version` + +8. Test coverage reports with degradation tracking. Currently integrated via Codecov on PR, merge-to-dev, and merge-to-main workflows. + +9. (Optional) Benchmark tracking with degradation alerts. Not required but encouraged. + +10. (Optional) Metadata file attached to artifacts containing: + - Commit hash + - Pipeline ID + - Build branch + - Build toolchain version + - Build timestamp + + Not required but encouraged. + +11. (Optional) Test result reports for debugging failed runs. Not required but encouraged. + + +# Implementation Priorities + +## High Priority + +- Protected branches (Git 1) +- Build release artifacts on merge to `main` with version from manifest (CI 5) +- Create GitHub release automatically (CI 5) +- Create git tag automatically (CI 5) +- Run unit tests as a quality gate (CI 1) + +## Medium Priority + +- Version validation before merge to `main` (CI 3) +- Changelog validation before merge to `main` (CI 4) +- Attach changelog section to GitHub release (CI 5) +- Build artifacts on `dev` with `dev-${SHORT_SHA}` versioning (CI 6) +- Branch merge rules enforcement — only `dev` and `hotfix-*` into `main` (Git 2, CI 2) +- Branch name format validation (Git 5, CI 1) +- Commit message format validation (Git 7, CI 1) +- Run integration / end-to-end tests as a quality gate (CI 1) +- Dependency audit as a quality gate (CI 1) +- Code formatting and linting checks (CI 1) +- Build toolchain pinning (CI 7) + +## Low Priority + +- Test coverage reports (CI 8) +- Benchmark tracking (CI 9) +- Metadata file attached to artifacts (CI 10) +- Test result reports (CI 11) +- Automated deployment of `dev` artifacts to staging (Future) + +## Future Considerations + +- Multiple approvals required for merging into `main`. +- Automated deployment of `dev` artifacts to staging. +- Multi-package / monorepo support (independent versioning, tags, changelogs, and releases per package). diff --git a/docs/policies/flows.md b/docs/policies/flows.md new file mode 100644 index 00000000..10d672e4 --- /dev/null +++ b/docs/policies/flows.md @@ -0,0 +1,32 @@ +# Flows + +## Feature Development Flow + +1. Create a feature branch from `dev`. +2. Develop with conventional commits. +3. Open a PR into `dev`. +4. CI runs all quality gate checks. +5. After review and checks pass, merge with a merge commit. +6. Delete the feature branch. + +## Release Flow + +1. Create a branch from `dev` (e.g., `prepare-release-X.Y.Z`). +2. Bump version in the project manifest. +3. Generate changelog draft via `git-cliff` (or equivalent). +4. Review and edit the generated changelog. +5. Open a PR into `dev`. Team reviews changelog and version bump. +6. After merge into `dev`, open a PR from `dev` into `main`. +7. CI validates version, changelog, source branch, and runs all checks. +8. After merge, the project owner creates a signed `vX.Y.Z` tag on the merge commit. The tag push triggers CI to run tests, build artifacts, and publish a GitHub release. + +## Hotfix Flow + +1. Create a `hotfix-*` branch from `main`. +2. Fix the issue with conventional commits. +3. Bump the patch version in the project manifest. +4. Add the changelog entry for the new patch version. +5. Open a PR into `main`. +6. CI validates version, changelog, and runs all checks. +7. After merge, the project owner creates a signed `vX.Y.Z` tag. The tag push triggers CI to run tests, build artifacts, and publish a GitHub release. +8. Immediately merge `main` back into `dev` to sync the fix, version bump, and changelog. diff --git a/docs/policies/git.md b/docs/policies/git.md new file mode 100644 index 00000000..53be90b4 --- /dev/null +++ b/docs/policies/git.md @@ -0,0 +1,32 @@ +# Git Policies + +1. Two protected branches: `main` (production-ready, released code) and `dev` (main working branch). Direct pushes to protected branches are not allowed — all changes go through pull requests. + +2. Only `dev` and `hotfix-*` branches can be merged into `main`. Feature branches and `main` (after hotfixes/releases) can be merged into `dev`. + +3. Hotfixes merged into `main` must be immediately merged back into `dev` to keep branches in sync. + +4. All merges use merge commits. No squash merges, no fast-forward. Individual commits are preserved for changelog generation and history traceability. + +5. Branch naming format: `username/issueN-type-short-description`. + - Only `short-description` in kebab-case is required. + - `username/`, `issueN-`, and `type-` are optional but encouraged. + - Exception: hotfix branches use the format `hotfix-short-description`. + - Examples: + ``` + anlis/issue42-feat-add-webhook-support + issue15-fix-payment-detection + prepare-release-0.8.2 + hotfix-fix-payment-race + ``` + +6. Feature branches are deleted after merge. Branches should be short-lived to minimize merge conflicts and drift. + +7. All commits must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification: `type(optional-scope): description`. + - Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `build`, `ci`, `chore`, `revert`, `perf`. + - Issue references use the `Refs: #N` footer — not a `[Issue #N]` prefix. + - Breaking changes are indicated with `!` after the type or a `BREAKING CHANGE:` footer. + +8. Rollbacks are treated as hotfixes. Existing release versions are never overwritten — a new patch version is created that reverts the problematic change. + +9. Patching older versions (e.g., releasing `8.0.5` when `main` is at `8.1.3`) is handled on a case-by-case basis using dedicated branches from the relevant tag. This is not part of the standard flow. diff --git a/docs/policies/release.md b/docs/policies/release.md new file mode 100644 index 00000000..a71ee412 --- /dev/null +++ b/docs/policies/release.md @@ -0,0 +1,28 @@ +# Release Policy + +* Artifact. Release artifact is a Docker Image. We’re not provide any guarantees that raw binary will work expectedly on any system. +* Infrequent releases. Prefer to make releases not frequently, but with significant updates like new functionality or critical bug fixes. +* Release worth updates. New capabilities, critical bug fixes are considered as release worth. Additional test coverage, dependency updates (except ones with critical bug fixes), new non-significant features of implemented capabilities are considered not worth releasing. +* Deprecation. Some old APIs or configs can be marked deprecated and will be removed 2 updates later. + + +# Backward Compatibility Policy + +As long as our final artifact is Docker Image we can consider next updates as backward incompatible: + +* Removing deprecated API handlers; +* Requirement of new attachable docker volumes; +* Introduction new mandatory configs or config fields; +* Removing or renaming config fields; +* Make earlier optional config field mandatory; + +In the same time next updates we consider backward compatible: + +* MSRV update; +* Major dependency updates; +* Introduction of new APIs; +* Introduction of new non mandatory configs; +* Introduction of new non mandatory config fields; +* Make earlier mandatory config field optional; +* Change config field default value (except paths which might/should be mounted); +* etc. diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..2ef5b8bc --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,48 @@ +site_name: Kalatori Docs +site_description: Documentation for the Kalatori payment gateway +repo_url: https://github.com/Kalapaja/Kalatori +repo_name: Kalapaja/Kalatori + +theme: + name: materialx + palette: + - scheme: default + primary: indigo + accent: indigo + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: indigo + accent: indigo + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.sections + - navigation.expand + - search.suggest + - content.code.copy + +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - toc: + permalink: true + +extra: + version: + provider: mike + +nav: + - Home: index.md + - Configuration: configuration.md + - Policies: + - Release: policies/release.md + - Git: policies/git.md + - CI: policies/ci.md + - Flows: policies/flows.md