Prototype of the shop app implementation used as a playground for integrating various distributed components.
The project is structured as a monorepo using npm workspaces. This structure primarily applies to node.js-based projects, although other projects (e.g., .NET projects) would follow a similar arrangement.
- Standalone applications reside in the
/apps
folder and do not rely on each other from a package reference standpoint. - Reusable packages across different apps are located in
/packages
. In node.js projects, they're referenced using workspace local references.- Each package in the
/packages
folder needs to be built before consuming the project as it relies on the existence of@package-name/dist
. - In a Docker environment, this is resolved by creating the base image
shop.app.packages
, already containing pre-built packages placed into the/app/packages
folder within the docker image (refer to exampleapps/shop.app.orders.api/Dockerfile
).
- Each package in the
- Each app can be launched from its respective
/apps
folder usingnpm run start
ornpm run start-dev
.- Apps may require specific environment variables for external dependencies, which would normally be set in
.env
file depending on the project. If dependencies are running in container, ensure they expose ports, as some services reside in a private network and don't expose ports to the host.
- Apps may require specific environment variables for external dependencies, which would normally be set in
- Additionally, apps can be started from the root folder (e.g.,
npm run start-web
startsshop.app.web
).- When running an app from the CLI, ensure to stop the corresponding container to avoid port conflicts.
- The root
.env
file contains most environment variables used by different docker services. - Running
docker-compose up --build -d
starts all containers, rebuilding them upfront. - Once started, the web app will be accessible at
http://localhost:3000
.- To allow access from other computers on the local network, change all instances of
localhost
in the.env
file to your local IP address (e.g.,192.168.0.1
) for proper CORS configuration for APIs.
- To allow access from other computers on the local network, change all instances of
- To test with ports not exposed for apps from app-private-network network run:
docker-compose -f docker-compose.yml -f docker-compose.no-ports.yml up --build -d
docker-compose down -v {service name}
: Takes down service volume, useful for re-running init scripts for the database.docker-compose up --build -d {service name}
: Starts/restarts a single container.docker-compose build --no-cache
: Rebuilds all containers without using cache.- Add
--progress plain
to view more command outputs.
- Add
docker-compose up --build
: Starts and rebuilds all containers.- Add
--remove-orphans
to remove orphan containers
- Add
To share common logic across different apps add new package under /packages
folder. This will be automatically recognized by npm workspace and will allow adding local references from package
to app
. Note, that package project should be built prior to dependant app. See more about npm workspace. Follow below steps when adding new package project
-
Add reference
package a
inapp a
:root> npm install ./packages/<package a> --workspace ./apps/<app a>
-
Update docker image for packages here -
packages/Dockerfile
and add build step for package -
Add link to
shop.app.packages
image to dependant container so that build order is correct andshop.app.packages
image is built before any container that uses itcontainer_app_a: links: - shop.app.packages
-
Update github workflow config -
.github/workflows/nodejs.yml
and add build step for new package
-
shop.app.web: Main front-end application built using React, Redux, CRA, etc.
-
shop.app.auth.api: Authentication provider API built on top of the open-source authentication framework Supertokens.io.
-
shop.app.catalog.api: REST API services providing access to the shop catalog (product categories, products, etc.), built using .NET minimal API. This API does not require authentication.
-
shop.app.orders.api: REST API & GraphQL services for order submission and retrieval. Built based on node.js using Express app.
Endpoints consumed by
shop.app.web
frontend necessitate user authentication via bearer tokens issued byshop.app.auth.api
during the login process.Some endpoints are exclusively available for backend-to-backend communication, such as changing order status from order processing workloads. A special technical API user is configured with the required
role
to access these APIs. -
shop.app.orders.processing: Node.js-based app simulating the order processing flow by updating its status over time (new order processing, payment processing, dispatching).
At each step, the order is placed in a message queue and picked by the order processing instance. Consequently, the order status changes over time and can be refreshed on the UI.
shop.app.catalog.db
: Database used byshop.app.catalog.api
app, storing all shop products. It utilizes the latest version of MySQL and includes an initialization script that automatically populates the catalog upon the first container startup.shop.app.auth.db
: Database used byshop.app.auth.core
app to store user details, based on the latest image of PostgreSQL.shop.app.auth.core
: Authentication core using the Supertokens image for PostgreSQL.shop.app.cache
: Key-Value caching service based on Redis.io.shop.app.messagebroker
: Message broker service providing AMQP messaging protocol powered by RabbitMQ, orchestrating order processing across different workloads.shop.app.orders.db
: NoSQL database managing orders placed by users via theshop.app.orders.api
REST API. Utilizes MongoDB.
- When running docker compose build on Windows machine some .sh file may fail to execute due to different line end feeding characters on Linux and Windows based systems. To quickly fix issue, in VS Code switch to CRLF EOL sequence see https://essenceofcode.com/2019/11/20/linux-style-line-feeds-in-docker-desktop-on-windows/ for some additional information
- Apply this to
apps/shop.app.web/scripts/update-env.sh
- Apply this to
- To get logs from container's health check use
docker inspect --format "{{json .State.Health}}" <container name> | jq
- or
docker inspect --format "{{json .State.Health }}" <container name> | jq '.Log[].Output'
- In case you are working behind the proxy that amends ssl certificates chain breaking ssl validation for some tools, follow below workarounds:
- For node based issues execute following command:
export NODE_TLS_REJECT_UNAUTHORIZED=0
- For .net on Linux:
-
Export certificates you see in a chain (e.g. in browser) to local folder
-
Copy files to certs store and install them, see example in
apps/shop.app.catalog.api/Dockerfile
:cp *.cer /usr/local/share/ca-certificates/. cp *.cer /etc/ssl/certs/. apt-get install ca-certificates
-
- For node based issues execute following command: