feat: revamp analytics dashboards and harden database migrations

Add dashboard and overview analytics, health monitoring, provider expense tracking, and announcement updates across the gateway and frontend.

Keep schema migrations free of historical backfills while preserving automatic backfill execution. Bound migration deadlines, run schema preparation before Compose replacement, and anonymize deleted dashboard users.

Include the current documentation cleanup and regression coverage.
This commit is contained in:
elky
2026-10-01 11:48:17 +08:00
parent 60b89cc840
commit 066ea87d72
327 changed files with 31728 additions and 20645 deletions
+100 -1
View File
@@ -19,6 +19,101 @@ make_fixture() {
chmod 0755 "${fixture}/compose/update.sh"
}
make_migration_docker_stub() {
local fixture="$1"
cat >"${fixture}/bin/docker" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >>"${AETHER_TEST_CALLS}"
case "$*" in
"compose version"|"info") exit 0 ;;
*"config --services") printf 'app\n' ;;
*"pull app") exit 0 ;;
*"run --rm --no-deps -T app --migrate") exit "${AETHER_TEST_MIGRATION_STATUS:-0}" ;;
*"up --help") printf '%s\n' ' --wait Wait for services' ;;
*"up -d --wait --wait-timeout 120 app"|*" ps") exit 0 ;;
*) printf 'Unexpected docker arguments: %s\n' "$*" >&2; exit 99 ;;
esac
EOF
chmod 0755 "${fixture}/bin/docker"
}
test_migration_succeeds_before_recreate() {
local fixture="${TEST_ROOT}/migration-before-recreate"
make_fixture "${fixture}"
make_migration_docker_stub "${fixture}"
PATH="${fixture}/bin:${PATH}" AETHER_TEST_CALLS="${fixture}/calls" \
"${fixture}/compose/update.sh" --compose-dir "${fixture}/compose" \
>"${fixture}/stdout" 2>"${fixture}/stderr"
local pull_line migration_line recreate_line
pull_line="$(grep -nF 'pull app' "${fixture}/calls" | cut -d: -f1)"
migration_line="$(grep -nF 'run --rm --no-deps -T app --migrate' "${fixture}/calls" | cut -d: -f1)"
recreate_line="$(grep -nF 'up -d --wait --wait-timeout 120 app' "${fixture}/calls" | cut -d: -f1)"
[[ "${pull_line}" -lt "${migration_line}" && "${migration_line}" -lt "${recreate_line}" ]] \
|| fail_test "update did not pull, migrate, then recreate in order"
[[ "$(grep -Fc ' --migrate' "${fixture}/calls")" -eq 1 ]] \
|| fail_test "update did not run migrations exactly once"
! grep -Eq 'db prepare|apply-backfills|--service-ports' "${fixture}/calls" \
|| fail_test "migration preflight enabled backfills or published service ports"
}
test_migration_failure_preserves_running_app() {
local fixture="${TEST_ROOT}/migration-failure"
make_fixture "${fixture}"
make_migration_docker_stub "${fixture}"
if PATH="${fixture}/bin:${PATH}" AETHER_TEST_CALLS="${fixture}/calls" \
AETHER_TEST_MIGRATION_STATUS=42 \
"${fixture}/compose/update.sh" --compose-dir "${fixture}/compose" \
>"${fixture}/stdout" 2>"${fixture}/stderr"; then
fail_test "update succeeded after schema migration failed"
fi
grep -Fq 'run --rm --no-deps -T app --migrate' "${fixture}/calls" \
|| fail_test "update did not attempt schema migration"
! grep -Eq ' (up|stop|down|restart|rm) ' "${fixture}/calls" \
|| fail_test "failed migration changed the running service"
grep -Fq 'app was not recreated' "${fixture}/stderr" \
|| fail_test "migration failure did not explain that app was left running"
! grep -Fq '>>> Done.' "${fixture}/stdout" \
|| fail_test "failed migration was reported as successful"
}
test_prepare_only_pulls_image() {
local fixture="${TEST_ROOT}/prepare-only"
make_fixture "${fixture}"
make_migration_docker_stub "${fixture}"
PATH="${fixture}/bin:${PATH}" AETHER_TEST_CALLS="${fixture}/calls" \
"${fixture}/compose/update.sh" --compose-dir "${fixture}/compose" --prepare \
>"${fixture}/stdout" 2>"${fixture}/stderr"
grep -Fq 'pull app' "${fixture}/calls" \
|| fail_test "--prepare did not pull the new app image"
! grep -Eq ' (run|up|stop|down|restart) ' "${fixture}/calls" \
|| fail_test "--prepare migrated or changed running services"
}
test_no_pull_still_migrates_before_recreate() {
local fixture="${TEST_ROOT}/migration-without-pull"
make_fixture "${fixture}"
make_migration_docker_stub "${fixture}"
PATH="${fixture}/bin:${PATH}" AETHER_TEST_CALLS="${fixture}/calls" \
"${fixture}/compose/update.sh" --compose-dir "${fixture}/compose" --no-pull \
>"${fixture}/stdout" 2>"${fixture}/stderr"
! grep -Fq 'pull app' "${fixture}/calls" \
|| fail_test "--no-pull downloaded an app image"
local migration_line recreate_line
migration_line="$(grep -nF 'run --rm --no-deps -T app --migrate' "${fixture}/calls" | cut -d: -f1)"
recreate_line="$(grep -nF 'up -d --wait --wait-timeout 120 app' "${fixture}/calls" | cut -d: -f1)"
[[ "${migration_line}" -lt "${recreate_line}" ]] \
|| fail_test "--no-pull skipped schema preparation before recreate"
}
test_wait_failure_is_not_ignored() {
local fixture="${TEST_ROOT}/wait-failure"
make_fixture "${fixture}"
@@ -126,9 +221,13 @@ test_option_like_service_name_is_rejected() {
|| fail_test "unsafe service name was not rejected by the identifier guard"
}
test_migration_succeeds_before_recreate
test_migration_failure_preserves_running_app
test_prepare_only_pulls_image
test_no_pull_still_migrates_before_recreate
test_wait_failure_is_not_ignored
test_legacy_compose_uses_health_polling
test_legacy_compose_health_failure_is_not_ignored
test_option_like_service_name_is_rejected
echo "PASS: compose updater failure and argument safety fixtures"
echo "PASS: compose updater migration preflight, failure, and argument safety fixtures"