{"id":22913603,"url":"https://github.com/fizmath/fizmath-plaza","last_synced_at":"2026-02-08T00:02:51.824Z","repository":{"id":267160313,"uuid":"900203240","full_name":"Fizmath/Fizmath-Plaza","owner":"Fizmath","description":"Next Gen Event-Driven  gRPC  e-commerce microservices with order-processing microservice. Created with Go, Nats Jetstream, Vue.js and PrimeVue","archived":false,"fork":false,"pushed_at":"2025-01-09T15:35:17.000Z","size":7169,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-07T06:42:57.223Z","etag":null,"topics":["axios","cqrs","echo-framework","event-driven-microservices","event-sourcing","go-microservice","golang","grpc-gateway","hexagonal-architecture","microservices","nats-streaming","pinia","prime-vue","tailwind-css","vue-router4","vuejs3"],"latest_commit_sha":null,"homepage":"","language":"CSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Fizmath.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2024-12-08T06:19:11.000Z","updated_at":"2025-01-17T09:54:10.000Z","dependencies_parsed_at":"2025-01-09T16:46:30.522Z","dependency_job_id":"940951eb-a089-4edc-bf49-fa614c0241d4","html_url":"https://github.com/Fizmath/Fizmath-Plaza","commit_stats":null,"previous_names":["fizmath/fizmath-plaza"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fizmath%2FFizmath-Plaza","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fizmath%2FFizmath-Plaza/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fizmath%2FFizmath-Plaza/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Fizmath%2FFizmath-Plaza/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Fizmath","download_url":"https://codeload.github.com/Fizmath/Fizmath-Plaza/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246635956,"owners_count":20809330,"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":["axios","cqrs","echo-framework","event-driven-microservices","event-sourcing","go-microservice","golang","grpc-gateway","hexagonal-architecture","microservices","nats-streaming","pinia","prime-vue","tailwind-css","vue-router4","vuejs3"],"created_at":"2024-12-14T05:10:13.218Z","updated_at":"2026-02-08T00:02:51.679Z","avatar_url":"https://github.com/Fizmath.png","language":"CSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# Fizmath Plaza\n\nTremendously simplified event-driven modular-monolith ( microservice ready ) e-commerce platform with order processing service. Created with the fantastic trio: Go, Nats JetStream  and  Vue.js  with rich CRUD operations and fun and luxury PrimeVue UI  with it's integrated Tailwind CSS features. \n\nBuilt in accordance with Hexagonal Architecture principles, this platform incorporates CQRS, gRPC-Gateway and  VUE.js compiled files  embedded via ECHO middleware, ... ensuring scalability, maintainability and high performance.\n\n## The Full Stack\n\n- Backend\n  - Go 1.23\n  - [NATS JetStream V2.10](https://docs.nats.io/)\n  - PostgreSQL\n  - [gRPC-Gateway](https://github.com/grpc-ecosystem/grpc-gateway)\n  - [Echo 4.12](https://echo.labstack.com/)\n\n- Frontend \n  - [Vue 3.4](https://vuejs.org/)\n  - [PrimeVue 4.0 ](https://primevue.org/)\n  - [Pinia 2.2](https://pinia.vuejs.org/)\n  - [Vue Router 4.4](https://router.vuejs.org/)\n  - [Axios 1.7](https://axios-http.com/)\n\n\n## \n\nLet the gRPC minds it's own API business, the asynchronous event-driven communications exclusively  implemented through NATS JetStream\n\n![general](docs/grpc-gateway.png)\n\nThe new  on-demand Pull Consumers in JetStream  substantially  simplifies any event-driven mechanism:  \"Since each subscription is fetching messages on-demand, multiple subscriptions can be create bound to the same pull consumer without any additional configuration. Each subscriber can fetch batches of messages and process them concurrently.\"\n\n\n## The single-click launcher   \n\nDonwload this repo to your local PC; RUN: \n\n```bash\n/Fizmath-Plaza-main$ docker compose -f docker-compose.yml up -d \n```\nafter the launching completed, see  docker compose logs to make sure that the database migrated  and ready to accept connections also observe  the satisfying JETSTREAM logo:\n\n```bash\n/Fizmath-Plaza-main$ docker compose logs -f\n```\nthen, open these endpoints :\n\n Service | URI\n --- | ---\nECHO-VUE proxy | [http://localhost:4173/](http://localhost:4173//)\nSwagger | [http://localhost:8080/](http://localhost:8080/)\n\nnow, you as both Plaza admin and customer, follow the slides below ... \n\n\n## Local Dev Mode \n\nThis is a development installation mode so that you can easily  modify  the code and the architecture both in frontend and backend stacks. For the sake of simplicity,  i did not include any make or bash file, nor did i bound any package to this repo.\n\nBefore launching the Dev Mode gracefully shut down the above prod mode :\n```bash\n/Fizmath-Plaza-main$ docker compose -f docker-compose.yml down\n```\n\n-  ## Backend \n\nFirst verify that GO is installed in your PC: \n\n```bash\n$ go version\ngo version go1.23.3 linux/amd64\n```\n\nthe project requires that the NATS server and the PostgreSQL database are both up and running. Nothing is more cleaner than  docker-compose to pull the images and to configure envs and volumes locally :\n\n```bash\n/Fizmath-Plaza-main$ docker compose -f docker-compose-Dev.yml up -d\n``` \n\nenter into  the docker compose logs:\n```bash\n/Fizmath-Plaza-main$ docker compose logs -f\n``` \n\nuncomment these two lines in our [main.go](cmd/main.go)\n\n```Go\n// os.Setenv(\"PG_CONN\", \"host=localhost dbname=fizmathplaza user=fizmathplaza_user password=fizmathplaza_pass  sslmode=disable \")\n// os.Setenv(\"NATS_URL\", \"http://localhost:4222\")\n```\n\n\n\u003e [!IMPORTANT]\n\u003e Compare our dev and prod docker composes. Analyze why those two lines should be un/commented.\n\n\nIn the `/cmd`  directory open another terminal;  RUN: \n\n```bash\n/Fizmath-Plaza-main/cmd$ go run . \n``` \n\ncheckout the Swagger endpoint :\n\n Service | URI\n --- | ---\n Swagger | [http://localhost:8080/](http://localhost:8080/)\n\n![swagger](docs/swagger.png)\n\nonce you see the above endpoint up and running it means that the backend service is ready.\nFor now do not mess with the Swagger, we have a nice frontend UI :\n\n- ## Frontend development server\n\nfor any modifications to the project, the frontend VUE source code  is available in the `ECHO/VUE` directory\n\nfirst make sure that Node.js and npm are installed in your laptop : \n\n```bash\n$ node -v\nv18.19.1\n\n$ npm -v\n9.2.0\n```\nwhile still  docker compose and the backend in `cmd`  are both up and running, open an another terminal int the `/ECHO/VUE` directory; RUN :\n\n```bash\n/Fizmath-Plaza-main/ECHO/VUE$ npm install\n``` \n\nthis installs the freezed packages from  [package.json](ECHO/VUE/package.json) \n\n\u003e [!WARNING]\n\u003e Javascript's dependencies are something out of  hell. Even packages that were frozen in place by `package.json`, which were installed without any issues just yesterday, are now causing dozens of error messages and \ndeprecation warnings when simply re-installed today - with no apparent explanation or solution.\n\na new heavy folder `node_modules` generated in the same directory; RUN :\n\n```bash\n/Fizmath-Plaza-main$/ECHO/VUE$ npm run dev\n``` \nopen this endpoint :\n\n Service | URI\n --- | ---\n VUE UI | [http://localhost:5173/](http://localhost:5173/)\n\nthis is a development server which auto-updates the browser when you save changes. Now you can make changes to the VUE's source code. For any pertinent backend changes you ought to re-compile the Go server in the `/cmd` directory.\n\nOnce your are happy with your new modifications, you can update the embedded `dist` folder by  `npm run build` for  your `ECHO` production server. Shut down the above server by `CTRL+C` then RUN : \n\n```bash\n/Fizmath-Plaza-main$/ECHO/VUE$ npm run build\n``` \n\n- ## Embedded frontend with ECHO middleware using reverse proxy\n\nfollowing re-freezing your `dist`  folder for production mode in this directory `ECHO/`  RUN :\n\n```bash\n/Fizmath-Plaza-main/ECHO$ go run .\n```\nthis launches the ECHO production server  :  [main.go](ECHO/main.go)\n\n\n Service | URI\n --- | ---\n ECHO reverse-proxy | [http://localhost:4173/](http://localhost:4173/)\n\n\n\n\u003e [!WARNING]\n\u003e  There might be a conflicting  issue  between  our `PostgreSQL` container and other dangling or running `PostgreSQL` containers in your\nPC, in this case shut down other running containers or remove dangling containers. \n\n\nIn the end, do not forget to remove the dev mode with grace, else you'll get ports already allocated errors for your next adventures :\n\n```bash\n/Fizmath-Plaza-main$ docker compose -f docker-compose-Dev.yml down\n``` \n\n- ## Additional installation hints for your dev environment\n\n- SWAGGER UI\n\nI downloaded the swagger UI from [here](https://github.com/swagger-api/swagger-ui). In our project we only need the `dist` folder of the bundle. The contents of `dist` pasted into `internal/web/swagger-ui` . Follow  `*services*/internal/rest`  folders  to learn how to  configure your own swagger endpoints.\n\n- BUF\n\nIf you modify  any of the   `.proto` files,  you ought to  re-compile buf files;  [buf.gen.yaml](ordering/buf.gen.yaml);  by running  `$ go generate` in the same directory. \nI installed  [BUF](https://github.com/bufbuild/buf) in Ubuntu by [Homebrew](https://brew.sh/)\n\n\n```bash\n$ buf --version\n1.47.2 \n``` \n\n- gRPC-Gateway\n\nin some dev cases in the same directory as `go.mod` you might also need these:\n\n```bash\n$ go get \\\n    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \\\n    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \\\n    google.golang.org/protobuf/cmd/protoc-gen-go \\\n    google.golang.org/grpc/cmd/protoc-gen-go-grpc\n```\n\nFinally, for added assurance: \n\n```bash\n$ export PATH=\"$PATH:$(go env GOPATH)/bin\"\n\n$ PATH=\"${PATH}:${HOME}/go/bin\" \n```\n\n\n## Screenshots and Discussions\n\nfrom the sidebar menu click  the Plaza Admin page then enter your inventory name and location  by clicking the `+new` dialog :\n\n![plaza](docs/a1.png)\n\nevery single entity in the project has it's own global `uuid` unique identifier. \n\n![plaza](docs/a2.png)\n\nAfter creating some stores, by toggling  participation, select stores that you want to participate in shopping. But first populate your\nstores with products by clicking the `Products` button which redirects to store's products page.\n\nClick the `+new`  dialog  to add your products. The SKU stand for Stock Keeping Unit, we need this\nto demo order's `OUT_OF_STOCK` event.\n\n![newdialog](docs/a3.png) \n\nAdd more products to your stores :\n\n![stores](docs/a4.png)\n\n\nby clicking `Shopping` in the sidebar menu  you see products of your stores which you toggled to participate.\nNow, as a customer add some products to your basket :\n\n![stores](docs/a5.png)\n\nclick the `Basket` button with a badge on it to review or delete your items then push `Checkout` in the menubar :\n\n![products](docs/a6.png)\n\nfirst enter any name and phone number then click to get your customer's ID, then just simply push the `Authorize` button to mock your payment.\nAfter getting your `Payment ID`  the `submit` button will be enabled, now you can submit your purchase :\n\n\n![shopping](docs/a7.png)\n\nafter pushing the submit button click the `Your Orders` tab then after a few seconds you see your initial order status `pending` :\n\n![order](docs/a8.png)\n\n\n## ORDER status events\n\nBy submitting your order  you just launched JetStream  publishers and consumers messaging. Now things gonna to be interesting. While in the `Your Orders` tab,  wait  a few seconds then refresh your order status by clicking the `Refresh` button : \n\n\n![orderaccept](docs/a9.png)\n\nonce your order `accepted`  the `Pay` button get enabled, so either push it to get `deliverd` status or click `cancel`  for whatever reason.\n\n -  Payment confirmation  event\n\nWithin  `5 seconds` your payment status will be double checked and confirmed  [here](payments/internal/application/application.go) is the backend code.\n\nFirstly, it double checks your payment ID, this is good for detecting frontend fraudulent activities. Since your authorized  payment amount was in the past time, you may have spent some money before submitting the current order.\nin our demo this is always verified as true.\n\nSecondly, if your order's total  amount is greater than your mocked authorized payment then your payment  get rejected. You can simply mock this rejection before submitting your order.\n\n - Stores Confirmation event\n\nAfter `15 seconds` you get store confirmation event. [here](stores/internal/application/commands/confirm_event.go) is the backend code.\n\n\nIf your order's  product  quantity is greater than SKU then you get `OUT_OF_STOCK` event. You can get this event  by deliberately entering the quantity greater than SKU. Note that this is just for demo: no frontend restrictions. \n\nThere is a more realistic way to get this rejection event: after submitting your order, immediately copy your Customer's ID before leaving the Customer's page ( since there is no KEEP ALIVE ) then jump to the `Plaza Admin` page and  find the store and one of our submitted products, there  push the edit button and in the SKU field enter `0` then save the dialog box.\nBack to the  the customer's page paste your id  then click `get your account` then go to the `Your Order` tab . if your have succeeded under `15` seconds refresh to see the  OUT_OF_STOCK` event.\n\n![orderreject](docs/a10.png)\n\nafter creating some orders, let's got to the `ORDER ADMIN` page in the menubar :\n\n\n##  Event Sourcing \n\nFinally, we arrive at the central purpose of this project.\n\n\nThe `refresh`  buttons retrieves final status of all orders  recorded by timelapse from  the database\n\n![orderadmin](docs/a11.png)\n\nThe order repository  has no `UPDATE` command. Every single row is an event sorted by timestamp. The [ordering database](PostgreSQL/3_create_ordering_schema.sh)  has a `SERIAL` auto-increment  pseudo-type as Primary Key, unlike other databases where Primary Keys set as `uuid`, therefore,  in conjunction with timestamptz and order's `uuid` identifier we have  impossible to duplicate and easy to manage `event versioning` mechanism. \n\nBy clicking on the `Event Sourcing` button, you'll receive all events for all orders. To single out a specific order just copy an order ID and paste it into the search box you'll see timeline of all events of a specific order. Use ` date created`  to sort by ascending or descending time :\n\n![orderevents](docs/a12.png)\n\n\n\nThis concludes our API's functionalities walkthrough.\n\n## Pinia and Vue Router \n\nJust like factoring out equations zyx(a+b+c) = xyza+zyxb+zxyc, Pinia allows you to 'factor out' some arrays and functions, so that independent Views or pages can share them as global variables. This  eliminates the need for a parent-child complex data transfer design. Here is our [Pinia stores](ECHO/VUE/src/stores/global.js) \n\nBesides VUE's features, those global `basket` and `sstores` arrays in our Pinia greatly eliminate backend complexities, just forget about the VUE frontend and try to \nfollow the above slides by the Swagger then you will appreciate that nice frontend stack. \n\nBesides Vue Router's main functionalities, sometimes you need  to convey small routing data. see  this [slide](docs/a4.png) \nwhere Pinia in conjunction with Vue Router's [:dynamic](ECHO/VUE/src/router/index.js) conveys some info, if you refresh the page the store's id stays the same but  name and location got lost ,so fix it ! \n\n\n\n## Befitting  NATS JetStream into Hexagonal Architecture\n\n![hexa](docs/hexagonal.png)\n\nInterface checkers:\n\n```Golang\nvar _ PubPort = (*IntegrationEventHandlers)(nil)\n```\nrepresent ports and adapters in a single page\n\nfor JetStream we have both publisher and consumer ports and adapters, consumed by domain and applications. \n\nConsumer adapters receive incoming messages  then \"DRIVE\" them into the application via ConfirmOrder and other Confirmation Ports this  is why i pinned them at the driver's side. \n\nActually, The Hexagonal Architecture provides a clear and concise 'blueprint' for building modular, scalable, and  adaptable software systems.\n\n\nInitiating your project with this Architecture or another approved CLEAN Architecture \nensures that you are at least adhering to a widely accepted framework, despite any potential \nfor **minor breaches**  to the architecture from your side, which is absolutely  natural.\n\n\n## Disclaimer\n\nIn developing this architectural proposal, I may have made some errors or oversights. In some general instances,  I may have glossed over important considerations or overlooked potential pitfalls.  Hence,  feel free to challenge every single line of this project. \n\n\nYou might remove CQRS in ordering and inventory services with impunity as in our payment service. This also gives you more _Pure_ domain. \n\n\nFor order creation scenarios, orchestrating a SAGA may not be strictly necessary. Firstly,  that global `basket` array in our Pinia is an ephemeral frontend cache.\nSecondly, what if a girlie just registered and confirmed the payment then changed  her mind and quitted the purchase not pushing the submit button?  since she may use her  ID after a month or so. For this case  you need to create a `Customers Admin`  page.\n \n[Here](ordering/internal/application/commands/create_order.go) is a simple ACID like SAGA where, first the order saved in the database then if any  error happens in publishing the message, the data removed from the database as if nothing happened.\n\nThat `15 seconds` stores confirmation event is more general than in a real-wold application : wouldn't it better to separate any single store as individual service with its own delivery confirmations time ? \n\nIn the  [Checkout page](ECHO/VUE/src/views/pages/Checkout.vue), the `getOrders()` method fires every time you load the page, it gets all orders from the backend then it filters out a Customer's orders. That is superfluous. **Exercise :** can you code to get orders just by Customer's ID from the backend ? \n\n\nThis demo may be small-scale, but the list of TODO or not TODO stretches on forever, suggesting that there's still a great deal of work to be done before this project reaches its \nfull potential...\n\nWhen it's go-live time for a mission-critical application in the cloud, with real users and revenue on the line, deployed  on Kubernetes clusters, with all the heck of load balancing and monitoring and tracing dogs dealing with millions of concurrent connections;  according to performance, scalability and maintainability issues you will have to modify and adapt the architecture to your business goals and business logic. Yet in this case you should design  enterprise-grade tests from the base of the pyramid mock up to the end to end testing. \n\nAnyway, I hope that this foundational demo contribution will be found helpful in understanding the key concepts.\n\n\n\n#  Additional  resources\n##  General\n\n- https://github.com/PacktPublishing/Event-Driven-Architecture-in-Golang\n- https://microservices.io/\n- https://www.oreilly.com/library/view/designing-event-driven-systems/9781492038252/\n- https://www.oreilly.com/library/view/building-microservices-2nd/9781492034018/\n- https://natsbyexample.com/\n- https://github.com/nats-io/nats.go/tree/main/jetstream\n- https://github.com/Sairyss/domain-driven-hexagon\n- https://github.com/GoogleCloudPlatform/microservices-demo\n- https://github.com/thangchung/go-coffeeshop\n\n\n##  VUE\n- https://vueschool.io/\n- https://www.packtpub.com/en-us/product/vuejs-3-design-patterns-and-best-practices-9781803249001\n- https://github.com/primefaces/sakai-vue\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffizmath%2Ffizmath-plaza","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffizmath%2Ffizmath-plaza","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffizmath%2Ffizmath-plaza/lists"}