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.
Files changed (255) hide show
  1. package/catalogue.json +1 -0
  2. package/model-routing.json +1 -0
  3. package/package.json +1 -1
  4. package/packs/converters/skills/md-to-html/manifest.json +1 -1
  5. package/packs/converters/skills/md-to-html/scripts/md_to_html.py +3 -0
  6. package/packs/design/skills/brand-kit/manifest.json +1 -1
  7. package/packs/design/skills/brand-kit/scripts/check_brand.py +11 -1
  8. package/packs/dev-team/skills/behaviour-equivalence/manifest.json +1 -1
  9. package/packs/dev-team/skills/behaviour-equivalence/scripts/golden_diff.py +11 -1
  10. package/packs/frontend/skills/bundle-size-review/manifest.json +1 -1
  11. package/packs/frontend/skills/bundle-size-review/scripts/bundle_stats.py +13 -1
  12. package/packs/frontend/skills/web-performance-review/manifest.json +1 -1
  13. package/packs/frontend/skills/web-performance-review/scripts/lh_summary.py +12 -2
  14. package/packs/grc/skills/risk-register/manifest.json +1 -1
  15. package/packs/grc/skills/risk-register/scripts/check_register.py +9 -1
  16. package/packs/infra-as-code/skills/terraform-plan-review/manifest.json +1 -1
  17. package/packs/infra-as-code/skills/terraform-plan-review/scripts/plan_summary.py +12 -2
  18. package/packs/product-manager/skills/feedback-synthesis/manifest.json +1 -1
  19. package/packs/product-manager/skills/feedback-synthesis/scripts/theme_counts.py +6 -1
  20. package/packs/research/skills/hypothesis-comparison/manifest.json +1 -1
  21. package/packs/research/skills/hypothesis-comparison/scripts/ach_matrix.py +10 -2
  22. package/packs/solution-architect/skills/context-graph/SKILL.md +119 -0
  23. package/packs/solution-architect/skills/context-graph/evals/eval_queries.json +11 -0
  24. package/packs/solution-architect/skills/context-graph/evals/evals.json +225 -0
  25. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0001-record-architecture-decisions.md +19 -0
  26. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0002-postgres-as-primary-database.md +16 -0
  27. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0003-use-redis-for-session-storage.md +24 -0
  28. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0004-structured-json-logging.md +15 -0
  29. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0005-session-lifetime-eight-hours.md +22 -0
  30. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0006-move-sessions-to-postgres.md +16 -0
  31. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0007-stateless-signed-session-cookies.md +35 -0
  32. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/__init__.py +0 -0
  33. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/db.py +0 -0
  34. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/logging_setup.py +0 -0
  35. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/__init__.py +0 -0
  36. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/cookie_sessions.py +7 -0
  37. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/redis_sessions.py +7 -0
  38. package/packs/solution-architect/skills/context-graph/evals/files/10/README.md +8 -0
  39. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0001-record-architecture-decisions.md +10 -0
  40. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0004-service-auth-hmac-shared-keys.md +21 -0
  41. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0007-secrets-from-vault-agent.md +19 -0
  42. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0011-service-auth-mtls.md +23 -0
  43. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/app.py +16 -0
  44. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/__init__.py +4 -0
  45. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/hmac_verify.py +31 -0
  46. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/config/settings.py +14 -0
  47. package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/__init__.py +4 -0
  48. package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/mtls.py +18 -0
  49. package/packs/solution-architect/skills/context-graph/evals/files/11/README.md +4 -0
  50. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/base.py +3 -0
  51. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/line_item.py +14 -0
  52. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/order.py +24 -0
  53. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-003-money-as-minor-units.md +10 -0
  54. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-005-orders-typed-columns-only.md +10 -0
  55. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-009-line-items-immutable.md +11 -0
  56. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-014-optional-order-attributes-json.md +16 -0
  57. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-016-order-attributes-table.md +11 -0
  58. package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0007_create_orders.sql +11 -0
  59. package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0012_add_order_attributes.sql +2 -0
  60. package/packs/solution-architect/skills/context-graph/evals/files/12/README.md +8 -0
  61. package/packs/solution-architect/skills/context-graph/evals/files/12/config/delivery.yaml +4 -0
  62. package/packs/solution-architect/skills/context-graph/evals/files/12/config/export.yaml +2 -0
  63. package/packs/solution-architect/skills/context-graph/evals/files/12/config/partners.yaml +10 -0
  64. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0001-record-architecture-decisions.md +10 -0
  65. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0002-postgres-delivery-log.md +15 -0
  66. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0003-redis-idempotency-keys.md +15 -0
  67. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0004-retry-policy.md +16 -0
  68. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0005-hmac-signed-payloads.md +10 -0
  69. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0006-postgres-idempotency.md +15 -0
  70. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0007-sftp-batch-export.md +12 -0
  71. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0008-partner-config-in-yaml.md +12 -0
  72. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0009-partner-config-admin-api.md +13 -0
  73. package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/003_idempotency_keys.sql +6 -0
  74. package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/004_partners.sql +7 -0
  75. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/dispatcher.py +29 -0
  76. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/retry.py +15 -0
  77. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/signing.py +13 -0
  78. package/packs/solution-architect/skills/context-graph/evals/files/12/src/export/s3_export.py +24 -0
  79. package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/pg_store.py +11 -0
  80. package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/redis_store.py +8 -0
  81. package/packs/solution-architect/skills/context-graph/evals/files/12/src/partners/loader.py +15 -0
  82. package/packs/solution-architect/skills/context-graph/evals/files/12/src/store/delivery_log.py +18 -0
  83. package/packs/solution-architect/skills/context-graph/evals/files/13/README.md +3 -0
  84. package/packs/solution-architect/skills/context-graph/evals/files/13/config/cache.yaml +2 -0
  85. package/packs/solution-architect/skills/context-graph/evals/files/13/config/settings.yaml +2 -0
  86. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-008-pricing-from-erp.md +10 -0
  87. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-012-pricing-cache.md +23 -0
  88. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-015-checkout-price-lock.md +15 -0
  89. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-019-pricing-service.md +17 -0
  90. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/catalog/views.py +8 -0
  91. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/checkout/lock.py +14 -0
  92. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/cache.py +22 -0
  93. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/client.py +10 -0
  94. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0001-idempotency-keys.md +33 -0
  95. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0002-processor-retry-policy.md +26 -0
  96. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0003-money-in-minor-units.md +31 -0
  97. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0004-webhook-signing.md +27 -0
  98. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0005-retry-with-jitter.md +30 -0
  99. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0006-idempotency-at-gateway.md +28 -0
  100. package/packs/solution-architect/skills/context-graph/evals/files/14/pr-summary.md +27 -0
  101. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/amount.ts +10 -0
  102. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/charge.ts +28 -0
  103. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/idempotency.ts +4 -0
  104. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/retry.ts +21 -0
  105. package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/send.ts +9 -0
  106. package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/sign.ts +6 -0
  107. package/packs/solution-architect/skills/context-graph/evals/files/15/deploy/services.yaml +14 -0
  108. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0001-record-architecture-decisions.md +20 -0
  109. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0002-use-postgresql-for-shipment-data.md +23 -0
  110. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0003-store-vehicle-telemetry-in-cassandra.md +22 -0
  111. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0004-use-redis-for-session-storage.md +22 -0
  112. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0005-use-react-for-dispatcher-dashboard.md +19 -0
  113. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0006-archive-delivered-shipments-to-object-storage.md +23 -0
  114. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0007-move-shipment-records-to-mongodb.md +23 -0
  115. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0008-store-vehicle-telemetry-in-timescaledb.md +28 -0
  116. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0009-stateless-sessions-with-signed-cookies.md +24 -0
  117. package/packs/solution-architect/skills/context-graph/evals/files/15/services/api/session.py +17 -0
  118. package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/db.py +30 -0
  119. package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/migrations.sql +3 -0
  120. package/packs/solution-architect/skills/context-graph/evals/files/15/services/telemetry/store.py +23 -0
  121. package/packs/solution-architect/skills/context-graph/evals/files/15/web/dashboard/App.jsx +3 -0
  122. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0001-record-architecture-decisions.md +11 -0
  123. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0002-rabbitmq-for-background-jobs.md +15 -0
  124. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0003-thumbnail-service.md +20 -0
  125. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0004-money-as-integer-minor-units.md +17 -0
  126. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0005-worker-retries.md +12 -0
  127. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0006-fx-amounts-with-four-decimals.md +18 -0
  128. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0007-feature-flags.md +16 -0
  129. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0008-retire-legacy-search.md +14 -0
  130. package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/__init__.py +0 -0
  131. package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/amount.py +9 -0
  132. package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/flags.py +1 -0
  133. package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/publish.py +0 -0
  134. package/packs/solution-architect/skills/context-graph/evals/files/2/services/media/resize.py +5 -0
  135. package/packs/solution-architect/skills/context-graph/evals/files/2/services/worker/consumer.py +0 -0
  136. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0001-how-we-write-rfcs.md +9 -0
  137. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0002-payments-service-boundary.md +16 -0
  138. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0003-webhook-retries-fixed-interval.md +19 -0
  139. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0004-webhook-idempotency-keys.md +16 -0
  140. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0005-notification-retries.md +16 -0
  141. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0006-webhook-retry-backoff.md +26 -0
  142. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0007-webhooks-on-the-job-queue.md +12 -0
  143. package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/__init__.py +0 -0
  144. package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/retry.py +4 -0
  145. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/__init__.py +0 -0
  146. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/__init__.py +0 -0
  147. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/retry.py +15 -0
  148. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/send.py +0 -0
  149. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0001-record-architecture-decisions.md +19 -0
  150. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0002-postgres-as-system-of-record.md +18 -0
  151. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0004-redis-locks-for-scheduler.md +19 -0
  152. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0007-remove-redis.md +27 -0
  153. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0009-money-as-integer-minor-units.md +19 -0
  154. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/onboarding.md +12 -0
  155. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/__init__.py +0 -0
  156. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/db/__init__.py +22 -0
  157. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/invoicing.py +9 -0
  158. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/money.py +10 -0
  159. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/__init__.py +0 -0
  160. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/lock.py +23 -0
  161. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/runner.py +17 -0
  162. package/packs/solution-architect/skills/context-graph/evals/files/5/lib/types/index.ts +13 -0
  163. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0001-service-layout.md +20 -0
  164. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0003-ingest-retry-policy.md +26 -0
  165. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0006-shared-retry-library.md +24 -0
  166. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0008-outbound-http-client.md +22 -0
  167. package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/client.ts +15 -0
  168. package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/retry.ts +12 -0
  169. package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/client.ts +14 -0
  170. package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/retry.ts +20 -0
  171. package/packs/solution-architect/skills/context-graph/evals/files/6/README.md +4 -0
  172. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0001-monorepo-layout.md +10 -0
  173. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0002-billing-on-postgres.md +13 -0
  174. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0004-ledger-sync-nightly-batch.md +9 -0
  175. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0003-invoice-ids.md +9 -0
  176. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0007-invoice-ids-ulid.md +11 -0
  177. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0009-billing-event-store.md +15 -0
  178. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0010-revenue-service.md +13 -0
  179. package/packs/solution-architect/skills/context-graph/evals/files/6/libs/money/ulid.py +8 -0
  180. package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/events.py +10 -0
  181. package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/store.py +10 -0
  182. package/packs/solution-architect/skills/context-graph/evals/files/6/services/invoicing/ids/generator.py +7 -0
  183. package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/README.md +4 -0
  184. package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/sync.py +3 -0
  185. package/packs/solution-architect/skills/context-graph/evals/files/7/README.md +4 -0
  186. package/packs/solution-architect/skills/context-graph/evals/files/7/db/queries/orders.sql +2 -0
  187. package/packs/solution-architect/skills/context-graph/evals/files/7/db/sharding/router.py +9 -0
  188. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-001-postgres-primary.md +8 -0
  189. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-002-kafka-event-bus.md +20 -0
  190. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-003-no-orm.md +9 -0
  191. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-006-tenant-sharding.md +9 -0
  192. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-011-orm-for-admin-console.md +11 -0
  193. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/fanout/router.py +4 -0
  194. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/consumer.py +5 -0
  195. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/topics.yaml +8 -0
  196. package/packs/solution-architect/skills/context-graph/evals/files/7/rfcs/0004-region-sharding.md +15 -0
  197. package/packs/solution-architect/skills/context-graph/evals/files/7/services/admin-console/models.py +11 -0
  198. package/packs/solution-architect/skills/context-graph/evals/files/7/services/orders/repo.py +9 -0
  199. package/packs/solution-architect/skills/context-graph/evals/files/8/README.md +11 -0
  200. package/packs/solution-architect/skills/context-graph/evals/files/8/api/ledger.proto +30 -0
  201. package/packs/solution-architect/skills/context-graph/evals/files/8/config/http.yaml +10 -0
  202. package/packs/solution-architect/skills/context-graph/evals/files/8/config/messaging.yaml +8 -0
  203. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0001-record-architecture-decisions.md +20 -0
  204. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0002-postgresql-for-ledger.md +22 -0
  205. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0003-rabbitmq-domain-events.md +22 -0
  206. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0004-integer-minor-units.md +32 -0
  207. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0005-provider-http-retries.md +26 -0
  208. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0006-openapi-generated-clients.md +20 -0
  209. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0007-kafka-domain-events.md +25 -0
  210. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0008-structured-logging.md +18 -0
  211. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/rfcs/RFC-012-idempotency-keys.md +19 -0
  212. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/idempotency.py +19 -0
  213. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/server.py +35 -0
  214. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/clients/provider.py +33 -0
  215. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0001_init.sql +14 -0
  216. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0008_idempotency_keys.sql +5 -0
  217. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0009_fx_entries.sql +4 -0
  218. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/events/publisher.py +28 -0
  219. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/logging.py +25 -0
  220. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/models/entry.py +16 -0
  221. package/packs/solution-architect/skills/context-graph/evals/files/9/.env.example +3 -0
  222. package/packs/solution-architect/skills/context-graph/evals/files/9/README.md +5 -0
  223. package/packs/solution-architect/skills/context-graph/evals/files/9/docker-compose.yml +18 -0
  224. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/001-session-storage.md +21 -0
  225. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/002-api-rate-limiting.md +32 -0
  226. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/003-jwt-sessions.md +29 -0
  227. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/004-catalog-cache.md +19 -0
  228. package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/cache.ts +13 -0
  229. package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/repository.ts +13 -0
  230. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/email.ts +3 -0
  231. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/export.ts +3 -0
  232. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/queue.ts +10 -0
  233. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/worker.ts +8 -0
  234. package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/db.ts +10 -0
  235. package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/redis.ts +8 -0
  236. package/packs/solution-architect/skills/context-graph/evals/files/9/src/middleware/rateLimit.ts +26 -0
  237. package/packs/solution-architect/skills/context-graph/evals/files/9/src/server.ts +17 -0
  238. package/packs/solution-architect/skills/context-graph/evals/files/9/src/session/store.ts +10 -0
  239. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0004-kafka-for-order-events.md +19 -0
  240. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0006-email-receipts.md +7 -0
  241. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0009-sqs-for-order-events.md +19 -0
  242. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/notifications/receipts.py +0 -0
  243. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/orders/publisher.py +0 -0
  244. package/packs/solution-architect/skills/context-graph/examples/order-events.md +63 -0
  245. package/packs/solution-architect/skills/context-graph/manifest.json +33 -0
  246. package/packs/solution-architect/skills/context-graph/reference.md +104 -0
  247. package/packs/solution-architect/skills/context-graph/scripts/context_graph.py +634 -0
  248. package/packs/solution-architect/skills/event-contract-draft/manifest.json +1 -1
  249. package/packs/solution-architect/skills/event-contract-draft/scripts/check_asyncapi.py +14 -2
  250. package/packs/sre-oncall/skills/cloud-cost-review/manifest.json +1 -1
  251. package/packs/sre-oncall/skills/cloud-cost-review/scripts/cost_summary.py +2 -0
  252. package/packs/trackers/skills/backlog-triage/manifest.json +1 -1
  253. package/packs/trackers/skills/backlog-triage/scripts/triage_backlog.py +4 -1
  254. package/packs/trackers/skills/team-status-report/manifest.json +1 -1
  255. package/packs/trackers/skills/team-status-report/scripts/status_counts.py +4 -1
