Skip to main content

PostgreSQL schema evolution with built-in multi-agent coordination 🍓

Project description

Confiture 🍓

PostgreSQL migrations, sweetly done.

Build from DDL. Adopt on day one against a database that already has migrations applied. Preflight every deploy against a parallel database with structural diff. Sync production data with PII anonymization.

PyPI Quality Gate Python 3.11+ PostgreSQL 12+ License: MIT


In 30 seconds

# 1. You already have a database at migration 004 (applied by hand or by another tool).
#    Tell Confiture about that history without re-running the SQL:
$ confiture migrate baseline --through 004 -c db/environments/production.yaml
   001 create_users (marked as applied)
   002 create_orders (marked as applied)
   003 add_user_email (marked as applied)
   004 add_user_preferences (marked as applied) Marked 4 migration(s) as applied, skipped 0 already applied

# 2. Machine-readable proof that the tracking is healthy:
$ confiture migrate status -c db/environments/production.yaml --format json | jq '.applied | length'
4

# 3. Preflight: replay pending migrations on a parallel DB, emit a structural diff vs. db/schema/.
$ confiture migrate preflight --against "$PREFLIGHT_URL" -c db/environments/production.yaml
▸ Replaying pending migrations on preflight DB    20260520143015_add_user_bio                 applied in 24 ms
▸ Comparing resulting schema vs. db/schema/    No drift  preflight matches db/schema/
✓ Preflight passed. Safe to deploy.
exit 0

That's the loop. Baseline once → status to confirm → preflight every deploy.


Already have migrations?

The single biggest reason migration tools fail adoption is the day-one cliff: existing tables already exist, so any tool that tries to apply migrations from scratch crashes on the first CREATE TABLE. Confiture's answer is migrate baseline:

confiture migrate baseline --through <last-applied-version>

The walkthrough — including failure modes, the integration test that backs the recipe, and what tb_confiture ends up looking like — is in docs/guides/legacy-bootstrap.md.


No db/schema/ directory? That works too.

confiture migrate up, down, down-to, status, current, baseline, and preflight are the migration runner — they don't require a db/schema/ directory (migrate current prints the latest applied revision as a narrow "what's deployed?" contract; migrate down --steps N rolls back relatively while migrate down-to <revision> rolls back to a specific revision, refusing atomically if any required .down.sql is missing). The "Build from DDL" pitch above the fold sells one of confiture's four strategies; the other three (incremental migrations, production sync, schema-to-schema FDW migration) work against a project whose only source of truth is the migration chain itself.

If you're evaluating confiture against Flyway / Alembic / dbmate / sqlx-cli as a pure migration runner, skip confiture build and use everything else. Walkthrough: docs/guides/02-incremental-migrations.md.


When to use Confiture?

Capability Confiture Flyway Alembic dbmate sqlx-cli plain psql
Source of truth DDL files or migration chain migration chain model classes migration chain migration chain DDL files
Tracking table yes yes yes yes yes no
Rollback (down.sql) yes paid yes yes yes no
Preflight against a copy DB yes (structural diff) no no no no no
Build from scratch in <1s yes no no no no yes (manual)
Production sync + anonymization yes no no no no no
Zero-downtime via FDW yes no no no no no
Multi-agent coordination yes no no no no no
Ecosystem maturity / stars early very mature mature mature mature n/a

Note on "source of truth": confiture can run as a pure migration tool against a project that has no db/schema/ directory — the DDL workflow is opt-in. See No db/schema/ directory? above.

Confiture wins on build-from-DDL, structural-diff preflight, production sync, and multi-agent coordination. It loses on ecosystem age — Flyway and Alembic have a decade of community knowledge. Pick honestly.

Adoption checklist

Situation Recommended tool
1 environment + 1 contributor, schema rarely changes plain psql
2+ environments, schema changes weekly Confiture, Flyway, Alembic, or dbmate
Multi-agent / AI-driven development on shared schemas Confiture
You have a migration chain (no db/schema/) and want preflight + tracking Confiture (use everything except confiture build)
You want db/schema/ to be source of truth, not a migration chain Confiture
You need zero-downtime schema swaps with postgres_fdw Confiture (Medium 4)
You're committed to SQLAlchemy ORM Alembic
You're committed to a JVM stack Flyway

CI integration

A migrate preflight gate on every PR, a migrate up step on deploy. Exit codes are semantic, so the CI configuration stays simple:

# .github/workflows/db.yml
name: DB

on:
  pull_request:
    paths:
      - 'db/**'
  push:
    branches: [main]

