
Kampung.SGMay-Aug 2023
Interfaith learning platform in collaboration with Google and Being Bridges. Designed and built with industry partners for the SUTD module 60.004 Service Design Studio.
Overview
Kampung.SG was a 12 week project delivered under Scrum methodology with a team of 7 students.
I was the Tech Lead and was responsible for DevOps and integration between the frontend and backend.
Our project site contains comprehensive documentation, including user journeys, service architecture, and design process.
Inspiration
Our team conducted user persona studies and interviews with our partner to understand the needs of their target users.
How might we make a platform to equip students with the prerequisite knowledge and an interactive learning community in a convenient and intuitive way?
Partners
From ideation to prototype, we worked with our industry partner Being Bridges to develop an AI-powered platform to equip Singapore students with interfaith knowledge and an interactive learning community.
Being Bridges is a Singapore-based social enterprise and consultancy with expertise developing practical community-building interventions around issues of diversity and social cohesion.
Mentors from Google also provided guidance on the technical aspects of the project.
Implementation
Configuration management
I was in charge of the microservices architecture and deployment. With six different services (API Gateway, User Service, Curriculum Service, Forum Service, ML Service, and Inactivity Checker), we needed to ensure consistent configuration while respecting each service's unique requirements.
Each service needed:
- Service-specific URLs
- Database credentials
- API keys
- Authentication details
- Port configurations
Our solution was to implement a hierarchical approach to environment variables:
- Default values coded in the application
- Environment-specific values (.env.development, .env.production)
- Secret values stored in Google Secret Manager for production
This allowed us to maintain flexibility and security across different environments.
Maintaining development environments
With developers using Windows, macOS, and Linux, creating a consistent development experience was challenging. Docker helped, but I ended up creating custom startup scripts for each OS:
# For macOS
osascript -e 'tell application "Terminal"
activate
tell application "System Events" to keystroke "t" using command down
delay 1
do script "cd '$PWD'/api-gateway" in selected tab of front window
do script "bundle install --without production && rails s" in selected tab of front window
# More services...
end tell'
REM For Windows
start "API Gateway" cmd.exe /k "cd api-gateway && rails s"
start "Curriculum" cmd.exe /k "cd curriculum-service && rails s"
REM More services...
# For Linux
tmux new-session -d -s kampung
tmux split-window -h
tmux select-pane -t 1
# Configure tmux panes for each service
Testing
Testing microservices properly required multiple levels of testing:
- Unit tests within each service
- Integration tests between directly connected services
- End-to-end tests across the entire system
Cypress became our best friend for end-to-end testing, but setting it up to work with multiple services was challenging.
Deployment orchestration
Perhaps the biggest challenge was orchestrating deployments across multiple services. We needed to ensure that:
- Services were deployed in the correct order
- Backwards compatibility was maintained during the transition
- Rollbacks were possible if issues were detected Database changes were applied at the right time
Our solution leveraged Google Cloud Build with service-specific triggers and dependencies. Each service had its own dedicated cloudbuild.yaml
file.
steps:
- id: "build image"
name: "gcr.io/cloud-builders/docker"
args: ["build", "-t", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}", "."]
- id: "push image"
name: "gcr.io/cloud-builders/docker"
args: ["push", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"]
- id: "run deploy"
name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
entrypoint: gcloud
args:
[
"run",
"deploy",
"${_SERVICE_NAME}",
"--platform",
"managed",
"--region",
"${_REGION}",
"--image",
"gcr.io/${PROJECT_ID}/${_SERVICE_NAME}",
"--port",
"${_PORT}",
"--allow-unauthenticated",
]