"Spaces" is supposed to bring people together that are in physical proximity to each other but have never really interacted. You can create a "space" bound to a physical location and set a specific radius to it. Then, other people who open the app and find themselves within the radius of the space's location can access the space and communicate with other members of the space. Once you have accessed a space "on site", you can access it from anywhere anytime.
One of the many use cases would be to create a space for your neighborhood. Another one is to create a space that is bound to a Pingpong table in the local park so people who play Pingpong there regularly can meet up without having to know each other's Whatsapp numbers. You only must have been there once and have accessed the space for the Pingpong table to be able to use the Pingpong table space from anywhere you want.
From a technical viewpoint, the application consists of a Golang backend with a Redis instance connected to it (that acts as the central data store) and a React Native frontend. The backend app will be deployed on a Kubernetes cluster (using Linode -> cheapest option) and split into microservices. I know this is a total overkill but this project is supposed to be a personal learning project, as a functional app at the end.
I will soon move most of the DB functionality from Redis to Postgres to take advantage of a relational database's benefits (foreign keys, schemas, complex queries, etc.).
My testing strategy for the backend service puts an emphasis on end-to-end tests to avoid having brittle tests. This way, I can have fast running tests that cover the whole API from authentication to the DB layer implementation. External APIs (eg Firebase) are mocked and tested using separate integration tests. Critical (util) functions are additionally tested using classic unit tests.
The E2E tests reflect an incorrect implementation of the Redis DB layer. This is why the E2E tests fail in around 20% of the cases. This will be fixed soon when replacing most of the Redis implementation with PostgreSQL.
In the services/server
directory, run:
make e2e
to run the E2E testmake integration
to run the integration tests (The value of the TEST_FIREBASE_API_KEY environment variable must be set in theservices/server/.env.test
file and the Firebase service account key must be stored as a JSON file namedservices/server/firebase_service_account_key.json
)make unit
to run all unit testsmake test
to run all tests
You are welcome to go through the code as you please. I'm happy about every bit of feedback!
Create backend with Redis as the main DBCreate screen designs in FigmaImplement screen designsHook up screens to backendCreate custom navigator for React Navigation to take advantage of gesturesCreate CI/CD pipeline- Split backend into microservices with single API Gateway
- Move from Redis to Postgresql as main DB
- Add missing backend API functionality
- Integrate Sentry
- Submit app to Appstore and Playstore
(golang-migrate must be installed locally)
migrate create -ext sql -dir services/server/postgres/migrations -seq <migration name>
to create a migration
- GCP project
- Linode project
- create a GCP service account with editor rights
- create a key file for the service account and put it into the
server/terraform
directory - get Linode API token
- create a
server/terraform/terraform.tfvars
file and populate it with the following values
google_project_id = <GCP project id>
credentials_file = ./<name of gcp key file>
linode_token = <Linode API token>
- run
terraform apply
in theserver/terraform
directory - Go to Firebase console, go to the project that was automatically created by GCP, create a service account key in and save it as
server/firebase_service_account_key.json
- Populate the Github Action secret
FIREBASE_SERVICE_ACCOUNT_KEY_BASE64
: Runbase64 -i server/firebase_service_account_key.json
(on Macos) and use the ouput for the Github Action secret's value - Populate the Github Action secret
LINODE_KUBECONFIG
: Copy the base64 kubeconfig value for the Linode Kubernetes cluster from theserver/terraform/terraform.tfstate
file (cat server/terraform/terraform.tfstate | jq -r ' .resources[1] | .instances[0] | attributes |.kubeconfig '
) and runecho \<value\> | base64 -d
and use the ouput for the Github Action secret's value - Populate the rest of the Githut Action secrets and variables:
DOCKERHUB_USERNAME
(f.e.nteeeeed
)DOCKERHUB_REPO
(f.e.spaces
)HELM_VERSION
(f.e.3.14.3
)
DOCKERHUB_TOKEN
FIREBASE_SERVICE_ACCOUNT_KEY_BASE64
LINODE_KUBECONFIG
POSTGRES_HOST
POSTGRES_PASSWORD
TEST_FIREBASE_API_KEY
TEST_FIREBASE_SERVICE_ACCOUNT_KEY_BASE64