jobs:
  preflight:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env: { POSTGRES_PASSWORD: x }
        ports: ['5432:5432']
        options: >-
          --health-cmd pg_isready --health-interval 10s
          --health-timeout 5s --health-retries 5
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
      - run: uv pip install --system "fraiseql-confiture[ast]"
      - name: Restore production snapshot to preflight DB
        run: ./scripts/restore-snapshot.sh   # your own; pg_restore from S3/GCS
      - name: Confiture preflight
        env:
          PREFLIGHT_URL: postgresql://postgres:x@localhost:5432/preflight
        run: |
          confiture migrate preflight \
            --against "$PREFLIGHT_URL" \
            -c db/environments/preflight.yaml \
            --format json --output preflight.json
      - uses: actions/upload-artifact@v4
        with:
          name: preflight-report
          path: preflight.json

  deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
      - run: uv pip install --system "fraiseql-confiture[ast]"
      # No YAML needed in CI — the migrate family reads DATABASE_URL directly
      # (or pass --database-url "$DSN"). See the connection-source docs below.
      - run: confiture migrate up
        env:
          DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}

migrate up/down/status/verify/preflight accept --database-url <dsn> (or read CONFITURE_DATABASE_URL / DATABASE_URL) so runtime-resolved DSNs need no temp YAML — precedence and details in the CLI reference.

Exit codes are a documented stability contract — see the exit-code reference. The most operationally important: 2 tracking table absent, 3 DB connection failed, 5 config invalid, 6 lock contention. For migrate preflight's drift-gate codes specifically, see the dry-run guide.

Migrations that open their own SAVEPOINTs, use psycopg's conn.transaction(), or wrap DO $$ … EXCEPTION WHEN … $$ blocks are supported under all three modes. The rules a migration body must follow for the SAVEPOINT-based rollback to stay clean are documented in the transaction & SAVEPOINT contract.


Python project snippet

Add Confiture as a dev dependency. The [ast] extra pulls in pglast for full PostgreSQL parsing — recommended for schemas with bulk seed data.

# pyproject.toml
[dependency-groups]
dev = [
  "fraiseql-confiture[ast]>=0.9",
  "pytest>=8",
]
# justfile
default:
    just --list

db-build:
    confiture build --env local

db-up:
    confiture migrate up

db-status:
    confiture migrate status

db-preflight:
    confiture migrate preflight --against "$PREFLIGHT_URL"

Or as a Makefile:

db-build:
	confiture build --env local

db-up:
	confiture migrate up

db-status:
	confiture migrate status

Library API

Confiture is a CLI first, but the migrator is fully usable from Python:

from confiture import Migrator

with Migrator.from_config("db/environments/prod.yaml") as m:
    status = m.status()
    if status.has_pending:
        result = m.up()
        print(f"Applied {len(result.applied)} migrations")

The Four Strategies

Strategy Use Case Command
Build from DDL Fresh databases, testing, CI confiture build --env local
Incremental Migrations Existing databases, production confiture migrate up
Production Sync Copy data with PII anonymization confiture sync --from prod --anonymize users.email
Zero-Downtime Complex migrations via FDW confiture migrate schema-to-schema

Documentation

Start here

Guides

Reference

For agents and tooling

  • Every machine-readable CLI output has a published JSON schema under docs/reference/json-schemas/ — see docs/reference/json-schemas.md.
  • On an error path in --format json mode, the migrate family emits a structured error envelope on stdout — {"ok": false, "error": {code, message, severity, actionable, details, migration, file, line}} — and exits with the exit code for that error. The full code list and the envelope schema are in the error-code codebook.
  • confiture migrate validate --list-patterns --format json exposes the full idempotency-detection catalog (read-only, no DB / config / migrations directory needed).
  • Quiet-success ambiguities surface advisory hints in payload["hints"] (or on stderr in text mode) — exit codes are unaffected.

Contributing

git clone https://github.com/fraiseql/confiture.git
cd confiture
uv sync --all-extras
uv run pytest

See CONTRIBUTING.md and CLAUDE.md.


Author & License

Vibe-engineered by Lionel Hamayon 🍓

MIT License — Copyright (c) 2025 Lionel Hamayon


