- [FE] React
- [BE] Express
- [DB] SQLite (in memory)
- [ORM] Sequelize
- [Logging] Winston with DataDog
-
Set up frontend
From root,
cd frontend/online-store npm install --legacy-peer-deps npm start
-
Set up backend
From root,
cd backend npm install --legacy-peer-deps npm start
-
Set up SQLite DB From root,
cd backend node db.js
-
Load dummy data into DB
node loadDummyData.js
How to deploy this app on a cloud environment (Bonus: How you would do this with serverless components)
-
[FE] React --> Cloud Run
Create a Dockerfile
FROM node:14.21.3 WORKDIR /frontend/snippet-sharing-service COPY package.json . RUN npm install --legacy-peer-deps COPY . . EXPOSE 3000 CMD ["npm", "start"]
From root,
cd frontend/online-store docker build -t online-store-fe-image . gcloud run deploy online-store-fe-image --source . --region=asia-southeast1 --port=3000
-
[BE] Express --> Cloud Run
Create a Dockerfile
FROM node:14.21.3 WORKDIR /backend COPY package.json . RUN npm install --legacy-peer-deps COPY . . EXPOSE 8000 CMD ["npm", "start"]
From root,
cd backend docker build -t online-store-be-image . gcloud run deploy online-store-be-image --source . --region=asia-southeast1 --port=8000 --add-cloudsql-instances YOUR_INSTANCE_CONNECTION_NAME --set-env-vars INSTANCE_UNIX_SOCKET="/cloudsql/YOUR_INSTANCE_CONNECTION_NAME" --set-env-vars INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME --set-env-vars DB_NAME=YOUR_DB_NAME --set-env-vars DB_USER=YOUR_DB_USER
-
[DB] SQLite (in memory) --> Cloud SQL MySQL
Set up Cloud SQL MySQL instance
- Follow the tutorial here to create a Cloud SQL instance. In this POC, we don't set a password (though it's good practice to)
- Create a database
itemsDb
, then a tableitems
inside this database - you can do this via Cloud Shell
CREATE DATABASE itemsDb; USE items; CREATE TABLE items ( id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL, description TEXT, price REAL NOT NULL, imageUrl TEXT, createdAt DATETIME DEFAULT CURRENT_TIMESTAMP, updatedAt DATETIME DEFAULT CURRENT_TIMESTAMP );
- Create a service account and place your service account key JSON in the project root. Then from root, run
./cloud_sql_proxy -instances=YOUR_INSTANCE_CONNECTION_NAME -credential_file=../YOUR_SERVICE_ACCOUNT_KEY.json
This will allow you to connect to your Cloud SQL instance via the Cloud SQL Auth proxy, as if it were a local database
Replace YOUR_INSTANCE_CONNECTION_NAME and YOUR_SERVICE_ACCOUNT_KEY
Example:
./cloud_sql_proxy -instances=tap-2023:asia-southeast1:sss-mysql=tcp:3306 -credential_file=../tap-2023-653687ae417e.json
-
[Logging] Winston with DataDog --> Winston with Cloud Logging
- Requires application level code change (winston config)
- Can use BigQuery as sink for analytics
- Input validation - sanitize inputs in backend to prevent SQL injection, XSS, etc.
- Use Content Security Policy (CSP) - implement CSP headers to prevent XSS attacks on React frontend
- Secure Secrets Management - use GCP Secret Manager to manage API keys, database credentials, etc.
- Private VPCs to control the IP address range, subnets, and configuration of route tables
- Eg. Db should not be directly exposed to the public internet, put it in a private subnet
- Firewalls to create rules that allow/deny traffic to VMs, containers, and other resources
- Enforce MFA for all IAM users
- Principal of least privilege, and use service accounts to deploy resources
- Regularly rotate and manage the lifecycle of service account keys
- Limit who and what can access resources, and regularly review permissions
- Google Cloud Armor, Cloud Security Command Center, and Cloud Security Scanner can help provide additional layers of security
Security - doesn't give any info about the number of records in the db, unlike auto-incrementing integers