Proof of concept aimed at putting into practice an e2e development cycle for an application.
Note
- 💡 Monorepo-like project in which services can be deployed and run independently.
- ❤️ Feel free to add any improvements or suggestions you consider.
- Goals
- Considerations
- Tech Stack
- Installation and running the project
- Samples
- Server side
- Tests (unit-tests and e2e)
- CI/CD - Containerization and Deployment
- Next steps
-
Create an application that displays trending films and TV shows in two rails.
-
Integrate the The Movie DB API (TMDB) to the application.
-
Add the capability of navigating the application using the keyboard (Arrow keys).
-
Implement a CI/CD process using GitHub Actions, Docker, and a Cloud application hosting service.
To implement the solution, we are required to sign up themoviedb.org, and also integrate it to our back-end then, we will be able to use their API services. For further details, check the specs here TMDB API specs.
Please, check this consideration out.
Important
- The architecture is a mono repo-like project that uses workspaces to share type definitions among the app's tiers.
- The application can be either started locally or containerized.
- Each app tier, within the project, can be started for development independently from the others.
This conceptual test has been developed using the following technologies:
- Front-end
- Back-end
- Tests (Unit test and E2E)
- Containerization and Deployment
- Architecture
The project requires:
Clone the repository:
git clone https://github.com/christianjtr/tv-app.git
Scripts:
Before executing these scripts, you must run npm install in the directory you just downloaded/cloned the codebase.
# Run the entire development environment for both client and server tiers
> npm run dev:app
# Run dev environment for the client-side
> npm run dev:client
# Run development environment for the server-side
> npm run dev:server
# Run unit tests for the client-side tier
> npm run test:client
# Run e2e tests for the client-side tier
> npm run test:client:cy
# Run unit tests for the server-side tier
> npm run test:server
# Build shared types across the application
> npm run build:shared-types
# Perform docker-compose to containerize and run the application
> npm run dev:docker:build-up
Environment variables:
Each app's tier within the project has its own environment variables file, you should create a .env file following the templates provided in the corresponding directory.
Tier | template | directory | environment file to create |
---|---|---|---|
client | .env.local | /app | .env |
server | .env.example | /server | .env |
Click on the following link GitHub page project.
Note: It's a mocked version of the project, although we can deploy the front-end project and fetch data from our back-end services hosted.
The server-side API follows the OpenAPI Specification - Version 3
# Enter the API's specs documentation by browsing to this URL.
<YOUR HOST>/api/docs
Both services have some examples of how to develop unit tests and e2e tests (including some mocking strategies).
-
Client-side:
- Unit testing for services, react-hooks, state-less components, and the entire sections (pages).
- E2E testing: Using Cypress. (i.e.: Navigate to the search section and look for a movie).
- Server-side:
- Unit testing for services, controllers, etc.
- E2E testing: Using SuperTest. (i.e.: Simulate a running back-end to perform requests).
flowchart LR
step0["`Developer pushes/merges code into the repository`"]
step1["`GitHub actions are triggered`"]
step2["`Tests are triggered, and Docker images are built`"]
step3["`Docker images are pushed to Docker Hub`"]
step4["`**Optional** Render cloud service should deploy the images by latest reference provided`"]
step0 --> step1 --> step2 --> step3 --> step4
The strategy followed to deploy the application implies:
- Create Dockerfiles per environment (dev, prod) to build each application service (client-side, server-side).
- Every Dockerfile perform a multi-stage image build.
- Consider workspaces and shared packages when building images.
- Create parametrized docker-compose.yml file per environment (dev, prod). (At root folder level only - main Docker context).
- Create .dockerignore files.
- Create a docker-compose run and build script.
- Obtain production environment variables given the application's source files.
- Provide every docker-compose.yml file with those variables to parametrize them.
- Note: Google Bard supported me on this.
- Implement a GitHub action workflow which is going to be dispatched whenever a pull-request or merge is performed.
- Create the repository's project secrets.
- Environment variables for production.
- Docker credentials
- Username.
- Docker TOKEN API. (Read, Write permissions).
- Include jobs:
- Run tests.
- Containerize applications.
- Push applications to Docker Hub.
- You must have a Docker Hub account.
Important
- At this point, the services are merged into the repository, tested, containerized, and published on Docker Hub (either as public or private images).
- Now, you should decide which Cloud provider service to host your application. (Azure, Amazon Web Services, Digital Ocean, Google Cloud Platform, and others).
Choice: I decided to use Render because it's free for hobby projects (under certain conditions, of course).
Look at this article on how to deploy pre-built docker images on their side.
-
Note: The application should consume API services published and provided by our back-end, which is intended to obtain data from the TMDB Movie service).
- Extend this documentation to the applications (client-side, server-side, GitHub actions).
- Enhance Dockerfiles and multi-stage builds.
- Better use of npm workspaces (mono-repos).
- Improve overall CD/CI process.
- Build back-end codebase.
- Polish up user experience and responsiveness.