Simple twitter clone with React frontend, Go backend and Server-Sent Events to support real-time refreshing. This example is based on HTTP Server push using SSE (Server-Sent Events). Supports multi-environment setup, containerization, CI/CD, cloud deployment.
- Implements common messaging patterns such as publish-subscribe, request-reply, and event-driven architecture in Go.
- Complete CI/CD pipeline: builds both backend and frontend services, runs unit and database integration tests, executes end-to-end tests in a full-scale environment, and deploys to Google Cloud Run.
- Support FireStore and Pub/Sub in Cloud setup.
- Hosted on Google Cloud DNS.
- Utilizes popular database and message broker technologies, including MySQL, Mongo and NATS.
- Using appsettings in Go applications.
- Includes Dockerfiles and Docker Compose configuration for containerizing the sample microservices.
- Supports basic Google OAuth2.
- Runs database integration tests during CI using github workflow actions.
- Includes common project structure for frontend projects.
- Runs frontend unit tests.
Application settings can be configured in internal/config/appsettings.json
file. Possible configurations include mode of the application, API server configuration, Tweets and Feeds database connections, NATS messaging connection.
First set GOOGLE_APPLICATION_CREDENTIALS
environment variable to point to service account key, for example for PowerShell this could be:
$env:GOOGLE_APPLICATION_CREDENTIALS = "D:\Downloads\twitter-clone-438407-4b74b07d276e.json"
Then in server
folder run
go run cmd\main.go
This project supports multiple deployment environments: in-memory, persistent, and cloud using Docker Compose. CI/CD workflow supports cloud deployment environment by default.
This setup provides a robust and flexible way to handle multiple environments while ensuring security and consistency across development and production workflows.
Below is a detailed explanation of the setup:
Environment variables are managed using .env
files tailored for each deployment mode:
.env
: Default environment for in-memory mode, suitable for local development..env.local
: Persistent mode, configured for local development with a database and messaging connections..env.cloud
: Cloud mode, used for deployment in cloud environment.
The compose.yaml
references several environment variables that can be dynamically loaded from the specified .env
file using the --env-file
option.
Example command:
docker-compose --env-file .env.local -f compose.yaml up -d --build
The ci-cd.yml
file integrates the configuration into a CI/CD workflow, using secrets stored securely in a GitHub Actions. Environment-specific secrets are injected during pipeline execution:
DOCKER_USER
andDOCKER_PASSWORD
for Docker image management.PROJECT_ID
,OAUTH2_CLIENT_ID
,OAUTH2_CLIENT_SECRET
GOOGLE_SERVICE_ACCOUNT_KEY
for cloud configuration.
To run all existing tests recursively execute in the root folder:
go test ./... -v
First make sure you have Mongo instance running, e.g. using docker:
docker run -d -p 27017:27017 --name mongo mongo:latest
Feed integation test will connect to Tests_FeedsDb
Mongo database. To run tests execute in root folder:
go test .\internal\repositories\feed\persistent_feedrepository_test.go -v
First make sure you have MySQL instance running, e.g. using docker:
docker run -d --name twitter-mysql-test -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_USER=myuser -e MYSQL_PASSWORD=mypassword -e MYSQL_DATABASE=Tests_TweetsDb -p 3306:3306 mysql:latest
Tweet integration test will connect to Tests_TweetsDb
MySql database. To run tests execute in root folder:
go test .\internal\repositories\tweet\persistent_tweetrepository_test.go -v
mockgen
can generate necessary mocks that can be used for testing:
mockgen -source .\internal\api\publisher.go -destination .\internal\__mocks__\api\mock_publisher.go -package=mocks
Router test can be run with
go test .\internal\api\router_test.go
There's a dedicated workflow installed on repository that would do the following:
- Spin up required services: MySQL and Mongo
- Check out code
- Set up Go environment
- Build
- Run all tests
- Server supports two authentication methods:
- Cookie-based authentication (visualized on the diagram above)
- Authorization header that can be used by server application (a.k.a. daemon app) without a real user entering credentials
- In Google Cloud Console there's a service account configured that would let server application to authenticate. Using OAuth 2.0 for Server to Server Applications. It also requires a Key to be created, which is basically a JSON document that you download.
- e2e tests rely on
GOOGLE_SERVICE_ACCOUNT_KEY
environment variable to generate JWT and then access token. You need to load content of private key JSON file into that environment variable, for example for PowerShell this could be:
$env:GOOGLE_SERVICE_ACCOUNT_KEY = Get-Content -Raw -Path "C:\Users\Maksym Ivanenko\Downloads\twitter-clone-438407-23XXXXXXXXX.json"
- To run e2e test locally execute in
e2e_tests
folder:
npm test
- In order to run e2e tests during CI private key JSON has been loaded into github secret under the same name. Github action then forwards it as environment variable:
- name: Run e2e tests
env:
GOOGLE_SERVICE_ACCOUNT_KEY: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
- e2e test action does several things:
- Checks out source code
- Runs docker-compose to start full scale environment. It uses github secret for google service account key.
- Installs NodeJS and dependencies in e2e_tests
- Runs the test with
npm test
src/
├── __mocks__/
│ └── configMock.js # Mocks common.js
│
├── __tests__/
│ ├── apiHandlers.tests.js # Tests for API request functions
│ └── eventSourceHandlers.test.js # Tests for even source request functions
│
├── api/
│ ├── apiHandlers.js # Contains all API request functions
│ └── eventSourceHandlers.js # Contains all event source request functions
│
├── components/
│ ├── auth/
│ │ └── AuthContext.tsx # Contains AuthContext, checkAuth function
│ │
│ ├── pages/
│ │ ├── Callback.js # Callback page for authentication redirection
│ │ ├── Logic.js # Login page
│ │ ├── Main.js # Main page combining TagList, TweetList, InputForm
│ │ ├── Nav.js # Main top navigation page
│ │ └── Profile.js # Profile page showing user info from AuthContext
│ │
│ ├── tweet/
│ │ ├── InputForm.js # Form for creating a new tweet
│ │ ├── TagList.js # Displays list of hashtags
│ │ ├── TweetCard.jsx # Represents a single tweet item in TweetList
│ │ └── TweetList.js # Displays a list of TweetCard components
│ │
├── models/
│ └── user.js # User model
│
├── styles/
│ ├── pages/ # Styles specific to page components
│ └── tweet/ # Styles specific to tweet-related components
│
├── App.js # Main app entry point
├── common.js # Loads environemnt variables and defines constants
├── env.json # Environment configuration
└── index.js # Entry point for rendering the React app
HTTP Server push using SSE (Server-Sent Events)