Making jam from strawberries, one migration at a time. 🍓→🍯

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fraiseql_confiture-0.38.0.tar.gz (2.1 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

fraiseql_confiture-0.38.0-cp314-cp314-win_amd64.whl (1.0 MB view details)

Uploaded CPython 3.14Windows x86-64

fraiseql_confiture-0.38.0-cp313-cp313-win_amd64.whl (1.0 MB view details)

Uploaded CPython 3.13Windows x86-64

fraiseql_confiture-0.38.0-cp313-cp313-manylinux_2_28_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ x86-64

fraiseql_confiture-0.38.0-cp313-cp313-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

fraiseql_confiture-0.38.0-cp312-cp312-win_amd64.whl (1.0 MB view details)

Uploaded CPython 3.12Windows x86-64

fraiseql_confiture-0.38.0-cp312-cp312-manylinux_2_28_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64

fraiseql_confiture-0.38.0-cp312-cp312-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

fraiseql_confiture-0.38.0-cp311-cp311-win_amd64.whl (1.0 MB view details)

Uploaded CPython 3.11Windows x86-64

fraiseql_confiture-0.38.0-cp311-cp311-manylinux_2_28_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

fraiseql_confiture-0.38.0-cp311-cp311-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

File details

Details for the file fraiseql_confiture-0.38.0.tar.gz.

File metadata

  • Download URL: fraiseql_confiture-0.38.0.tar.gz
  • Upload date:
  • Size: 2.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0.tar.gz
Algorithm Hash digest
SHA256 40380d830c8add823e5803f55006feffe49b157419696c972fce8e62813b109a
MD5 f1eee62ea3d09abc606ae8d386827516
BLAKE2b-256 faba594b4d85bebb149b7b274eeb60e01424904417e69021b90f04c2e62ef45a

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 ea2df521f4ba346aa6c3e06b16885199ca332bc780f4380b4b0bea31a57e65db
MD5 56d0c9f5ffe8fdf5146f31ae1e8bf727
BLAKE2b-256 80b08804c92d85ea1b2a168657b1082281d07d0ab1d1414605713966e28823a8

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 64e3938c2e15cb9c7695171b7d96de38ea31468475ae8eadc95b66348d3ec9c6
MD5 20ffad2821530b653dd641fe58bdbeab
BLAKE2b-256 394b3507d3187d48080f53d35edddfc39d58be0e569a85ad256c461a8ff19e0e

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp313-cp313-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp313-cp313-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.13, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp313-cp313-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 bed3c80eb1b833b99674d7a3b294effbbda48edf42b58e991ac1d9eca6669a15
MD5 09686ae705094bff09772f27653788c6
BLAKE2b-256 05ea2e9e51047a679b86e55fb7f766dbea0b8d3ae30419d473ecb4613e99bb1b

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp313-cp313-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.13, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 31e9bdd34c4124288d7266cd8c0640d8ed77e47c9a57b6abbb182a178d6cdddd
MD5 e274f46959c12c3bdb026d71cb1d576d
BLAKE2b-256 25d20064e2214e9af21b7da25da8636f15c825d77c4aef63029677e3deda112e

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 06389b21aa123f68caef47837f03d088f69441ba1274940e28a5f3536626a691
MD5 7014573b04514b7d08cddda58cedaafe
BLAKE2b-256 ba65c351c00c2bca0c9b094e15972cd112a7109d281ad6380237f773e3716981

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp312-cp312-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.12, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 945fa95fc01dbfc225c358d08c59785e7cf07c4c4a96b7608bb9b5d02dc245bf
MD5 8f8758596bb23bce76807a9544d7c3c3
BLAKE2b-256 58209bc5e69921b29b6ceb7239cfbb62d44f6cadd39cbde1ecbf9b4c7a9506f0

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp312-cp312-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.12, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 61674f59b9a45c8d4cfac2837dbb922ba0dc9388cbc001f960d9493d0134b017
MD5 d7ed7c4dffc5aff6bcb1a896541e8069
BLAKE2b-256 28090ce8373f53c68ea0191fcdd1d0784e39236b229d9f2522c00995fdc3c1f3

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 557b208dc7b546ed34a6e3bf9bbab90b4f40c088dedaa3c698686d2fefc4bb7c
MD5 e3efd78cdac780f5c66b6384c2323d09
BLAKE2b-256 1314d535ff723795af9746b8d71d6c5246e60e22ff410328037f533417552c3f

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp311-cp311-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.11, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 abc452ba1f14955854d3747bf909a98ffd0a3f8c46bd41133dab50b5ac82f475
MD5 e56a206cbfb4294fb9cd269b0b5c07da
BLAKE2b-256 6c7260d32d84d5a57803cd970ba1158e9a2350576319ba96057b2e04631602fa

See more details on using hashes here.

File details

Details for the file fraiseql_confiture-0.38.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

  • Download URL: fraiseql_confiture-0.38.0-cp311-cp311-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.11, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fraiseql_confiture-0.38.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3e4bcbd9b018367b4e0dae4bea281a2938e30eba1016754614f7acb60dac4dcd
MD5 00a50e12dead7035319d6ab9ce70a48c
BLAKE2b-256 d19118e9cafb678705abbbcc0941b2b1ac48276729e0b9c9de1f131a94bf144e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page