mirror of
https://github.com/hknsh/project-knedita.git
synced 2024-11-28 09:31:16 +00:00
Fixed Docker and tests. Replaced ioredis.
This commit is contained in:
parent
14e3990d76
commit
4e96576f5d
33 changed files with 1183 additions and 616 deletions
|
@ -25,7 +25,6 @@ SERVER_PORT=<placeholder>
|
|||
JWT_ACCESS_SECRET=<placeholder>
|
||||
|
||||
# Localstack - The data can be fake (Change this to real data on production)
|
||||
DOCKER_HOST=unix:///var/run/docker.sock
|
||||
SERVICES=s3
|
||||
AWS_ACCESS_KEY_ID=<placeholder>
|
||||
AWS_SECRET_ACCESS_KEY=<placeholder>
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -8,4 +8,5 @@ client
|
|||
dist
|
||||
pnpm-lock.yaml
|
||||
package_backup.json
|
||||
logs/
|
||||
logs/
|
||||
docker.env
|
11
.swcrc
11
.swcrc
|
@ -7,7 +7,16 @@
|
|||
"dynamicImport": true
|
||||
},
|
||||
"target": "es2020",
|
||||
"baseUrl": "./"
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"clients/*": ["clients/*"],
|
||||
"config/*": ["config/*"],
|
||||
"controllers/*": ["controllers/*"],
|
||||
"interfaces/*": ["interfaces/*"],
|
||||
"helpers/*": ["helpers/*"],
|
||||
"middlewares/*": ["middlewares/*"],
|
||||
"services/*": ["services/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["@types/", "interfaces/"],
|
||||
"module": {
|
||||
|
|
|
@ -23,11 +23,12 @@ RUN npm i pm2 -g
|
|||
COPY --from=builder /app/package*.json ./
|
||||
COPY --from=builder /app/prisma ./prisma/
|
||||
COPY --from=builder /app/dist ./dist/
|
||||
COPY --from=builder /app/docker.env ./
|
||||
|
||||
RUN mv docker.env .env
|
||||
|
||||
RUN npm ci
|
||||
|
||||
RUN npm run prisma:deploy
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["npm", "run", "prod:start"]
|
|
@ -1,5 +1,10 @@
|
|||
version: '3.8'
|
||||
|
||||
networks:
|
||||
localstack-net:
|
||||
name: localstack-net
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:alpine
|
||||
|
@ -8,7 +13,7 @@ services:
|
|||
ports:
|
||||
- 5432:5432
|
||||
env_file:
|
||||
- .env
|
||||
- docker.env
|
||||
volumes:
|
||||
- postgres:/var/lib/postgresql/data
|
||||
|
||||
|
@ -22,6 +27,24 @@ services:
|
|||
volumes:
|
||||
- redis:/data
|
||||
|
||||
localstack:
|
||||
image: localstack/localstack
|
||||
container_name: localstack_main
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- localstack-net
|
||||
ports:
|
||||
- 4566:4566
|
||||
- 4572:4572
|
||||
env_file:
|
||||
- docker.env
|
||||
volumes:
|
||||
- localstack:/data
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
|
||||
volumes:
|
||||
postgres:
|
||||
name: backend-db
|
||||
redis:
|
||||
driver: local
|
||||
localstack:
|
||||
|
|
|
@ -19,7 +19,7 @@ services:
|
|||
- redis
|
||||
- localstack
|
||||
env_file:
|
||||
- .env
|
||||
- docker.env
|
||||
|
||||
postgres:
|
||||
image: postgres:alpine
|
||||
|
@ -28,7 +28,7 @@ services:
|
|||
ports:
|
||||
- 5432:5432
|
||||
env_file:
|
||||
- .env
|
||||
- docker.env
|
||||
volumes:
|
||||
- postgres:/var/lib/postgresql/data
|
||||
|
||||
|
@ -42,7 +42,7 @@ services:
|
|||
- 4566:4566
|
||||
- 4572:4572
|
||||
env_file:
|
||||
- .env
|
||||
- docker.env
|
||||
volumes:
|
||||
- localstack:/data
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
|
|
30
docker.env.example
Normal file
30
docker.env.example
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Environment
|
||||
NODE_ENV=production
|
||||
|
||||
# Postgres config
|
||||
POSTGRES_DB=<placeholder>
|
||||
POSTGRES_USER=<placeholder>
|
||||
POSTGRES_PASSWORD=<placeholder>
|
||||
DB_HOST=postgres
|
||||
|
||||
DATABASE_URL=postgresql://<placeholder>:<placeholder>@${DB_HOST}:<placeholder>/${POSTGRES_DB}?schema=<placeholder>
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=redis
|
||||
|
||||
REDIS_PORT=<placeholder>
|
||||
REDIS_PASSWORD=<placeholder>
|
||||
|
||||
# Express
|
||||
SERVER_PORT=<placeholder>
|
||||
|
||||
# Security
|
||||
JWT_ACCESS_SECRET=<placeholder>
|
||||
|
||||
# Localstack - The data can be fake
|
||||
SERVICES=s3
|
||||
AWS_ACCESS_KEY_ID=<placeholder>
|
||||
AWS_SECRET_ACCESS_KEY=<placeholder>
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_DEFAULT_OUTPUT=json
|
||||
AWS_BUCKET=<placeholder>
|
|
@ -1,9 +0,0 @@
|
|||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
setupFilesAfterEnv: ['<rootDir>/setupTest.ts'],
|
||||
transform: {
|
||||
'^.+\\.(t|j)sx?$': '@swc/jest'
|
||||
}
|
||||
}
|
17
jest.config.ts
Normal file
17
jest.config.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { pathsToModuleNameMapper } from 'ts-jest'
|
||||
import { compilerOptions } from './tsconfig.json'
|
||||
import type { JestConfigWithTsJest } from 'ts-jest'
|
||||
|
||||
const jestConfig: JestConfigWithTsJest = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
setupFilesAfterEnv: ['<rootDir>/setupTest.ts'],
|
||||
transform: {
|
||||
'^.+\\.(t|j)sx?$': '@swc/jest'
|
||||
},
|
||||
roots: ['<rootDir>'],
|
||||
modulePaths: [compilerOptions.baseUrl],
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths)
|
||||
}
|
||||
|
||||
export default jestConfig
|
1569
package-lock.json
generated
1569
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -5,7 +5,7 @@
|
|||
"scripts": {
|
||||
"build": "swc src -d dist",
|
||||
"dev:start": "ts-node-dev -r tsconfig-paths/register --transpile-only --respawn src/server.ts",
|
||||
"docker": "docker compose up -d",
|
||||
"docker": "docker compose --env-file docker.env up -d",
|
||||
"docker:build": "docker build -t api . && docker compose up -d",
|
||||
"docker:db": "docker compose -f docker-compose.db.yml up -d",
|
||||
"docker:seed": "docker exec -it api npm run prisma:seed",
|
||||
|
@ -16,8 +16,7 @@
|
|||
"prisma:generate": "npx prisma generate",
|
||||
"prisma:seed": "prisma db seed",
|
||||
"prisma:studio": "npx prisma studio",
|
||||
"prisma:deploy": "npx prisma migrate deploy",
|
||||
"prod:start": "pm2-runtime start dist/server.js",
|
||||
"prod:start": "npx prisma migrate deploy && pm2-runtime start dist/server.js",
|
||||
"test": "jest"
|
||||
},
|
||||
"ts-standard": {
|
||||
|
@ -54,7 +53,7 @@
|
|||
"eslint-plugin-import": "^2.28.0",
|
||||
"eslint-plugin-n": "^16.0.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"jest": "^29.5.0",
|
||||
"jest": "^29.6.2",
|
||||
"nodemon": "^3.0.1",
|
||||
"pm2": "^4.2.3",
|
||||
"prettier": "^3.0.0",
|
||||
|
@ -80,9 +79,10 @@
|
|||
"multer": "^1.4.5-lts.1",
|
||||
"multer-s3": "^3.0.1",
|
||||
"rate-limit-redis": "^3.0.2",
|
||||
"redis": "^4.6.7",
|
||||
"sharp": "^0.32.3",
|
||||
"socket.io": "^4.7.2",
|
||||
"validator": "^13.9.0",
|
||||
"winston": "^3.10.0"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import prisma from './src/clients/prisma-client'
|
||||
import redis from './src/clients/redis-client'
|
||||
|
||||
process.env.NODE_ENV = 'development'
|
||||
|
||||
afterAll(async () => {
|
||||
redis.disconnect()
|
||||
await redis.disconnect()
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
|
|
|
@ -9,6 +9,8 @@ import router from './routes'
|
|||
|
||||
const app = express()
|
||||
|
||||
// TODO: test socket io, emit notifications when create one.
|
||||
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
app.use(morganMiddleware)
|
||||
|
@ -23,7 +25,7 @@ app.use(cors({
|
|||
|
||||
app.use((_req, res) => {
|
||||
res.status(404).json({
|
||||
error: 'Not found'
|
||||
error: 'Endpoint not found'
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
import RedisClient from 'ioredis'
|
||||
import logger from 'helpers/logger'
|
||||
import { createClient, type RedisClientOptions } from 'redis'
|
||||
|
||||
const redisPort = parseInt(process.env.REDIS_PORT ?? '6379', 10)
|
||||
const redisHost = process.env.REDIS_HOST ?? '127.0.0.1'
|
||||
const redisPassword = process.env.REDIS_PASSWORD ?? ''
|
||||
const redisHost = process.env.REDIS_HOST ?? ''
|
||||
const redisPort = process.env.REDIS_PORT ?? ''
|
||||
|
||||
const redis = new RedisClient(
|
||||
`redis://:${redisPassword}@${redisHost}:${redisPort}/0`
|
||||
)
|
||||
const redisConfig: RedisClientOptions = {
|
||||
url: `redis://:${redisPassword}@${redisHost}:${redisPort}/0`
|
||||
}
|
||||
|
||||
const redis = createClient(redisConfig)
|
||||
|
||||
redis.connect().then(() => {
|
||||
logger.info('Successfully connected to Redis')
|
||||
}).catch((e: Error) => {
|
||||
logger.error(`Error while connecting to Redis: ${e.message}`)
|
||||
})
|
||||
|
||||
redis.on('error', async (e: Error) => {
|
||||
logger.error(`Error in Redis client: ${e.message}`)
|
||||
})
|
||||
|
||||
export default redis
|
||||
|
|
|
@ -10,6 +10,6 @@ const comments = {
|
|||
fetch: commentFetchController,
|
||||
fetchLikes: commentFetchLikesController,
|
||||
update: commentUpdateController
|
||||
}
|
||||
} as const
|
||||
|
||||
export default comments
|
||||
|
|
|
@ -10,6 +10,6 @@ const post = {
|
|||
fetch: postFetchInfoController,
|
||||
fetchLikes: postFetchLikesController,
|
||||
update: postUpdateController
|
||||
}
|
||||
} as const
|
||||
|
||||
export default post
|
||||
|
|
|
@ -22,6 +22,6 @@ const user = {
|
|||
signup: userSignupController,
|
||||
update: userUpdateController,
|
||||
uploadPicture: userUploadPictureController
|
||||
}
|
||||
} as const
|
||||
|
||||
export default user
|
||||
|
|
|
@ -20,8 +20,7 @@ const limiter = rateLimit({
|
|||
|
||||
// Store configuration
|
||||
store: new RedisStore({
|
||||
// @ts-expect-error - `call` function is not present in @types/ioredis
|
||||
sendCommand: async (...args: string[]) => await redis.call(...args)
|
||||
sendCommand: async (...args: string[]) => await redis.sendCommand(args)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import app from './app'
|
||||
import { createServer } from 'http'
|
||||
import logger from 'helpers/logger'
|
||||
import createSocketIOInstance from 'socket'
|
||||
import createSocketIOInstance from './socket'
|
||||
|
||||
const server = createServer(app)
|
||||
const io = createSocketIOInstance(server)
|
||||
|
|
|
@ -10,6 +10,6 @@ const comment = {
|
|||
fetch: commentFetchService,
|
||||
fetchLikes: commentFetchLikesService,
|
||||
update: commentUpdateService
|
||||
}
|
||||
} as const
|
||||
|
||||
export default comment
|
||||
|
|
|
@ -10,6 +10,6 @@ const post = {
|
|||
fetch: postFetchInfoService,
|
||||
fetchLikes: postFetchLikesService,
|
||||
update: postUpdateService
|
||||
}
|
||||
} as const
|
||||
|
||||
export default post
|
||||
|
|
|
@ -22,6 +22,6 @@ const user = {
|
|||
signup: userSignupService,
|
||||
update: userUpdateService,
|
||||
uploadPicture: userUploadPictureService
|
||||
}
|
||||
} as const
|
||||
|
||||
export default user
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 9.1 KiB |
|
@ -2,7 +2,7 @@ import app from '../../app'
|
|||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import app from '../../app'
|
|||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import app from '../../app'
|
|||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let postId: string
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import app from '../../app'
|
|||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import request from 'supertest'
|
|||
import app from '../../app'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
@ -22,7 +22,7 @@ describe('POST /user/auth', () => {
|
|||
.expect(400)
|
||||
|
||||
expect(response.body).toHaveProperty('error')
|
||||
expect(response.body.error).toBe('User does not exists')
|
||||
expect(response.body.error).toBe('Invalid email or password')
|
||||
})
|
||||
|
||||
it('should respond with a error if receive an invalid email or password', async () => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import app from '../../app'
|
||||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import app from '../../app'
|
|||
import request from 'supertest'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import request from 'supertest'
|
|||
import app from '../../app'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import request from 'supertest'
|
|||
import app from '../../app'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
import deleteUser from '../utils/delete-user'
|
||||
import type User from '../../interfaces/user'
|
||||
import type User from 'interfaces/user'
|
||||
|
||||
let user: User
|
||||
|
||||
|
|
|
@ -1,46 +1,25 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
/* Language and Environment */
|
||||
"target": "es2016",
|
||||
/* Modules */
|
||||
"target": "ESNext",
|
||||
"module": "commonjs",
|
||||
"rootDir": "./",
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"clients/*": [
|
||||
"clients/*"
|
||||
],
|
||||
"config/*": [
|
||||
"config/*"
|
||||
],
|
||||
"controllers/*": [
|
||||
"controllers/*"
|
||||
],
|
||||
"interfaces/*": [
|
||||
"interfaces/*"
|
||||
],
|
||||
"lib/*": [
|
||||
"lib/*"
|
||||
],
|
||||
"middlewares/*": [
|
||||
"middlewares/*"
|
||||
],
|
||||
"services/*": [
|
||||
"services/*"
|
||||
],
|
||||
"clients/*": ["clients/*"],
|
||||
"config/*": ["config/*"],
|
||||
"controllers/*": ["controllers/*"],
|
||||
"interfaces/*": ["interfaces/*"],
|
||||
"helpers/*": ["helpers/*"],
|
||||
"middlewares/*": ["middlewares/*"],
|
||||
"services/*": ["services/*"]
|
||||
},
|
||||
"typeRoots": [
|
||||
"./src/@types",
|
||||
"./node_modules/@types"
|
||||
],
|
||||
/* Emit */
|
||||
"typeRoots": ["./src/@types", "./node_modules/@types"],
|
||||
"outDir": "./dist",
|
||||
"removeComments": true,
|
||||
/* Interop Constraints */
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
/* Type Checking */
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue