Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) 2026 CoverIt Labs. All Rights Reserved.
# Proprietary and confidential. Unauthorized use is strictly prohibited.
# See LICENSE file in the project root for full license information.

name: Tests

on:
push:
branches: [main, develop]
paths-ignore:
- "**.md"
- "docs/**"
- ".github/**"
- ".husky/**"
- ".vscode/**"
pull_request:
branches: [main, develop]
paths-ignore:
- "**.md"
- "docs/**"
- ".github/**"
- ".husky/**"
- ".vscode/**"

permissions:
contents: read
packages: read
pull-requests: write

jobs:
test:
uses: CoveritLabs/.github/.github/workflows/test-and-coverage.yml@main
secrets: inherit
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ node_modules
# Build output
dist

# Test / coverage
coverage

# Editor directories and files
.vscode/*
!.vscode/extensions.json
Expand All @@ -32,3 +35,5 @@ dist
.env
.env.local
.env.*.local

/src/generated/prisma
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@coveritlabs:registry=https://npm.pkg.github.com
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"tabWidth": 2
"tabWidth": 2,
"printWidth": 120
}
20 changes: 17 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ FROM node:22-alpine AS build
WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
RUN --mount=type=secret,id=npm_token \
printf "@coveritlabs:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)\n" > .npmrc \
&& npm ci --ignore-scripts \
&& rm -f .npmrc

COPY prisma ./prisma
COPY prisma.config.ts ./
RUN npx prisma generate

COPY tsconfig.json ./
COPY src ./src
Expand All @@ -18,12 +25,19 @@ WORKDIR /app
ENV NODE_ENV=production

COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts --omit=dev
RUN --mount=type=secret,id=npm_token \
printf "@coveritlabs:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)\n" > .npmrc \
&& npm ci --ignore-scripts --omit=dev \
&& rm -f .npmrc

COPY prisma ./prisma
COPY prisma.config.ts ./
RUN npx prisma generate

COPY --from=build /app/dist ./dist

EXPOSE 3000

USER node

CMD ["node", "dist/index.js"]
CMD ["sh", "-c", "npx prisma db push && node dist/index.js"]
22 changes: 22 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Build stage for development
FROM node:22-alpine

WORKDIR /app

# Install dependencies (including devDependencies)
COPY package.json package-lock.json ./
RUN --mount=type=secret,id=npm_token \
printf "@coveritlabs:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)\n" > .npmrc \
&& npm ci --ignore-scripts \
&& rm -f .npmrc

COPY prisma ./prisma
COPY prisma.config.ts ./
RUN npx prisma generate

# Source code will be mounted at runtime via docker-compose
ENV NODE_ENV=development

EXPOSE 3000

CMD ["sh", "-c", "npx prisma db push && npx nodemon"]
10 changes: 0 additions & 10 deletions docker-compose.local.yml

This file was deleted.

49 changes: 49 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Proprietary and confidential. Unauthorized use is strictly prohibited.
# See LICENSE file in the project root for full license information.

name: coverit

services:
api:
image: ghcr.io/coveritlabs/coverit-api:${API_TAG:-dev}
Expand All @@ -11,4 +13,51 @@ services:
environment:
- NODE_ENV=${NODE_ENV:-development}
- PORT=3000
- DATABASE_URL=postgresql://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@db:5432/${DB_NAME:-coverit}?schema=public
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET:-change-me-in-production}
- JWT_ACCESS_EXPIRY=${JWT_ACCESS_EXPIRY:-15m}
- JWT_REFRESH_EXPIRY_SECONDS=${JWT_REFRESH_EXPIRY_SECONDS:-604800}
- RESET_TOKEN_TTL_SECONDS=${RESET_TOKEN_TTL_SECONDS:-900}
- CORS_ORIGINS=${CORS_ORIGINS:-http://localhost:5173}
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy

db:
image: postgres:18
container_name: coverit-postgres
environment:
- POSTGRES_USER=${DB_USER:-postgres}
- POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
- POSTGRES_DB=${DB_NAME:-coverit}
volumes:
- postgres_data:/var/lib/postgresql
- ./database:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres}"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped

redis:
image: redis:7-alpine
container_name: coverit-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped

volumes:
postgres_data:
redis_data:
66 changes: 38 additions & 28 deletions docker.sh
Original file line number Diff line number Diff line change
@@ -1,63 +1,73 @@
#!/bin/sh

# Copyright (c) 2026 CoverIt Labs. All Rights Reserved.
# Proprietary and confidential. Unauthorized use is strictly prohibited.
# See LICENSE file in the project root for full license information.


# Copyright (c) 2026 CoverIt Labs. All Rights Reserved.
# Proprietary and confidential. Unauthorized use is strictly prohibited.
# See LICENSE file in the project root for full license information.


# Copyright (c) 2026 CoverIt Labs. All Rights Reserved.
# Proprietary and confidential. Unauthorized use is strictly prohibited.
# See LICENSE file in the project root for full license information.

# Usage:
# ./docker.sh up → start with :dev (default)
# ./docker.sh up --tag latest → start with :latest
# ./docker.sh up --tag 1.2.3 → start with specific version
# ./docker.sh up --local → build from local source
# ./docker.sh down → stop all services
# ./docker.sh logs → tail logs
# ./docker.sh up → remote image + cloud db/redis
# ./docker.sh up --local → local dev build + hot-reload + local db/redis
# ./docker.sh up --test-prod → local prod build + cloud db/redis
# ./docker.sh up --tag latest → remote image (specific tag) + cloud db/redis

print_help() {
echo "Usage: $0 [up|down|logs] [--tag <tag>] [--local]"
echo
echo "Commands:"
echo " up Start services (default tag: dev)"
echo " down Stop all services"
echo " logs Tail logs of all services"
echo
echo "Options:"
echo " --tag <tag> Specify API image tag (default: dev)"
echo " --local Build API image from local source"
echo "Usage: $0 [up|down|logs] [--tag <tag>] [--local] [--test-prod]"
}


set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
export API_DIR="$SCRIPT_DIR"

CMD="${1:-up}"
shift 2>/dev/null || true

TAG="dev"
# Defaults
export API_TAG="dev"
LOCAL=false
TEST_PROD=false

while [ $# -gt 0 ]; do
case "$1" in
--tag) TAG="$2"; shift 2 ;;
--tag) export API_TAG="$2"; shift 2 ;;
--local) LOCAL=true; shift ;;
--test-prod) TEST_PROD=true; shift ;;
-h|--help) print_help; exit 0 ;;
*) echo "Unknown flag: $1"; exit 1 ;;
esac
done

# Only --local uses local db/redis. Everything else connects to cloud.
if [ "$LOCAL" = true ]; then
echo "Starting API in local dev mode (local db + redis)..."
EXEC_CMD="docker compose -f docker-compose.yml -f overrides/api.dev.yml"
elif [ "$TEST_PROD" = true ]; then
echo "Starting API in Production Test mode (local prod build + cloud)..."
EXEC_CMD="docker compose -f docker-compose.yml -f overrides/api.cloud.yml -f overrides/api.test.yml"
else
echo "Starting API using remote image (API_TAG=$API_TAG) + cloud..."
EXEC_CMD="docker compose -f docker-compose.yml -f overrides/api.cloud.yml"
fi

case "$CMD" in
up)
if [ "$LOCAL" = true ]; then
echo "Starting services (local build)..."
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d --build
else
echo "Starting services (API_TAG=$TAG)..."
API_TAG="$TAG" docker compose up -d
fi
$EXEC_CMD up -d --build
;;
down)
docker compose down
$EXEC_CMD down
;;
logs)
docker compose logs -f
$EXEC_CMD logs -f
;;
*)
echo "Unknown command: $CMD"
Expand Down
28 changes: 28 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2026 CoverIt Labs. All Rights Reserved.
// Proprietary and confidential. Unauthorized use is strictly prohibited.
// See LICENSE file in the project root for full license information.

/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.test.ts'],
moduleFileExtensions: ['ts', 'js', 'json'],
moduleNameMapper: {
'^@api/(.*)$': '<rootDir>/src/api/$1',
'^@config/(.*)$': '<rootDir>/src/config/$1',
'^@lib/(.*)$': '<rootDir>/src/lib/$1',
'^@services/(.*)$': '<rootDir>/src/services/$1',
'^@utils/(.*)$': '<rootDir>/src/utils/$1',
'^@models/(.*)$': '<rootDir>/src/models/$1',
'^@constants/(.*)$': '<rootDir>/src/constants/$1',
'^@generated/(.*)$': '<rootDir>/src/generated/$1',
},
clearMocks: true,
collectCoverageFrom: [
'src/**/*.ts',
'!src/generated/**',
'!src/index.ts',
],
};
3 changes: 2 additions & 1 deletion nodemon.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"ignore": [
"src/**/*.spec.ts"
],
"exec": "ts-node src/index.ts"
"legacyWatch": true,
"exec": "ts-node -r tsconfig-paths/register src/index.ts"
}
19 changes: 19 additions & 0 deletions overrides/api.cloud.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2026 CoverIt Labs. All Rights Reserved.
# Proprietary and confidential. Unauthorized use is strictly prohibited.
# See LICENSE file in the project root for full license information.

# Cloud override — points API at cloud db/redis (e.g. Aiven).
# Requires DATABASE_URL, REDIS_URL, and JWT_SECRET in .env.
#
# Used by:
# ./docker.sh up → remote image + cloud
# ./docker.sh up --test-prod → local prod build + cloud

services:
api:
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
- JWT_SECRET=${JWT_SECRET}
depends_on: []
30 changes: 30 additions & 0 deletions overrides/api.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (c) 2026 CoverIt Labs. All Rights Reserved.
# Proprietary and confidential. Unauthorized use is strictly prohibited.
# See LICENSE file in the project root for full license information.

# Modular override for API development with hot-reload
# Inherits JWT_ACCESS_EXPIRY, JWT_REFRESH_EXPIRY_SECONDS, RESET_TOKEN_TTL_SECONDS,
# REDIS_URL, and CORS_ORIGINS from the base docker-compose.yml.

services:
api:
image: coverit-api-dev-local
build:
context: ${API_DIR}
dockerfile: Dockerfile.dev
secrets:
- npm_token
volumes:
- ${API_DIR}/src:/app/src
- ${API_DIR}/prisma:/app/prisma
- ${API_DIR}/prisma.config.ts:/app/prisma.config.ts
- ${API_DIR}/nodemon.json:/app/nodemon.json
- ${API_DIR}/tsconfig.json:/app/tsconfig.json
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:postgres@db:5432/coverit_dev?schema=public
- JWT_SECRET=dev-secret-do-not-use-in-production

secrets:
npm_token:
environment: GITHUB_TOKEN
Loading
Loading