@shortlink-org/portolan 0.1.0
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/LICENSE +21 -0
- package/README.md +387 -0
- package/catalog/enum_test.go +46 -0
- package/catalog/model.go +932 -0
- package/catalog/roundtrip_test.go +185 -0
- package/catalog/via_test.go +38 -0
- package/cli/portolan.mjs +368 -0
- package/go.mod +14 -0
- package/go.sum +14 -0
- package/index.html +13 -0
- package/internal/commands/cargo.go +154 -0
- package/internal/commands/commands.go +143 -0
- package/internal/commands/commands_test.go +323 -0
- package/internal/commands/gradle.go +77 -0
- package/internal/commands/justfile.go +82 -0
- package/internal/commands/makefile.go +106 -0
- package/internal/commands/maven.go +93 -0
- package/internal/commands/packagejson.go +159 -0
- package/internal/commands/pyproject.go +169 -0
- package/internal/commands/taskfile.go +101 -0
- package/internal/commands/testdata/estate/.cargo/config.toml +7 -0
- package/internal/commands/testdata/estate/Makefile +33 -0
- package/internal/commands/testdata/estate/Taskfile.yml +21 -0
- package/internal/commands/testdata/estate/build.gradle.kts +21 -0
- package/internal/commands/testdata/estate/justfile +20 -0
- package/internal/commands/testdata/estate/package.json +13 -0
- package/internal/commands/testdata/estate/pom.xml +29 -0
- package/internal/commands/testdata/estate/pyproject.toml +27 -0
- package/internal/commands/testdata/estate/xtask/src/main.rs +27 -0
- package/internal/commands/testdata/golden/commands.json +305 -0
- package/internal/gohttp/analyze.go +2500 -0
- package/internal/gohttp/endpoints.go +1067 -0
- package/internal/gohttp/roots.go +320 -0
- package/internal/gohttp/typed.go +143 -0
- package/internal/goscan/constants.go +85 -0
- package/internal/goscan/goscan_test.go +227 -0
- package/internal/goscan/names.go +52 -0
- package/internal/goscan/parse_test.go +11 -0
- package/internal/goscan/source.go +36 -0
- package/internal/goscan/tree.go +155 -0
- package/internal/goscan/types.go +99 -0
- package/internal/wsdl/ids.go +127 -0
- package/internal/wsdl/ids_test.go +21 -0
- package/internal/wsdl/model.go +62 -0
- package/internal/wsdl/parse.go +920 -0
- package/internal/wsdl/parse_test.go +133 -0
- package/package.json +117 -0
- package/plugin/describe.go +107 -0
- package/plugin/describe_test.go +114 -0
- package/plugin/protocol.go +117 -0
- package/plugin/schematest/schematest.go +126 -0
- package/plugins/README.md +1160 -0
- package/plugins/extract-adr/describe.go +19 -0
- package/plugins/extract-adr/describe_test.go +11 -0
- package/plugins/extract-adr/extract.go +153 -0
- package/plugins/extract-adr/extract_test.go +350 -0
- package/plugins/extract-adr/history.go +99 -0
- package/plugins/extract-adr/main.go +65 -0
- package/plugins/extract-adr/options.schema.json +26 -0
- package/plugins/extract-adr/parse.go +642 -0
- package/plugins/extract-adr/parse_test.go +405 -0
- package/plugins/extract-asyncapi/describe.go +19 -0
- package/plugins/extract-asyncapi/describe_test.go +11 -0
- package/plugins/extract-asyncapi/extract.go +315 -0
- package/plugins/extract-asyncapi/extract_test.go +197 -0
- package/plugins/extract-asyncapi/main.go +48 -0
- package/plugins/extract-asyncapi/options.schema.json +26 -0
- package/plugins/extract-asyncapi/spec.go +151 -0
- package/plugins/extract-celery/README.md +169 -0
- package/plugins/extract-celery/extract.py +346 -0
- package/plugins/extract-celery/extract_test.py +192 -0
- package/plugins/extract-celery/main.py +66 -0
- package/plugins/extract-celery/options.py +31 -0
- package/plugins/extract-celery/options.schema.json +31 -0
- package/plugins/extract-celery/producers.py +156 -0
- package/plugins/extract-celery/routes_test.py +106 -0
- package/plugins/extract-commands/describe.go +19 -0
- package/plugins/extract-commands/describe_test.go +11 -0
- package/plugins/extract-commands/extract.go +79 -0
- package/plugins/extract-commands/extract_test.go +92 -0
- package/plugins/extract-commands/main.go +55 -0
- package/plugins/extract-commands/options.schema.json +20 -0
- package/plugins/extract-csr/avro.go +258 -0
- package/plugins/extract-csr/describe.go +19 -0
- package/plugins/extract-csr/describe_test.go +11 -0
- package/plugins/extract-csr/extract.go +338 -0
- package/plugins/extract-csr/extract_test.go +374 -0
- package/plugins/extract-csr/jsonschema.go +343 -0
- package/plugins/extract-csr/lock.go +25 -0
- package/plugins/extract-csr/main.go +84 -0
- package/plugins/extract-csr/options.schema.json +43 -0
- package/plugins/extract-csr/subject.go +102 -0
- package/plugins/extract-django/README.md +386 -0
- package/plugins/extract-django/apps.py +100 -0
- package/plugins/extract-django/auth.py +302 -0
- package/plugins/extract-django/auth_test.py +188 -0
- package/plugins/extract-django/clients.py +121 -0
- package/plugins/extract-django/contracts.py +458 -0
- package/plugins/extract-django/database.py +119 -0
- package/plugins/extract-django/domain.py +318 -0
- package/plugins/extract-django/events.py +86 -0
- package/plugins/extract-django/extract.py +601 -0
- package/plugins/extract-django/extract_test.py +397 -0
- package/plugins/extract-django/flows.py +1278 -0
- package/plugins/extract-django/flows_test.py +338 -0
- package/plugins/extract-django/ids.py +42 -0
- package/plugins/extract-django/ids_test.py +30 -0
- package/plugins/extract-django/lifecycle.py +222 -0
- package/plugins/extract-django/lifecycle_test.py +76 -0
- package/plugins/extract-django/main.py +66 -0
- package/plugins/extract-django/openapi.py +229 -0
- package/plugins/extract-django/openapi_test.py +60 -0
- package/plugins/extract-django/operations.py +96 -0
- package/plugins/extract-django/options.py +61 -0
- package/plugins/extract-django/options.schema.json +126 -0
- package/plugins/extract-django/routing.py +214 -0
- package/plugins/extract-django/routing_test.py +198 -0
- package/plugins/extract-django/serializers.py +558 -0
- package/plugins/extract-django/store.py +434 -0
- package/plugins/extract-django/transport.py +242 -0
- package/plugins/extract-flows/describe.go +19 -0
- package/plugins/extract-flows/describe_test.go +11 -0
- package/plugins/extract-flows/extract.go +91 -0
- package/plugins/extract-flows/main.go +45 -0
- package/plugins/extract-flows/options.schema.json +16 -0
- package/plugins/extract-flows/parse.go +593 -0
- package/plugins/extract-flows/parse_test.go +204 -0
- package/plugins/extract-glossary/describe.go +19 -0
- package/plugins/extract-glossary/describe_test.go +11 -0
- package/plugins/extract-glossary/extract.go +115 -0
- package/plugins/extract-glossary/extract_test.go +220 -0
- package/plugins/extract-glossary/main.go +59 -0
- package/plugins/extract-glossary/options.schema.json +21 -0
- package/plugins/extract-glossary/parse.go +214 -0
- package/plugins/extract-glossary/parse_test.go +203 -0
- package/plugins/extract-go/aggregate.go +214 -0
- package/plugins/extract-go/client.go +409 -0
- package/plugins/extract-go/client_test.go +266 -0
- package/plugins/extract-go/describe.go +19 -0
- package/plugins/extract-go/describe_test.go +11 -0
- package/plugins/extract-go/enum.go +195 -0
- package/plugins/extract-go/enum_test.go +82 -0
- package/plugins/extract-go/event.go +99 -0
- package/plugins/extract-go/extract.go +191 -0
- package/plugins/extract-go/extract_test.go +261 -0
- package/plugins/extract-go/flow.go +1441 -0
- package/plugins/extract-go/flow_test.go +609 -0
- package/plugins/extract-go/httpclient.go +174 -0
- package/plugins/extract-go/httpclient_test.go +296 -0
- package/plugins/extract-go/ids.go +92 -0
- package/plugins/extract-go/layout.go +225 -0
- package/plugins/extract-go/layout_test.go +125 -0
- package/plugins/extract-go/lifecycle.go +324 -0
- package/plugins/extract-go/lifecycle_test.go +108 -0
- package/plugins/extract-go/main.go +79 -0
- package/plugins/extract-go/operation.go +157 -0
- package/plugins/extract-go/options.schema.json +66 -0
- package/plugins/extract-go/source.go +316 -0
- package/plugins/extract-go/transport.go +321 -0
- package/plugins/extract-go/transport_test.go +145 -0
- package/plugins/extract-go/wiring.go +434 -0
- package/plugins/extract-go-nats/describe.go +19 -0
- package/plugins/extract-go-nats/describe_test.go +11 -0
- package/plugins/extract-go-nats/extract.go +177 -0
- package/plugins/extract-go-nats/extract_test.go +389 -0
- package/plugins/extract-go-nats/index.go +379 -0
- package/plugins/extract-go-nats/main.go +42 -0
- package/plugins/extract-go-nats/options.schema.json +21 -0
- package/plugins/extract-go-nats/resolve.go +161 -0
- package/plugins/extract-go-nats/sites.go +224 -0
- package/plugins/extract-graphql/describe.go +19 -0
- package/plugins/extract-graphql/describe_test.go +11 -0
- package/plugins/extract-graphql/extract.go +433 -0
- package/plugins/extract-graphql/extract_test.go +256 -0
- package/plugins/extract-graphql/ids.go +49 -0
- package/plugins/extract-graphql/lex.go +237 -0
- package/plugins/extract-graphql/main.go +51 -0
- package/plugins/extract-graphql/options.schema.json +31 -0
- package/plugins/extract-graphql/parse.go +621 -0
- package/plugins/extract-graphql/parse_test.go +122 -0
- package/plugins/extract-http-clients/describe.go +19 -0
- package/plugins/extract-http-clients/describe_test.go +11 -0
- package/plugins/extract-http-clients/extract.go +705 -0
- package/plugins/extract-http-clients/extract_test.go +1263 -0
- package/plugins/extract-http-clients/main.go +42 -0
- package/plugins/extract-http-clients/options.schema.json +33 -0
- package/plugins/extract-java/README.md +190 -0
- package/plugins/extract-java/build/org/portolan/extract/Catalog.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$2.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Call.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Client.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Route.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain$Aggregate.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events$Found.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Extract.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Binding.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Draft.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Frame.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Ids.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$Move.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Main.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Operation.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Spec.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$UseCase.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Rpc.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Service.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Builder.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Input.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Project.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Unit.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport$Endpoint.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Line.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml.class +0 -0
- package/plugins/extract-java/options.schema.json +70 -0
- package/plugins/extract-openapi/describe.go +19 -0
- package/plugins/extract-openapi/describe_test.go +11 -0
- package/plugins/extract-openapi/discover.go +243 -0
- package/plugins/extract-openapi/extract.go +526 -0
- package/plugins/extract-openapi/extract_test.go +545 -0
- package/plugins/extract-openapi/main.go +75 -0
- package/plugins/extract-openapi/options.schema.json +62 -0
- package/plugins/extract-openapi/spec.go +350 -0
- package/plugins/extract-project/README.md +22 -0
- package/plugins/extract-project/describe.go +19 -0
- package/plugins/extract-project/describe_test.go +11 -0
- package/plugins/extract-project/extract.go +221 -0
- package/plugins/extract-project/extract_test.go +109 -0
- package/plugins/extract-project/main.go +41 -0
- package/plugins/extract-project/options.schema.json +48 -0
- package/plugins/extract-proto/ast.go +125 -0
- package/plugins/extract-proto/consumes.go +77 -0
- package/plugins/extract-proto/describe.go +19 -0
- package/plugins/extract-proto/extract.go +293 -0
- package/plugins/extract-proto/extract_test.go +459 -0
- package/plugins/extract-proto/ids.go +89 -0
- package/plugins/extract-proto/ids_test.go +57 -0
- package/plugins/extract-proto/lex.go +285 -0
- package/plugins/extract-proto/main.go +100 -0
- package/plugins/extract-proto/module.go +120 -0
- package/plugins/extract-proto/options.schema.json +51 -0
- package/plugins/extract-proto/parse.go +720 -0
- package/plugins/extract-proto/parse_test.go +307 -0
- package/plugins/extract-proto/provides.go +236 -0
- package/plugins/extract-proto/resolve.go +222 -0
- package/plugins/extract-proto/resolve_test.go +119 -0
- package/plugins/extract-python-kafka/README.md +36 -0
- package/plugins/extract-python-kafka/extract.py +211 -0
- package/plugins/extract-python-kafka/extract_test.py +68 -0
- package/plugins/extract-python-kafka/main.py +59 -0
- package/plugins/extract-python-kafka/options.py +29 -0
- package/plugins/extract-python-kafka/options.schema.json +31 -0
- package/plugins/extract-redis/README.md +11 -0
- package/plugins/extract-redis/describe.go +19 -0
- package/plugins/extract-redis/describe_test.go +11 -0
- package/plugins/extract-redis/extract.go +183 -0
- package/plugins/extract-redis/extract_test.go +168 -0
- package/plugins/extract-redis/keyspaces.go +469 -0
- package/plugins/extract-redis/main.go +44 -0
- package/plugins/extract-redis/options.schema.json +30 -0
- package/plugins/extract-river/describe.go +19 -0
- package/plugins/extract-river/describe_test.go +11 -0
- package/plugins/extract-river/extract.go +507 -0
- package/plugins/extract-river/extract_test.go +132 -0
- package/plugins/extract-river/main.go +42 -0
- package/plugins/extract-river/options.schema.json +21 -0
- package/plugins/extract-rust/Cargo.lock +133 -0
- package/plugins/extract-rust/Cargo.toml +23 -0
- package/plugins/extract-rust/README.md +204 -0
- package/plugins/extract-rust/options.schema.json +65 -0
- package/plugins/extract-rust/rustfmt.toml +1 -0
- package/plugins/extract-sql/ddl.go +893 -0
- package/plugins/extract-sql/ddl_test.go +401 -0
- package/plugins/extract-sql/describe.go +19 -0
- package/plugins/extract-sql/describe_test.go +11 -0
- package/plugins/extract-sql/layout.go +221 -0
- package/plugins/extract-sql/layout_test.go +55 -0
- package/plugins/extract-sql/lineage.go +107 -0
- package/plugins/extract-sql/main.go +141 -0
- package/plugins/extract-sql/maps.go +564 -0
- package/plugins/extract-sql/maps_java.go +117 -0
- package/plugins/extract-sql/maps_rust.go +333 -0
- package/plugins/extract-sql/maps_rust_test.go +70 -0
- package/plugins/extract-sql/maps_test.go +204 -0
- package/plugins/extract-sql/maps_ts.go +398 -0
- package/plugins/extract-sql/maps_ts_test.go +136 -0
- package/plugins/extract-sql/options.schema.json +53 -0
- package/plugins/extract-sql/projection.go +70 -0
- package/plugins/extract-sql/projection_test.go +50 -0
- package/plugins/extract-sql/store.go +420 -0
- package/plugins/extract-sql/store_test.go +233 -0
- package/plugins/extract-sql/view.go +295 -0
- package/plugins/extract-ts/README.md +306 -0
- package/plugins/extract-ts/ast.test.ts +178 -0
- package/plugins/extract-ts/ast.ts +648 -0
- package/plugins/extract-ts/clients.ts +185 -0
- package/plugins/extract-ts/domain.ts +164 -0
- package/plugins/extract-ts/extract.test.ts +208 -0
- package/plugins/extract-ts/extract.ts +200 -0
- package/plugins/extract-ts/flows.ts +783 -0
- package/plugins/extract-ts/graphql.test.ts +73 -0
- package/plugins/extract-ts/graphql.ts +181 -0
- package/plugins/extract-ts/ids.test.ts +21 -0
- package/plugins/extract-ts/ids.ts +52 -0
- package/plugins/extract-ts/lifecycle.ts +138 -0
- package/plugins/extract-ts/main.ts +48 -0
- package/plugins/extract-ts/openapi.test.ts +64 -0
- package/plugins/extract-ts/openapi.ts +99 -0
- package/plugins/extract-ts/operations.ts +93 -0
- package/plugins/extract-ts/options.schema.json +96 -0
- package/plugins/extract-ts/source.test.ts +174 -0
- package/plugins/extract-ts/source.ts +465 -0
- package/plugins/extract-ts/transport.ts +147 -0
- package/plugins/extract-ts/tsconfig.json +13 -0
- package/plugins/extract-ts/wiring.ts +190 -0
- package/plugins/extract-watermill/describe.go +19 -0
- package/plugins/extract-watermill/describe_test.go +11 -0
- package/plugins/extract-watermill/extract.go +1228 -0
- package/plugins/extract-watermill/extract_test.go +234 -0
- package/plugins/extract-watermill/main.go +41 -0
- package/plugins/extract-watermill/options.schema.json +21 -0
- package/plugins/extract-wsdl/describe.go +19 -0
- package/plugins/extract-wsdl/describe_test.go +11 -0
- package/plugins/extract-wsdl/extract.go +148 -0
- package/plugins/extract-wsdl/extract_test.go +45 -0
- package/plugins/extract-wsdl/main.go +53 -0
- package/plugins/extract-wsdl/options.schema.json +59 -0
- package/plugins/fetch-bsr/auth.go +114 -0
- package/plugins/fetch-bsr/bsr.go +240 -0
- package/plugins/fetch-bsr/cache.go +66 -0
- package/plugins/fetch-bsr/describe.go +19 -0
- package/plugins/fetch-bsr/fetch.go +192 -0
- package/plugins/fetch-bsr/fetch_test.go +465 -0
- package/plugins/fetch-bsr/lock.go +71 -0
- package/plugins/fetch-bsr/main.go +117 -0
- package/plugins/fetch-bsr/options.schema.json +42 -0
- package/plugins/fetch-csr/auth.go +95 -0
- package/plugins/fetch-csr/cache.go +69 -0
- package/plugins/fetch-csr/describe.go +19 -0
- package/plugins/fetch-csr/describe_test.go +11 -0
- package/plugins/fetch-csr/fetch.go +254 -0
- package/plugins/fetch-csr/fetch_test.go +494 -0
- package/plugins/fetch-csr/lock.go +95 -0
- package/plugins/fetch-csr/main.go +122 -0
- package/plugins/fetch-csr/options.schema.json +42 -0
- package/plugins/fetch-csr/registry.go +209 -0
- package/plugins/fetch-git/cache.go +65 -0
- package/plugins/fetch-git/describe.go +19 -0
- package/plugins/fetch-git/describe_test.go +11 -0
- package/plugins/fetch-git/fetch.go +181 -0
- package/plugins/fetch-git/fetch_test.go +332 -0
- package/plugins/fetch-git/git.go +169 -0
- package/plugins/fetch-git/lock.go +72 -0
- package/plugins/fetch-git/main.go +127 -0
- package/plugins/fetch-git/offline.go +39 -0
- package/plugins/fetch-git/options.schema.json +42 -0
- package/plugins/fetch-git/pin.go +90 -0
- package/plugins/fetch-git/pin_test.go +74 -0
- package/plugins/gen-backstage/describe.go +17 -0
- package/plugins/gen-backstage/main.go +22 -0
- package/plugins/gen-backstage/options.schema.json +30 -0
- package/plugins/gen-backstage/plugin.go +473 -0
- package/plugins/gen-backstage/plugin_test.go +145 -0
- package/plugins/gen-backstage.wasm +0 -0
- package/plugins/gen-markdown/adr.go +162 -0
- package/plugins/gen-markdown/aggregate.go +362 -0
- package/plugins/gen-markdown/canonical.go +93 -0
- package/plugins/gen-markdown/context.go +90 -0
- package/plugins/gen-markdown/coverage_test.go +89 -0
- package/plugins/gen-markdown/describe.go +19 -0
- package/plugins/gen-markdown/describe_test.go +11 -0
- package/plugins/gen-markdown/external.go +71 -0
- package/plugins/gen-markdown/flow.go +277 -0
- package/plugins/gen-markdown/glossary.go +76 -0
- package/plugins/gen-markdown/glossary_test.go +148 -0
- package/plugins/gen-markdown/llms.go +302 -0
- package/plugins/gen-markdown/main.go +22 -0
- package/plugins/gen-markdown/markdown.go +254 -0
- package/plugins/gen-markdown/markdown_test.go +100 -0
- package/plugins/gen-markdown/module.go +107 -0
- package/plugins/gen-markdown/options.schema.json +16 -0
- package/plugins/gen-markdown/plugin.go +39 -0
- package/plugins/gen-markdown/quality_test.go +176 -0
- package/plugins/gen-markdown/redis_test.go +38 -0
- package/plugins/gen-markdown/render.go +344 -0
- package/plugins/gen-markdown/render_test.go +186 -0
- package/plugins/gen-markdown/service.go +456 -0
- package/plugins/gen-markdown/source.go +177 -0
- package/plugins/gen-markdown/store.go +201 -0
- package/plugins/gen-markdown.wasm +0 -0
- package/plugins/gen-mermaid/describe.go +17 -0
- package/plugins/gen-mermaid/main.go +22 -0
- package/plugins/gen-mermaid/options.schema.json +10 -0
- package/plugins/gen-mermaid/plugin.go +104 -0
- package/plugins/gen-mermaid/plugin_test.go +33 -0
- package/plugins/gen-mermaid.wasm +0 -0
- package/plugins/openapi/ids.go +261 -0
- package/plugins/openapi/ids_test.go +98 -0
- package/plugins/pyplugin/catalog.py +209 -0
- package/plugins/pyplugin/celery_conf.py +436 -0
- package/plugins/pyplugin/celery_tasks.py +76 -0
- package/plugins/pyplugin/kafka.py +570 -0
- package/plugins/pyplugin/names.py +38 -0
- package/plugins/pyplugin/protocol.py +79 -0
- package/plugins/pyplugin/source.py +285 -0
- package/plugins/verify-codeowners/describe.go +19 -0
- package/plugins/verify-codeowners/describe_test.go +11 -0
- package/plugins/verify-codeowners/main.go +75 -0
- package/plugins/verify-codeowners/match.go +85 -0
- package/plugins/verify-codeowners/match_test.go +47 -0
- package/plugins/verify-codeowners/options.schema.json +15 -0
- package/plugins/verify-codeowners/owners.go +164 -0
- package/plugins/verify-codeowners/owners_test.go +225 -0
- package/plugins/verify-codeowners/parse.go +90 -0
- package/plugins/verify-codeowners/parse_test.go +62 -0
- package/plugins/verify-otel/describe.go +19 -0
- package/plugins/verify-otel/describe_test.go +11 -0
- package/plugins/verify-otel/main.go +53 -0
- package/plugins/verify-otel/match.go +336 -0
- package/plugins/verify-otel/options.schema.json +30 -0
- package/plugins/verify-otel/otlp.go +200 -0
- package/plugins/verify-otel/verify.go +734 -0
- package/plugins/verify-otel/verify_test.go +460 -0
- package/portolan.json +1073 -0
- package/public/favicon.svg +12 -0
- package/schema/portolan.schema.json +2558 -0
- package/scripts/README.md +53 -0
- package/scripts/build-report.mjs +60 -0
- package/scripts/build-report.test.mjs +44 -0
- package/scripts/builtin-plugins.mjs +49 -0
- package/scripts/catalog-sources.mjs +67 -0
- package/scripts/diff.mjs +315 -0
- package/scripts/diff.test.mjs +151 -0
- package/scripts/forge-comment.mjs +144 -0
- package/scripts/forge-comment.test.mjs +151 -0
- package/scripts/forge-release.mjs +138 -0
- package/scripts/forge-release.test.mjs +106 -0
- package/scripts/forge.mjs +61 -0
- package/scripts/gen-likec4.mjs +854 -0
- package/scripts/gen-likec4.test.mjs +258 -0
- package/scripts/gen.mjs +603 -0
- package/scripts/generated-docs.test.mjs +66 -0
- package/scripts/local-api.mjs +1192 -0
- package/scripts/local-api.test.mjs +387 -0
- package/scripts/manifest.mjs +214 -0
- package/scripts/manifest.test.mjs +148 -0
- package/scripts/output-path.mjs +79 -0
- package/scripts/output-path.test.mjs +45 -0
- package/scripts/package-smoke.mjs +37 -0
- package/scripts/plugin-host.mjs +419 -0
- package/scripts/plugin-host.test.mjs +109 -0
- package/scripts/plugin-wasm-worker.mjs +34 -0
- package/scripts/run-builtin.mjs +81 -0
- package/scripts/schema.mjs +357 -0
- package/scripts/site-docs.mjs +295 -0
- package/scripts/site-docs.test.mjs +181 -0
- package/scripts/vendor-lock.mjs +58 -0
- package/scripts/vendor-lock.test.mjs +69 -0
- package/src/README.md +38 -0
- package/src/app/App.tsx +448 -0
- package/src/app/BranchPicker.test.ts +46 -0
- package/src/app/BranchPicker.tsx +153 -0
- package/src/app/Breadcrumbs.test.ts +38 -0
- package/src/app/Breadcrumbs.tsx +223 -0
- package/src/app/BuildStamp.tsx +146 -0
- package/src/app/CommandPalette.tsx +292 -0
- package/src/app/HashScroll.tsx +45 -0
- package/src/app/Sidebar.tsx +1742 -0
- package/src/app/TopBar.tsx +393 -0
- package/src/app/density.tsx +64 -0
- package/src/app/forge-access.test.ts +27 -0
- package/src/app/forge-access.tsx +80 -0
- package/src/app/panels.tsx +141 -0
- package/src/app/pins.tsx +242 -0
- package/src/app/query-client.ts +24 -0
- package/src/app/responsive.ts +55 -0
- package/src/app/shortcuts.test.ts +39 -0
- package/src/app/shortcuts.tsx +282 -0
- package/src/app/theme.tsx +51 -0
- package/src/app/title.test.ts +14 -0
- package/src/app/title.ts +30 -0
- package/src/app/toast.tsx +59 -0
- package/src/app/tree-keys.test.ts +80 -0
- package/src/app/tree-keys.ts +87 -0
- package/src/app/ui-store.ts +52 -0
- package/src/catalog-error.test.ts +105 -0
- package/src/catalog-profile.test.ts +59 -0
- package/src/catalog-profile.ts +101 -0
- package/src/catalog-stores.test.ts +431 -0
- package/src/catalog.test.ts +1215 -0
- package/src/catalog.ts +3125 -0
- package/src/chat/Cards.tsx +408 -0
- package/src/chat/ChatPanel.tsx +79 -0
- package/src/chat/ChatSettings.tsx +219 -0
- package/src/chat/Composer.tsx +99 -0
- package/src/chat/Conversation.tsx +281 -0
- package/src/chat/Header.tsx +46 -0
- package/src/chat/Message.tsx +49 -0
- package/src/chat/Notice.tsx +195 -0
- package/src/chat/Starter.tsx +67 -0
- package/src/chat/Steps.tsx +45 -0
- package/src/chat/Waiting.tsx +87 -0
- package/src/chat/flags.test.ts +59 -0
- package/src/chat/flags.ts +155 -0
- package/src/chat/linkify.test.ts +30 -0
- package/src/chat/linkify.ts +45 -0
- package/src/chat/prefs.ts +56 -0
- package/src/chat/prompt.test.ts +43 -0
- package/src/chat/prompt.ts +157 -0
- package/src/chat/store.ts +35 -0
- package/src/chat/tools.ts +58 -0
- package/src/chat/transport.ts +70 -0
- package/src/components/AdrRow.tsx +29 -0
- package/src/components/AnchorLink.tsx +67 -0
- package/src/components/ApiReference.tsx +134 -0
- package/src/components/AsyncApiReference.tsx +120 -0
- package/src/components/CatalogStamp.tsx +155 -0
- package/src/components/ChannelRows.tsx +132 -0
- package/src/components/CommandRows.tsx +139 -0
- package/src/components/DiagramSkeleton.tsx +71 -0
- package/src/components/EditorLink.tsx +85 -0
- package/src/components/FieldTree.tsx +305 -0
- package/src/components/FlowTrigger.tsx +34 -0
- package/src/components/Ident.tsx +89 -0
- package/src/components/Integrations.tsx +243 -0
- package/src/components/LifecycleDiagram.tsx +110 -0
- package/src/components/MachineDocs.tsx +42 -0
- package/src/components/Markdown.tsx +173 -0
- package/src/components/MarkdownTable.tsx +206 -0
- package/src/components/Mermaid.tsx +211 -0
- package/src/components/MethodRows.tsx +309 -0
- package/src/components/Overlay.tsx +125 -0
- package/src/components/PageHeader.tsx +189 -0
- package/src/components/RowActions.tsx +97 -0
- package/src/components/SchemaDocument.tsx +89 -0
- package/src/components/Select.tsx +126 -0
- package/src/components/ShapeRows.tsx +118 -0
- package/src/components/SourceDoc.tsx +82 -0
- package/src/components/SourcePreview.tsx +441 -0
- package/src/components/TabRow.tsx +182 -0
- package/src/components/TechIcon.tsx +34 -0
- package/src/components/Toc.tsx +132 -0
- package/src/components/WhatLinksHere.tsx +273 -0
- package/src/components/WsdlReference.tsx +84 -0
- package/src/components/ddd-icons.tsx +107 -0
- package/src/components/kind.tsx +157 -0
- package/src/components/logo.tsx +61 -0
- package/src/components/primitives.tsx +264 -0
- package/src/data.test.ts +18 -0
- package/src/data.ts +202 -0
- package/src/enrich.test.ts +1150 -0
- package/src/enrich.ts +672 -0
- package/src/er/ErCanvas.tsx +533 -0
- package/src/er/RedisSchema.tsx +74 -0
- package/src/er/RelationCard.tsx +267 -0
- package/src/er/StoreHeader.tsx +155 -0
- package/src/er/TableNode.tsx +84 -0
- package/src/er/ViewNode.tsx +83 -0
- package/src/er/layout.test.ts +115 -0
- package/src/er/layout.ts +77 -0
- package/src/er/lineage.test.ts +140 -0
- package/src/er/lineage.ts +107 -0
- package/src/er/markers.tsx +79 -0
- package/src/er/spec.test.ts +344 -0
- package/src/er/spec.ts +426 -0
- package/src/flow/ChainList.tsx +162 -0
- package/src/flow/FlowTable.tsx +123 -0
- package/src/flow/FlowToolbar.tsx +372 -0
- package/src/flow/StepDetail.tsx +380 -0
- package/src/flow/StepRail.tsx +428 -0
- package/src/flow/answers.test.ts +50 -0
- package/src/flow/answers.ts +58 -0
- package/src/flow/chain.test.ts +383 -0
- package/src/flow/chain.ts +353 -0
- package/src/flow/chapters.test.ts +185 -0
- package/src/flow/chapters.ts +225 -0
- package/src/flow/continues.test.ts +102 -0
- package/src/flow/continues.ts +65 -0
- package/src/flow/cross-context.test.ts +97 -0
- package/src/flow/cross-context.ts +35 -0
- package/src/flow/mermaid.test.ts +22 -0
- package/src/flow/mermaid.ts +141 -0
- package/src/flow/outline.test.ts +212 -0
- package/src/flow/outline.ts +170 -0
- package/src/flow/paths.test.ts +129 -0
- package/src/flow/paths.ts +147 -0
- package/src/flow/prefs.test.ts +80 -0
- package/src/flow/prefs.ts +104 -0
- package/src/graph/DependencyGraph.tsx +283 -0
- package/src/graph/DependencyNodes.tsx +162 -0
- package/src/graph/EdgeLabel.tsx +61 -0
- package/src/graph/FocusedEventGraph.tsx +211 -0
- package/src/graph/GraphToolbar.tsx +187 -0
- package/src/graph/RoutedEdge.tsx +80 -0
- package/src/graph/dependency-layout.test.ts +360 -0
- package/src/graph/dependency-layout.ts +444 -0
- package/src/graph/elk.test.ts +70 -0
- package/src/graph/elk.ts +287 -0
- package/src/graph/nodes.tsx +97 -0
- package/src/graph/theme.ts +81 -0
- package/src/graph/useElkFlow.ts +125 -0
- package/src/index.css +1547 -0
- package/src/language/InLanguage.tsx +40 -0
- package/src/language/TermCard.tsx +132 -0
- package/src/language/cards.test.ts +114 -0
- package/src/language/cards.ts +111 -0
- package/src/lib/admonition.test.ts +49 -0
- package/src/lib/admonition.ts +48 -0
- package/src/lib/adr.test.ts +131 -0
- package/src/lib/adr.ts +68 -0
- package/src/lib/api.test.ts +122 -0
- package/src/lib/api.ts +135 -0
- package/src/lib/backlinks.test.ts +330 -0
- package/src/lib/backlinks.ts +567 -0
- package/src/lib/branch-compare.ts +16 -0
- package/src/lib/build-info.test.ts +76 -0
- package/src/lib/build-info.ts +80 -0
- package/src/lib/catalog-diff.test.ts +275 -0
- package/src/lib/catalog-diff.ts +655 -0
- package/src/lib/clipboard.ts +43 -0
- package/src/lib/comparison-memory.test.ts +40 -0
- package/src/lib/comparison-memory.ts +39 -0
- package/src/lib/context-color.ts +27 -0
- package/src/lib/context-map.test.ts +148 -0
- package/src/lib/context-map.ts +399 -0
- package/src/lib/data-model.test.ts +245 -0
- package/src/lib/data-model.ts +399 -0
- package/src/lib/data-problems.test.ts +178 -0
- package/src/lib/data-problems.ts +314 -0
- package/src/lib/derive.test.ts +251 -0
- package/src/lib/derive.ts +515 -0
- package/src/lib/editor-link.test.ts +125 -0
- package/src/lib/editor-link.ts +96 -0
- package/src/lib/editor-prefs.ts +27 -0
- package/src/lib/event-graph.test.ts +237 -0
- package/src/lib/event-graph.ts +327 -0
- package/src/lib/export-canvas.ts +37 -0
- package/src/lib/export-file.test.ts +30 -0
- package/src/lib/export-file.ts +20 -0
- package/src/lib/flow-tree.test.ts +177 -0
- package/src/lib/flow-tree.ts +160 -0
- package/src/lib/forge-refs.test.ts +50 -0
- package/src/lib/forge-refs.ts +60 -0
- package/src/lib/format.test.ts +35 -0
- package/src/lib/format.ts +64 -0
- package/src/lib/github-catalog.test.ts +301 -0
- package/src/lib/github-catalog.ts +610 -0
- package/src/lib/integrations.test.ts +119 -0
- package/src/lib/integrations.ts +133 -0
- package/src/lib/kinds.test.ts +91 -0
- package/src/lib/kinds.ts +204 -0
- package/src/lib/lifecycle.test.ts +93 -0
- package/src/lib/lifecycle.ts +165 -0
- package/src/lib/local-api.ts +194 -0
- package/src/lib/motion-features.ts +11 -0
- package/src/lib/motion.test.ts +120 -0
- package/src/lib/motion.tsx +269 -0
- package/src/lib/palette-recent.test.ts +80 -0
- package/src/lib/palette-recent.ts +90 -0
- package/src/lib/palette.test.ts +365 -0
- package/src/lib/palette.ts +593 -0
- package/src/lib/pins.test.ts +139 -0
- package/src/lib/pins.ts +130 -0
- package/src/lib/problems.test.ts +112 -0
- package/src/lib/project-preview.ts +5 -0
- package/src/lib/proto-problems.test.ts +121 -0
- package/src/lib/proto-problems.ts +65 -0
- package/src/lib/queries.test.ts +113 -0
- package/src/lib/queries.ts +131 -0
- package/src/lib/registry.test.ts +219 -0
- package/src/lib/registry.ts +208 -0
- package/src/lib/scenarios.ts +547 -0
- package/src/lib/setup-info.test.ts +199 -0
- package/src/lib/setup-info.ts +415 -0
- package/src/lib/shape.test.ts +289 -0
- package/src/lib/shape.ts +454 -0
- package/src/lib/sidebar-prefs.test.ts +32 -0
- package/src/lib/sidebar-prefs.ts +75 -0
- package/src/lib/source-code.test.ts +159 -0
- package/src/lib/source-code.ts +286 -0
- package/src/lib/source-doc.test.ts +131 -0
- package/src/lib/source-doc.ts +103 -0
- package/src/lib/source-highlight.test.ts +29 -0
- package/src/lib/source-highlight.ts +24 -0
- package/src/lib/source-link.test.ts +153 -0
- package/src/lib/source-link.ts +201 -0
- package/src/lib/spec-files.test.ts +24 -0
- package/src/lib/spec-files.ts +23 -0
- package/src/lib/table-directive.test.ts +139 -0
- package/src/lib/table-directive.ts +106 -0
- package/src/lib/tech.test.ts +120 -0
- package/src/lib/tech.ts +421 -0
- package/src/lib/terms.test.ts +67 -0
- package/src/lib/terms.ts +179 -0
- package/src/lib/wire-problems.test.ts +263 -0
- package/src/lib/wire-problems.ts +281 -0
- package/src/likec4/C4View.tsx +55 -0
- package/src/likec4/CanvasBridge.tsx +187 -0
- package/src/likec4/FlowView.tsx +235 -0
- package/src/likec4/InteractiveView.tsx +144 -0
- package/src/likec4/canvas-viewport.test.ts +149 -0
- package/src/likec4/canvas-viewport.ts +135 -0
- package/src/likec4/flow-edges.test.ts +51 -0
- package/src/likec4/flow-edges.ts +89 -0
- package/src/likec4/frame-theme.test.ts +76 -0
- package/src/likec4/frame-theme.ts +101 -0
- package/src/likec4/highlight-css.test.ts +49 -0
- package/src/likec4/highlight-css.ts +52 -0
- package/src/likec4/ids.test.ts +151 -0
- package/src/likec4/ids.ts +115 -0
- package/src/likec4/levels.tsx +70 -0
- package/src/likec4/mapping.test.ts +66 -0
- package/src/likec4/mapping.ts +54 -0
- package/src/likec4/reserved.json +141 -0
- package/src/likec4/view-index.ts +78 -0
- package/src/main.tsx +13 -0
- package/src/map/ContextMapGraph.tsx +274 -0
- package/src/map/ContextNode.tsx +70 -0
- package/src/map/FloatingEdge.tsx +86 -0
- package/src/merge.test.ts +1038 -0
- package/src/merge.ts +1004 -0
- package/src/pages/AdrDetail.tsx +242 -0
- package/src/pages/AdrIndex.tsx +114 -0
- package/src/pages/AggregatePage.tsx +727 -0
- package/src/pages/BlockPage.tsx +478 -0
- package/src/pages/CatalogFailure.tsx +111 -0
- package/src/pages/Changes.tsx +313 -0
- package/src/pages/ContextMap.tsx +534 -0
- package/src/pages/ContextPage.tsx +346 -0
- package/src/pages/EnumPage.tsx +282 -0
- package/src/pages/EventPage.tsx +686 -0
- package/src/pages/ExternalPage.tsx +204 -0
- package/src/pages/FlowDetail.tsx +663 -0
- package/src/pages/FlowIndex.tsx +303 -0
- package/src/pages/GraphPage.tsx +217 -0
- package/src/pages/Language.tsx +257 -0
- package/src/pages/ModulePage.tsx +366 -0
- package/src/pages/NotFound.tsx +54 -0
- package/src/pages/Overview.tsx +344 -0
- package/src/pages/Problems.tsx +360 -0
- package/src/pages/RegistryIndex.tsx +118 -0
- package/src/pages/ServicePage.tsx +746 -0
- package/src/pages/Settings.tsx +975 -0
- package/src/pages/StorePage.tsx +114 -0
- package/src/peek/PeekCard.test.ts +35 -0
- package/src/peek/PeekCard.tsx +118 -0
- package/src/peek/PeekLayer.tsx +147 -0
- package/src/peek/model.test.ts +156 -0
- package/src/peek/model.ts +253 -0
- package/src/routes.test.ts +222 -0
- package/src/routes.ts +449 -0
- package/src/selection/DetailPanel.tsx +1407 -0
- package/src/selection/hash.test.ts +73 -0
- package/src/selection/hash.ts +58 -0
- package/src/selection/model.test.ts +199 -0
- package/src/selection/model.ts +473 -0
- package/src/selection/pages.test.ts +115 -0
- package/src/selection/pages.ts +268 -0
- package/src/selection/store.test.ts +62 -0
- package/src/selection/store.ts +46 -0
- package/src/selection/sync.tsx +99 -0
- package/src/table/ColumnsMenu.tsx +72 -0
- package/src/table/DataTable.tsx +780 -0
- package/src/table/Facets.tsx +54 -0
- package/src/table/GroupMenu.tsx +69 -0
- package/src/table/Toolbar.tsx +190 -0
- package/src/table/cells.tsx +117 -0
- package/src/table/compare.test.ts +117 -0
- package/src/table/compare.ts +196 -0
- package/src/table/export.test.ts +88 -0
- package/src/table/export.ts +66 -0
- package/src/table/facet-groups.test.ts +74 -0
- package/src/table/facet-groups.ts +56 -0
- package/src/table/grouping.test.ts +84 -0
- package/src/table/grouping.ts +82 -0
- package/src/table/infer.test.ts +57 -0
- package/src/table/infer.ts +50 -0
- package/src/table/persist.test.ts +76 -0
- package/src/table/persist.ts +112 -0
- package/src/table/sort-url.test.ts +75 -0
- package/src/table/sort-url.ts +52 -0
- package/src/table/types.ts +80 -0
- package/src/table/useTableState.ts +220 -0
- package/src/test-catalog.ts +7 -0
- package/src/testing/estate/data__catalog.json +2847 -0
- package/src/testing/estate/data__flows.json +1724 -0
- package/src/testing/estate/examples__auth__portolan__api.json +212 -0
- package/src/testing/estate/examples__auth__portolan__domain.json +1204 -0
- package/src/testing/estate/examples__auth__portolan__glossary.json +226 -0
- package/src/testing/estate/examples__auth__portolan__observed.json +757 -0
- package/src/testing/estate/examples__auth__portolan__stores.json +195 -0
- package/src/testing/estate/examples__shop__cart__portolan__api.json +234 -0
- package/src/testing/estate/examples__shop__cart__portolan__commands.json +86 -0
- package/src/testing/estate/examples__shop__cart__portolan__domain.json +966 -0
- package/src/testing/estate/examples__shop__cart__portolan__observed.json +498 -0
- package/src/testing/estate/examples__shop__cart__portolan__stores.json +208 -0
- package/src/testing/estate/examples__shop__oms__portolan__glossary.json +98 -0
- package/src/testing/estate/examples__shop__oms__portolan__proto.json +186 -0
- package/src/testing/estate.ts +49 -0
- package/src/trail/Trail.tsx +81 -0
- package/src/trail/model.test.ts +157 -0
- package/src/trail/model.ts +189 -0
- package/src/trail/record.tsx +32 -0
- package/src/trail/store.test.ts +66 -0
- package/src/trail/store.ts +102 -0
- package/tsconfig.json +35 -0
- package/vite.config.ts +171 -0
|
@@ -0,0 +1,1724 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generatedAt": "2026-09-05T00:22:18+07:00",
|
|
3
|
+
"commit": "8149120",
|
|
4
|
+
"contexts": [],
|
|
5
|
+
"defs": {},
|
|
6
|
+
"flows": [
|
|
7
|
+
{
|
|
8
|
+
"id": "flow.checkout",
|
|
9
|
+
"slug": "checkout",
|
|
10
|
+
"name": "Checkout",
|
|
11
|
+
"summary": "Basket to dispatch, as the e2e suite drives it: a priced basket, a risk call whose peer is not in the catalog, an outbox publish, an authorization at the gateway, a capture retried with backoff, and a shipment held until the money lands. Three branches and two hops are read from the code rather than observed.",
|
|
12
|
+
"source": "services/oms/test/e2e/checkout_test.go",
|
|
13
|
+
"owner": "shop",
|
|
14
|
+
"participants": [
|
|
15
|
+
{
|
|
16
|
+
"id": "customer",
|
|
17
|
+
"kind": "actor",
|
|
18
|
+
"context": null
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "shop.oms",
|
|
22
|
+
"kind": "service",
|
|
23
|
+
"context": "shop"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "oms-db",
|
|
27
|
+
"kind": "store",
|
|
28
|
+
"context": "shop",
|
|
29
|
+
"label": "oms-db (postgres)"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "shop.pricing",
|
|
33
|
+
"kind": "service",
|
|
34
|
+
"context": "shop"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "fraud-scoring",
|
|
38
|
+
"kind": "unknown",
|
|
39
|
+
"context": null,
|
|
40
|
+
"label": "fraud-scoring (unknown)"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "bus",
|
|
44
|
+
"kind": "broker",
|
|
45
|
+
"context": null
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "payments.ledger",
|
|
49
|
+
"kind": "service",
|
|
50
|
+
"context": "payments"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "psp-gateway",
|
|
54
|
+
"kind": "external",
|
|
55
|
+
"context": null,
|
|
56
|
+
"label": "psp-gateway (external)"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "delivery.core",
|
|
60
|
+
"kind": "service",
|
|
61
|
+
"context": "delivery"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"steps": [
|
|
65
|
+
{
|
|
66
|
+
"type": "step",
|
|
67
|
+
"id": "s1",
|
|
68
|
+
"from": "customer",
|
|
69
|
+
"to": "shop.oms",
|
|
70
|
+
"kind": "rpc",
|
|
71
|
+
"label": "PlaceOrder",
|
|
72
|
+
"status": "verified",
|
|
73
|
+
"note": "HTTP edge. The handler requires an Idempotency-Key header and replays the stored response for a key it has already answered, so a double-tapped checkout cannot open two orders.",
|
|
74
|
+
"line": "checkout_test.go:62"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "step",
|
|
78
|
+
"id": "s2",
|
|
79
|
+
"from": "shop.oms",
|
|
80
|
+
"to": "oms-db",
|
|
81
|
+
"kind": "call",
|
|
82
|
+
"label": "loadBasket",
|
|
83
|
+
"status": "verified",
|
|
84
|
+
"line": "internal/oms/adapter/postgres/basket_repo.go:58"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"type": "step",
|
|
88
|
+
"id": "s3",
|
|
89
|
+
"from": "shop.oms",
|
|
90
|
+
"to": "shop.oms",
|
|
91
|
+
"kind": "call",
|
|
92
|
+
"label": "validateBasket",
|
|
93
|
+
"status": "verified",
|
|
94
|
+
"note": "Rejects empty baskets and lines whose stock reservation has expired. Runs before anything leaves the process.",
|
|
95
|
+
"line": "internal/oms/app/checkout.go:88"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"type": "step",
|
|
99
|
+
"id": "s4",
|
|
100
|
+
"from": "shop.oms",
|
|
101
|
+
"to": "shop.pricing",
|
|
102
|
+
"kind": "rpc",
|
|
103
|
+
"ref": "shop.v1.Pricing/GetQuote",
|
|
104
|
+
"label": "GetQuote",
|
|
105
|
+
"status": "verified",
|
|
106
|
+
"note": "250 ms deadline, one retry on UNAVAILABLE.",
|
|
107
|
+
"line": "internal/oms/app/checkout.go:104"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "alt",
|
|
111
|
+
"id": "alt-quote",
|
|
112
|
+
"branches": [
|
|
113
|
+
{
|
|
114
|
+
"title": "pricing answers within the deadline",
|
|
115
|
+
"steps": [
|
|
116
|
+
{
|
|
117
|
+
"type": "step",
|
|
118
|
+
"id": "s5",
|
|
119
|
+
"from": "shop.pricing",
|
|
120
|
+
"to": "bus",
|
|
121
|
+
"kind": "event",
|
|
122
|
+
"ref": "shop.pricing.quote.QuoteIssued",
|
|
123
|
+
"label": "QuoteIssued",
|
|
124
|
+
"status": "verified",
|
|
125
|
+
"note": "Published for the audit trail. The price checkout actually uses is the synchronous response above, not this event.",
|
|
126
|
+
"line": "checkout_test.go:96"
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"title": "pricing deadline exceeded",
|
|
132
|
+
"steps": [
|
|
133
|
+
{
|
|
134
|
+
"type": "step",
|
|
135
|
+
"id": "s6",
|
|
136
|
+
"from": "shop.oms",
|
|
137
|
+
"to": "oms-db",
|
|
138
|
+
"kind": "call",
|
|
139
|
+
"label": "readLastPriceSnapshot",
|
|
140
|
+
"status": "declared",
|
|
141
|
+
"note": "Falls back to the snapshot written by the last price-list import and marks the order repriceable. The e2e suite has no case for this branch; it is read from the code.",
|
|
142
|
+
"line": "internal/oms/app/checkout.go:118"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"type": "step",
|
|
150
|
+
"id": "s7",
|
|
151
|
+
"from": "shop.oms",
|
|
152
|
+
"to": "fraud-scoring",
|
|
153
|
+
"kind": "rpc",
|
|
154
|
+
"ref": "fraud.v2.Scoring/Score",
|
|
155
|
+
"label": "Score",
|
|
156
|
+
"status": "unresolved",
|
|
157
|
+
"note": "No service in the catalog provides fraud.v2.Scoring. The address comes from FRAUD_ADDR at runtime, so the peer cannot be resolved statically.",
|
|
158
|
+
"line": "internal/oms/client/fraud.go:22"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"type": "alt",
|
|
162
|
+
"id": "alt-risk",
|
|
163
|
+
"branches": [
|
|
164
|
+
{
|
|
165
|
+
"title": "score below 40",
|
|
166
|
+
"steps": [
|
|
167
|
+
{
|
|
168
|
+
"type": "step",
|
|
169
|
+
"id": "s8",
|
|
170
|
+
"from": "shop.oms",
|
|
171
|
+
"to": "shop.oms",
|
|
172
|
+
"kind": "call",
|
|
173
|
+
"label": "acceptOrder",
|
|
174
|
+
"status": "verified",
|
|
175
|
+
"line": "checkout_test.go:131"
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"title": "score at or above 40",
|
|
181
|
+
"steps": [
|
|
182
|
+
{
|
|
183
|
+
"type": "step",
|
|
184
|
+
"id": "s9",
|
|
185
|
+
"from": "shop.oms",
|
|
186
|
+
"to": "bus",
|
|
187
|
+
"kind": "event",
|
|
188
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
189
|
+
"label": "OrderCancelled",
|
|
190
|
+
"status": "declared",
|
|
191
|
+
"note": "The customer is shown a generic decline and the score never reaches the edge. Declared: the suite has no high-score fixture.",
|
|
192
|
+
"line": "internal/oms/app/checkout.go:176"
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
"terminal": true
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"title": "scorer did not answer within 800 ms",
|
|
199
|
+
"steps": [
|
|
200
|
+
{
|
|
201
|
+
"type": "step",
|
|
202
|
+
"id": "s10",
|
|
203
|
+
"from": "shop.oms",
|
|
204
|
+
"to": "shop.oms",
|
|
205
|
+
"kind": "call",
|
|
206
|
+
"label": "failOpenAndFlagForReview",
|
|
207
|
+
"status": "declared",
|
|
208
|
+
"note": "The order continues and is queued for manual review. Failing open is read from the code; nothing exercises the timeout.",
|
|
209
|
+
"line": "internal/oms/app/checkout.go:161"
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"type": "step",
|
|
217
|
+
"id": "s11",
|
|
218
|
+
"from": "shop.oms",
|
|
219
|
+
"to": "oms-db",
|
|
220
|
+
"kind": "call",
|
|
221
|
+
"label": "persistOrderAndOutboxRow",
|
|
222
|
+
"status": "verified",
|
|
223
|
+
"note": "One transaction for the order and the OrderPlaced outbox row. The order-accepted flow pins this hop on its own.",
|
|
224
|
+
"line": "internal/oms/app/checkout.go:191"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"type": "loop",
|
|
228
|
+
"id": "loop-outbox",
|
|
229
|
+
"title": "outbox relay, every 200 ms until the batch is empty",
|
|
230
|
+
"steps": [
|
|
231
|
+
{
|
|
232
|
+
"type": "step",
|
|
233
|
+
"id": "s12",
|
|
234
|
+
"from": "shop.oms",
|
|
235
|
+
"to": "bus",
|
|
236
|
+
"kind": "event",
|
|
237
|
+
"ref": "shop.oms.order.OrderPlaced",
|
|
238
|
+
"label": "OrderPlaced",
|
|
239
|
+
"status": "verified",
|
|
240
|
+
"line": "checkout_test.go:118"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"type": "step",
|
|
244
|
+
"id": "s13",
|
|
245
|
+
"from": "shop.oms",
|
|
246
|
+
"to": "oms-db",
|
|
247
|
+
"kind": "call",
|
|
248
|
+
"label": "markOutboxRowSent",
|
|
249
|
+
"status": "verified",
|
|
250
|
+
"note": "Marking happens after the broker acks, so a crash in between republishes rather than drops. Consumers are expected to tolerate the repeat.",
|
|
251
|
+
"line": "internal/oms/adapter/postgres/outbox.go:73"
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"type": "parallel",
|
|
257
|
+
"id": "par-placed",
|
|
258
|
+
"title": "OrderPlaced fan-out",
|
|
259
|
+
"branches": [
|
|
260
|
+
[
|
|
261
|
+
{
|
|
262
|
+
"type": "step",
|
|
263
|
+
"id": "s14",
|
|
264
|
+
"from": "bus",
|
|
265
|
+
"to": "payments.ledger",
|
|
266
|
+
"kind": "event",
|
|
267
|
+
"ref": "shop.oms.order.OrderPlaced",
|
|
268
|
+
"label": "OrderPlaced",
|
|
269
|
+
"status": "verified",
|
|
270
|
+
"note": "Consumer group `ledger-orders`. Opens the reconciliation record the gateway webhook later matches against.",
|
|
271
|
+
"line": "checkout_test.go:126"
|
|
272
|
+
}
|
|
273
|
+
],
|
|
274
|
+
[
|
|
275
|
+
{
|
|
276
|
+
"type": "step",
|
|
277
|
+
"id": "s15",
|
|
278
|
+
"from": "bus",
|
|
279
|
+
"to": "shop.pricing",
|
|
280
|
+
"kind": "event",
|
|
281
|
+
"ref": "shop.oms.order.OrderPlaced",
|
|
282
|
+
"label": "OrderPlaced",
|
|
283
|
+
"status": "declared",
|
|
284
|
+
"note": "Pricing marks the quote consumed. The subscription is registered in code but no test drives it.",
|
|
285
|
+
"line": "internal/pricing/app/subscribe.go:38"
|
|
286
|
+
}
|
|
287
|
+
]
|
|
288
|
+
]
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"type": "step",
|
|
292
|
+
"id": "s16",
|
|
293
|
+
"from": "shop.oms",
|
|
294
|
+
"to": "payments.ledger",
|
|
295
|
+
"kind": "rpc",
|
|
296
|
+
"ref": "payments.v1.Payments/Authorize",
|
|
297
|
+
"label": "Authorize",
|
|
298
|
+
"status": "verified",
|
|
299
|
+
"note": "Carries the same idempotency key as the edge request, so a retried checkout cannot authorize twice.",
|
|
300
|
+
"line": "checkout_test.go:141"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"type": "alt",
|
|
304
|
+
"id": "alt-currency",
|
|
305
|
+
"branches": [
|
|
306
|
+
{
|
|
307
|
+
"title": "order currency is the acquirer's settlement currency",
|
|
308
|
+
"steps": [
|
|
309
|
+
{
|
|
310
|
+
"type": "step",
|
|
311
|
+
"id": "s17",
|
|
312
|
+
"from": "payments.ledger",
|
|
313
|
+
"to": "payments.ledger",
|
|
314
|
+
"kind": "call",
|
|
315
|
+
"label": "settleDirect",
|
|
316
|
+
"status": "verified",
|
|
317
|
+
"note": "No conversion and no FX row: `settlement` is the order amount. This is every EUR order, which is most of them.",
|
|
318
|
+
"line": "checkout_test.go:144"
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"title": "order currency differs from the settlement currency",
|
|
324
|
+
"steps": [
|
|
325
|
+
{
|
|
326
|
+
"type": "step",
|
|
327
|
+
"id": "s18",
|
|
328
|
+
"from": "payments.ledger",
|
|
329
|
+
"to": "payments.ledger",
|
|
330
|
+
"kind": "call",
|
|
331
|
+
"label": "quoteFxRate",
|
|
332
|
+
"status": "declared",
|
|
333
|
+
"note": "The rate comes from the acquirer, not from the daily reference feed, and is refused if it is more than 60 s old. It is stored on the payment so the posting can be reproduced later.",
|
|
334
|
+
"line": "internal/ledger/app/fx.go:38"
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"title": "no acquirer is configured for the currency",
|
|
340
|
+
"steps": [
|
|
341
|
+
{
|
|
342
|
+
"type": "step",
|
|
343
|
+
"id": "s19",
|
|
344
|
+
"from": "payments.ledger",
|
|
345
|
+
"to": "bus",
|
|
346
|
+
"kind": "event",
|
|
347
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
348
|
+
"label": "PaymentDeclined",
|
|
349
|
+
"status": "declared",
|
|
350
|
+
"note": "Code `currency_unsupported`, category `hard`. Nothing retries it and no other acquirer is tried, because there is only one.",
|
|
351
|
+
"line": "internal/ledger/app/authorize.go:61"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"type": "step",
|
|
355
|
+
"id": "s20",
|
|
356
|
+
"from": "bus",
|
|
357
|
+
"to": "shop.oms",
|
|
358
|
+
"kind": "event",
|
|
359
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
360
|
+
"label": "PaymentDeclined",
|
|
361
|
+
"status": "declared",
|
|
362
|
+
"line": "internal/oms/app/decline.go:18"
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
"type": "step",
|
|
366
|
+
"id": "s21",
|
|
367
|
+
"from": "shop.oms",
|
|
368
|
+
"to": "bus",
|
|
369
|
+
"kind": "event",
|
|
370
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
371
|
+
"label": "OrderCancelled",
|
|
372
|
+
"status": "declared",
|
|
373
|
+
"note": "The customer is told the currency is not accepted. This is the one decline that is worth saying out loud, and the edge says it.",
|
|
374
|
+
"line": "internal/oms/app/decline.go:29"
|
|
375
|
+
}
|
|
376
|
+
],
|
|
377
|
+
"terminal": true
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"type": "step",
|
|
383
|
+
"id": "s22",
|
|
384
|
+
"from": "payments.ledger",
|
|
385
|
+
"to": "psp-gateway",
|
|
386
|
+
"kind": "rpc",
|
|
387
|
+
"ref": "psp.v2.Charges/Create",
|
|
388
|
+
"label": "Charges.Create (auth only)",
|
|
389
|
+
"status": "unresolved",
|
|
390
|
+
"note": "Third-party gateway; no service in the estate provides psp.v2.Charges. A timeout here leaves the charge in a state only the gateway knows — the gateway-webhook flow is what resolves it.",
|
|
391
|
+
"line": "internal/ledger/adapter/psp/client.go:64"
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"type": "alt",
|
|
395
|
+
"id": "alt-auth",
|
|
396
|
+
"branches": [
|
|
397
|
+
{
|
|
398
|
+
"title": "gateway approves",
|
|
399
|
+
"steps": [
|
|
400
|
+
{
|
|
401
|
+
"type": "step",
|
|
402
|
+
"id": "s23",
|
|
403
|
+
"from": "payments.ledger",
|
|
404
|
+
"to": "payments.ledger",
|
|
405
|
+
"kind": "call",
|
|
406
|
+
"label": "postAuthorizationHold",
|
|
407
|
+
"status": "verified",
|
|
408
|
+
"line": "internal/ledger/app/authorize.go:88"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"type": "step",
|
|
412
|
+
"id": "s24",
|
|
413
|
+
"from": "payments.ledger",
|
|
414
|
+
"to": "bus",
|
|
415
|
+
"kind": "event",
|
|
416
|
+
"ref": "payments.ledger.payment.PaymentAuthorized",
|
|
417
|
+
"label": "PaymentAuthorized",
|
|
418
|
+
"status": "verified",
|
|
419
|
+
"line": "checkout_test.go:151"
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"type": "step",
|
|
423
|
+
"id": "s25",
|
|
424
|
+
"from": "bus",
|
|
425
|
+
"to": "shop.oms",
|
|
426
|
+
"kind": "event",
|
|
427
|
+
"ref": "payments.ledger.payment.PaymentAuthorized",
|
|
428
|
+
"label": "PaymentAuthorized",
|
|
429
|
+
"status": "verified",
|
|
430
|
+
"line": "checkout_test.go:154"
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"title": "gateway declines",
|
|
436
|
+
"steps": [
|
|
437
|
+
{
|
|
438
|
+
"type": "step",
|
|
439
|
+
"id": "s26",
|
|
440
|
+
"from": "payments.ledger",
|
|
441
|
+
"to": "bus",
|
|
442
|
+
"kind": "event",
|
|
443
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
444
|
+
"label": "PaymentDeclined",
|
|
445
|
+
"status": "verified",
|
|
446
|
+
"line": "checkout_test.go:167"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"type": "step",
|
|
450
|
+
"id": "s27",
|
|
451
|
+
"from": "bus",
|
|
452
|
+
"to": "shop.oms",
|
|
453
|
+
"kind": "event",
|
|
454
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
455
|
+
"label": "PaymentDeclined",
|
|
456
|
+
"status": "verified",
|
|
457
|
+
"line": "checkout_test.go:170"
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"type": "step",
|
|
461
|
+
"id": "s28",
|
|
462
|
+
"from": "shop.oms",
|
|
463
|
+
"to": "bus",
|
|
464
|
+
"kind": "event",
|
|
465
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
466
|
+
"label": "OrderCancelled",
|
|
467
|
+
"status": "declared",
|
|
468
|
+
"note": "The order is cancelled and the basket released. The publish is in the decline handler; no assertion covers it.",
|
|
469
|
+
"line": "internal/oms/app/decline.go:29"
|
|
470
|
+
}
|
|
471
|
+
],
|
|
472
|
+
"terminal": true
|
|
473
|
+
}
|
|
474
|
+
]
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"type": "step",
|
|
478
|
+
"id": "s29",
|
|
479
|
+
"from": "shop.oms",
|
|
480
|
+
"to": "bus",
|
|
481
|
+
"kind": "event",
|
|
482
|
+
"ref": "shop.oms.order.OrderConfirmed",
|
|
483
|
+
"label": "OrderConfirmed",
|
|
484
|
+
"status": "verified",
|
|
485
|
+
"line": "checkout_test.go:158"
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"type": "step",
|
|
489
|
+
"id": "s30",
|
|
490
|
+
"from": "bus",
|
|
491
|
+
"to": "delivery.core",
|
|
492
|
+
"kind": "event",
|
|
493
|
+
"ref": "shop.oms.order.OrderConfirmed",
|
|
494
|
+
"label": "OrderConfirmed",
|
|
495
|
+
"status": "verified",
|
|
496
|
+
"note": "Creates the shipment in `held`. Nothing is handed to a carrier until the capture lands.",
|
|
497
|
+
"line": "internal/delivery/app/subscribe.go:44"
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
"type": "loop",
|
|
501
|
+
"id": "loop-capture",
|
|
502
|
+
"title": "capture retried with exponential backoff, at most 5 attempts over 24 h",
|
|
503
|
+
"steps": [
|
|
504
|
+
{
|
|
505
|
+
"type": "step",
|
|
506
|
+
"id": "s31",
|
|
507
|
+
"from": "shop.oms",
|
|
508
|
+
"to": "payments.ledger",
|
|
509
|
+
"kind": "rpc",
|
|
510
|
+
"ref": "payments.v1.Payments/Capture",
|
|
511
|
+
"label": "Capture",
|
|
512
|
+
"status": "declared",
|
|
513
|
+
"note": "The e2e suite stubs the ledger from this point, so the capture leg is read from the client rather than observed.",
|
|
514
|
+
"line": "internal/oms/app/capture.go:33"
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
"type": "step",
|
|
518
|
+
"id": "s32",
|
|
519
|
+
"from": "payments.ledger",
|
|
520
|
+
"to": "psp-gateway",
|
|
521
|
+
"kind": "rpc",
|
|
522
|
+
"ref": "psp.v2.Charges/Capture",
|
|
523
|
+
"label": "Charges.Capture",
|
|
524
|
+
"status": "unresolved",
|
|
525
|
+
"line": "internal/ledger/adapter/psp/client.go:102"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
"type": "step",
|
|
529
|
+
"id": "s33",
|
|
530
|
+
"from": "payments.ledger",
|
|
531
|
+
"to": "payments.ledger",
|
|
532
|
+
"kind": "call",
|
|
533
|
+
"label": "postJournalEntry",
|
|
534
|
+
"status": "verified",
|
|
535
|
+
"note": "Idempotent by (order_id, attempt), so a retry after a timeout cannot double-post. See ADR payments.0004.",
|
|
536
|
+
"line": "internal/ledger/app/capture.go:59"
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
"type": "step",
|
|
540
|
+
"id": "s34",
|
|
541
|
+
"from": "payments.ledger",
|
|
542
|
+
"to": "bus",
|
|
543
|
+
"kind": "event",
|
|
544
|
+
"ref": "payments.ledger.payment.PaymentCaptured",
|
|
545
|
+
"label": "PaymentCaptured",
|
|
546
|
+
"status": "declared",
|
|
547
|
+
"line": "internal/ledger/app/capture.go:91"
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
"type": "alt",
|
|
553
|
+
"id": "alt-capture",
|
|
554
|
+
"branches": [
|
|
555
|
+
{
|
|
556
|
+
"title": "captured within the attempt budget",
|
|
557
|
+
"steps": [
|
|
558
|
+
{
|
|
559
|
+
"type": "parallel",
|
|
560
|
+
"id": "par-captured",
|
|
561
|
+
"title": "PaymentCaptured fan-out",
|
|
562
|
+
"branches": [
|
|
563
|
+
[
|
|
564
|
+
{
|
|
565
|
+
"type": "step",
|
|
566
|
+
"id": "s35",
|
|
567
|
+
"from": "bus",
|
|
568
|
+
"to": "delivery.core",
|
|
569
|
+
"kind": "event",
|
|
570
|
+
"ref": "payments.ledger.payment.PaymentCaptured",
|
|
571
|
+
"label": "PaymentCaptured",
|
|
572
|
+
"status": "verified",
|
|
573
|
+
"note": "Releases the held shipment. This is the hop that turns money into a parcel.",
|
|
574
|
+
"line": "checkout_test.go:188"
|
|
575
|
+
}
|
|
576
|
+
],
|
|
577
|
+
[
|
|
578
|
+
{
|
|
579
|
+
"type": "step",
|
|
580
|
+
"id": "s36",
|
|
581
|
+
"from": "bus",
|
|
582
|
+
"to": "shop.oms",
|
|
583
|
+
"kind": "event",
|
|
584
|
+
"ref": "payments.ledger.payment.PaymentCaptured",
|
|
585
|
+
"label": "PaymentCaptured",
|
|
586
|
+
"status": "verified",
|
|
587
|
+
"line": "checkout_test.go:190"
|
|
588
|
+
}
|
|
589
|
+
]
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
]
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
"title": "declined on every attempt",
|
|
596
|
+
"steps": [
|
|
597
|
+
{
|
|
598
|
+
"type": "step",
|
|
599
|
+
"id": "s37",
|
|
600
|
+
"from": "payments.ledger",
|
|
601
|
+
"to": "bus",
|
|
602
|
+
"kind": "event",
|
|
603
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
604
|
+
"label": "PaymentDeclined",
|
|
605
|
+
"status": "declared",
|
|
606
|
+
"note": "After the fifth attempt the authorization has expired anyway. Category `soft`: the customer can pay again, but not on this order.",
|
|
607
|
+
"line": "internal/ledger/app/capture.go:118"
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
"type": "step",
|
|
611
|
+
"id": "s38",
|
|
612
|
+
"from": "bus",
|
|
613
|
+
"to": "shop.oms",
|
|
614
|
+
"kind": "event",
|
|
615
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
616
|
+
"label": "PaymentDeclined",
|
|
617
|
+
"status": "declared",
|
|
618
|
+
"line": "internal/oms/app/decline.go:18"
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
"type": "step",
|
|
622
|
+
"id": "s39",
|
|
623
|
+
"from": "shop.oms",
|
|
624
|
+
"to": "bus",
|
|
625
|
+
"kind": "event",
|
|
626
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
627
|
+
"label": "OrderCancelled",
|
|
628
|
+
"status": "declared",
|
|
629
|
+
"line": "internal/oms/app/decline.go:29"
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
"type": "step",
|
|
633
|
+
"id": "s40",
|
|
634
|
+
"from": "bus",
|
|
635
|
+
"to": "delivery.core",
|
|
636
|
+
"kind": "event",
|
|
637
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
638
|
+
"label": "OrderCancelled",
|
|
639
|
+
"status": "declared",
|
|
640
|
+
"note": "Drops the shipment that has been sitting in `held` since the order was confirmed. Nothing observed this hop — it is the failure path nobody has watched run.",
|
|
641
|
+
"line": "internal/delivery/app/subscribe.go:62"
|
|
642
|
+
}
|
|
643
|
+
],
|
|
644
|
+
"terminal": true
|
|
645
|
+
}
|
|
646
|
+
]
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
"type": "step",
|
|
650
|
+
"id": "s41",
|
|
651
|
+
"from": "delivery.core",
|
|
652
|
+
"to": "delivery.core",
|
|
653
|
+
"kind": "call",
|
|
654
|
+
"label": "planRoute",
|
|
655
|
+
"status": "verified",
|
|
656
|
+
"line": "internal/delivery/app/route.go:71"
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
"type": "step",
|
|
660
|
+
"id": "s42",
|
|
661
|
+
"from": "delivery.core",
|
|
662
|
+
"to": "bus",
|
|
663
|
+
"kind": "event",
|
|
664
|
+
"ref": "delivery.core.route.RoutePlanned",
|
|
665
|
+
"label": "RoutePlanned",
|
|
666
|
+
"status": "declared",
|
|
667
|
+
"note": "OMS subscribes to this for the promised delivery date. The publish is in the planner; the suite asserts the shipment, not the route.",
|
|
668
|
+
"line": "internal/delivery/app/route.go:94"
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
"type": "step",
|
|
672
|
+
"id": "s43",
|
|
673
|
+
"from": "delivery.core",
|
|
674
|
+
"to": "bus",
|
|
675
|
+
"kind": "event",
|
|
676
|
+
"ref": "delivery.core.shipment.ShipmentDispatched",
|
|
677
|
+
"label": "ShipmentDispatched",
|
|
678
|
+
"status": "verified",
|
|
679
|
+
"line": "checkout_test.go:203"
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"type": "step",
|
|
683
|
+
"id": "s44",
|
|
684
|
+
"from": "bus",
|
|
685
|
+
"to": "shop.oms",
|
|
686
|
+
"kind": "event",
|
|
687
|
+
"ref": "delivery.core.shipment.ShipmentDispatched",
|
|
688
|
+
"label": "ShipmentDispatched",
|
|
689
|
+
"status": "verified",
|
|
690
|
+
"line": "checkout_test.go:206"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
"type": "step",
|
|
694
|
+
"id": "s45",
|
|
695
|
+
"from": "shop.oms",
|
|
696
|
+
"to": "customer",
|
|
697
|
+
"kind": "rpc",
|
|
698
|
+
"label": "order confirmation",
|
|
699
|
+
"status": "declared",
|
|
700
|
+
"note": "Handed to the transactional mail provider. The hop leaves the estate and nothing in the catalog covers what happens to it.",
|
|
701
|
+
"line": "internal/oms/notify/confirmation.go:27"
|
|
702
|
+
}
|
|
703
|
+
]
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
"id": "flow.gateway-webhook",
|
|
707
|
+
"slug": "gateway-webhook",
|
|
708
|
+
"name": "Gateway webhook",
|
|
709
|
+
"summary": "The gateway's side of the story, arriving after the fact. One signed callback, four ways to read it: a replay to ignore, a capture to record, a charge with no local payment to adopt, and a failure to pass on. The adopt branch is the only repair for a checkout that timed out mid-authorization, and it is the one branch no test covers.",
|
|
710
|
+
"source": "services/ledger/test/integration/webhook_test.go",
|
|
711
|
+
"owner": "payments",
|
|
712
|
+
"participants": [
|
|
713
|
+
{
|
|
714
|
+
"id": "psp-gateway",
|
|
715
|
+
"kind": "external",
|
|
716
|
+
"context": null,
|
|
717
|
+
"label": "psp-gateway (external)"
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
"id": "payments.ledger",
|
|
721
|
+
"kind": "service",
|
|
722
|
+
"context": "payments"
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
"id": "bus",
|
|
726
|
+
"kind": "broker",
|
|
727
|
+
"context": null
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
"id": "shop.oms",
|
|
731
|
+
"kind": "service",
|
|
732
|
+
"context": "shop"
|
|
733
|
+
}
|
|
734
|
+
],
|
|
735
|
+
"steps": [
|
|
736
|
+
{
|
|
737
|
+
"type": "step",
|
|
738
|
+
"id": "w1",
|
|
739
|
+
"from": "psp-gateway",
|
|
740
|
+
"to": "payments.ledger",
|
|
741
|
+
"kind": "rpc",
|
|
742
|
+
"label": "POST /webhooks/psp/v2",
|
|
743
|
+
"status": "verified",
|
|
744
|
+
"note": "HMAC-signed body. The gateway retries for three days with backoff until it gets a 2xx, so every branch below has to tolerate being run twice.",
|
|
745
|
+
"line": "webhook_test.go:38"
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
"type": "step",
|
|
749
|
+
"id": "w2",
|
|
750
|
+
"from": "payments.ledger",
|
|
751
|
+
"to": "payments.ledger",
|
|
752
|
+
"kind": "call",
|
|
753
|
+
"label": "verifySignatureAndParse",
|
|
754
|
+
"status": "verified",
|
|
755
|
+
"note": "A bad signature is answered 401 and never reaches the dedup table. The test drives a tampered body for this.",
|
|
756
|
+
"line": "internal/ledger/adapter/psp/webhook.go:44"
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
"type": "alt",
|
|
760
|
+
"id": "alt-webhook",
|
|
761
|
+
"branches": [
|
|
762
|
+
{
|
|
763
|
+
"title": "event id already applied",
|
|
764
|
+
"steps": [
|
|
765
|
+
{
|
|
766
|
+
"type": "step",
|
|
767
|
+
"id": "w3",
|
|
768
|
+
"from": "payments.ledger",
|
|
769
|
+
"to": "payments.ledger",
|
|
770
|
+
"kind": "call",
|
|
771
|
+
"label": "dropDuplicate",
|
|
772
|
+
"status": "verified",
|
|
773
|
+
"note": "Dedup table keyed by the gateway's event id, rows kept 30 days. A replay older than that would be applied again; nothing guards it.",
|
|
774
|
+
"line": "webhook_test.go:71"
|
|
775
|
+
}
|
|
776
|
+
]
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
"title": "charge.succeeded, matching a local authorization",
|
|
780
|
+
"steps": [
|
|
781
|
+
{
|
|
782
|
+
"type": "step",
|
|
783
|
+
"id": "w4",
|
|
784
|
+
"from": "payments.ledger",
|
|
785
|
+
"to": "payments.ledger",
|
|
786
|
+
"kind": "call",
|
|
787
|
+
"label": "markCaptured",
|
|
788
|
+
"status": "verified",
|
|
789
|
+
"line": "internal/ledger/app/webhook.go:96"
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
"type": "step",
|
|
793
|
+
"id": "w5",
|
|
794
|
+
"from": "payments.ledger",
|
|
795
|
+
"to": "bus",
|
|
796
|
+
"kind": "event",
|
|
797
|
+
"ref": "payments.ledger.payment.PaymentCaptured",
|
|
798
|
+
"label": "PaymentCaptured",
|
|
799
|
+
"status": "verified",
|
|
800
|
+
"line": "webhook_test.go:104"
|
|
801
|
+
}
|
|
802
|
+
]
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
"title": "charge.succeeded, no local payment",
|
|
806
|
+
"steps": [
|
|
807
|
+
{
|
|
808
|
+
"type": "step",
|
|
809
|
+
"id": "w6",
|
|
810
|
+
"from": "payments.ledger",
|
|
811
|
+
"to": "shop.oms",
|
|
812
|
+
"kind": "rpc",
|
|
813
|
+
"ref": "shop.v1.Orders/GetOrder",
|
|
814
|
+
"label": "GetOrder",
|
|
815
|
+
"status": "verified",
|
|
816
|
+
"note": "The order reference travels in the gateway's metadata. The ledger reads the order back to decide whether the charge belongs to this estate at all.",
|
|
817
|
+
"line": "internal/ledger/app/webhook.go:132"
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
"type": "step",
|
|
821
|
+
"id": "w7",
|
|
822
|
+
"from": "payments.ledger",
|
|
823
|
+
"to": "payments.ledger",
|
|
824
|
+
"kind": "call",
|
|
825
|
+
"label": "adoptOrphanCharge",
|
|
826
|
+
"status": "declared",
|
|
827
|
+
"note": "Closes the gap left when the synchronous Authorize in checkout timed out after the gateway had already charged. Read from the code; the integration suite has no fixture for it, and it is the only path that keeps a customer from being charged for an order the estate never opened.",
|
|
828
|
+
"line": "internal/ledger/app/webhook.go:151"
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
"type": "step",
|
|
832
|
+
"id": "w8",
|
|
833
|
+
"from": "payments.ledger",
|
|
834
|
+
"to": "bus",
|
|
835
|
+
"kind": "event",
|
|
836
|
+
"ref": "payments.ledger.payment.PaymentAuthorized",
|
|
837
|
+
"label": "PaymentAuthorized",
|
|
838
|
+
"status": "declared",
|
|
839
|
+
"note": "Published late and out of order — consumers see the authorization after the charge already settled.",
|
|
840
|
+
"line": "internal/ledger/app/webhook.go:168"
|
|
841
|
+
}
|
|
842
|
+
]
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
"title": "charge.failed",
|
|
846
|
+
"steps": [
|
|
847
|
+
{
|
|
848
|
+
"type": "step",
|
|
849
|
+
"id": "w9",
|
|
850
|
+
"from": "payments.ledger",
|
|
851
|
+
"to": "bus",
|
|
852
|
+
"kind": "event",
|
|
853
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
854
|
+
"label": "PaymentDeclined",
|
|
855
|
+
"status": "verified",
|
|
856
|
+
"line": "webhook_test.go:126"
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
"type": "step",
|
|
860
|
+
"id": "w10",
|
|
861
|
+
"from": "bus",
|
|
862
|
+
"to": "shop.oms",
|
|
863
|
+
"kind": "event",
|
|
864
|
+
"ref": "payments.ledger.payment.PaymentDeclined",
|
|
865
|
+
"label": "PaymentDeclined",
|
|
866
|
+
"status": "verified",
|
|
867
|
+
"line": "webhook_test.go:131"
|
|
868
|
+
}
|
|
869
|
+
]
|
|
870
|
+
}
|
|
871
|
+
]
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
"type": "step",
|
|
875
|
+
"id": "w11",
|
|
876
|
+
"from": "payments.ledger",
|
|
877
|
+
"to": "psp-gateway",
|
|
878
|
+
"kind": "rpc",
|
|
879
|
+
"label": "ack 200",
|
|
880
|
+
"status": "verified",
|
|
881
|
+
"note": "Acked only after the branch above has committed. Anything else and the gateway replays, which is what makes the dedup table load-bearing.",
|
|
882
|
+
"line": "webhook_test.go:142"
|
|
883
|
+
}
|
|
884
|
+
]
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
"id": "flow.order-accepted",
|
|
888
|
+
"slug": "order-accepted",
|
|
889
|
+
"name": "Order accepted",
|
|
890
|
+
"summary": "The narrow slice one integration test pins end to end: an order commits with its outbox row, the relay publishes it, the ledger picks it up and the authorization comes back. Every hop here is asserted, which is why this is the only flow with no gaps in it.",
|
|
891
|
+
"source": "services/oms/test/integration/order_accepted_test.go",
|
|
892
|
+
"owner": "shop",
|
|
893
|
+
"participants": [
|
|
894
|
+
{
|
|
895
|
+
"id": "shop.oms",
|
|
896
|
+
"kind": "service",
|
|
897
|
+
"context": "shop"
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
"id": "oms-db",
|
|
901
|
+
"kind": "store",
|
|
902
|
+
"context": "shop",
|
|
903
|
+
"label": "oms-db (postgres)"
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
"id": "bus",
|
|
907
|
+
"kind": "broker",
|
|
908
|
+
"context": null
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
"id": "payments.ledger",
|
|
912
|
+
"kind": "service",
|
|
913
|
+
"context": "payments"
|
|
914
|
+
}
|
|
915
|
+
],
|
|
916
|
+
"steps": [
|
|
917
|
+
{
|
|
918
|
+
"type": "step",
|
|
919
|
+
"id": "a1",
|
|
920
|
+
"from": "shop.oms",
|
|
921
|
+
"to": "oms-db",
|
|
922
|
+
"kind": "call",
|
|
923
|
+
"label": "insertOrderAndOutboxRow",
|
|
924
|
+
"status": "verified",
|
|
925
|
+
"note": "The order row and the OrderPlaced outbox row commit in one transaction, so the event cannot be published before the order exists or lost after it does.",
|
|
926
|
+
"line": "internal/oms/adapter/postgres/order_repo.go:141"
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
"type": "step",
|
|
930
|
+
"id": "a2",
|
|
931
|
+
"from": "shop.oms",
|
|
932
|
+
"to": "bus",
|
|
933
|
+
"kind": "event",
|
|
934
|
+
"ref": "shop.oms.order.OrderPlaced",
|
|
935
|
+
"label": "OrderPlaced",
|
|
936
|
+
"status": "verified",
|
|
937
|
+
"note": "Published by the outbox relay, not by the request handler. The test waits on the relay rather than on PlaceOrder returning.",
|
|
938
|
+
"line": "order_accepted_test.go:58"
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
"type": "step",
|
|
942
|
+
"id": "a3",
|
|
943
|
+
"from": "bus",
|
|
944
|
+
"to": "payments.ledger",
|
|
945
|
+
"kind": "event",
|
|
946
|
+
"ref": "shop.oms.order.OrderPlaced",
|
|
947
|
+
"label": "OrderPlaced",
|
|
948
|
+
"status": "verified",
|
|
949
|
+
"note": "Consumer group `ledger-orders`, at-least-once. The test replays the same message a second time and asserts nothing changes.",
|
|
950
|
+
"line": "order_accepted_test.go:71"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
"type": "step",
|
|
954
|
+
"id": "a4",
|
|
955
|
+
"from": "payments.ledger",
|
|
956
|
+
"to": "payments.ledger",
|
|
957
|
+
"kind": "call",
|
|
958
|
+
"label": "openReconciliationRecord",
|
|
959
|
+
"status": "verified",
|
|
960
|
+
"note": "The event only opens the record the gateway webhook later matches against. Authorizing is the synchronous call below, because checkout needs the answer before it can confirm.",
|
|
961
|
+
"line": "internal/ledger/app/intent.go:47"
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
"type": "step",
|
|
965
|
+
"id": "a5",
|
|
966
|
+
"from": "shop.oms",
|
|
967
|
+
"to": "payments.ledger",
|
|
968
|
+
"kind": "rpc",
|
|
969
|
+
"ref": "payments.v1.Payments/Authorize",
|
|
970
|
+
"label": "Authorize",
|
|
971
|
+
"status": "verified",
|
|
972
|
+
"note": "Carries the order's idempotency key. The gateway behind the ledger is the sandbox stub here; the real hop out of the estate is drawn in the checkout flow.",
|
|
973
|
+
"line": "order_accepted_test.go:88"
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
"type": "step",
|
|
977
|
+
"id": "a6",
|
|
978
|
+
"from": "payments.ledger",
|
|
979
|
+
"to": "bus",
|
|
980
|
+
"kind": "event",
|
|
981
|
+
"ref": "payments.ledger.payment.PaymentAuthorized",
|
|
982
|
+
"label": "PaymentAuthorized",
|
|
983
|
+
"status": "verified",
|
|
984
|
+
"line": "order_accepted_test.go:103"
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
"type": "step",
|
|
988
|
+
"id": "a7",
|
|
989
|
+
"from": "bus",
|
|
990
|
+
"to": "shop.oms",
|
|
991
|
+
"kind": "event",
|
|
992
|
+
"ref": "payments.ledger.payment.PaymentAuthorized",
|
|
993
|
+
"label": "PaymentAuthorized",
|
|
994
|
+
"status": "verified",
|
|
995
|
+
"line": "order_accepted_test.go:114"
|
|
996
|
+
}
|
|
997
|
+
]
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
"id": "flow.order-cancelled",
|
|
1001
|
+
"slug": "order-cancelled",
|
|
1002
|
+
"name": "Order cancelled",
|
|
1003
|
+
"summary": "A customer cancels before the parcel moves, and two compensations run side by side: the money is unwound at the gateway, and the stop is taken off the route. Whether the money is voided or refunded depends on how far payment got, and the delivery half is declared everywhere and observed nowhere.",
|
|
1004
|
+
"source": "services/oms/test/e2e/cancel_test.go",
|
|
1005
|
+
"owner": "shop",
|
|
1006
|
+
"participants": [
|
|
1007
|
+
{
|
|
1008
|
+
"id": "customer",
|
|
1009
|
+
"kind": "actor",
|
|
1010
|
+
"context": null
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
"id": "shop.oms",
|
|
1014
|
+
"kind": "service",
|
|
1015
|
+
"context": "shop"
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
"id": "bus",
|
|
1019
|
+
"kind": "broker",
|
|
1020
|
+
"context": null
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
"id": "payments.ledger",
|
|
1024
|
+
"kind": "service",
|
|
1025
|
+
"context": "payments"
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
"id": "psp-gateway",
|
|
1029
|
+
"kind": "external",
|
|
1030
|
+
"context": null,
|
|
1031
|
+
"label": "psp-gateway (external)"
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
"id": "delivery.core",
|
|
1035
|
+
"kind": "service",
|
|
1036
|
+
"context": "delivery"
|
|
1037
|
+
}
|
|
1038
|
+
],
|
|
1039
|
+
"steps": [
|
|
1040
|
+
{
|
|
1041
|
+
"type": "step",
|
|
1042
|
+
"id": "x1",
|
|
1043
|
+
"from": "customer",
|
|
1044
|
+
"to": "shop.oms",
|
|
1045
|
+
"kind": "rpc",
|
|
1046
|
+
"label": "CancelOrder",
|
|
1047
|
+
"status": "verified",
|
|
1048
|
+
"line": "cancel_test.go:44"
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
"type": "step",
|
|
1052
|
+
"id": "x2",
|
|
1053
|
+
"from": "shop.oms",
|
|
1054
|
+
"to": "delivery.core",
|
|
1055
|
+
"kind": "rpc",
|
|
1056
|
+
"ref": "delivery.v1.Delivery/GetShipment",
|
|
1057
|
+
"label": "GetShipment",
|
|
1058
|
+
"status": "declared",
|
|
1059
|
+
"note": "Cancelling is only allowed while the shipment is `held` or `planned`. The state comes from delivery, not from the order, so a stale read here is what lets a dispatched parcel be cancelled.",
|
|
1060
|
+
"line": "internal/oms/client/delivery.go:41"
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
"type": "alt",
|
|
1064
|
+
"id": "alt-cancel",
|
|
1065
|
+
"branches": [
|
|
1066
|
+
{
|
|
1067
|
+
"title": "shipment not yet dispatched",
|
|
1068
|
+
"steps": [
|
|
1069
|
+
{
|
|
1070
|
+
"type": "step",
|
|
1071
|
+
"id": "x3",
|
|
1072
|
+
"from": "shop.oms",
|
|
1073
|
+
"to": "bus",
|
|
1074
|
+
"kind": "event",
|
|
1075
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
1076
|
+
"label": "OrderCancelled",
|
|
1077
|
+
"status": "verified",
|
|
1078
|
+
"line": "cancel_test.go:61"
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
"type": "parallel",
|
|
1082
|
+
"id": "par-compensate",
|
|
1083
|
+
"title": "compensations, which do not wait for each other",
|
|
1084
|
+
"branches": [
|
|
1085
|
+
[
|
|
1086
|
+
{
|
|
1087
|
+
"type": "step",
|
|
1088
|
+
"id": "x4",
|
|
1089
|
+
"from": "bus",
|
|
1090
|
+
"to": "payments.ledger",
|
|
1091
|
+
"kind": "event",
|
|
1092
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
1093
|
+
"label": "OrderCancelled",
|
|
1094
|
+
"status": "verified",
|
|
1095
|
+
"line": "cancel_test.go:70"
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
"type": "alt",
|
|
1099
|
+
"id": "alt-money",
|
|
1100
|
+
"branches": [
|
|
1101
|
+
{
|
|
1102
|
+
"title": "authorization not yet captured",
|
|
1103
|
+
"steps": [
|
|
1104
|
+
{
|
|
1105
|
+
"type": "step",
|
|
1106
|
+
"id": "x5",
|
|
1107
|
+
"from": "payments.ledger",
|
|
1108
|
+
"to": "psp-gateway",
|
|
1109
|
+
"kind": "rpc",
|
|
1110
|
+
"ref": "psp.v2.Charges/Void",
|
|
1111
|
+
"label": "Charges.Void",
|
|
1112
|
+
"status": "unresolved",
|
|
1113
|
+
"note": "Voiding costs nothing and leaves no trace on the customer's statement, which is why the capture is held back until dispatch in the first place.",
|
|
1114
|
+
"line": "internal/ledger/adapter/psp/client.go:171"
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
"type": "step",
|
|
1118
|
+
"id": "x6",
|
|
1119
|
+
"from": "payments.ledger",
|
|
1120
|
+
"to": "payments.ledger",
|
|
1121
|
+
"kind": "call",
|
|
1122
|
+
"label": "releaseHold",
|
|
1123
|
+
"status": "verified",
|
|
1124
|
+
"line": "cancel_test.go:83"
|
|
1125
|
+
}
|
|
1126
|
+
]
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
"title": "payment already captured",
|
|
1130
|
+
"steps": [
|
|
1131
|
+
{
|
|
1132
|
+
"type": "step",
|
|
1133
|
+
"id": "x7",
|
|
1134
|
+
"from": "payments.ledger",
|
|
1135
|
+
"to": "psp-gateway",
|
|
1136
|
+
"kind": "rpc",
|
|
1137
|
+
"ref": "psp.v2.Charges/Refund",
|
|
1138
|
+
"label": "Charges.Refund",
|
|
1139
|
+
"status": "unresolved",
|
|
1140
|
+
"line": "internal/ledger/adapter/psp/client.go:138"
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
"type": "step",
|
|
1144
|
+
"id": "x8",
|
|
1145
|
+
"from": "payments.ledger",
|
|
1146
|
+
"to": "bus",
|
|
1147
|
+
"kind": "event",
|
|
1148
|
+
"ref": "payments.ledger.refund.RefundIssued",
|
|
1149
|
+
"label": "RefundIssued",
|
|
1150
|
+
"status": "declared",
|
|
1151
|
+
"note": "The same event the support refund publishes. Nothing in the payload says which of the two happened, so a consumer cannot tell a cancelled order from a returned one.",
|
|
1152
|
+
"line": "internal/ledger/app/refund.go:88"
|
|
1153
|
+
}
|
|
1154
|
+
]
|
|
1155
|
+
}
|
|
1156
|
+
]
|
|
1157
|
+
}
|
|
1158
|
+
],
|
|
1159
|
+
[
|
|
1160
|
+
{
|
|
1161
|
+
"type": "step",
|
|
1162
|
+
"id": "x9",
|
|
1163
|
+
"from": "bus",
|
|
1164
|
+
"to": "delivery.core",
|
|
1165
|
+
"kind": "event",
|
|
1166
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
1167
|
+
"label": "OrderCancelled",
|
|
1168
|
+
"status": "declared",
|
|
1169
|
+
"note": "The subscription is registered in the delivery repo, but no test covers it and no trace in the sampled window shows it firing.",
|
|
1170
|
+
"line": "internal/delivery/app/subscribe.go:62"
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
"type": "step",
|
|
1174
|
+
"id": "x10",
|
|
1175
|
+
"from": "delivery.core",
|
|
1176
|
+
"to": "delivery.core",
|
|
1177
|
+
"kind": "call",
|
|
1178
|
+
"label": "removeStopAndReplan",
|
|
1179
|
+
"status": "declared",
|
|
1180
|
+
"line": "internal/delivery/app/route.go:112"
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
"type": "step",
|
|
1184
|
+
"id": "x11",
|
|
1185
|
+
"from": "delivery.core",
|
|
1186
|
+
"to": "bus",
|
|
1187
|
+
"kind": "event",
|
|
1188
|
+
"ref": "delivery.core.route.RoutePlanned",
|
|
1189
|
+
"label": "RoutePlanned",
|
|
1190
|
+
"status": "declared",
|
|
1191
|
+
"note": "The route is republished without the stop. Consumers see a second RoutePlanned for the same route and are expected to take the later one.",
|
|
1192
|
+
"line": "internal/delivery/app/route.go:94"
|
|
1193
|
+
}
|
|
1194
|
+
]
|
|
1195
|
+
]
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
"type": "step",
|
|
1199
|
+
"id": "x12",
|
|
1200
|
+
"from": "shop.oms",
|
|
1201
|
+
"to": "customer",
|
|
1202
|
+
"kind": "rpc",
|
|
1203
|
+
"label": "cancellation confirmation",
|
|
1204
|
+
"status": "declared",
|
|
1205
|
+
"line": "internal/oms/notify/cancellation.go:19"
|
|
1206
|
+
}
|
|
1207
|
+
]
|
|
1208
|
+
},
|
|
1209
|
+
{
|
|
1210
|
+
"title": "shipment already dispatched",
|
|
1211
|
+
"steps": [
|
|
1212
|
+
{
|
|
1213
|
+
"type": "step",
|
|
1214
|
+
"id": "x13",
|
|
1215
|
+
"from": "shop.oms",
|
|
1216
|
+
"to": "customer",
|
|
1217
|
+
"kind": "rpc",
|
|
1218
|
+
"label": "409 Conflict",
|
|
1219
|
+
"status": "verified",
|
|
1220
|
+
"note": "The edge refuses and points the customer at returns instead. What happens from there is the refund-requested flow, and none of it is observed.",
|
|
1221
|
+
"line": "cancel_test.go:118"
|
|
1222
|
+
}
|
|
1223
|
+
],
|
|
1224
|
+
"terminal": true
|
|
1225
|
+
}
|
|
1226
|
+
]
|
|
1227
|
+
}
|
|
1228
|
+
]
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
"id": "flow.quote-expired-on-checkout",
|
|
1232
|
+
"slug": "quote-expired-on-checkout",
|
|
1233
|
+
"name": "Quote expired on checkout",
|
|
1234
|
+
"summary": "A basket that has been checked out is a basket whose quote is spent. Pricing hears the event the cart publishes and expires the quote it issued for that basket, so a second checkout of the same basket has to be priced again rather than reuse a number the price list may have moved on from.",
|
|
1235
|
+
"source": "services/pricing/internal/policy/expire_quote.go",
|
|
1236
|
+
"owner": "shop",
|
|
1237
|
+
"participants": [
|
|
1238
|
+
{
|
|
1239
|
+
"id": "bus",
|
|
1240
|
+
"kind": "broker",
|
|
1241
|
+
"context": null
|
|
1242
|
+
},
|
|
1243
|
+
{
|
|
1244
|
+
"id": "shop.pricing",
|
|
1245
|
+
"kind": "service",
|
|
1246
|
+
"context": "shop"
|
|
1247
|
+
},
|
|
1248
|
+
{
|
|
1249
|
+
"id": "pricing-db",
|
|
1250
|
+
"kind": "store",
|
|
1251
|
+
"context": "shop",
|
|
1252
|
+
"label": "pricing-db (postgres)"
|
|
1253
|
+
}
|
|
1254
|
+
],
|
|
1255
|
+
"steps": [
|
|
1256
|
+
{
|
|
1257
|
+
"type": "step",
|
|
1258
|
+
"id": "s1",
|
|
1259
|
+
"from": "bus",
|
|
1260
|
+
"to": "shop.pricing",
|
|
1261
|
+
"kind": "event",
|
|
1262
|
+
"ref": "shop.cart.basket.BasketCheckedOut",
|
|
1263
|
+
"label": "BasketCheckedOut",
|
|
1264
|
+
"status": "declared",
|
|
1265
|
+
"note": "One consumer group, the basket id as the routing key. A basket with no quote on file is ignored, not an error: not every basket was priced.",
|
|
1266
|
+
"line": "internal/policy/expire_quote.go:24"
|
|
1267
|
+
},
|
|
1268
|
+
{
|
|
1269
|
+
"type": "step",
|
|
1270
|
+
"id": "s2",
|
|
1271
|
+
"from": "shop.pricing",
|
|
1272
|
+
"to": "pricing-db",
|
|
1273
|
+
"kind": "call",
|
|
1274
|
+
"label": "expireQuote",
|
|
1275
|
+
"status": "declared",
|
|
1276
|
+
"line": "internal/adapter/postgres/quotes.go:71"
|
|
1277
|
+
},
|
|
1278
|
+
{
|
|
1279
|
+
"type": "step",
|
|
1280
|
+
"id": "s3",
|
|
1281
|
+
"from": "shop.pricing",
|
|
1282
|
+
"to": "bus",
|
|
1283
|
+
"kind": "event",
|
|
1284
|
+
"ref": "shop.pricing.quote.QuoteExpired",
|
|
1285
|
+
"label": "QuoteExpired",
|
|
1286
|
+
"status": "declared",
|
|
1287
|
+
"note": "Published for the audit trail; nothing in the estate acts on it yet.",
|
|
1288
|
+
"line": "internal/policy/expire_quote.go:31"
|
|
1289
|
+
}
|
|
1290
|
+
]
|
|
1291
|
+
},
|
|
1292
|
+
{
|
|
1293
|
+
"id": "flow.refund-requested",
|
|
1294
|
+
"slug": "refund-requested",
|
|
1295
|
+
"name": "Refund requested",
|
|
1296
|
+
"summary": "How a support-initiated refund is meant to travel: the window is read off the shipment, an undispatched parcel is recalled first, and the money is returned through the ledger. Written by hand from the design doc — not one step has been observed in a test or a trace, which is why every hop on this page is declared.",
|
|
1297
|
+
"source": "docs/flows/refund-requested.md",
|
|
1298
|
+
"owner": "shop",
|
|
1299
|
+
"participants": [
|
|
1300
|
+
{
|
|
1301
|
+
"id": "agent",
|
|
1302
|
+
"kind": "actor",
|
|
1303
|
+
"context": null,
|
|
1304
|
+
"label": "support agent"
|
|
1305
|
+
},
|
|
1306
|
+
{
|
|
1307
|
+
"id": "shop.oms",
|
|
1308
|
+
"kind": "service",
|
|
1309
|
+
"context": "shop"
|
|
1310
|
+
},
|
|
1311
|
+
{
|
|
1312
|
+
"id": "delivery.core",
|
|
1313
|
+
"kind": "service",
|
|
1314
|
+
"context": "delivery"
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
"id": "bus",
|
|
1318
|
+
"kind": "broker",
|
|
1319
|
+
"context": null
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
"id": "payments.ledger",
|
|
1323
|
+
"kind": "service",
|
|
1324
|
+
"context": "payments"
|
|
1325
|
+
}
|
|
1326
|
+
],
|
|
1327
|
+
"steps": [
|
|
1328
|
+
{
|
|
1329
|
+
"type": "step",
|
|
1330
|
+
"id": "c1",
|
|
1331
|
+
"from": "agent",
|
|
1332
|
+
"to": "shop.oms",
|
|
1333
|
+
"kind": "rpc",
|
|
1334
|
+
"label": "RequestRefund",
|
|
1335
|
+
"status": "declared",
|
|
1336
|
+
"note": "The support console, not the storefront. The doc does not say what authorizes the agent or whether a partial amount is allowed.",
|
|
1337
|
+
"line": "refund-requested.md:24"
|
|
1338
|
+
},
|
|
1339
|
+
{
|
|
1340
|
+
"type": "step",
|
|
1341
|
+
"id": "c2",
|
|
1342
|
+
"from": "shop.oms",
|
|
1343
|
+
"to": "delivery.core",
|
|
1344
|
+
"kind": "rpc",
|
|
1345
|
+
"ref": "delivery.v1.Delivery/GetShipment",
|
|
1346
|
+
"label": "GetShipment",
|
|
1347
|
+
"status": "declared",
|
|
1348
|
+
"note": "The refund window runs from the delivery date on the shipment, not from the order date, so the shipment has to be read before anything is decided.",
|
|
1349
|
+
"line": "internal/oms/client/delivery.go:41"
|
|
1350
|
+
},
|
|
1351
|
+
{
|
|
1352
|
+
"type": "step",
|
|
1353
|
+
"id": "c3",
|
|
1354
|
+
"from": "shop.oms",
|
|
1355
|
+
"to": "shop.oms",
|
|
1356
|
+
"kind": "call",
|
|
1357
|
+
"label": "checkRefundWindow",
|
|
1358
|
+
"status": "declared",
|
|
1359
|
+
"note": "30 days after delivery. Orders never delivered have no window at all — the doc leaves that case open.",
|
|
1360
|
+
"line": "internal/oms/app/refund.go:52"
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
"type": "alt",
|
|
1364
|
+
"id": "alt-parcel",
|
|
1365
|
+
"branches": [
|
|
1366
|
+
{
|
|
1367
|
+
"title": "shipment already delivered",
|
|
1368
|
+
"steps": [
|
|
1369
|
+
{
|
|
1370
|
+
"type": "step",
|
|
1371
|
+
"id": "c4",
|
|
1372
|
+
"from": "shop.oms",
|
|
1373
|
+
"to": "shop.oms",
|
|
1374
|
+
"kind": "call",
|
|
1375
|
+
"label": "openReturnLabel",
|
|
1376
|
+
"status": "declared",
|
|
1377
|
+
"line": "internal/oms/app/refund.go:71"
|
|
1378
|
+
}
|
|
1379
|
+
]
|
|
1380
|
+
},
|
|
1381
|
+
{
|
|
1382
|
+
"title": "shipment still in transit",
|
|
1383
|
+
"steps": [
|
|
1384
|
+
{
|
|
1385
|
+
"type": "step",
|
|
1386
|
+
"id": "c5",
|
|
1387
|
+
"from": "shop.oms",
|
|
1388
|
+
"to": "bus",
|
|
1389
|
+
"kind": "event",
|
|
1390
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
1391
|
+
"label": "OrderCancelled",
|
|
1392
|
+
"status": "declared",
|
|
1393
|
+
"line": "refund-requested.md:58"
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
"type": "step",
|
|
1397
|
+
"id": "c6",
|
|
1398
|
+
"from": "bus",
|
|
1399
|
+
"to": "delivery.core",
|
|
1400
|
+
"kind": "event",
|
|
1401
|
+
"ref": "shop.oms.order.OrderCancelled",
|
|
1402
|
+
"label": "OrderCancelled",
|
|
1403
|
+
"status": "declared",
|
|
1404
|
+
"note": "Delivery is expected to recall the parcel here. The handler is described in the design doc, but no subscription for OrderCancelled was found in the delivery repository.",
|
|
1405
|
+
"line": "refund-requested.md:61"
|
|
1406
|
+
}
|
|
1407
|
+
]
|
|
1408
|
+
}
|
|
1409
|
+
]
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
"type": "step",
|
|
1413
|
+
"id": "c7",
|
|
1414
|
+
"from": "shop.oms",
|
|
1415
|
+
"to": "payments.ledger",
|
|
1416
|
+
"kind": "rpc",
|
|
1417
|
+
"ref": "payments.v1.Payments/Refund",
|
|
1418
|
+
"label": "Refund",
|
|
1419
|
+
"status": "declared",
|
|
1420
|
+
"note": "Both branches rejoin here. The doc does not say what the amount is when the parcel was recalled but the shipping was already billed.",
|
|
1421
|
+
"line": "internal/oms/client/payments.go:104"
|
|
1422
|
+
},
|
|
1423
|
+
{
|
|
1424
|
+
"type": "step",
|
|
1425
|
+
"id": "c8",
|
|
1426
|
+
"from": "payments.ledger",
|
|
1427
|
+
"to": "payments.ledger",
|
|
1428
|
+
"kind": "call",
|
|
1429
|
+
"label": "openRefund",
|
|
1430
|
+
"status": "declared",
|
|
1431
|
+
"line": "internal/ledger/app/refund.go:31"
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
"type": "loop",
|
|
1435
|
+
"id": "loop-settle",
|
|
1436
|
+
"title": "polled hourly until the gateway leaves `pending`, up to 7 days",
|
|
1437
|
+
"steps": [
|
|
1438
|
+
{
|
|
1439
|
+
"type": "step",
|
|
1440
|
+
"id": "c9",
|
|
1441
|
+
"from": "payments.ledger",
|
|
1442
|
+
"to": "payments.ledger",
|
|
1443
|
+
"kind": "call",
|
|
1444
|
+
"label": "pollGatewaySettlement",
|
|
1445
|
+
"status": "declared",
|
|
1446
|
+
"note": "The doc says the gateway confirms by webhook and that the poll is only the fallback. Neither path is covered by a test, and nothing says what happens on day 8.",
|
|
1447
|
+
"line": "internal/ledger/app/refund.go:64"
|
|
1448
|
+
}
|
|
1449
|
+
]
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
"type": "alt",
|
|
1453
|
+
"id": "alt-settlement",
|
|
1454
|
+
"branches": [
|
|
1455
|
+
{
|
|
1456
|
+
"title": "the gateway settles the refund",
|
|
1457
|
+
"steps": [
|
|
1458
|
+
{
|
|
1459
|
+
"type": "step",
|
|
1460
|
+
"id": "c10",
|
|
1461
|
+
"from": "payments.ledger",
|
|
1462
|
+
"to": "bus",
|
|
1463
|
+
"kind": "event",
|
|
1464
|
+
"ref": "payments.ledger.refund.RefundIssued",
|
|
1465
|
+
"label": "RefundIssued",
|
|
1466
|
+
"status": "declared",
|
|
1467
|
+
"line": "refund-requested.md:83"
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
"type": "parallel",
|
|
1471
|
+
"id": "par-refunded",
|
|
1472
|
+
"title": "RefundIssued fan-out",
|
|
1473
|
+
"branches": [
|
|
1474
|
+
[
|
|
1475
|
+
{
|
|
1476
|
+
"type": "step",
|
|
1477
|
+
"id": "c11",
|
|
1478
|
+
"from": "bus",
|
|
1479
|
+
"to": "shop.oms",
|
|
1480
|
+
"kind": "event",
|
|
1481
|
+
"ref": "payments.ledger.refund.RefundIssued",
|
|
1482
|
+
"label": "RefundIssued",
|
|
1483
|
+
"status": "declared",
|
|
1484
|
+
"note": "Moves the order to `refunded`.",
|
|
1485
|
+
"line": "refund-requested.md:88"
|
|
1486
|
+
}
|
|
1487
|
+
],
|
|
1488
|
+
[
|
|
1489
|
+
{
|
|
1490
|
+
"type": "step",
|
|
1491
|
+
"id": "c12",
|
|
1492
|
+
"from": "bus",
|
|
1493
|
+
"to": "delivery.core",
|
|
1494
|
+
"kind": "event",
|
|
1495
|
+
"ref": "payments.ledger.refund.RefundIssued",
|
|
1496
|
+
"label": "RefundIssued",
|
|
1497
|
+
"status": "declared",
|
|
1498
|
+
"note": "Closes the return leg. Same gap as the cancel handler above: declared in the doc, absent from the repository.",
|
|
1499
|
+
"line": "refund-requested.md:91"
|
|
1500
|
+
}
|
|
1501
|
+
]
|
|
1502
|
+
]
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
"type": "step",
|
|
1506
|
+
"id": "c13",
|
|
1507
|
+
"from": "shop.oms",
|
|
1508
|
+
"to": "agent",
|
|
1509
|
+
"kind": "rpc",
|
|
1510
|
+
"label": "refund receipt",
|
|
1511
|
+
"status": "declared",
|
|
1512
|
+
"line": "refund-requested.md:96"
|
|
1513
|
+
}
|
|
1514
|
+
]
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
"title": "the gateway refuses the refund",
|
|
1518
|
+
"steps": [
|
|
1519
|
+
{
|
|
1520
|
+
"type": "step",
|
|
1521
|
+
"id": "c14",
|
|
1522
|
+
"from": "payments.ledger",
|
|
1523
|
+
"to": "payments.ledger",
|
|
1524
|
+
"kind": "call",
|
|
1525
|
+
"label": "recordRejection",
|
|
1526
|
+
"status": "declared",
|
|
1527
|
+
"note": "The code and category are stored on the refund and nothing publishes them. Support finds out by looking, which the doc admits and does not fix.",
|
|
1528
|
+
"line": "refund-requested.md:101"
|
|
1529
|
+
}
|
|
1530
|
+
],
|
|
1531
|
+
"terminal": true
|
|
1532
|
+
}
|
|
1533
|
+
]
|
|
1534
|
+
}
|
|
1535
|
+
]
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
"id": "flow.shipment-tracking",
|
|
1539
|
+
"slug": "shipment-tracking",
|
|
1540
|
+
"name": "Shipment tracking",
|
|
1541
|
+
"summary": "Reconstructed from production traces over a 24 hour window: the tracking page, the carrier's scan webhook, and what each scan code sets off. Two things only the traces know about — a consumer no repository accounts for, and an exception path whose reader emits no spans at all.",
|
|
1542
|
+
"source": "data/flows/shipment-tracking.flow.md",
|
|
1543
|
+
"owner": "delivery",
|
|
1544
|
+
"participants": [
|
|
1545
|
+
{
|
|
1546
|
+
"id": "customer",
|
|
1547
|
+
"kind": "actor",
|
|
1548
|
+
"context": null
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
"id": "carrier-api",
|
|
1552
|
+
"kind": "external",
|
|
1553
|
+
"context": null,
|
|
1554
|
+
"label": "carrier-api (external)"
|
|
1555
|
+
},
|
|
1556
|
+
{
|
|
1557
|
+
"id": "delivery.core",
|
|
1558
|
+
"kind": "service",
|
|
1559
|
+
"context": "delivery"
|
|
1560
|
+
},
|
|
1561
|
+
{
|
|
1562
|
+
"id": "shop.oms",
|
|
1563
|
+
"kind": "service",
|
|
1564
|
+
"context": "shop"
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
"id": "bus",
|
|
1568
|
+
"kind": "broker",
|
|
1569
|
+
"context": null
|
|
1570
|
+
},
|
|
1571
|
+
{
|
|
1572
|
+
"id": "analytics-sink",
|
|
1573
|
+
"kind": "unknown",
|
|
1574
|
+
"context": null,
|
|
1575
|
+
"label": "analytics-sink (unknown)"
|
|
1576
|
+
}
|
|
1577
|
+
],
|
|
1578
|
+
"steps": [
|
|
1579
|
+
{
|
|
1580
|
+
"type": "step",
|
|
1581
|
+
"id": "d1",
|
|
1582
|
+
"from": "customer",
|
|
1583
|
+
"to": "delivery.core",
|
|
1584
|
+
"kind": "rpc",
|
|
1585
|
+
"label": "TrackShipment",
|
|
1586
|
+
"status": "verified",
|
|
1587
|
+
"note": "Storefront tracking page. 41k calls in the window, p95 180 ms.",
|
|
1588
|
+
"line": "trace 9f2c1a../span 04"
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
"type": "step",
|
|
1592
|
+
"id": "d2",
|
|
1593
|
+
"from": "delivery.core",
|
|
1594
|
+
"to": "shop.oms",
|
|
1595
|
+
"kind": "rpc",
|
|
1596
|
+
"ref": "shop.v1.Orders/GetOrder",
|
|
1597
|
+
"label": "GetOrder",
|
|
1598
|
+
"status": "verified",
|
|
1599
|
+
"note": "Resolves the order reference shown beside the parcel. Present in 96% of the traces; the rest are served from the tracking cache.",
|
|
1600
|
+
"line": "trace 9f2c1a../span 06"
|
|
1601
|
+
},
|
|
1602
|
+
{
|
|
1603
|
+
"type": "loop",
|
|
1604
|
+
"id": "loop-scan",
|
|
1605
|
+
"title": "one iteration per carrier scan; 4 scans per shipment at p50 over the window",
|
|
1606
|
+
"steps": [
|
|
1607
|
+
{
|
|
1608
|
+
"type": "step",
|
|
1609
|
+
"id": "d3",
|
|
1610
|
+
"from": "carrier-api",
|
|
1611
|
+
"to": "delivery.core",
|
|
1612
|
+
"kind": "rpc",
|
|
1613
|
+
"label": "POST /webhooks/carrier/scan",
|
|
1614
|
+
"status": "verified",
|
|
1615
|
+
"note": "Signed with the carrier's shared secret. 1.3% of scans in the window are retries after a 5xx, and the traces show the retry landing on the same shipment without a second state change.",
|
|
1616
|
+
"line": "trace 7be40d../span 01"
|
|
1617
|
+
},
|
|
1618
|
+
{
|
|
1619
|
+
"type": "step",
|
|
1620
|
+
"id": "d4",
|
|
1621
|
+
"from": "delivery.core",
|
|
1622
|
+
"to": "delivery.core",
|
|
1623
|
+
"kind": "call",
|
|
1624
|
+
"label": "RecordScan",
|
|
1625
|
+
"status": "verified",
|
|
1626
|
+
"line": "trace 7be40d../span 03"
|
|
1627
|
+
}
|
|
1628
|
+
]
|
|
1629
|
+
},
|
|
1630
|
+
{
|
|
1631
|
+
"type": "alt",
|
|
1632
|
+
"id": "alt-scan",
|
|
1633
|
+
"branches": [
|
|
1634
|
+
{
|
|
1635
|
+
"title": "scan code DELIVERED",
|
|
1636
|
+
"steps": [
|
|
1637
|
+
{
|
|
1638
|
+
"type": "step",
|
|
1639
|
+
"id": "d5",
|
|
1640
|
+
"from": "delivery.core",
|
|
1641
|
+
"to": "bus",
|
|
1642
|
+
"kind": "event",
|
|
1643
|
+
"ref": "delivery.core.shipment.ShipmentDelivered",
|
|
1644
|
+
"label": "ShipmentDelivered",
|
|
1645
|
+
"status": "verified",
|
|
1646
|
+
"line": "trace 7be40d../span 27"
|
|
1647
|
+
},
|
|
1648
|
+
{
|
|
1649
|
+
"type": "parallel",
|
|
1650
|
+
"id": "par-delivered",
|
|
1651
|
+
"title": "ShipmentDelivered fan-out",
|
|
1652
|
+
"branches": [
|
|
1653
|
+
[
|
|
1654
|
+
{
|
|
1655
|
+
"type": "step",
|
|
1656
|
+
"id": "d6",
|
|
1657
|
+
"from": "bus",
|
|
1658
|
+
"to": "shop.oms",
|
|
1659
|
+
"kind": "event",
|
|
1660
|
+
"ref": "delivery.core.shipment.ShipmentDelivered",
|
|
1661
|
+
"label": "ShipmentDelivered",
|
|
1662
|
+
"status": "verified",
|
|
1663
|
+
"note": "Closes the order and starts the 30-day refund window the refund flow reads.",
|
|
1664
|
+
"line": "trace 7be40d../span 29"
|
|
1665
|
+
}
|
|
1666
|
+
],
|
|
1667
|
+
[
|
|
1668
|
+
{
|
|
1669
|
+
"type": "step",
|
|
1670
|
+
"id": "d7",
|
|
1671
|
+
"from": "bus",
|
|
1672
|
+
"to": "analytics-sink",
|
|
1673
|
+
"kind": "event",
|
|
1674
|
+
"ref": "delivery.core.shipment.ShipmentDelivered",
|
|
1675
|
+
"label": "ShipmentDelivered",
|
|
1676
|
+
"status": "unresolved",
|
|
1677
|
+
"note": "Seen in traces only, under client id `analytics-sink-2`. No subscription registration exists in any indexed repository, so the owning team is unknown and nobody can be told before this topic changes shape.",
|
|
1678
|
+
"line": "trace 7be40d../span 31"
|
|
1679
|
+
}
|
|
1680
|
+
]
|
|
1681
|
+
]
|
|
1682
|
+
}
|
|
1683
|
+
]
|
|
1684
|
+
},
|
|
1685
|
+
{
|
|
1686
|
+
"title": "scan code EXCEPTION",
|
|
1687
|
+
"steps": [
|
|
1688
|
+
{
|
|
1689
|
+
"type": "step",
|
|
1690
|
+
"id": "d8",
|
|
1691
|
+
"from": "delivery.core",
|
|
1692
|
+
"to": "delivery.core",
|
|
1693
|
+
"kind": "call",
|
|
1694
|
+
"label": "openDeliveryException",
|
|
1695
|
+
"status": "verified",
|
|
1696
|
+
"note": "The trace ends here. Whatever reads the exception queue emits no spans, so the catalog cannot say what happens to the parcel next.",
|
|
1697
|
+
"line": "trace 4c81f3../span 09"
|
|
1698
|
+
}
|
|
1699
|
+
],
|
|
1700
|
+
"terminal": true
|
|
1701
|
+
},
|
|
1702
|
+
{
|
|
1703
|
+
"title": "scan code IN_TRANSIT",
|
|
1704
|
+
"steps": [
|
|
1705
|
+
{
|
|
1706
|
+
"type": "step",
|
|
1707
|
+
"id": "d9",
|
|
1708
|
+
"from": "delivery.core",
|
|
1709
|
+
"to": "delivery.core",
|
|
1710
|
+
"kind": "call",
|
|
1711
|
+
"label": "updateEta",
|
|
1712
|
+
"status": "verified",
|
|
1713
|
+
"note": "No event is published for an in-transit scan; the tracking page reads the shipment directly. 83% of the scans in the window end here.",
|
|
1714
|
+
"line": "trace 7be40d../span 12"
|
|
1715
|
+
}
|
|
1716
|
+
]
|
|
1717
|
+
}
|
|
1718
|
+
]
|
|
1719
|
+
}
|
|
1720
|
+
]
|
|
1721
|
+
}
|
|
1722
|
+
],
|
|
1723
|
+
"adrs": []
|
|
1724
|
+
}
|