[
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n\n# misc\n.DS_Store\n\n/logs"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guidelines you need to follow.\n\n## Contributor License Agreement\n\nContributions to this project must be accompanied by a Contributor License\nAgreement. You (or your employer) retain the copyright to your contribution;\nthis simply gives us permission to use and redistribute your contributions as\npart of the project. Head over to <https://cla.developers.google.com/> to see\nyour current agreements on file or to sign a new one.\n\nYou generally only need to submit a CLA once, so if you've already submitted one\n(even if it was for a different project), you probably don't need to do it\nagain.\n\n## Code reviews\n\nAll submissions, including submissions by project members, require review. We\nuse GitHub pull requests for this purpose. Consult\n[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more\ninformation on using pull requests.\n\n## Community Guidelines\n\nThis project follows [Google's Open Source Community\nGuidelines](https://opensource.google.com/conduct/)."
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# Monolith to Microservices\n\n## NOTE: This is not an officially supported Google product\n\n## Introduction\n\n### This project is used by the Google Cloud Platform team to demonstrate different services within Google Cloud. This project contains two versions of the same application, one architected as a monolith and the other as a set of microservices\n\n## Setup\n\n### **NOTE:** Make sure you have a newer version of NodeJS (16.13.0) or newer (in Cloud Shell you can run `nvm install --lts`)\n\n```bash\ngit clone https://github.com/googlecodelabs/monolith-to-microservices\ncd monolith-to-microservices\n./setup.sh\n```\n\n## Monolith\n\n### To run the monolith project use the following commands from the top level directory\n\n```bash\ncd monolith\nnpm start\n```\n\nYou should see output similar to the following\n\n```text\nMonolith listening on port 8080!\n```\n\n#### That's it! You now have a perfectly functioning monolith running on your machine\n\n### Docker - Monolith\n\n#### To create a Docker image for the monolith, execute the following commands\n\n```bash\ncd monolith\ndocker build -t monolith:1.0.0 .\n```\n\nTo run the Docker image, execute the following commands\n\n```bash\ndocker run --rm -p 8080:8080 monolith:1.0.0\n```\n\n## Microservices\n\n### To run the microservices project use the following commands from the top level directory\n\n```bash\ncd microservices\nnpm start\n```\n\nYou should see output similar to the following\n\n```text\n[0] Frontend microservice listening on port 8080!\n[2] Orders microservice listening on port 8081!\n[1] Products microservice listening on port 8082!\n```\n\n### That's it! You now have a perfectly functioning set of microservices running on your machine\n\n### Docker - Microservices\n\n### To create a Docker image for the microservices, you will have to create a Docker image for each service. Execute the following commands for each folder under the microservices folder\n\n```bash\ncd microservices/src/frontend\ndocker build -t frontend:1.0.0 .\n\ncd ../products\ndocker build -t products:1.0.0 .\n\ncd ../orders\ndocker build -t orders:1.0.0 .\n```\n\nTo run the Docker image, execute the following commands\n\n```bash\ndocker run -d --rm -p 8080:8080 monolith:1.0.0\ndocker run -d --rm -p 8081:8081 orders:1.0.0\ndocker run -d --rm -p 8082:8082 products:1.0.0\n```\n\n#### To stop the containers, you will need to find the CONTAINER ID for each and stop them individually. See the steps below\n\n```bash\ndocker ps -a\n\nCONTAINER ID        IMAGE                        COMMAND                CREATED\n4c01db0b339c        frontend:1.0.0               bash                   17 seconds ago\nd7886598dbe2        orders:1.0.0                 bash                   17 seconds ago\nd85756f57265        products:1.0.0               bash                   17 seconds ago\n\ndocker stop 4c01db0b339c\ndocker stop d7886598dbe2\ndocker stop d85756f57265\n```\n\n## React App\n\n### The react-app folder contains a React application created from `create-react-app`. You can modify this fronted, but afterwards, you will need to build and move the static files to the monolith and microservices project. You can do this by running the standard create-react-app build command below\n\n```bash\nnpm run build\n```\n\n#### This will run the build script to create the static files two times. The first will build with relative URLs and copy the static files to the monolith/public folder. The second run will build with the standard microservices URLs and copy the static files to the microservices/src/frontend/public folder\n"
  },
  {
    "path": "deploy-monolith.sh",
    "content": "#!/bin/bash\n\n# Copyright 2019 Google LLC\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     https://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nprintf \"Enabling Cloud Build APIs...\\n\"\ngcloud services enable cloudbuild.googleapis.com\nprintf \"Completed.\\n\\n\"\n\nprintf \"Building Monolith Container...\\n\"\ncd ~/monolith-to-microservices/monolith\ngcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 .\nprintf \"Completed.\\n\\n\"\n\nprintf \"Deploying Monolith To GKE Cluster...\\n\"\nkubectl create deployment monolith --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0\nkubectl expose deployment monolith --type=LoadBalancer --port 80 --target-port 8080\nprintf \"Completed.\\n\\n\"\n\nprintf \"Please run the following command to find the IP address for the monolith service: kubectl get service monolith\\n\\n\"\n\nprintf \"Deployment completed successfully!\\n\"\n"
  },
  {
    "path": "microservices/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n\n\n# misc\n.DS_Store"
  },
  {
    "path": "microservices/package.json",
    "content": "{\n  \"name\": \"microservices\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"start\": \"concurrently \\\"npm run frontend\\\" \\\"npm run products\\\" \\\"npm run orders\\\"\",\n    \"frontend\": \"node ./src/frontend/server.js\",\n    \"products\": \"node ./src/products/server.js\",\n    \"orders\": \"node ./src/orders/server.js\",\n    \"install-all\": \"npm-recursive-install\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"Apache-2.0\",\n  \"devDependencies\": {\n    \"concurrently\": \"^7.6.0\"\n  },\n  \"dependencies\": {\n    \"cors\": \"^2.8.5\",\n    \"express\": \"^4.18.2\"\n  }\n}\n"
  },
  {
    "path": "microservices/src/frontend/.dockerignore",
    "content": "node_modules\nnpm-debug.log\n"
  },
  {
    "path": "microservices/src/frontend/.gcloudignore",
    "content": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n.git\n.gitignore\nnode_modules/\n"
  },
  {
    "path": "microservices/src/frontend/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/public\n\n# misc\n.DS_Store"
  },
  {
    "path": "microservices/src/frontend/Dockerfile",
    "content": "# Copyright 2019 Google LLC\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     https://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 8080\nCMD [ \"node\", \"server.js\" ]"
  },
  {
    "path": "microservices/src/frontend/k8s/deployment.yml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: frontend\n  labels:\n    app: frontend\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: frontend\n  template:\n    metadata:\n      labels:\n        app: frontend\n    spec:\n      containers:\n      - name: frontend\n        image: gcr.io/<PROJECT_ID>/frontend:1.0.0\n        imagePullPolicy: Always\n        ports:\n        - containerPort: 8080"
  },
  {
    "path": "microservices/src/frontend/k8s/service.yml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: frontend\nspec:\n  type: LoadBalancer\n  ports:\n  - port: 80\n    targetPort: 8080\n    protocol: TCP\n  selector:\n    app: frontend"
  },
  {
    "path": "microservices/src/frontend/package.json",
    "content": "{\n  \"name\": \"frontend\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"server.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"start\": \"node server.js\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"express\": \"^4.17.2\"\n  }\n}\n"
  },
  {
    "path": "microservices/src/frontend/server.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nconst express = require(\"express\");\nconst path = require(\"path\");\nconst app = express();\nconst port = process.env.PORT || 8080;\n\n//Serve website\napp.use(express.static(path.join(__dirname, \"public\")));\n\n//Client side routing fix on page refresh or direct browsing to non-root directory\napp.get(\"/*\", (req, res) => {\n  res.sendFile(path.join(__dirname, \"public\", \"index.html\"), err => {\n    if (err) {\n      res.status(500).send(err);\n    }\n  });\n});\n\n//Start the server\napp.listen(port, () => console.log(`Frontend microservice listening on port ${port}!`));\n"
  },
  {
    "path": "microservices/src/orders/.dockerignore",
    "content": "node_modules\nnpm-debug.log\n"
  },
  {
    "path": "microservices/src/orders/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n\n# misc\n.DS_Store"
  },
  {
    "path": "microservices/src/orders/Dockerfile",
    "content": "# Copyright 2019 Google LLC\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     https://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 8081\nCMD [ \"node\", \"server.js\" ]"
  },
  {
    "path": "microservices/src/orders/data/orders.json",
    "content": "{\n  \"orders\": [\n    {\n      \"id\": \"ORD-000001-MICROSERVICE\",\n      \"date\": \"7/01/2019\",\n      \"cost\": 67.99,\n      \"items\": [\"OLJCESPC7Z\"]\n    },\n    {\n      \"id\": \"ORD-000002-MICROSERVICE\",\n      \"date\": \"7/24/2019\",\n      \"cost\": 124,\n      \"items\": [\"1YMWWN1N4O\"]\n    },\n    {\n      \"id\": \"ORD-000003-MICROSERVICE\",\n      \"date\": \"8/03/2019\",\n      \"cost\": 12.49,\n      \"items\": [\"66VCHSJNUP\"]\n    },\n    {\n      \"id\": \"ORD-000004-MICROSERVICE\",\n      \"date\": \"8/14/2019\",\n      \"cost\": 89.83,\n      \"items\": [\"0PUK6V6EV0\", \"LS4PSXUNUM\"]\n    },\n    {\n      \"id\": \"ORD-000005-MICROSERVICE\",\n      \"date\": \"8/29/2019\",\n      \"cost\": 12.30,\n      \"items\": [\"6E92ZMYYFZ\"]\n    }\n  ]\n}\n"
  },
  {
    "path": "microservices/src/orders/k8s/deployment.yml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: orders\n  labels:\n    app: orders\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: orders\n  template:\n    metadata:\n      labels:\n        app: orders\n    spec:\n      containers:\n      - name: orders\n        image: gcr.io/<PROJECT_ID>/orders:1.0.0\n        imagePullPolicy: Always\n        ports:\n        - containerPort: 8080"
  },
  {
    "path": "microservices/src/orders/k8s/service.yml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: orders\nspec:\n  type: LoadBalancer\n  ports:\n  - port: 80\n    targetPort: 8080\n    protocol: TCP\n  selector:\n    app: orders"
  },
  {
    "path": "microservices/src/orders/package.json",
    "content": "{\n  \"name\": \"orders\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"server.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"start\": \"node server.js\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"cors\": \"^2.8.5\",\n    \"express\": \"^4.17.2\"\n  }\n}\n"
  },
  {
    "path": "microservices/src/orders/server.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nconst express = require(\"express\");\nconst cors = require(\"cors\");\nconst app = express();\nconst port = process.env.PORT || 8081;\n\n//Load orders for pseudo database\nconst orders = require(\"./data/orders.json\").orders;\n\n//Enable cors\napp.use(cors());\n\n//Get all orders\napp.get(\"/api/orders\", (req, res) => res.json(orders));\n\n//Get orders by ID\napp.get(\"/api/orders/:id\", (req, res) =>\n  res.json(orders.find(order => order.id === req.params.id))\n);\n\napp.listen(port, () =>\n  console.log(`Orders microservice listening on port ${port}!`)\n);\n"
  },
  {
    "path": "microservices/src/products/.dockerignore",
    "content": "node_modules\nnpm-debug.log\n"
  },
  {
    "path": "microservices/src/products/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n\n# misc\n.DS_Store"
  },
  {
    "path": "microservices/src/products/Dockerfile",
    "content": "# Copyright 2019 Google LLC\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     https://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 8082\nCMD [ \"node\", \"server.js\" ]"
  },
  {
    "path": "microservices/src/products/data/products.json",
    "content": "{\n    \"products\": [\n        {\n            \"id\": \"OLJCESPC7Z\",\n            \"name\": \"MS -  Vintage Typewriter\",\n            \"description\": \"This typewriter looks good in your living room.\",\n            \"picture\": \"static/img/products/typewriter.jpg\",\n            \"cost\": 67.99,\n            \"categories\": [\"vintage\"]\n        },\n        {\n            \"id\": \"66VCHSJNUP\",\n            \"name\": \"MS -  Vintage Camera Lens\",\n            \"description\": \"You won't have a camera to use it and it probably doesn't work anyway.\",\n            \"picture\": \"static/img/products/camera-lens.jpg\",\n            \"cost\": 12.49,\n            \"categories\": [\"photography\", \"vintage\"]\n        },\n        {\n            \"id\": \"1YMWWN1N4O\",\n            \"name\": \"MS -  Home Barista Kit\",\n            \"description\": \"Always wanted to brew coffee with Chemex and Aeropress at home?\",\n            \"picture\": \"static/img/products/barista-kit.jpg\",\n            \"cost\": 124,\n            \"categories\": [\"cookware\"]\n        },\n        {\n            \"id\": \"L9ECAV7KIM\",\n            \"name\": \"MS -  Terrarium\",\n            \"description\": \"This terrarium will looks great in your white painted living room.\",\n            \"picture\": \"static/img/products/terrarium.jpg\",\n            \"cost\": 36.45,\n            \"categories\": [\"gardening\"]\n        },\n        {\n            \"id\": \"2ZYFJ3GM2N\",\n            \"name\": \"MS -  Film Camera\",\n            \"description\": \"This camera looks like it's a film camera, but it's actually digital.\",\n            \"picture\": \"static/img/products/film-camera.jpg\",\n            \"cost\": 2245,\n            \"categories\": [\"photography\", \"vintage\"]\n        },\n        {\n            \"id\": \"0PUK6V6EV0\",\n            \"name\": \"MS -  Vintage Record Player\",\n            \"description\": \"It still works.\",\n            \"picture\": \"static/img/products/record-player.jpg\",\n            \"cost\": 65.50,\n            \"categories\": [\"music\", \"vintage\"]\n        },\n        {\n            \"id\": \"LS4PSXUNUM\",\n            \"description\": \"You probably don't go camping that often but this is better than plastic cups.\",\n            \"name\": \"MS -  Metal Camping Mug\",\n            \"picture\": \"static/img/products/camp-mug.jpg\",\n            \"cost\": 24.33,\n            \"categories\": [\"cookware\"]\n        },\n        {\n            \"id\": \"9SIQT8TOJO\",\n            \"name\": \"MS -  City Bike\",\n            \"description\": \"This single gear bike probably cannot climb the hills of San Francisco.\",\n            \"picture\": \"static/img/products/city-bike.jpg\",\n            \"cost\": 789.50,\n            \"categories\": [\"cycling\"]\n        },\n        {\n            \"id\": \"6E92ZMYYFZ\",\n            \"name\": \"MS -  Air Plant\",\n            \"description\": \"Have you ever wondered whether air plants need water? Buy one and figure out.\",\n            \"picture\": \"static/img/products/air-plant.jpg\",\n            \"cost\": 12.30,\n            \"categories\": [\"gardening\"]\n        }\n    ]\n}"
  },
  {
    "path": "microservices/src/products/k8s/deployment.yml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: products\n  labels:\n    app: products\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: products\n  template:\n    metadata:\n      labels:\n        app: products\n    spec:\n      containers:\n      - name: products\n        image: gcr.io/<PROJECT_ID>/products:1.0.0\n        imagePullPolicy: Always\n        ports:\n        - containerPort: 8080"
  },
  {
    "path": "microservices/src/products/k8s/service.yml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: products\nspec:\n  type: LoadBalancer\n  ports:\n  - port: 80\n    targetPort: 8080\n    protocol: TCP\n  selector:\n    app: products"
  },
  {
    "path": "microservices/src/products/package.json",
    "content": "{\n  \"name\": \"products\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"server.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"start\": \"node server.js\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"cors\": \"^2.8.5\",\n    \"express\": \"^4.17.2\"\n  }\n}\n"
  },
  {
    "path": "microservices/src/products/server.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nconst express = require(\"express\");\nconst cors = require(\"cors\");\nconst app = express();\nconst port = process.env.PORT || 8082;\n\n//Load product for pseudo database\nconst products = require(\"./data/products.json\").products;\n\n//Enable cors\napp.use(cors());\n\n//Get all products\napp.get(\"/api/products\", (req, res) => res.json(products));\n\n//Get products by ID\napp.get(\"/api/products/:id\", (req, res) =>\n  res.json(products.find(product => product.id === req.params.id))\n);\n\napp.listen(port, () =>\n  console.log(`Products microservice listening on port ${port}!`)\n);\n"
  },
  {
    "path": "monolith/.dockerignore",
    "content": "node_modules\nnpm-debug.log\n"
  },
  {
    "path": "monolith/.gcloudignore",
    "content": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n.git\n.gitignore\nnode_modules/\n"
  },
  {
    "path": "monolith/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/public\n\n# misc\n.DS_Store"
  },
  {
    "path": "monolith/Dockerfile",
    "content": "# Copyright 2019 Google LLC\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     https://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM node:16\n\n# Create app directory\nWORKDIR /usr/src/app\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json ./\n\nRUN npm install\n# If you are building your code for production\n# RUN npm ci --only=production\n\n# Bundle app source\nCOPY . .\n\nEXPOSE 8080\nCMD [ \"node\", \"src/server.js\" ]"
  },
  {
    "path": "monolith/data/orders.json",
    "content": "{\n  \"orders\": [\n    {\n      \"id\": \"ORD-000001\",\n      \"date\": \"7/01/2019\",\n      \"cost\": 67.99,\n      \"items\": [\"OLJCESPC7Z\"]\n    },\n    {\n      \"id\": \"ORD-000002\",\n      \"date\": \"7/24/2019\",\n      \"cost\": 124,\n      \"items\": [\"1YMWWN1N4O\"]\n    },\n    {\n      \"id\": \"ORD-000003\",\n      \"date\": \"8/03/2019\",\n      \"cost\": 12.49,\n      \"items\": [\"66VCHSJNUP\"]\n    },\n    {\n      \"id\": \"ORD-000004\",\n      \"date\": \"8/14/2019\",\n      \"cost\": 89.83,\n      \"items\": [\"0PUK6V6EV0\", \"LS4PSXUNUM\"]\n    },\n    {\n      \"id\": \"ORD-000005\",\n      \"date\": \"8/29/2019\",\n      \"cost\": 12.30,\n      \"items\": [\"6E92ZMYYFZ\"]\n    }\n  ]\n}\n"
  },
  {
    "path": "monolith/data/products.json",
    "content": "{\n    \"products\": [\n        {\n            \"id\": \"OLJCESPC7Z\",\n            \"name\": \"Vintage Typewriter\",\n            \"description\": \"This typewriter looks good in your living room.\",\n            \"picture\": \"static/img/products/typewriter.jpg\",\n            \"cost\": 67.99,\n            \"categories\": [\"vintage\"]\n        },\n        {\n            \"id\": \"66VCHSJNUP\",\n            \"name\": \"Vintage Camera Lens\",\n            \"description\": \"You won't have a camera to use it and it probably doesn't work anyway.\",\n            \"picture\": \"static/img/products/camera-lens.jpg\",\n            \"cost\": 12.49,\n            \"categories\": [\"photography\", \"vintage\"]\n        },\n        {\n            \"id\": \"1YMWWN1N4O\",\n            \"name\": \"Home Barista Kit\",\n            \"description\": \"Always wanted to brew coffee with Chemex and Aeropress at home?\",\n            \"picture\": \"static/img/products/barista-kit.jpg\",\n            \"cost\": 124,\n            \"categories\": [\"cookware\"]\n        },\n        {\n            \"id\": \"L9ECAV7KIM\",\n            \"name\": \"Terrarium\",\n            \"description\": \"This terrarium will looks great in your white painted living room.\",\n            \"picture\": \"static/img/products/terrarium.jpg\",\n            \"cost\": 36.45,\n            \"categories\": [\"gardening\"]\n        },\n        {\n            \"id\": \"2ZYFJ3GM2N\",\n            \"name\": \"Film Camera\",\n            \"description\": \"This camera looks like it's a film camera, but it's actually digital.\",\n            \"picture\": \"static/img/products/film-camera.jpg\",\n            \"cost\": 2245,\n            \"categories\": [\"photography\", \"vintage\"]\n        },\n        {\n            \"id\": \"0PUK6V6EV0\",\n            \"name\": \"Vintage Record Player\",\n            \"description\": \"It still works.\",\n            \"picture\": \"static/img/products/record-player.jpg\",\n            \"cost\": 65.50,\n            \"categories\": [\"music\", \"vintage\"]\n        },\n        {\n            \"id\": \"LS4PSXUNUM\",\n            \"name\": \"Metal Camping Mug\",\n            \"description\": \"You probably don't go camping that often but this is better than plastic cups.\",\n            \"picture\": \"static/img/products/camp-mug.jpg\",\n            \"cost\": 24.33,\n            \"categories\": [\"cookware\"]\n        },\n        {\n            \"id\": \"9SIQT8TOJO\",\n            \"name\": \"City Bike\",\n            \"description\": \"This single gear bike probably cannot climb the hills of San Francisco.\",\n            \"picture\": \"static/img/products/city-bike.jpg\",\n            \"cost\": 789.50,\n            \"categories\": [\"cycling\"]\n        },\n        {\n            \"id\": \"6E92ZMYYFZ\",\n            \"name\": \"Air Plant\",\n            \"description\": \"Have you ever wondered whether air plants need water? Buy one and figure out.\",\n            \"picture\": \"static/img/products/air-plant.jpg\",\n            \"cost\": 12.30,\n            \"categories\": [\"gardening\"]\n        }\n    ]\n}"
  },
  {
    "path": "monolith/k8s/deployment.yml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: monolith\n  labels:\n    app: monolith\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: monolith\n  template:\n    metadata:\n      labels:\n        app: monolith\n    spec:\n      containers:\n      - name: monolith\n        image: gcr.io/<PROJECT_ID>/monolith:1.0.0\n        imagePullPolicy: Always\n        ports:\n        - containerPort: 8080"
  },
  {
    "path": "monolith/k8s/service.yml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: monolith\nspec:\n  type: LoadBalancer\n  ports:\n  - port: 80\n    targetPort: 8080\n    protocol: TCP\n  selector:\n    app: monolith\n"
  },
  {
    "path": "monolith/package.json",
    "content": "{\n  \"name\": \"monolith\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"start\": \"node ./src/server.js\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"body-parser\": \"^1.20.2\",\n    \"express\": \"^4.18.2\"\n  }\n}\n"
  },
  {
    "path": "monolith/src/server.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nconst express = require(\"express\");\nconst path = require(\"path\");\nconst app = express();\nconst port = process.env.PORT || 8080;\n\n//Load orders and products for pseudo database\nconst orders = require(\"../data/orders.json\").orders;\nconst products = require(\"../data/products.json\").products;\n\n//Serve website\napp.use(express.static(path.join(__dirname, \"..\", \"public\")));\n\n//Get all products\napp.get(\"/service/products\", (req, res) => res.json(products));\n\n//Get products by ID\napp.get(\"/service/products/:id\", (req, res) =>\n  res.json(products.find((product) => product.id === req.params.id))\n);\n\n//Get all orders\napp.get(\"/service/orders\", (req, res) => res.json(orders));\n\n//Get orders by ID\napp.get(\"/service/orders/:id\", (req, res) =>\n  res.json(orders.find((order) => order.id === req.params.id))\n);\n\n//Client side routing fix on page refresh or direct browsing to non-root directory\napp.get(\"/*\", (req, res) => {\n  res.sendFile(path.join(__dirname, \"..\", \"public\", \"index.html\"), (err) => {\n    if (err) {\n      res.status(500).send(err);\n    }\n  });\n});\n\n//Start the server\napp.listen(port, () => console.log(`Monolith listening on port ${port}!`));\n"
  },
  {
    "path": "react-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "react-app/README.md",
    "content": "This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).\n\n## Available Scripts\n\nIn the project directory, you can run:\n\n### `npm start`\n\nRuns the app in the development mode.<br>\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nThe page will reload if you make edits.<br>\nYou will also see any lint errors in the console.\n\n### `npm test`\n\nLaunches the test runner in the interactive watch mode.<br>\nSee the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.<br>\nIt correctly bundles React in production mode and optimizes the build for the best performance.\n\nThe build is minified and the filenames include the hashes.<br>\nYour app is ready to be deployed!\n\nSee the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.\n\n### `npm run eject`\n\n**Note: this is a one-way operation. Once you `eject`, you can’t go back!**\n\nIf you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.\n\nInstead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.\n\nYou don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.\n\n## Learn More\n\nYou can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).\n\nTo learn React, check out the [React documentation](https://reactjs.org/).\n\n### Code Splitting\n\nThis section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting\n\n### Analyzing the Bundle Size\n\nThis section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size\n\n### Making a Progressive Web App\n\nThis section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app\n\n### Advanced Configuration\n\nThis section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration\n\n### Deployment\n\nThis section has moved here: https://facebook.github.io/create-react-app/docs/deployment\n\n### `npm run build` fails to minify\n\nThis section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify\n"
  },
  {
    "path": "react-app/package.json",
    "content": "{\n  \"name\": \"frontend\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@emotion/react\": \"^11.7.1\",\n    \"@emotion/styled\": \"^11.6.0\",\n    \"@mui/material\": \"^5.3.1\",\n    \"@mui/styles\": \"^5.3.0\",\n    \"env-cmd\": \"^10.1.0\",\n    \"express\": \"^4.21.0\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router-dom\": \"^5.3.0\",\n    \"react-scripts\": \"^5.0.0\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"prebuild\": \"npm run build:monolith\",\n    \"build\": \"react-scripts build\",\n    \"postbuild\": \"node scripts/post-build.js ./build ../microservices/src/frontend/public\",\n    \"build:monolith\": \"env-cmd -f .env.monolith react-scripts build\",\n    \"postbuild:monolith\": \"node scripts/post-build.js ./build ../monolith/public\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": \"react-app\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"devDependencies\": {\n    \"ncp\": \"^2.0.0\",\n    \"rimraf\": \"^3.0.2\"\n  }\n}\n"
  },
  {
    "path": "react-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"shortcut icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"Web site created using create-react-app\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>Fancy Store</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "react-app/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "react-app/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\n"
  },
  {
    "path": "react-app/public/static/img/products/credits.txt",
    "content": "film-camera.jpg,CC0 Public Domain,https://pxhere.com/en/photo/829555\ncamera-lens.jpg,CC0 Public Domain,https://pxhere.com/en/photo/670041\nair-plant.jpg,,https://unsplash.com/photos/uUwEAW5jFLE\ncamp-mug.jpg,,https://unsplash.com/photos/h9VhRlMfVkg\nrecord-player.jpg,,https://unsplash.com/photos/pEEHFSX1vak\ncity-bike.jpg,,https://unsplash.com/photos/Lpe9u9etwMU\ntypewriter.jpg,,https://unsplash.com/photos/mk7D-4UCfmg\nbarista-kit.jpg,,https://unsplash.com/photos/ZiRyGGIpRCw\nterrarium.jpg,,https://unsplash.com/photos/E9QYLj0724Y\n"
  },
  {
    "path": "react-app/scripts/post-build.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nconst path = require(\"path\");\nconst ncp = require(\"ncp\");\nconst rimraf = require(\"rimraf\");\n\nif(process.argv.length < 4){\n  console.error(\"Invalid arguments, two arguments are required <source> <destination>\");\n}\n\n//const sourceFolder = path.join(__dirname, \"..\", \"build\");\n//const destFolder = path.join(__dirname, \"..\", \"..\", \"..\", \"monolith\", \"public\");\n\nconst sourceFolder = process.argv[2];\nconst destFolder = process.argv[3];\n\nconsole.log(`Deleting stale folder: ${destFolder}`);\n\nrimraf(destFolder, err => {\n  if (err) {\n    console.log(`Failed to delete stale destination folder: ${destFolder}`);\n    return;\n  }\n  console.log(`Deleted stale destination folder: ${destFolder}`);\n\n  console.log(`Copying files from ${sourceFolder} to ${destFolder}`)\n\n  ncp(sourceFolder, destFolder, err => {\n    if (err) {\n      return console.error(`Failed to copy ${sourceFolder} to ${destFolder}!`);\n    }\n    console.log(`Copied ${sourceFolder} to ${destFolder} successfully!`);\n  });\n});\n"
  },
  {
    "path": "react-app/src/App.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport React from \"react\";\n\nimport ClippedDrawer from \"./components/ClippedDrawer\";\n\nfunction App() {\n  return <ClippedDrawer />;\n}\n\nexport default App;\n"
  },
  {
    "path": "react-app/src/components/ClippedDrawer/index.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React from \"react\";\nimport {\n  Drawer,\n  AppBar,\n  CssBaseline,\n  Toolbar,\n  List,\n  Typography,\n  ListItem,\n  ListItemText,\n  Box,\n} from \"@mui/material\";\n\nimport {\n  BrowserRouter as Router,\n  Route,\n  Switch,\n  NavLink,\n} from \"react-router-dom\";\n\n//Import Pages\nimport Home from \"../../pages/Home\";\nimport Products from \"../../pages/Products\";\nimport Orders from \"../../pages/Orders\";\nimport OrderDetails from \"../../pages/OrderDetails\";\nimport NotFound from \"../../pages/NotFound\";\n\nconst drawerWidth = 200;\n\nexport default function ClippedDrawer() {\n  return (\n    <Box sx={{ display: \"flex\" }}>\n      <Router>\n        <CssBaseline />\n        <AppBar\n          position=\"fixed\"\n          sx={{\n            zIndex: (theme) => theme.zIndex.drawer + 1,\n          }}\n        >\n          <Toolbar>\n            <Typography variant=\"h6\" noWrap>\n              Fancy Store\n            </Typography>\n          </Toolbar>\n        </AppBar>\n        <Drawer\n          variant=\"permanent\"\n          sx={{\n            width: drawerWidth,\n            flexShrink: 0,\n            [`& .MuiDrawer-paper`]: {\n              width: drawerWidth,\n              boxSizing: \"border-box\",\n            },\n          }}\n        >\n          <Toolbar />\n          <List>\n            <ListItem\n              component={NavLink}\n              exact\n              sx={{ color: \"rgba(0, 0, 0, 0.54)\" }}\n              activeClassName=\"Mui-selected\"\n              to=\"/\"\n            >\n              <ListItemText primary=\"Home\" />\n            </ListItem>{\" \"}\n            <ListItem\n              component={NavLink}\n              exact\n              sx={{ color: \"rgba(0, 0, 0, 0.54)\" }}\n              activeClassName=\"Mui-selected\"\n              to=\"/products\"\n            >\n              <ListItemText primary=\"Products\" />\n            </ListItem>{\" \"}\n            <ListItem\n              component={NavLink}\n              sx={{ color: \"rgba(0, 0, 0, 0.54)\" }}\n              activeClassName=\"Mui-selected\"\n              to=\"/orders\"\n            >\n              <ListItemText primary=\"Orders\" />\n            </ListItem>\n          </List>\n        </Drawer>\n        <Box component=\"main\" sx={{ flexGrow: 1, p: 3 }}>\n          <Toolbar />\n          <Switch>\n            <Route exact path=\"/\">\n              <Home />\n            </Route>\n            <Route exact path=\"/products\">\n              <Products />\n            </Route>\n            <Route path=\"/orders/:id\">\n              <OrderDetails />\n            </Route>\n            <Route path=\"/orders\">\n              <Orders />\n            </Route>\n            <Route>\n              <NotFound />\n            </Route>\n          </Switch>\n        </Box>\n      </Router>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "react-app/src/index.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\n\nReactDOM.render(<App />, document.getElementById('root'));"
  },
  {
    "path": "react-app/src/pages/Home/index.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React from \"react\";\nimport { Box, Paper, Typography } from \"@mui/material\";\n\nexport default function Home() {\n  return (\n    <Box sx={{ flexGrow: 1 }}>\n      <Paper\n        elevation={3}\n        sx={{\n          width: \"800px\",\n          margin: \"0 auto\",\n          padding: (theme) => theme.spacing(3, 2),\n        }}\n      >\n        <Typography variant=\"h5\">Welcome to the Fancy Store!</Typography>\n        <br />\n        <Typography variant=\"body1\">\n          Take a look at our wide variety of products.\n        </Typography>\n      </Paper>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "react-app/src/pages/Home/index.js.new",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React from \"react\";\nimport { Box, Paper, Typography } from \"@mui/material\";\n\nexport default function Home() {\n  return (\n    <Box sx={{ flexGrow: 1 }}>\n      <Paper\n        elevation={3}\n        sx={{\n          width: \"800px\",\n          margin: \"0 auto\",\n          padding: (theme) => theme.spacing(3, 2),\n        }}\n      >\n        <Typography variant=\"h5\">Fancy Fashion &amp; Style Online</Typography>\n        <br />\n        <Typography variant=\"body1\">\n          Tired of mainstream fashion ideas, popular trends and societal norms?\n          This line of lifestyle products will help you catch up with the Fancy\n          trend and express your personal style. Start shopping Fancy items now!\n        </Typography>\n      </Paper>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "react-app/src/pages/NotFound/index.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React from \"react\";\nimport { Box, Paper, Typography } from \"@mui/material\";\n\nexport default function Orders() {\n  return (\n    <Box sx={{ flexGrow: 1 }}>\n      <Paper elevation={3} sx={{ padding: (theme) => theme.spacing(3, 2) }}>\n        <Typography component=\"p\">Page not found</Typography>\n      </Paper>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "react-app/src/pages/OrderDetails/index.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React, { useState, useEffect } from \"react\";\nimport { useRouteMatch } from \"react-router-dom\";\nimport { Box, Paper, Grid, Typography } from \"@mui/material\";\n\nexport default function OrderDetails() {\n  const match = useRouteMatch();\n\n  const [hasErrors, setErrors] = useState(false);\n  const [order, setOrder] = useState({});\n\n  const orderId = match.params.id;\n\n  async function fetchOrder(orderId) {\n    try {\n      const response = await fetch(\n        `${process.env.REACT_APP_ORDERS_URL}/${orderId}`\n      );\n      const order = await response.json();\n      setOrder(order);\n    } catch (err) {\n      setErrors(true);\n    }\n  }\n\n  useEffect(() => {\n    fetchOrder(orderId);\n  }, [orderId]);\n\n  return (\n    <Box sx={{ flexGrow: 1 }}>\n      {hasErrors && (\n        <Paper\n          elevation={3}\n          sx={{\n            background: \"#f99\",\n            padding: (theme) => theme.spacing(3, 2),\n          }}\n        >\n          <Typography component=\"p\">\n            An error has occurred, please try reloading the page.\n          </Typography>\n        </Paper>\n      )}\n      {!hasErrors && (\n        <Paper\n          elevation={3}\n          sx={{\n            maxWidth: \"800px\",\n            margin: \"0 auto\",\n            padding: (theme) => theme.spacing(3, 2),\n          }}\n        >\n          <Grid\n            container\n            spacing={3}\n            justifyContent=\"flex-start\"\n            alignItems=\"stretch\"\n          >\n            <Grid item xs={12}>\n              <Typography variant=\"h5\">{order.id}</Typography>\n            </Grid>\n            <Grid item md={6} xs={12}>\n              <Typography component=\"p\">\n                <b>Date: </b>\n                {order.date}\n              </Typography>\n              <Typography component=\"p\">\n                <b>Cost: </b>${order.cost}\n              </Typography>\n            </Grid>\n            <Grid item md={6} xs={12}>\n              <Typography component=\"p\">\n                <b>Order Items: </b>\n              </Typography>\n              {order.items &&\n                order.items.map((item) => (\n                  <Typography key={item}>{item}</Typography>\n                ))}\n            </Grid>\n          </Grid>\n        </Paper>\n      )}\n    </Box>\n  );\n}\n"
  },
  {
    "path": "react-app/src/pages/Orders/index.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React, { useState, useEffect } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport {\n  Box,\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableRow,\n  Paper,\n  Typography,\n} from \"@mui/material\";\n\nexport default function Orders() {\n  const history = useHistory();\n\n  const [hasErrors, setErrors] = useState(false);\n  const [orders, setOrders] = useState([]);\n\n  async function fetchOrders() {\n    try {\n      const response = await fetch(`${process.env.REACT_APP_ORDERS_URL}`);\n      const orders = await response.json();\n      setOrders(orders);\n    } catch (err) {\n      setErrors(true);\n    }\n  }\n\n  useEffect(() => {\n    fetchOrders();\n  }, []);\n\n  return (\n    <Box sx={{ flexGrow: 1 }}>\n      {hasErrors && (\n        <Paper\n          elevation={3}\n          sx={{\n            background: \"#f99\",\n            padding: (theme) => theme.spacing(3, 2),\n          }}\n        >\n          <Typography component=\"p\">\n            An error has occurred, please try reloading the page.\n          </Typography>\n        </Paper>\n      )}\n      {!hasErrors && (\n        <Paper\n          elevation={3}\n          sx={{\n            maxWidth: \"800px\",\n            margin: \"0 auto\",\n            padding: (theme) => theme.spacing(3, 2),\n          }}\n        >\n          <Typography variant=\"h5\">Orders</Typography>\n          <Table sx={{ minWidth: \"650px\" }}>\n            <TableHead>\n              <TableRow>\n                <TableCell>Order Id</TableCell>\n                <TableCell>Date</TableCell>\n                <TableCell>Total Items</TableCell>\n                <TableCell>Cost</TableCell>\n              </TableRow>\n            </TableHead>\n            <TableBody>\n              {orders.map((order) => (\n                <TableRow\n                  hover\n                  sx={{ cursor: \"pointer\" }}\n                  key={order.id}\n                  onClick={() => {\n                    history.push(`/orders/${order.id}`);\n                  }}\n                >\n                  <TableCell component=\"th\" scope=\"row\">\n                    {order.id}\n                  </TableCell>\n                  <TableCell>{order.date}</TableCell>\n                  <TableCell>\n                    {(order.items && order.items.length) || 0}\n                  </TableCell>\n                  <TableCell>${order.cost}</TableCell>\n                </TableRow>\n              ))}\n            </TableBody>\n          </Table>\n        </Paper>\n      )}\n    </Box>\n  );\n}\n"
  },
  {
    "path": "react-app/src/pages/Products/index.js",
    "content": "/*\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport React, { useState, useEffect } from \"react\";\nimport {\n  Box,\n  Paper,\n  Card,\n  CardMedia,\n  CardContent,\n  Grid,\n  Typography,\n} from \"@mui/material\";\n\nexport default function Products() {\n  const [hasErrors, setErrors] = useState(false);\n  const [products, setProducts] = useState([]);\n\n  async function fetchData() {\n    try {\n      const response = await fetch(`${process.env.REACT_APP_PRODUCTS_URL}`);\n      const products = await response.json();\n      setProducts(products);\n    } catch (err) {\n      setErrors(true);\n    }\n  }\n\n  useEffect(() => {\n    fetchData();\n  }, []);\n\n  return (\n    <Box sx={{ flexGrow: 1 }}>\n      {hasErrors && (\n        <Paper\n          elevation={3}\n          sx={{\n            background: \"#f99\",\n            padding: (theme) => theme.spacing(3, 2),\n          }}\n        >\n          <Typography component=\"p\">\n            An error has occurred, please try reloading the page.\n          </Typography>\n        </Paper>\n      )}\n      {!hasErrors && (\n        <Grid\n          sx={{ maxWidth: \"1000px\", margin: \"0 auto\" }}\n          container\n          spacing={3}\n          justify=\"flex-start\"\n          alignItems=\"stretch\"\n        >\n          {products.map((product) => {\n            return (\n              <Grid key={product.id} item md={4} xs={12}>\n                <Card>\n                  <CardMedia\n                    sx={{ height: 0, paddingTop: \"56.25%\" }}\n                    image={product.picture}\n                    title={product.name}\n                  />\n                  <CardContent>\n                    <Typography variant=\"body1\">\n                      {product.name} - ${product.cost}\n                    </Typography>\n                  </CardContent>\n                </Card>\n              </Grid>\n            );\n          })}\n        </Grid>\n      )}\n    </Box>\n  );\n}\n"
  },
  {
    "path": "setup.sh",
    "content": "#!/usr/bin/env bash\n\n# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nset -eEo pipefail\n\nif [ -z \"$CLOUD_SHELL\" ]; then\n  printf \"Checking for required npm version...\\n\"\n\n  npm install -g npm > /dev/null 2>&1\n  printf \"Completed.\\n\\n\"\n\n  printf \"Setting up NVM...\\n\"\n  export NVM_DIR=\"/usr/local/nvm\"\n  [ -s \"$NVM_DIR/nvm.sh\" ] && \\. \"$NVM_DIR/nvm.sh\"  # This loads nvm\n  [ -s \"$NVM_DIR/bash_completion\" ] && \\. \"$NVM_DIR/bash_completion\"  # This loads nvm bash_completion\n  printf \"Completed.\\n\\n\"\n  \n  printf \"Updating nodeJS version...\\n\"\n  nvm install --lts\n  printf \"Completed.\\n\\n\"\nfi\n\nprintf \"Installing monolith dependencies...\\n\"\ncd ./monolith\nnpm install\nprintf \"Completed.\\n\\n\"\n\nprintf \"Installing microservices dependencies...\\n\"\ncd ../microservices\nnpm install\nprintf \"Completed.\\n\\n\"\n\nprintf \"Installing React app dependencies...\\n\"\ncd ../react-app\nnpm install\nprintf \"Completed.\\n\\n\"\n\nprintf \"Building React app and placing into sub projects...\\n\"\nnpm run build\nprintf \"Completed.\\n\\n\"\n\nprintf \"Setup completed successfully!\\n\"\n\nif [ -z \"$CLOUD_SHELL\" ]; then\n  printf \"\\n\"\n  printf \"###############################################################################\\n\"\n  printf \"#                                   NOTICE                                    #\\n\"\n  printf \"#                                                                             #\\n\"\n  printf \"# Make sure you have a compatible nodeJS version with the following command:  #\\n\"\n  printf \"#                                                                             #\\n\"\n  printf \"# nvm install --lts                                                           #\\n\"\n  printf \"#                                                                             #\\n\"\n  printf \"###############################################################################\\n\"\nfi\n"
  }
]