{"id":27455589,"url":"https://github.com/nkonev/go-cqrs-example","last_synced_at":"2025-04-15T16:44:14.751Z","repository":{"id":286375606,"uuid":"961227001","full_name":"nkonev/go-cqrs-example","owner":"nkonev","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-13T17:18:21.000Z","size":77,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-13T17:25:39.172Z","etag":null,"topics":["cqrs","cqrs-architectural-pattern","cqrs-pattern","docker","docker-compose","go","golang","kafka","postgres","postgresql","watermill"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nkonev.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-04-06T03:24:18.000Z","updated_at":"2025-04-13T17:18:25.000Z","dependencies_parsed_at":"2025-04-06T04:26:18.582Z","dependency_job_id":"3e13b58d-56af-4266-a6b6-161ac24c582b","html_url":"https://github.com/nkonev/go-cqrs-example","commit_stats":null,"previous_names":["nkonev/go-cqrs-example"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkonev%2Fgo-cqrs-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkonev%2Fgo-cqrs-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkonev%2Fgo-cqrs-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkonev%2Fgo-cqrs-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nkonev","download_url":"https://codeload.github.com/nkonev/go-cqrs-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249110849,"owners_count":21214410,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cqrs","cqrs-architectural-pattern","cqrs-pattern","docker","docker-compose","go","golang","kafka","postgres","postgresql","watermill"],"created_at":"2025-04-15T16:44:14.307Z","updated_at":"2025-04-15T16:44:14.742Z","avatar_url":"https://github.com/nkonev.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Example Golang CQRS application\n\nThis application is using [Watermill CQRS](http://watermill.io/docs/cqrs) component.\n\nIt's an improved [6-cqrs-ordered-events](https://github.com/ThreeDotsLabs/watermill/tree/v1.4.6/_examples/basic/6-cqrs-ordered-events) example.\n\nEvents are stored in Kafka, projections are stored in PostgreSQL.\n\nWe can reset our projections and then restore their state from Kafka by resetting offsets.\n\nSee [It's Okay To Store Data In Kafka](https://www.confluent.io/blog/okay-store-data-apache-kafka/).\n\n# Start\n```bash\ndocker compose up -d\ngo run .\n```\n\n# Play with\n```bash\n# create a subscriber\ncurl -i -X POST --url 'http://localhost:8080/subscribe'\n\n# see subscribers\ncurl -Ss -X GET --url 'http://localhost:8080/subscribers' | jq\n\n# update the subscriber\ncurl -i -X PUT --url 'http://localhost:8080/update/216681f5-e73e-4461-926e-019445b9913b'\n\n# unsubscribe\ncurl -i -X POST --url 'http://localhost:8080/unsubscribe/216681f5-e73e-4461-926e-019445b9913b'\n\n# see activities\ncurl -Ss -X GET --url 'http://localhost:8080/activities' | jq\n\n# clear projections\ndocker compose exec -it postgresql psql -U postgres -c 'truncate subscriber; truncate activity_timeline;'\n\n# now there are zeroes\ncurl -Ss -X GET --url 'http://localhost:8080/subscribers' | jq\ncurl -Ss -X GET --url 'http://localhost:8080/activities' | jq\n\n# stop app\n\n# reset offsets for consumer groups\ndocker compose exec -it kafka /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server kafka:29092 --group SubscriberProjection --reset-offsets --to-earliest --execute --topic events\ndocker compose exec -it kafka /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server kafka:29092 --group ActivityTimelineProjection --reset-offsets --to-earliest --execute --topic events\n\n# start app again\ngo run .\n# and it will restore tables from the zeroth offset, see\ncurl -Ss -X GET --url 'http://localhost:8080/subscribers' | jq\ncurl -Ss -X GET --url 'http://localhost:8080/activities' | jq\n```\n\n# Tracing\nSee `Trace-Id` header and put its value into [Jaeger UI](http://localhost:16686)\n\n# Various commands\n```bash\n# see logs\ndocker compose logs -f kafka\ndocker compose logs -f postgresql\n\n# see projections\ndocker compose exec -it postgresql psql -U postgres\nselect * from subscriber order by created_timestamp;\nselect * from activity_timeline order by created_timestamp;\n\ndocker compose exec -it kafka bash\ndocker compose exec -it kafka /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server kafka:29092 --list\ndocker compose exec -it kafka /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server kafka:29092 --describe --group SubscriberProjection --offsets\ndocker compose exec -it kafka /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server kafka:29092 --describe --group ActivityTimelineProjection --offsets\n\n# see kafka topic\ndocker compose exec -it kafka /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server kafka:29092 --topic events --from-beginning --property print.key=true --property print.headers=true\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnkonev%2Fgo-cqrs-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnkonev%2Fgo-cqrs-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnkonev%2Fgo-cqrs-example/lists"}