@@ -0,0 +1,33 @@
1
+ ---
2
+ rfc: 0001
3
+ title: Idempotency keys on every charge request
4
+ status: accepted
5
+ date: 2024-02-12
6
+ authors: [mira.okafor]
7
+ governs:
8
+ - src/payments/charge.ts
9
+ ---
10
+
11
+ # RFC-0001: Idempotency keys on every charge request
12
+
13
+ ## Problem
14
+
15
+ Mobile clients retry on flaky networks. Without a dedupe key, a retried
16
+ `POST /charges` can bill a customer twice. We had 14 double-charge tickets in
17
+ January 2024.
18
+
19
+ ## Decision
20
+
21
+ Every `POST /charges` request MUST carry an `Idempotency-Key` header. The
22
+ charge handler rejects requests without one (HTTP 400) and stores the key with
23
+ the charge for 24 hours. A repeat key returns the original response instead of
24
+ creating a new charge.
25
+
26
+ The check lives in the charge handler itself, not in the retry layer: the
27
+ retry layer only sees our own outbound retries to the card processor, not
28
+ inbound client retries.
29
+
30
+ ## Consequences
31
+
32
+ - Clients must generate a UUID per logical charge.
33
+ - The `idempotency_keys` table grows; rows expire after 24 hours.
@@ -0,0 +1,26 @@
1
+ ---
2
+ rfc: 0002
3
+ title: Fixed-interval retries to the card processor
4
+ status: superseded
5
+ superseded_by: 0005
6
+ date: 2024-02-20
7
+ authors: [dev.raman]
8
+ governs:
9
+ - src/payments/retry.ts
10
+ ---
11
+
12
+ # RFC-0002: Fixed-interval retries to the card processor
13
+
14
+ ## Problem
15
+
16
+ Calls to the card processor occasionally time out. We need a retry policy.
17
+
18
+ ## Decision
19
+
20
+ Retry failed processor calls up to 3 times with a fixed 2-second delay
21
+ between attempts.
22
+
23
+ ## Consequences
24
+
25
+ - Simple to reason about.
26
+ - Under a processor outage every instance retries in lockstep.
@@ -0,0 +1,31 @@
1
+ ---
2
+ rfc: 0003
3
+ title: Represent money as integer minor units
4
+ status: accepted
5
+ date: 2024-03-04
6
+ authors: [mira.okafor]
7
+ governs:
8
+ - src/payments/amount.ts
9
+ - src/payments/charge.ts
10
+ ---
11
+
12
+ # RFC-0003: Represent money as integer minor units
13
+
14
+ ## Problem
15
+
16
+ A refund of 19.99 was stored as 19.989999999999998 after a floating-point
17
+ round trip, and the ledger failed to reconcile.
18
+
19
+ ## Decision
20
+
21
+ All monetary amounts inside the service and on the wire are integers in the
22
+ currency's minor unit (cents for USD, pence for GBP), in a field named
23
+ `amountMinor`, paired with an ISO 4217 `currency` code. No decimal or
24
+ floating-point money fields anywhere in `src/payments/`. Conversion to a
25
+ display string happens only at the edge, via `formatAmount()` in
26
+ `src/payments/amount.ts`.
27
+
28
+ ## Consequences
29
+
30
+ - API consumers must send `amountMinor: 1999`, not `amount: 19.99`.
31
+ - Currencies with three minor digits (e.g. KWD) work without special cases.
@@ -0,0 +1,27 @@
1
+ ---
2
+ rfc: 0004
3
+ title: HMAC-SHA256 signatures on outbound webhooks
4
+ status: accepted
5
+ date: 2024-04-15
6
+ authors: [dev.raman]
7
+ governs:
8
+ - src/webhooks/sign.ts
9
+ ---
10
+
11
+ # RFC-0004: HMAC-SHA256 signatures on outbound webhooks
12
+
13
+ ## Problem
14
+
15
+ Merchants cannot tell a genuine `charge.succeeded` webhook from a forged one.
16
+
17
+ ## Decision
18
+
19
+ Every outbound webhook carries a `Ledgerline-Signature` header: an
20
+ HMAC-SHA256 of `timestamp + "." + body`, keyed with the merchant's webhook
21
+ secret. Signing is implemented in one place, `src/webhooks/sign.ts`, and every
22
+ sender must call `signPayload()` from it.
23
+
24
+ ## Consequences
25
+
26
+ - Merchants verify with a constant-time compare.
27
+ - Rotating a merchant secret invalidates in-flight retries.
@@ -0,0 +1,30 @@
1
+ ---
2
+ rfc: 0005
3
+ title: Exponential backoff with full jitter for processor retries
4
+ status: accepted
5
+ supersedes: 0002
6
+ date: 2024-06-03
7
+ authors: [dev.raman, mira.okafor]
8
+ governs:
9
+ - src/payments/retry.ts
10
+ ---
11
+
12
+ # RFC-0005: Exponential backoff with full jitter for processor retries
13
+
14
+ ## Problem
15
+
16
+ During the processor outage on 2024-05-21, RFC-0002's fixed 2-second retries
17
+ made all 40 instances hit the processor in synchronised waves, extending the
18
+ outage on our side by about 25 minutes.
19
+
20
+ ## Decision
21
+
22
+ Replace RFC-0002. Retry failed processor calls up to 4 times using
23
+ exponential backoff with full jitter: before attempt `n`, wait a random delay
24
+ between 0 and `min(8000, 250 * 2^n)` milliseconds. Never retry a 4xx response
25
+ from the processor.
26
+
27
+ ## Consequences
28
+
29
+ - Retries spread out; no lockstep under outage.
30
+ - Worst-case added latency is bounded at roughly 15 seconds.
@@ -0,0 +1,28 @@
1
+ ---
2
+ rfc: 0006
3
+ title: Move idempotency handling to the API gateway
4
+ status: proposed
5
+ date: 2024-09-30
6
+ authors: [tomas.vey]
7
+ governs:
8
+ - src/payments/charge.ts
9
+ ---
10
+
11
+ # RFC-0006: Move idempotency handling to the API gateway
12
+
13
+ ## Problem
14
+
15
+ Three services now implement their own idempotency-key tables, each slightly
16
+ differently.
17
+
18
+ ## Proposal
19
+
20
+ Enforce `Idempotency-Key` once at the API gateway and remove the per-service
21
+ checks, including the one RFC-0001 put in the charge handler.
22
+
23
+ ## Open questions
24
+
25
+ - The gateway team has not yet committed to a delivery date.
26
+ - How are responses replayed for keys the gateway has seen?
27
+
28
+ Not yet reviewed. Until this is accepted, RFC-0001 stands.
@@ -0,0 +1,27 @@
1
+ # PR #412 — "Simplify charge path" (author: tomas.vey)
2
+
3
+ Description from the author:
4
+ > Cleanup of the charge path. Retries are back to the simple policy from RFC-0002,
5
+ > which is much easier to reason about. Dedupe now happens in the retry layer so the
6
+ > header check in the handler is redundant. All in line with our RFCs.
7
+
8
+ ## Files changed
9
+
10
+ ### src/payments/charge.ts (+9 / -14)
11
+ - `ChargeRequest.amountMinor: number` renamed to `amount: number`; value is now
12
+ decimal major units (e.g. `19.99`) "to match what the mobile app sends".
13
+ - Removed the `Idempotency-Key` header check and the `idempotencyStore.get/put`
14
+ calls. Comment added: `// dedupe handled by retry layer`.
15
+ - `assertMinorUnits(req.amountMinor)` call removed.
16
+
17
+ ### src/payments/retry.ts (+6 / -12)
18
+ - `MAX_ATTEMPTS` 4 -> 3.
19
+ - Backoff replaced with a fixed `await sleep(2000)` between attempts.
20
+ - 4xx short-circuit kept.
21
+ - Header comment changed to `// Processor retry policy: RFC-0002`.
22
+
23
+ ### src/webhooks/sign.ts -> src/webhooks/signature.ts (rename, no content change)
24
+ - `send.ts` import updated to `./signature`.
25
+
26
+ ### src/webhooks/send.ts (+1 / -1)
27
+ - `console.log` replaced with `logger.info` (same fields).
@@ -0,0 +1,10 @@
1
+ // RFC-0003: money is integer minor units.
2
+ export function assertMinorUnits(amountMinor: number): void {
3
+ if (!Number.isInteger(amountMinor) || amountMinor < 0) {
4
+ throw new Error("amountMinor must be a non-negative integer");
5
+ }
6
+ }
7
+
8
+ export function formatAmount(amountMinor: number, currency: string, digits = 2): string {
9
+ return `${(amountMinor / 10 ** digits).toFixed(digits)} ${currency}`;
10
+ }
@@ -0,0 +1,28 @@
1
+ import { retryProcessorCall } from "./retry";
2
+ import { assertMinorUnits } from "./amount";
3
+ import { idempotencyStore } from "./idempotency";
4
+ import { sendWebhook } from "../webhooks/send";
5
+
6
+ export interface ChargeRequest {
7
+ amountMinor: number; // integer minor units, see RFC-0003
8
+ currency: string; // ISO 4217
9
+ cardToken: string;
10
+ }
11
+
12
+ export async function createCharge(req: ChargeRequest, headers: Record<string, string>) {
13
+ const key = headers["idempotency-key"];
14
+ if (!key) {
15
+ return { status: 400, body: { error: "Idempotency-Key header is required" } }; // RFC-0001
16
+ }
17
+ const previous = await idempotencyStore.get(key);
18
+ if (previous) return previous;
19
+
20
+ assertMinorUnits(req.amountMinor);
21
+ const result = await retryProcessorCall(() => processor.charge(req));
22
+ const response = { status: 201, body: result };
23
+ await idempotencyStore.put(key, response, 24 * 3600);
24
+ await sendWebhook("charge.succeeded", result);
25
+ return response;
26
+ }
27
+
28
+ declare const processor: { charge(req: ChargeRequest): Promise<unknown> };
@@ -0,0 +1,4 @@
1
+ export const idempotencyStore = {
2
+ async get(_key: string): Promise<any> { return undefined; },
3
+ async put(_key: string, _value: unknown, _ttlSeconds: number): Promise<void> {},
4
+ };
@@ -0,0 +1,21 @@
1
+ // Processor retry policy: RFC-0005 (supersedes RFC-0002).
2
+ const MAX_ATTEMPTS = 4;
3
+ const BASE_MS = 250;
4
+ const CAP_MS = 8000;
5
+
6
+ export async function retryProcessorCall<T>(fn: () => Promise<T>): Promise<T> {
7
+ let lastErr: unknown;
8
+ for (let n = 0; n < MAX_ATTEMPTS; n++) {
9
+ try {
10
+ return await fn();
11
+ } catch (err: any) {
12
+ if (err?.status >= 400 && err?.status < 500) throw err; // never retry 4xx
13
+ lastErr = err;
14
+ const ceiling = Math.min(CAP_MS, BASE_MS * 2 ** n);
15
+ await sleep(Math.random() * ceiling); // full jitter
16
+ }
17
+ }
18
+ throw lastErr;
19
+ }
20
+
21
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
@@ -0,0 +1,9 @@
1
+ import { signPayload } from "./sign";
2
+
3
+ export async function sendWebhook(event: string, payload: unknown): Promise<void> {
4
+ const body = JSON.stringify({ event, payload });
5
+ const ts = Math.floor(Date.now() / 1000);
6
+ const signature = signPayload(process.env.WEBHOOK_SECRET ?? "placeholder-secret", ts, body);
7
+ console.log("webhook", event, signature.slice(0, 8));
8
+ // HTTP delivery omitted in this excerpt
9
+ }
@@ -0,0 +1,6 @@
1
+ import { createHmac } from "crypto";
2
+
3
+ // RFC-0004: the single place outbound webhooks are signed.
4
+ export function signPayload(secret: string, timestamp: number, body: string): string {
5
+ return createHmac("sha256", secret).update(`${timestamp}.${body}`).digest("hex");
6
+ }
@@ -0,0 +1,14 @@
1
+ # Services deployed to the production cluster
2
+ services:
3
+ - name: shipments
4
+ path: services/shipments
5
+ datastores: [postgres:haulmark_core]
6
+ - name: telemetry
7
+ path: services/telemetry
8
+ datastores: [postgres:haulmark_telemetry]
9
+ - name: api
10
+ path: services/api
11
+ datastores: [postgres:haulmark_core]
12
+ - name: dashboard
13
+ path: web/dashboard
14
+ datastores: []
@@ -0,0 +1,20 @@
1
+ # 1. Record architecture decisions
2
+
3
+ Date: 2021-01-18
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ We need to record the architectural decisions made on Haulmark.
12
+
13
+ ## Decision
14
+
15
+ We will use Architecture Decision Records, as described by Michael Nygard,
16
+ kept in `doc/adr/`.
17
+
18
+ ## Consequences
19
+
20
+ See Michael Nygard's article "Documenting Architecture Decisions".
@@ -0,0 +1,23 @@
1
+ # 2. Use PostgreSQL for shipment data
2
+
3
+ Date: 2021-02-10
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Shipments, stops and consignees are relational and need transactional
12
+ updates when a stop is marked delivered. The team already runs PostgreSQL 13.
13
+
14
+ ## Decision
15
+
16
+ Shipment data lives in a single PostgreSQL database, `haulmark_core`, owned by
17
+ `services/shipments/`. Other services read shipment data only through the
18
+ shipments API, never by connecting to the database directly.
19
+
20
+ ## Consequences
21
+
22
+ Strong consistency for status transitions. Schema migrations are needed for
23
+ new shipment fields.
@@ -0,0 +1,22 @@
1
+ # 3. Store vehicle telemetry in Cassandra
2
+
3
+ Date: 2021-06-02
4
+
5
+ ## Status
6
+
7
+ Superseded by [8. Store vehicle telemetry in TimescaleDB](0008-store-vehicle-telemetry-in-timescaledb.md)
8
+
9
+ ## Context
10
+
11
+ Each truck reports GPS position every 5 seconds. At 1,200 trucks this is
12
+ about 20 million rows a day, too much write volume for `haulmark_core`.
13
+
14
+ ## Decision
15
+
16
+ Vehicle telemetry is written to a 3-node Cassandra cluster by
17
+ `services/telemetry/`, partitioned by vehicle and day.
18
+
19
+ ## Consequences
20
+
21
+ High write throughput. Ad-hoc queries (e.g. "all trucks within 5 km of the
22
+ depot yesterday") are hard to express.
@@ -0,0 +1,22 @@
1
+ # 4. Use Redis for session storage
2
+
3
+ Date: 2021-07-19
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The dispatcher web app needs server-side sessions shared across the API
12
+ instances in `services/api/`.
13
+
14
+ ## Decision
15
+
16
+ Sessions are stored in Redis with a 12-hour TTL, keyed by an opaque session
17
+ ID held in a cookie.
18
+
19
+ ## Consequences
20
+
21
+ One more piece of infrastructure to run. Logging out everywhere is a single
22
+ key delete.
@@ -0,0 +1,19 @@
1
+ # 5. Use React for the dispatcher dashboard
2
+
3
+ Date: 2021-09-06
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The dispatcher dashboard is moving off server-rendered templates.
12
+
13
+ ## Decision
14
+
15
+ We will build the dashboard in React.
16
+
17
+ ## Consequences
18
+
19
+ The front-end team needs a separate build pipeline.
@@ -0,0 +1,23 @@
1
+ # 6. Archive delivered shipments to object storage
2
+
3
+ Date: 2022-03-14
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ `haulmark_core` has grown to 900 GB, most of it shipments delivered more
12
+ than a year ago that are only read for audits.
13
+
14
+ ## Decision
15
+
16
+ A nightly job in `services/archiver/` moves shipments delivered more than
17
+ 90 days ago out of `haulmark_core` into S3-compatible object storage as
18
+ Parquet files, one file per depot per day, and deletes them from PostgreSQL.
19
+
20
+ ## Consequences
21
+
22
+ `haulmark_core` stays small. Audit queries over archived shipments go
23
+ through the object store, not the shipments API.
@@ -0,0 +1,23 @@
1
+ # 7. Move shipment records to MongoDB
2
+
3
+ Date: 2022-08-22
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Enterprise customers want custom fields on shipments (purchase order numbers,
12
+ temperature bands, hazmat codes) that differ per customer. Every new field
13
+ currently needs a PostgreSQL migration.
14
+
15
+ ## Decision
16
+
17
+ Shipment records will be stored as documents in MongoDB, owned by
18
+ `services/shipments/`, so per-customer fields need no schema migration.
19
+
20
+ ## Consequences
21
+
22
+ Status transitions that touch several stops lose multi-row transactions
23
+ unless we use MongoDB multi-document transactions.
@@ -0,0 +1,28 @@
1
+ # 8. Store vehicle telemetry in TimescaleDB
2
+
3
+ Date: 2023-04-11
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ Supersedes [3. Store vehicle telemetry in Cassandra](0003-store-vehicle-telemetry-in-cassandra.md)
10
+
11
+ ## Context
12
+
13
+ The Cassandra cluster from ADR 3 needs specialist operations knowledge
14
+ nobody on the team has, and geo queries over telemetry are now a product
15
+ requirement.
16
+
17
+ ## Decision
18
+
19
+ Vehicle telemetry moves to TimescaleDB (a PostgreSQL extension) in a
20
+ separate database, `haulmark_telemetry`, written by `services/telemetry/`,
21
+ using a hypertable partitioned by time with PostGIS for geo queries.
22
+ Raw points are kept for 30 days and downsampled after that, as set out in
23
+ [10. Telemetry retention and downsampling](0010-telemetry-retention-and-downsampling.md).
24
+
25
+ ## Consequences
26
+
27
+ One database technology to operate instead of two. Write throughput must be
28
+ watched as the fleet grows past 2,000 trucks.
@@ -0,0 +1,24 @@
1
+ # 9. Stateless sessions with signed cookies
2
+
3
+ Date: 2024-05-07
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ Supersedes [4. Use Redis for session storage](0004-use-redis-for-session-storage.md)
10
+
11
+ ## Context
12
+
13
+ Redis was the only stateful dependency of `services/api/` and caused two
14
+ outages in Q1 2024 when its primary failed over.
15
+
16
+ ## Decision
17
+
18
+ Sessions are stateless: a signed, encrypted cookie carries the dispatcher's
19
+ user ID, role and an 8-hour expiry. Redis is removed from `services/api/`.
20
+
21
+ ## Consequences
22
+
23
+ No session store to operate. Revoking a single session before expiry needs a
24
+ short deny-list, kept in `haulmark_core`.
@@ -0,0 +1,17 @@
1
+ """Dispatcher sessions for services/api (ADR 9): signed, encrypted cookies, no server store."""
2
+ import os
3
+ import time
4
+
5
+ from itsdangerous import URLSafeTimedSerializer
6
+
7
+ SECRET = os.environ.get("SESSION_SECRET", "placeholder-not-a-real-secret")
8
+ MAX_AGE_SECONDS = 8 * 3600
9
+ _serializer = URLSafeTimedSerializer(SECRET, salt="haulmark-session")
10
+
11
+
12
+ def issue(user_id: str, role: str) -> str:
13
+ return _serializer.dumps({"uid": user_id, "role": role, "iat": int(time.time())})
14
+
15
+
16
+ def read(cookie: str):
17
+ return _serializer.loads(cookie, max_age=MAX_AGE_SECONDS)
@@ -0,0 +1,30 @@
1
+ """Shipment persistence for services/shipments (ADR 2)."""
2
+ import os
3
+
4
+ import psycopg
5
+
6
+ DSN = os.environ.get("SHIPMENTS_DSN", "postgresql://haulmark:placeholder@localhost:5432/haulmark_core")
7
+
8
+
9
+ def connect():
10
+ return psycopg.connect(DSN)
11
+
12
+
13
+ def get_shipment(conn, shipment_id: str):
14
+ with conn.cursor() as cur:
15
+ cur.execute(
16
+ "SELECT id, customer_id, status, custom_fields FROM shipments WHERE id = %s",
17
+ (shipment_id,),
18
+ )
19
+ return cur.fetchone()
20
+
21
+
22
+ def mark_stop_delivered(conn, shipment_id: str, stop_id: str):
23
+ with conn.transaction():
24
+ with conn.cursor() as cur:
25
+ cur.execute("UPDATE stops SET status = 'delivered' WHERE id = %s", (stop_id,))
26
+ cur.execute(
27
+ "UPDATE shipments SET status = 'delivered' WHERE id = %s "
28
+ "AND NOT EXISTS (SELECT 1 FROM stops WHERE shipment_id = %s AND status <> 'delivered')",
29
+ (shipment_id, shipment_id),
30
+ )
@@ -0,0 +1,3 @@
1
+ -- 2022-09-30: per-customer custom fields as JSONB instead of new columns
2
+ ALTER TABLE shipments ADD COLUMN custom_fields JSONB NOT NULL DEFAULT '{}'::jsonb;
3
+ CREATE INDEX shipments_custom_fields_gin ON shipments USING GIN (custom_fields);
@@ -0,0 +1,23 @@
1
+ """Telemetry writer for services/telemetry (ADR 8)."""
2
+ import os
3
+
4
+ import psycopg
5
+
6
+ DSN = os.environ.get("TELEMETRY_DSN", "postgresql://haulmark:placeholder@localhost:5432/haulmark_telemetry")
7
+
8
+ SCHEMA = """
9
+ CREATE TABLE IF NOT EXISTS positions (
10
+ vehicle_id TEXT NOT NULL,
11
+ recorded_at TIMESTAMPTZ NOT NULL,
12
+ location GEOGRAPHY(POINT) NOT NULL
13
+ );
14
+ SELECT create_hypertable('positions', 'recorded_at', if_not_exists => TRUE);
15
+ """
16
+
17
+
18
+ def write_position(conn, vehicle_id: str, recorded_at, lon: float, lat: float):
19
+ with conn.cursor() as cur:
20
+ cur.execute(
21
+ "INSERT INTO positions VALUES (%s, %s, ST_MakePoint(%s, %s)::geography)",
22
+ (vehicle_id, recorded_at, lon, lat),
23
+ )
@@ -0,0 +1,3 @@
1
+ export default function App() {
2
+ return <h1>Haulmark dispatch</h1>;
3
+ }
@@ -0,0 +1,11 @@
1
+ # 1. Record architecture decisions
2
+
3
+ Date: 2023-04-03
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Decision
10
+
11
+ We record architecture decisions as ADRs in `docs/adr/`, one numbered file each.
@@ -0,0 +1,15 @@
1
+ ---
2
+ status: accepted
3
+ date: 2023-05-22
4
+ ---
5
+
6
+ # RabbitMQ for background jobs
7
+
8
+ ## Context and Problem Statement
9
+
10
+ Checkout sends receipts and stock updates inline, which slows the request.
11
+
12
+ ## Decision Outcome
13
+
14
+ Chosen option: "RabbitMQ", because the hosting provider offers it managed. Jobs are consumed by
15
+ `services/worker/`, and `services/checkout/` only publishes.
@@ -0,0 +1,20 @@
1
+ # 3. A separate thumbnail service
2
+
3
+ Date: 2023-09-11
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Resizing product images inside the API blocks request threads.
12
+
13
+ ## Decision
14
+
15
+ Image resizing runs in its own service, `services/thumbnailer/`, which consumes `resize` jobs
16
+ from the queue described in ADR-0002.
17
+
18
+ ## Consequences
19
+
20
+ The API never touches image bytes after upload.