A Full Stack app built with Node, React, PostgreSQL, REST API, AWS and GitHub Actions
Live site: https://recipeapp.link
- Hosted on AWS.
- Infrastructure as Code with Terraform
- CI/CD with GitHub Actions.
- Local development with Docker Compose.
- 100% TypeScript, zero JavaScript.
- React single-page application.
- State management with Valtio.
- Routing with React Router 6.
- UI design with Chakra UI.
- Node.js server built with Express.js.
- Database with PostgreSQL.
- Data validation with zod.
- Testing
- Unit tests for functions with Jest.
- Unit tests for route handlers and middleware with node-mocks-http.
- Integration tests for routes with supertest.
- Frontend deployed to S3 and CloudFront automatically using GitHub Actions.
- Authentication: register, login, validate email, recover password.
- Settings: change the user's name, email and password. Delete the user account.
- Recipe: publish, edit and delete recipes.
The application is available at:
- Web (React): http://localhost:3000
- Server (API): http://localhost:5000
- Database: localhost:5432
To run the app locally, do:
cp .env.example .env
# (Optional) Edit .env to adjust values
# Start all services
docker compose up --build
# (Optional) Seed the database with users and recipes
./scripts/seed-database.sh
# View service status
docker compose ps
# Stop everything, but keep the database data
docker compose down
# Stop everything and discard the database data
docker compose down --volumesTo run only a single service do:
cd server # Or cd web
npm install
npm run devThe database is created automatically when you run docker compose up --build. You can interact with it from within the Docker container.
# Connect to database from within the Docker container
docker compose exec db psql -U postgres -d recipemanager
# Backup database
docker compose exec db pg_dump -U postgres recipemanager > backup.sql
# Restore database
docker compose exec -T db psql -U postgres -d recipemanager < backup.sqlThe database port is exposed to localhost:5432 on the host machine. This allows you to connect to the database using a client from your machine.
# Connect to database from your host machine
psql -h localhost -p 5432 -U postgres -d recipemanagerYou will be prompted for the password, which is defined in your .env file.
Once the database is created, you can automatically fill the database with users and recipes using the provided script:
./scripts/seed-database.shThis script will:
- Create two test users.
- Seed the database with sample recipe data.
Alternatively, you can run the steps manually:
curl http://localhost:5000/api/auth/register -H "Content-Type: application/json" -d '{"name":"Albert", "email":"[email protected]", "password":"123456"}'curl http://localhost:5000/api/auth/register -H "Content-Type: application/json" -d '{"name":"Blanca", "email":"[email protected]", "password":"123456"}'docker compose exec -T db psql -U postgres -d recipemanager < server/database-seed.sql
Sending emails requires creating an account at https://ethereal.email. Click the 'Create Ethereal Account' button and copy-paste the user and password to the .env file environment variables EMAIL_USER and EMAIL_PASSWORD.
You can view the emails at https://ethereal.email/messages. URLs to view each email sent are also logged at the server console.
To run Prettier and ESLint on every commit, run cp pre-commit .git/hooks.
Note that the checks do not abort the commit, they only inform you of any issues found.
To deploy the AWS infrastructure with Terraform, do:
cd terraform/web/environments/dev # Or prod
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars.example with your values if needed
terraform init
terraform plan -out tfplan
terraform apply tfplanOnce the AWS infrastructure is deployed, you can set up automatic deployment of the React web app to S3 and CloudFront using GitHub Actions.
At the GitHub repository, go to Settings → Environments and create an environment named "dev" or "prod". On that page, click the environment and add the following environment variables (not secrets):
| Environment variable | Value |
|---|---|
AWS_REGION |
terraform output aws_region |
AWS_GITHUB_ACTIONS_OIDC_ROLE_ARN |
terraform output oidc_role_arn |
WEB_S3_BUCKET |
terraform output website_s3_bucket_name |
WEB_CLOUDFRONT_DISTRIBUTION_ID |
terraform output website_cloudfront_distribution_id |
cd web
npm run build
aws s3 sync build s3://<s3-bucket-name> --delete
aws cloudfront create-invalidation --distribution-id <distribution-id> --paths '/*'Note that there's a GitHub action that does this automatically, see Automatic deployment with GitHub Actions.