skilldrop-cli 0.16.44 → 0.16.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/catalogue.json +1 -0
- package/model-routing.json +1 -0
- package/package.json +1 -1
- package/packs/converters/skills/md-to-html/manifest.json +1 -1
- package/packs/converters/skills/md-to-html/scripts/md_to_html.py +3 -0
- package/packs/design/skills/brand-kit/manifest.json +1 -1
- package/packs/design/skills/brand-kit/scripts/check_brand.py +11 -1
- package/packs/dev-team/skills/behaviour-equivalence/manifest.json +1 -1
- package/packs/dev-team/skills/behaviour-equivalence/scripts/golden_diff.py +11 -1
- package/packs/frontend/skills/bundle-size-review/manifest.json +1 -1
- package/packs/frontend/skills/bundle-size-review/scripts/bundle_stats.py +13 -1
- package/packs/frontend/skills/web-performance-review/manifest.json +1 -1
- package/packs/frontend/skills/web-performance-review/scripts/lh_summary.py +12 -2
- package/packs/grc/skills/risk-register/manifest.json +1 -1
- package/packs/grc/skills/risk-register/scripts/check_register.py +9 -1
- package/packs/infra-as-code/skills/terraform-plan-review/manifest.json +1 -1
- package/packs/infra-as-code/skills/terraform-plan-review/scripts/plan_summary.py +12 -2
- package/packs/product-manager/skills/feedback-synthesis/manifest.json +1 -1
- package/packs/product-manager/skills/feedback-synthesis/scripts/theme_counts.py +6 -1
- package/packs/research/skills/hypothesis-comparison/manifest.json +1 -1
- package/packs/research/skills/hypothesis-comparison/scripts/ach_matrix.py +10 -2
- package/packs/solution-architect/skills/context-graph/SKILL.md +119 -0
- package/packs/solution-architect/skills/context-graph/evals/eval_queries.json +11 -0
- package/packs/solution-architect/skills/context-graph/evals/evals.json +225 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0001-record-architecture-decisions.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0002-postgres-as-primary-database.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0003-use-redis-for-session-storage.md +24 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0004-structured-json-logging.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0005-session-lifetime-eight-hours.md +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0006-move-sessions-to-postgres.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0007-stateless-signed-session-cookies.md +35 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/db.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/logging_setup.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/cookie_sessions.py +7 -0
- package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/redis_sessions.py +7 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/README.md +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0001-record-architecture-decisions.md +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0004-service-auth-hmac-shared-keys.md +21 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0007-secrets-from-vault-agent.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0011-service-auth-mtls.md +23 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/app.py +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/__init__.py +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/hmac_verify.py +31 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/config/settings.py +14 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/__init__.py +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/mtls.py +18 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/README.md +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/base.py +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/line_item.py +14 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/order.py +24 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-003-money-as-minor-units.md +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-005-orders-typed-columns-only.md +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-009-line-items-immutable.md +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-014-optional-order-attributes-json.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-016-order-attributes-table.md +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0007_create_orders.sql +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0012_add_order_attributes.sql +2 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/README.md +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/config/delivery.yaml +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/config/export.yaml +2 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/config/partners.yaml +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0001-record-architecture-decisions.md +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0002-postgres-delivery-log.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0003-redis-idempotency-keys.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0004-retry-policy.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0005-hmac-signed-payloads.md +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0006-postgres-idempotency.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0007-sftp-batch-export.md +12 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0008-partner-config-in-yaml.md +12 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0009-partner-config-admin-api.md +13 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/003_idempotency_keys.sql +6 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/004_partners.sql +7 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/dispatcher.py +29 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/retry.py +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/signing.py +13 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/export/s3_export.py +24 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/pg_store.py +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/redis_store.py +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/partners/loader.py +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/12/src/store/delivery_log.py +18 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/README.md +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/config/cache.yaml +2 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/config/settings.yaml +2 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-008-pricing-from-erp.md +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-012-pricing-cache.md +23 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-015-checkout-price-lock.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-019-pricing-service.md +17 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/catalog/views.py +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/checkout/lock.py +14 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/cache.py +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/client.py +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0001-idempotency-keys.md +33 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0002-processor-retry-policy.md +26 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0003-money-in-minor-units.md +31 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0004-webhook-signing.md +27 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0005-retry-with-jitter.md +30 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0006-idempotency-at-gateway.md +28 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/pr-summary.md +27 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/amount.ts +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/charge.ts +28 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/idempotency.ts +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/retry.ts +21 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/send.ts +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/sign.ts +6 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/deploy/services.yaml +14 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0001-record-architecture-decisions.md +20 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0002-use-postgresql-for-shipment-data.md +23 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0003-store-vehicle-telemetry-in-cassandra.md +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0004-use-redis-for-session-storage.md +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0005-use-react-for-dispatcher-dashboard.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0006-archive-delivered-shipments-to-object-storage.md +23 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0007-move-shipment-records-to-mongodb.md +23 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0008-store-vehicle-telemetry-in-timescaledb.md +28 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0009-stateless-sessions-with-signed-cookies.md +24 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/services/api/session.py +17 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/db.py +30 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/migrations.sql +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/services/telemetry/store.py +23 -0
- package/packs/solution-architect/skills/context-graph/evals/files/15/web/dashboard/App.jsx +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0001-record-architecture-decisions.md +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0002-rabbitmq-for-background-jobs.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0003-thumbnail-service.md +20 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0004-money-as-integer-minor-units.md +17 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0005-worker-retries.md +12 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0006-fx-amounts-with-four-decimals.md +18 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0007-feature-flags.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0008-retire-legacy-search.md +14 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/amount.py +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/flags.py +1 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/publish.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/services/media/resize.py +5 -0
- package/packs/solution-architect/skills/context-graph/evals/files/2/services/worker/consumer.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0001-how-we-write-rfcs.md +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0002-payments-service-boundary.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0003-webhook-retries-fixed-interval.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0004-webhook-idempotency-keys.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0005-notification-retries.md +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0006-webhook-retry-backoff.md +26 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0007-webhooks-on-the-job-queue.md +12 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/retry.py +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/retry.py +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/send.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0001-record-architecture-decisions.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0002-postgres-as-system-of-record.md +18 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0004-redis-locks-for-scheduler.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0007-remove-redis.md +27 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0009-money-as-integer-minor-units.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/docs/onboarding.md +12 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/db/__init__.py +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/invoicing.py +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/money.py +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/__init__.py +0 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/lock.py +23 -0
- package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/runner.py +17 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/lib/types/index.ts +13 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0001-service-layout.md +20 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0003-ingest-retry-policy.md +26 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0006-shared-retry-library.md +24 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0008-outbound-http-client.md +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/client.ts +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/retry.ts +12 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/client.ts +14 -0
- package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/retry.ts +20 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/README.md +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0001-monorepo-layout.md +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0002-billing-on-postgres.md +13 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0004-ledger-sync-nightly-batch.md +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0003-invoice-ids.md +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0007-invoice-ids-ulid.md +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0009-billing-event-store.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0010-revenue-service.md +13 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/libs/money/ulid.py +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/events.py +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/store.py +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/services/invoicing/ids/generator.py +7 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/README.md +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/sync.py +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/README.md +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/db/queries/orders.sql +2 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/db/sharding/router.py +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-001-postgres-primary.md +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-002-kafka-event-bus.md +20 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-003-no-orm.md +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-006-tenant-sharding.md +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-011-orm-for-admin-console.md +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/fanout/router.py +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/consumer.py +5 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/topics.yaml +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/rfcs/0004-region-sharding.md +15 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/services/admin-console/models.py +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/7/services/orders/repo.py +9 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/README.md +11 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/api/ledger.proto +30 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/config/http.yaml +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/config/messaging.yaml +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0001-record-architecture-decisions.md +20 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0002-postgresql-for-ledger.md +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0003-rabbitmq-domain-events.md +22 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0004-integer-minor-units.md +32 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0005-provider-http-retries.md +26 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0006-openapi-generated-clients.md +20 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0007-kafka-domain-events.md +25 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0008-structured-logging.md +18 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/docs/rfcs/RFC-012-idempotency-keys.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/idempotency.py +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/server.py +35 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/clients/provider.py +33 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0001_init.sql +14 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0008_idempotency_keys.sql +5 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0009_fx_entries.sql +4 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/events/publisher.py +28 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/logging.py +25 -0
- package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/models/entry.py +16 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/.env.example +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/README.md +5 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/docker-compose.yml +18 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/001-session-storage.md +21 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/002-api-rate-limiting.md +32 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/003-jwt-sessions.md +29 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/004-catalog-cache.md +19 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/cache.ts +13 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/repository.ts +13 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/email.ts +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/export.ts +3 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/queue.ts +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/worker.ts +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/db.ts +10 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/redis.ts +8 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/middleware/rateLimit.ts +26 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/server.ts +17 -0
- package/packs/solution-architect/skills/context-graph/evals/files/9/src/session/store.ts +10 -0
- package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0004-kafka-for-order-events.md +19 -0
- package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0006-email-receipts.md +7 -0
- package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0009-sqs-for-order-events.md +19 -0
- package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/notifications/receipts.py +0 -0
- package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/orders/publisher.py +0 -0
- package/packs/solution-architect/skills/context-graph/examples/order-events.md +63 -0
- package/packs/solution-architect/skills/context-graph/manifest.json +33 -0
- package/packs/solution-architect/skills/context-graph/reference.md +104 -0
- package/packs/solution-architect/skills/context-graph/scripts/context_graph.py +634 -0
- package/packs/solution-architect/skills/event-contract-draft/manifest.json +1 -1
- package/packs/solution-architect/skills/event-contract-draft/scripts/check_asyncapi.py +14 -2
- package/packs/sre-oncall/skills/cloud-cost-review/manifest.json +1 -1
- package/packs/sre-oncall/skills/cloud-cost-review/scripts/cost_summary.py +2 -0
- package/packs/trackers/skills/backlog-triage/manifest.json +1 -1
- package/packs/trackers/skills/backlog-triage/scripts/triage_backlog.py +4 -1
- package/packs/trackers/skills/team-status-report/manifest.json +1 -1
- package/packs/trackers/skills/team-status-report/scripts/status_counts.py +4 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Ingest retry policy — RFC-0003. Do not change to a fixed interval (see INC-114).
|
|
2
|
+
const BASE_MS = 200;
|
|
3
|
+
const CAP_MS = 30_000;
|
|
4
|
+
const MAX_ATTEMPTS = 6;
|
|
5
|
+
|
|
6
|
+
export async function withRetry<T>(fn: () => Promise<T>): Promise<T> {
|
|
7
|
+
let attempt = 0;
|
|
8
|
+
for (;;) {
|
|
9
|
+
try {
|
|
10
|
+
return await fn();
|
|
11
|
+
} catch (err) {
|
|
12
|
+
attempt += 1;
|
|
13
|
+
if (attempt >= MAX_ATTEMPTS) throw err;
|
|
14
|
+
const ceiling = Math.min(CAP_MS, BASE_MS * 2 ** attempt);
|
|
15
|
+
await sleep(Math.random() * ceiling); // full jitter
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0001-monorepo-layout.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# ADR-0001: Monorepo layout
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2023-02-10
|
|
5
|
+
- Deciders: Platform team (H. Okafor, L. Brandt)
|
|
6
|
+
- Governs: `services/`, `libs/`
|
|
7
|
+
|
|
8
|
+
## Decision
|
|
9
|
+
One repository. Each deployable service gets its own folder under `services/<name>/`; shared code goes
|
|
10
|
+
under `libs/`. A service folder is never shared by two deployables.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# ADR-0002: Billing data lives in Postgres
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2023-05-03
|
|
5
|
+
- Deciders: H. Okafor, M. Szabo
|
|
6
|
+
- Governs: `services/billing/`
|
|
7
|
+
|
|
8
|
+
## Decision
|
|
9
|
+
The billing service stores charges and the invoice ledger in the shared Postgres cluster
|
|
10
|
+
(table `invoices_ledger`). Writes are transactional updates in place.
|
|
11
|
+
|
|
12
|
+
## Consequences
|
|
13
|
+
Reporting can join billing tables directly. Corrections overwrite the row and keep no history.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# ADR-0004: Ledger sync runs as a nightly batch
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2023-09-12
|
|
5
|
+
- Deciders: L. Brandt
|
|
6
|
+
- Governs: `services/ledger-sync/`
|
|
7
|
+
|
|
8
|
+
## Decision
|
|
9
|
+
Ledger sync to the finance system runs once a night at 02:00 UTC as a batch job, not as a stream.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# RFC-0007: Switch invoice identifiers to ULIDs
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2024-03-01
|
|
5
|
+
- Author: R. Achebe
|
|
6
|
+
- Supersedes: RFC-0003
|
|
7
|
+
- Governs: `services/invoicing/ids/`
|
|
8
|
+
|
|
9
|
+
## Proposal
|
|
10
|
+
Sequential IDs leaked customer invoice volumes and forced a single writer. Invoice IDs become ULIDs,
|
|
11
|
+
generated in-process, formatted `INV-<ulid>`. Existing `INV-000123` IDs stay valid.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# RFC-0009: Billing writes go to an append-only event store
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2024-08-14
|
|
5
|
+
- Author: R. Achebe
|
|
6
|
+
- Governs: `services/billing/`
|
|
7
|
+
- Builds on: RFC-0012 (event schema registry)
|
|
8
|
+
|
|
9
|
+
## Proposal
|
|
10
|
+
Billing records every charge and correction as an immutable event in the DynamoDB table
|
|
11
|
+
`billing-events`. Current balances are projections of the event stream. This gives auditors a full
|
|
12
|
+
history of corrections.
|
|
13
|
+
|
|
14
|
+
## Rollout
|
|
15
|
+
Phase 1: write events alongside the existing store. Phase 2: read balances from projections.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# RFC-0010: Merge billing and invoicing into a revenue service
|
|
2
|
+
|
|
3
|
+
- Status: Proposed
|
|
4
|
+
- Date: 2026-09-30
|
|
5
|
+
- Author: L. Brandt
|
|
6
|
+
- Governs: `services/revenue/` (new)
|
|
7
|
+
|
|
8
|
+
## Proposal
|
|
9
|
+
Move `services/billing/` and `services/invoicing/` into a single deployable at `services/revenue/`,
|
|
10
|
+
with `billing/` and `invoicing/` as internal modules. Both old folders are deleted after the move.
|
|
11
|
+
|
|
12
|
+
## Records affected
|
|
13
|
+
- ADR-0002 (billing storage) — path changes to `services/revenue/billing/`.
|
package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/events.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Phase 1 of the event store rollout: append every charge as an event."""
|
|
2
|
+
|
|
3
|
+
EVENTS_TABLE = "billing-events"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def append_charge_event(client, invoice_id, amount_minor, at):
|
|
7
|
+
client.put_item(
|
|
8
|
+
TableName=EVENTS_TABLE,
|
|
9
|
+
Item={"invoice_id": invoice_id, "type": "charge", "amount_minor": amount_minor, "at": at},
|
|
10
|
+
)
|
package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/store.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Billing persistence: in-place updates to the Postgres invoice ledger."""
|
|
2
|
+
|
|
3
|
+
LEDGER_TABLE = "invoices_ledger"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def record_charge(conn, invoice_id, amount_minor):
|
|
7
|
+
conn.execute(
|
|
8
|
+
f"UPDATE {LEDGER_TABLE} SET balance_minor = balance_minor + %s WHERE invoice_id = %s",
|
|
9
|
+
(amount_minor, invoice_id),
|
|
10
|
+
)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# DD-002: Kafka is the event bus
|
|
2
|
+
|
|
3
|
+
Status: Accepted
|
|
4
|
+
Date: 2022-06-02
|
|
5
|
+
Deciders: O. Mensah, T. Lindqvist
|
|
6
|
+
Governs: pipelines/ingest/, pipelines/fanout/
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
Ingest events must reach several independent consumers (fan-out, billing export, the audit sink),
|
|
10
|
+
and a consumer that is down for a deploy must be able to catch up afterwards.
|
|
11
|
+
|
|
12
|
+
## Options considered
|
|
13
|
+
1. Postgres LISTEN/NOTIFY — rejected: notifications are lost if no listener is connected at the
|
|
14
|
+
moment they fire, there is no replay, and payloads are capped at 8000 bytes.
|
|
15
|
+
2. RabbitMQ — rejected: no long replay window without extra plugins.
|
|
16
|
+
3. Kafka — chosen.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
Use Kafka. Every topic keeps 7 days of retention so any consumer can replay a week of events.
|
|
20
|
+
Retention policy details: see DD-007.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# DD-003: No ORM in services
|
|
2
|
+
|
|
3
|
+
Status: Accepted
|
|
4
|
+
Date: 2022-07-19
|
|
5
|
+
Deciders: T. Lindqvist
|
|
6
|
+
Governs: services/
|
|
7
|
+
|
|
8
|
+
Services use hand-written SQL kept in db/queries/. No ORM: we want query plans reviewable in code
|
|
9
|
+
review and no lazy-loading surprises on hot paths.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# DD-006: Shard by tenant
|
|
2
|
+
|
|
3
|
+
Status: Accepted
|
|
4
|
+
Date: 2023-01-30
|
|
5
|
+
Deciders: Platform guild (O. Mensah, R. Vidal)
|
|
6
|
+
Governs: db/sharding/
|
|
7
|
+
|
|
8
|
+
Each tenant's data lives on exactly one shard, chosen by a hash of tenant_id. Cross-tenant queries
|
|
9
|
+
go through the reporting replica, never the shards.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# DD-011: Allow SQLAlchemy in the admin console
|
|
2
|
+
|
|
3
|
+
Status: Accepted
|
|
4
|
+
Date: 2024-05-08
|
|
5
|
+
Deciders: R. Vidal
|
|
6
|
+
Amends: DD-003
|
|
7
|
+
Governs: services/admin-console/
|
|
8
|
+
|
|
9
|
+
The admin console is internal, low-traffic CRUD over ~40 tables. Hand-written SQL there cost more
|
|
10
|
+
than it saved. SQLAlchemy is allowed in services/admin-console/ only. Every other service keeps
|
|
11
|
+
DD-003's no-ORM rule.
|
package/packs/solution-architect/skills/context-graph/evals/files/7/rfcs/0004-region-sharding.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# RFC 0004: Shard by region instead of tenant
|
|
2
|
+
|
|
3
|
+
Status: Withdrawn
|
|
4
|
+
Date: 2025-02-14
|
|
5
|
+
Author: P. Tamboli
|
|
6
|
+
Supersedes: DD-006
|
|
7
|
+
Governs: db/sharding/
|
|
8
|
+
|
|
9
|
+
## Proposal
|
|
10
|
+
Move from tenant sharding to region sharding (eu, us, apac) so data-residency rules map to shards.
|
|
11
|
+
|
|
12
|
+
## Withdrawal note (2025-03-20)
|
|
13
|
+
Withdrawn after the cost review: re-sharding every tenant was estimated at two quarters of work and
|
|
14
|
+
residency can be met by pinning tenants to regional shards under the existing scheme. Tenant
|
|
15
|
+
sharding (DD-006) stays.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# harbor-ledger
|
|
2
|
+
|
|
3
|
+
Double-entry ledger service for the Harbor payments platform.
|
|
4
|
+
|
|
5
|
+
- `services/ledger/` — the ledger service (Python)
|
|
6
|
+
- `api/` — service interface definitions
|
|
7
|
+
- `config/` — runtime configuration
|
|
8
|
+
- `docs/adr/` — architecture decision records
|
|
9
|
+
- `docs/rfcs/` — proposals under discussion
|
|
10
|
+
|
|
11
|
+
`services/ledger/api/gen/` is generated from `api/ledger.proto` at build time and is not checked in.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package harbor.ledger.v1;
|
|
4
|
+
|
|
5
|
+
// Public interface of the ledger service. Client stubs are generated from this file.
|
|
6
|
+
service Ledger {
|
|
7
|
+
rpc PostEntry(PostEntryRequest) returns (PostEntryResponse);
|
|
8
|
+
rpc GetBalance(GetBalanceRequest) returns (Balance);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
message PostEntryRequest {
|
|
12
|
+
string idempotency_key = 1;
|
|
13
|
+
string account_id = 2;
|
|
14
|
+
int64 amount_minor = 3;
|
|
15
|
+
string currency = 4;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
message PostEntryResponse {
|
|
19
|
+
string entry_id = 1;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
message GetBalanceRequest {
|
|
23
|
+
string account_id = 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
message Balance {
|
|
27
|
+
string account_id = 1;
|
|
28
|
+
int64 balance_minor = 2;
|
|
29
|
+
string currency = 3;
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 1. Record architecture decisions
|
|
2
|
+
|
|
3
|
+
Date: 2024-01-10
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Accepted
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
We need to record the architectural decisions made on this project.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
We will use Architecture Decision Records, as described by Michael Nygard, kept in `docs/adr/`.
|
|
16
|
+
Larger proposals that need discussion first go in `docs/rfcs/` and become an ADR once accepted.
|
|
17
|
+
|
|
18
|
+
## Consequences
|
|
19
|
+
|
|
20
|
+
See Michael Nygard's article for a detailed description of the process.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 2. Use PostgreSQL for ledger storage
|
|
2
|
+
|
|
3
|
+
Date: 2024-01-22
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Accepted
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
The ledger needs transactional writes across journal entries and account balances, and the
|
|
12
|
+
team already operates PostgreSQL for two other services.
|
|
13
|
+
|
|
14
|
+
## Decision
|
|
15
|
+
|
|
16
|
+
Ledger state lives in PostgreSQL. Schema changes are plain SQL migrations under
|
|
17
|
+
`services/ledger/db/migrations/`, numbered sequentially and never edited once merged.
|
|
18
|
+
|
|
19
|
+
## Consequences
|
|
20
|
+
|
|
21
|
+
- Balances are computed inside a transaction with the entries that change them.
|
|
22
|
+
- No ORM-generated migrations.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 3. Publish domain events over RabbitMQ
|
|
2
|
+
|
|
3
|
+
Date: 2024-02-14
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Accepted
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
Downstream services (notifications, reporting) need to react when entries are posted.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
The ledger publishes `EntryPosted` and `AccountFrozen` events to a RabbitMQ topic exchange
|
|
16
|
+
named `ledger.events`. Publishing code lives in `services/ledger/events/`. Broker settings
|
|
17
|
+
are in `config/messaging.yaml`.
|
|
18
|
+
|
|
19
|
+
## Consequences
|
|
20
|
+
|
|
21
|
+
- Consumers bind their own queues; the ledger does not know who listens.
|
|
22
|
+
- Events are at-least-once; consumers must be idempotent.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ADR-0004
|
|
3
|
+
title: Store money as integer minor units
|
|
4
|
+
status: accepted
|
|
5
|
+
date: 2024-03-05
|
|
6
|
+
deciders: [m.okafor, j.lindqvist]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Store money as integer minor units
|
|
10
|
+
|
|
11
|
+
## Context and Problem Statement
|
|
12
|
+
|
|
13
|
+
Floating point and arbitrary-precision decimals have both caused rounding bugs on previous
|
|
14
|
+
projects. How should monetary amounts be represented in the ledger?
|
|
15
|
+
|
|
16
|
+
## Considered Options
|
|
17
|
+
|
|
18
|
+
* `NUMERIC` columns with Python `Decimal`
|
|
19
|
+
* Integer minor units (cents, pence) with a separate ISO 4217 currency code
|
|
20
|
+
|
|
21
|
+
## Decision Outcome
|
|
22
|
+
|
|
23
|
+
Chosen option: "Integer minor units", because sums are exact and every currency we support
|
|
24
|
+
has a fixed minor-unit exponent.
|
|
25
|
+
|
|
26
|
+
Every amount column in `services/ledger/db/migrations/` is `BIGINT` named `*_minor`, paired
|
|
27
|
+
with a `currency CHAR(3)` column. `services/ledger/models/entry.py` exposes amounts as `int`.
|
|
28
|
+
|
|
29
|
+
### Consequences
|
|
30
|
+
|
|
31
|
+
* Good, because addition is exact and fast.
|
|
32
|
+
* Bad, because display code must apply the currency exponent.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ADR 0005: Retry and timeout policy for payment-provider calls
|
|
2
|
+
|
|
3
|
+
* Status: Accepted
|
|
4
|
+
* Date: 2024-04-18
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
The payment provider occasionally returns 502/503 during their deploys. Unbounded retries
|
|
9
|
+
during an outage amplified load on them last year and held our worker threads.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Calls from `services/ledger/clients/provider.py` to the provider:
|
|
14
|
+
|
|
15
|
+
| Setting | Value |
|
|
16
|
+
|--------------------|-----------------------------------------|
|
|
17
|
+
| Request timeout | 5 seconds |
|
|
18
|
+
| Max retries | 3 |
|
|
19
|
+
| Backoff | exponential, 200 ms base, full jitter |
|
|
20
|
+
| Retry on | GET and idempotent POST (with key) only |
|
|
21
|
+
|
|
22
|
+
Values are read from `config/http.yaml`; the code must not hard-code them.
|
|
23
|
+
|
|
24
|
+
## Consequences
|
|
25
|
+
|
|
26
|
+
Worst-case latency of a provider call is bounded at roughly 21 seconds.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 6. Generate service clients from an OpenAPI spec
|
|
2
|
+
|
|
3
|
+
Date: 2024-06-03
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Accepted
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
Three internal teams call the ledger and each hand-wrote a client.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
The ledger's public interface is defined in `api/openapi.yaml`. Clients are generated from it
|
|
16
|
+
into `clients/generated/` on every release; hand-written clients are not accepted.
|
|
17
|
+
|
|
18
|
+
## Consequences
|
|
19
|
+
|
|
20
|
+
- The spec is the source of truth; the server is checked against it in CI.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ADR-0007
|
|
3
|
+
title: Move domain events to Kafka
|
|
4
|
+
status: accepted
|
|
5
|
+
date: 2025-03-11
|
|
6
|
+
supersedes: ADR-0003
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Move domain events to Kafka
|
|
10
|
+
|
|
11
|
+
## Context and Problem Statement
|
|
12
|
+
|
|
13
|
+
Reporting now needs to replay the full history of posted entries, which RabbitMQ queues
|
|
14
|
+
cannot give us once a message is acknowledged.
|
|
15
|
+
|
|
16
|
+
## Decision Outcome
|
|
17
|
+
|
|
18
|
+
Domain events are published to the Kafka topic `ledger.entry-events`, keyed by account id,
|
|
19
|
+
with 30-day retention. This supersedes ADR-0003. Publishing stays in
|
|
20
|
+
`services/ledger/events/`; broker settings stay in `config/messaging.yaml`.
|
|
21
|
+
|
|
22
|
+
### Consequences
|
|
23
|
+
|
|
24
|
+
* Good, because consumers can replay from any offset within retention.
|
|
25
|
+
* Bad, because the team now operates a Kafka cluster.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# ADR 0008: Structured JSON logging
|
|
2
|
+
|
|
3
|
+
* Status: Accepted
|
|
4
|
+
* Date: 2025-05-20
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Log search across services is painful because each one logs free text differently.
|
|
9
|
+
|
|
10
|
+
## Decision
|
|
11
|
+
|
|
12
|
+
All ledger logging goes through `services/ledger/logging.py`, which emits one JSON object per
|
|
13
|
+
line with `ts`, `level`, `msg`, `trace_id` and `account_id` fields. The `trace_id` comes from
|
|
14
|
+
the tracing setup described in ADR-0011.
|
|
15
|
+
|
|
16
|
+
## Consequences
|
|
17
|
+
|
|
18
|
+
Plain `print` and ad-hoc `logging.basicConfig` calls are not allowed in service code.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# RFC-012: Idempotency keys for posting entries
|
|
2
|
+
|
|
3
|
+
- **State:** Draft
|
|
4
|
+
- **Author:** j.lindqvist
|
|
5
|
+
- **Opened:** 2025-08-02
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
Clients send an `Idempotency-Key` with every `PostEntry` call. The ledger stores the key and
|
|
10
|
+
the response for 24 hours and returns the stored response on a repeat.
|
|
11
|
+
|
|
12
|
+
## Proposed implementation
|
|
13
|
+
|
|
14
|
+
`services/ledger/api/idempotency.py`, backed by a table `idempotency_keys` in PostgreSQL.
|
|
15
|
+
|
|
16
|
+
## Open questions
|
|
17
|
+
|
|
18
|
+
- Is 24 hours long enough for the batch importer, which can retry after a day?
|
|
19
|
+
- Should a key reused with a different body be a 409 or a 422?
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from datetime import timedelta
|
|
3
|
+
|
|
4
|
+
KEY_TTL = timedelta(hours=24)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def lookup(conn, key: str):
|
|
8
|
+
row = conn.execute(
|
|
9
|
+
"SELECT response FROM idempotency_keys WHERE key = %s AND created_at > now() - %s",
|
|
10
|
+
(key, KEY_TTL),
|
|
11
|
+
).fetchone()
|
|
12
|
+
return json.loads(row[0]) if row else None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def store(conn, key: str, response: dict) -> None:
|
|
16
|
+
conn.execute(
|
|
17
|
+
"INSERT INTO idempotency_keys (key, response) VALUES (%s, %s) ON CONFLICT DO NOTHING",
|
|
18
|
+
(key, json.dumps(response)),
|
|
19
|
+
)
|