Skip to content

Commit baa2c50

Browse files
authored
Merge pull request #14 from davidsilva/chore/readme-and-clean-up
Chore/readme and clean up
2 parents bdb8ece + 82eb6ab commit baa2c50

37 files changed

+308
-240
lines changed

.github/workflows/ci.yml

+14-2
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,23 @@ jobs:
7070
working-directory: ./backend
7171
run: npm install
7272

73-
- name: Run backend tests
73+
# Run integration tests separately to avoid db conflicts
74+
- name: Run backend integration tests for users
7475
working-directory: ./backend
7576
env:
7677
DATABASE_URL: postgres://postgres:postgres@localhost:5432/testdb
77-
run: npm test
78+
run: npm test -- src/__tests__/integration/users.integration.test.ts
79+
80+
- name: Run backend integration tests for products
81+
working-directory: ./backend
82+
env:
83+
DATABASE_URL: postgres://postgres:postgres@localhost:5432/testdb
84+
run: npm test -- src/__tests__/integration/products.integration.test.ts
85+
86+
# Unit tests can be run together
87+
- name: Run backend unit tests
88+
working-directory: ./backend
89+
run: npm test -- src/__tests__/unit
7890

7991
- name: Install dependencies for frontend
8092
working-directory: ./frontend

README.md

+131-25
Large diffs are not rendered by default.

backend/Dockerfile

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Stage 1: Build the Node.js application
22
FROM node:20 AS build
33

4-
WORKDIR /app
4+
WORKDIR /app/backend
55

66
COPY package.json ./
77

@@ -14,15 +14,18 @@ RUN npm run build
1414
# Stage 2: Prepare to serve the application
1515
FROM node:20-alpine
1616

17-
WORKDIR /app
17+
WORKDIR /app/backend
1818

19-
COPY --from=build /app/dist /app/dist
20-
COPY --from=build /app/package.json /app/package.json
21-
22-
# Exclude devDependencies
23-
RUN npm install --only=production
19+
COPY --from=build /app/backend/dist /app/backend/dist
20+
COPY --from=build /app/backend/package.json /app/backend/package.json
21+
COPY --from=build /app/backend/src /app/backend/src
22+
COPY --from=build /app/backend/jest.config.ts /app/backend/jest.config.ts
23+
COPY --from=build /app/backend/tsconfig.json /app/backend/tsconfig.json
24+
COPY --from=build /app/backend/migrations /app/backend/migrations
25+
COPY --from=build /app/backend/seeds /app/backend/seeds
26+
RUN npm install
2427

25-
ENV DEBUG=* NPM_CONFIG_LOGLEVEL=verbose
28+
# ENV DEBUG=* NPM_CONFIG_LOGLEVEL=error
2629

2730
EXPOSE 3000
2831

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { Knex } from "knex";
2+
3+
4+
export async function up(knex: Knex): Promise<void> {
5+
return knex.schema.table('users', (table) => {
6+
table.string('street_address').nullable();
7+
});
8+
}
9+
10+
11+
export async function down(knex: Knex): Promise<void> {
12+
return knex.schema.table('users', (table) => {
13+
table.dropColumn('street_address');
14+
});
15+
}
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { Knex } from "knex";
2+
3+
4+
export async function up(knex: Knex): Promise<void> {
5+
return knex.schema.table('products', (table) => {
6+
table.integer('quantity').notNullable().defaultTo(0);
7+
});
8+
}
9+
10+
11+
export async function down(knex: Knex): Promise<void> {
12+
return knex.schema.table('products', (table) => {
13+
table.dropColumn('quantity');
14+
});
15+
}

backend/package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "interview-prep-backend",
3-
"version": "0.0.0",
3+
"version": "0.1.0",
44
"main": "dist/server.js",
55
"scripts": {
66
"start": "node dist/server.js",

backend/src/__tests__/integration/products.integration.test.ts

-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@ import request from 'supertest';
22
import app from '../../app';
33
import knex from 'knex';
44
import knexConfig from '../../knexFile';
5-
import dotenv from 'dotenv';
65
import {
76
Product,
87
ProductStatus,
98
} from '@onyxdevtutorials/interview-prep-shared';
109
import retry from "retry";
1110

12-
dotenv.config({ path: '../../../.env.test' });
13-
1411
const db = knex(knexConfig['test_products']);
1512

1613
const productsPath = '/api/v0/products';

backend/src/__tests__/integration/users.integration.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import request from 'supertest';
22
import app from '../../app';
33
import knex from 'knex';
44
import knexConfig from '../../knexFile';
5-
import dotenv from 'dotenv';
5+
// import dotenv from 'dotenv';
66
import { User, UserStatus } from '@onyxdevtutorials/interview-prep-shared';
77
import retry from "retry";
88

9-
dotenv.config({ path: '../../../.env.test' });
9+
// dotenv.config({ path: '../../../.env.test' });
1010

1111
const db = knex(knexConfig['test_users']);
1212

backend/src/__tests__/server.test.ts renamed to backend/src/__tests__/unit/server.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import request from 'supertest';
2-
import app from '../app';
2+
import app from '../../app';
33
import http from 'http';
44

55
describe('Server', () => {

backend/src/app.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,27 @@ import bodyParser from 'body-parser';
33
import cors from 'cors';
44
import usersRouter from './routes/users';
55
import productsRouter from './routes/products';
6+
import healthRouter from './routes/health';
67
import { errorHandler } from './middleware/errorHandler';
78
import { logger } from './middleware/logger';
89
import knex from 'knex';
910
import knexConfig from './knexFile';
10-
import dotenv from 'dotenv';
1111
import { Request, Response, NextFunction } from 'express-serve-static-core';
1212

13-
const envFile =
14-
process.env['NODE_ENV'] === 'production'
15-
? '../.env.production'
16-
: process.env['NODE_ENV'] === 'test'
17-
? '../.env.test'
18-
: '../.env.local';
19-
20-
dotenv.config({ path: envFile });
21-
2213
const app = express();
2314
app.use(bodyParser.json());
2415

16+
let corsOrigin: string;
17+
18+
if (process.env['NODE_ENV'] === 'local') {
19+
corsOrigin = 'http://localhost:4200';
20+
} else {
21+
corsOrigin = 'http://dev.interviewprep.onyxdevtutorials.com';
22+
}
23+
2524
const corsOptions = {
26-
origin: process.env['CORS_ORIGIN'] || 'http://dev.interviewprep.onyxdevtutorials.com',
27-
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
25+
origin: corsOrigin,
26+
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
2827
credentials: true,
2928
optionsSuccessStatus: 200,
3029
};
@@ -57,6 +56,8 @@ app.use(
5756
productsRouter
5857
);
5958

59+
app.use('/health', healthRouter);
60+
6061
app.get('/', (req, res) => {
6162
res.send('Hello, world!');
6263
});

backend/src/routes/health.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Router } from 'express';
2+
3+
const healthRouter = Router();
4+
5+
healthRouter.get('/', (req, res) => {
6+
res.status(200).send('OK');
7+
});
8+
9+
export default healthRouter;

docker-compose.migrate.yml

-18
This file was deleted.

docker-compose.test.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ services:
3333
- NODE_ENV=test
3434
- DATABASE_URL=${DATABASE_URL}
3535
image: interview-prep-backend-tests:latest
36-
working_dir: /app
36+
working_dir: /app/backend
3737
depends_on:
3838
- db-test
39-
command: sh -c "npx jest --clearCache && npm run test -- --watch=false --verbose"
39+
command: sh -c "npx jest --clearCache && npx jest --watch=false --config ./jest.config.ts"
4040
# command: tail -f /dev/null
4141
networks:
4242
- devnetwork

docker-compose.yml

+5-4
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ services:
2828

2929
backend:
3030
build:
31-
context: .
32-
dockerfile: backend/Dockerfile
31+
context: ./backend
32+
dockerfile: Dockerfile
3333
image: interview-prep-backend:latest
3434
ports:
3535
- "3000:3000"
3636
environment:
3737
- DATABASE_URL=${DATABASE_URL}
38+
- NODE_ENV=${NODE_ENV}
3839
volumes:
3940
# The following works but shouldn't be necessary:
4041
# - /Users/davidsilva/Dev/interview-prep/backend:/app/backend
@@ -63,8 +64,8 @@ services:
6364

6465
migrate:
6566
build:
66-
context: .
67-
dockerfile: backend/Dockerfile
67+
context: ./backend
68+
dockerfile: Dockerfile
6869
working_dir: /app/backend
6970
environment:
7071
- NODE_ENV=${NODE_ENV}

frontend/nginx.conf

+5-7
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ server {
77
try_files $uri $uri/ /index.html;
88
}
99

10-
# location /api/v0/ {
11-
# proxy_pass http://api.dev.interviewprep.onyxdevtutorials.com:3000/;
12-
# proxy_set_header Host $host;
13-
# proxy_set_header X-Real-IP $remote_addr;
14-
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
15-
# proxy_set_header X-Forwarded-Proto $scheme;
16-
# }
10+
location /health {
11+
access_log off;
12+
return 200 'OK';
13+
add_header Content-Type text/plain;
14+
}
1715

1816
error_page 500 502 503 504 /50x.html;
1917
location = /50x.html {

frontend/package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "interview-prep",
3-
"version": "0.0.0",
3+
"version": "0.1.0",
44
"scripts": {
55
"ng": "ng",
66
"start": "ng serve --host 0.0.0.0 --port 4200 --configuration local",
Loading

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "interview-prep",
3+
"version": "0.1.0",
4+
"private": true
5+
}

terraform/environments/development/main.tf

+5-12
Original file line numberDiff line numberDiff line change
@@ -47,31 +47,22 @@ module "rds" {
4747
environment = var.environment
4848
}
4949

50-
module "service_discovery" {
51-
source = "../../modules/service_discovery"
52-
environment = var.environment
53-
vpc_id = module.vpc.vpc_id
54-
}
55-
5650
module "ecs" {
5751
source = "../../modules/ecs"
52+
project_name = var.project_name
5853
environment = var.environment
5954
region = var.region
6055
frontend_image = "interview-prep-frontend"
6156
frontend_repository_url = module.ecr.frontend_repository_url
6257
backend_image = "interview-prep-backend"
6358
backend_repository_url = module.ecr.backend_repository_url
6459
database_url = module.rds.db_instance_endpoint
65-
public_subnet_ids = [module.subnets.public_subnet_a_id, module.subnets.public_subnet_b_id]
6660
private_subnet_ids = [module.subnets.private_subnet_a_id, module.subnets.private_subnet_b_id]
6761
frontend_sg_id = module.security_groups.frontend_sg_id
6862
backend_sg_id = module.security_groups.backend_sg_id
6963
alb_sg_id = module.security_groups.alb_sg_id
70-
bastion_sg_id = module.security_groups.bastion_sg_id
7164
ecs_task_execution_role = module.iam.ecs_task_execution_role_arn
7265
ecs_task_role_arn = module.iam.ecs_task_role_arn
73-
service_discovery_namespace_id = module.service_discovery.namespace_id
74-
backend_service_arn = module.service_discovery.backend_service_arn
7566
db_username = var.db_username
7667
db_password = var.db_password
7768
frontend_target_group_arn = module.load_balancer.frontend_target_group_arn
@@ -118,7 +109,7 @@ module "lambda_migrate" {
118109
function_name = "${var.environment}-interview-prep-migrate"
119110
handler = "index.handler"
120111
runtime = "nodejs20.x"
121-
timeout = 60
112+
timeout = 300
122113
memory_size = 128
123114
lambda_package = var.lambda_package_migrate
124115
lambda_subnet_ids = [module.subnets.private_subnet_a_id, module.subnets.private_subnet_b_id]
@@ -160,7 +151,8 @@ module "load_balancer" {
160151
security_groups = [module.security_groups.alb_sg_id]
161152
public_subnet_ids = [module.subnets.public_subnet_a_id, module.subnets.public_subnet_b_id]
162153
vpc_id = module.vpc.vpc_id
163-
health_check_path = "/"
154+
frontend_health_check_path = "/health"
155+
backend_health_check_path = "/health"
164156
}
165157

166158
module "dns" {
@@ -181,4 +173,5 @@ module "api_gateway" {
181173
lb_dns_name = module.load_balancer.lb_dns_name
182174
region = var.region
183175
certificate_arn = var.certificate_arn
176+
cors_origin = "http://dev.interviewprep.onyxdevtutorials.com"
184177
}

terraform/environments/development/outputs.tf

-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# environments/development/outputs.tf
2-
31
output "vpc_id" {
42
description = "The ID of the VPC"
53
value = module.vpc.vpc_id
@@ -95,11 +93,6 @@ output "alb_sg_id" {
9593
value = module.security_groups.alb_sg_id
9694
}
9795

98-
output "backend_service_arn" {
99-
description = "The ARN of the backend service in service discovery"
100-
value = module.ecs.backend_service_arn
101-
}
102-
10396
output "db_instance_endpoint" {
10497
description = "The endpoint of the RDS instance"
10598
value = module.rds.db_instance_endpoint

0 commit comments

Comments
 (0)