Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e842a19
feat(infra): setup multi-stage dockerfiles and compose orchestration
soorq Apr 10, 2026
8019995
chore: resolve merge conflicts
soorq Apr 10, 2026
90889cb
chore: add api boilerplate packages
soorq Apr 10, 2026
a231cdb
feat(bootstrap): implement unified bootstrap service and fix fastify …
soorq Apr 10, 2026
330ee74
feat(bootstrap): implement zod ecosystem contracts
soorq Apr 10, 2026
97d3560
chore: resolve merge conflicts
soorq Apr 10, 2026
ae98bf2
ci: add docker build check workflow
soorq Apr 10, 2026
656beec
docs(gh): setup issue templates and community configuration
soorq Apr 10, 2026
084467e
Merge branch 'dev' of https://github.com/Task-Tracker-Lab/task-tracke…
soorq Apr 10, 2026
4e56a09
feat: implement observability stack prometheus
soorq Apr 10, 2026
7596057
feat(dump): implement module
soorq Apr 10, 2026
f74f19d
feat(shared): add health module and integrate into app module
soorq Apr 10, 2026
5ea3872
resolve: resolve merge error
soorq Apr 10, 2026
23cf64a
resolve: resolve merge error
soorq Apr 10, 2026
9ba930d
chore: setup husky, commitlint and lint-staged
maksberegovoi Apr 10, 2026
9033200
resolve: resolve merge error
soorq Apr 10, 2026
3063d3f
resolve: resolve merge error
soorq Apr 10, 2026
62b8b15
chore: resolve error with merges
soorq Apr 10, 2026
c951454
chore: bump docker pnpm
soorq Apr 10, 2026
0bf1056
feat: add users module and standardized API error responses
soorq Apr 10, 2026
ebf5bf0
feat: core domain entity type / add service and repository
soorq Apr 10, 2026
32f7f53
chore: add auth module arch
soorq Apr 10, 2026
d1dfd32
feat(shared): add ApiBaseController decorator for global swagger resp…
maksberegovoi Apr 11, 2026
a6f81eb
feat(swagger): add reusable swagger error decorators
maksberegovoi Apr 11, 2026
525449c
docs(users): describe user api endpoints in swagger
maksberegovoi Apr 11, 2026
eb60b41
feat(auth): scaffold auth controller with route stubs
maksberegovoi Apr 11, 2026
c7afb1a
feat(auth): scaffold auth service with dependencies
maksberegovoi Apr 11, 2026
28d1235
feat(auth): add zod-based dtos for authentication and 2fa
maksberegovoi Apr 11, 2026
0f4a5c5
refactor(swagger): rename ApiRequireAuth to ApiUnauthorized for bette…
maksberegovoi Apr 11, 2026
037c024
docs(auth): describe auth api endpoints in swagger
maksberegovoi Apr 11, 2026
f778e5c
chore: feat libs per auth flow / rename endpoints
soorq Apr 11, 2026
ab77373
chore: feat per auth module libs and redis
soorq Apr 11, 2026
cb834fd
feat(auth): intergrate with jwt module and update config module
soorq Apr 11, 2026
d4c4f9c
feat(redis):chore(infra): integrate redis and setup correct infra
soorq Apr 11, 2026
cf60222
feat(auth):chore(ua-parser): integrate logic per register flow #1
soorq Apr 11, 2026
759a6f9
feat(auth): integrate logic per sign flow #2
soorq Apr 11, 2026
4174a2c
feat(mail): add mail module and Handlebars templates
maksberegovoi Apr 11, 2026
84d9764
feat(user): implement user controller with facade integration
maksberegovoi Apr 11, 2026
552b08b
feat(auth): integrate logic per reset password flow #3 / bug with otp…
soorq Apr 11, 2026
6d43059
fix(auth): fix OTP verification bypass in AuthService
maksberegovoi Apr 12, 2026
62719c4
fix(auth): correct session expiration time in signIn and verify
maksberegovoi Apr 12, 2026
e33fde7
fix(email): fix verification code copy formatting
maksberegovoi Apr 12, 2026
64de91e
fix(infra): specify postgres user and db for healthcheck
maksberegovoi Apr 12, 2026
c358765
fix(cors): normalize origins to hostname to resolve local blocks
maksberegovoi Apr 12, 2026
c877b81
fix(compose): resolve error with depends and correct output per users
soorq Apr 12, 2026
187b121
feat(s3):chore(aws): add s3 module at libs and env file
soorq Apr 12, 2026
dabedca
refactor(auth): fix type inconsistencies in user models
soorq Apr 12, 2026
4f216db
feat(infra): setup migrations, optimize pg pool, and add ghcr workflow
soorq Apr 12, 2026
9b20271
chore(auth): add password reset and sign-up confirmation Swagger docu…
maksberegovoi Apr 13, 2026
b2703ba
chore: resolve merge error
soorq Apr 13, 2026
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
32 changes: 28 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --- APP ---
PORT=3000
NODE_ENV=development
CORS_ALLOWED_ORIGINS=http://localhost:3000
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000

# --- POSTGRES ---
DB_USERNAME=admin
Expand All @@ -18,6 +18,30 @@ DB_SCHEMA=base
DATABASE_URL=postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost:${DB_PORT}/${DB_DATABASE}

# --- REDIS ---
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_EXTERNAL_PORT=6380
# in the docker network will be, not show port redis, at prod env
# REDIS_HOST=redis
# at development mode
REDIS_HOST=127.0.0.1
REDIS_PORT=7000

JWT_ACCESS_SECRET=same-same-same-same-same
JWT_ACCESS_EXPIRES_IN=15m

JWT_REFRESH_SECRET=same-same-same-same-same
JWT_REFRESH_EXPIRES_IN=15m

# --- MAIL SETTINGS ---
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_USER=example@gmail.com

# 16x password
MAIL_PASSWORD=xxxxxxxxyyyyyyyy
MAIL_FROM_NAME="Task Tracker"
MAIL_FROM_EMAIL=example@gmail.com

S3_BUCKET_NAME=''
S3_ENDPOINT=''
S3_REGION=''
S3_ACCESS_KEY=''
S3_SECRET_KEY=''
19 changes: 10 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Build and Push

on:
push:
branches: [dev, main]
branches: [dev, main, feat/**]

env:
REGISTRY: ghcr.io
Expand All @@ -13,20 +13,20 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
# packages: write
packages: write

steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# - name: Log in to the Container registry
# uses: docker/login-action@v3
# with:
# registry: ${{ env.REGISTRY }}
# username: ${{ github.actor }}
# password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
Expand All @@ -36,13 +36,14 @@ jobs:
tags: |
type=ref,event=branch
type=sha,format=short
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.prod
push: false # add true, if your setup variables
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
pull_request:
branches: [dev, main]
branches: [dev, main, "feat/**"]
push:
branches: [dev, main]
branches: [dev, main, "feat/**"]

jobs:
quality-check:
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile.prod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ COPY . .
RUN pnpm run build

RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm prune --prod
pnpm prune --prod --ignore-scripts

FROM node:20-alpine AS runner
WORKDIR /app
Expand All @@ -28,7 +28,9 @@ ENV PORT=3000

COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/migrations ./migrations
COPY --from=build /app/package.json ./
COPY --from=build /app/drizzle.config.ts ./drizzle.config.ts

EXPOSE 3000

Expand Down
7 changes: 7 additions & 0 deletions infra/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Command to run infra at dev mode

Run it by pwd at root! Not include at this dir

```sh
docker compose -f ./infra/dev/compose.dev.yaml --env-file .env --profile infra up --build -d -V
```
54 changes: 0 additions & 54 deletions infra/compose.dev.yaml

This file was deleted.

41 changes: 41 additions & 0 deletions infra/dev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Файл для фронт разрабов

## Описание

Данный конфиг разворачивает полный инстанс бэкенда (API + DB + Redis)
для локальной разработки фронтенда.

## ТРЕБОВАНИЯ:

1. Положить актуальный файл .env в директорию с этим файлом
(путь: ./infra/dev/.env).
2. Наличие Docker Desktop / Docker Engine.

## ЗАПУСК:

Выполните команду из корня проекта:

```sh
docker compose -f ./infra/dev/compose.dev.yaml --profile infra up --pull always --build -d -V
```

## ЧТО ВНУТРИ:

- API: http://localhost:3000
- Postgres: localhost:6000 (пароли и база берутся из .env)
- Redis: localhost:7000

## ОСОБЕННОСТИ:

- Авто-миграции: Приложение само накатит SQL-схему при старте.
- Healthchecks: Контейнер API не поднимется, пока DB и Redis
не станут доступны (status: healthy).
- Изоляция: Используется выделенная сеть 'task-tracker-gateway'.

## RESET:

Если нужно полностью очистить базу и начать с нуля:

```sh
docker compose -f ./infra/dev/compose.dev.yaml --profile infra down -v
```
83 changes: 83 additions & 0 deletions infra/dev/compose.dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
version: "3.9"

name: task-tracker-api

services:
api:
hostname: api
container_name: api
image: ghcr.io/task-tracker-lab/task-tracker-backend:feat-user
env_file:
- .env
ports:
- "3000:3000"
depends_on:
database:
condition: service_healthy
redis:
condition: service_healthy
networks:
- backend
deploy:
resources:
limits:
cpus: "2.0"
memory: 1024M
reservations:
cpus: "0.5"
memory: 256M

database:
hostname: database
container_name: database
image: postgres:16-alpine
restart: always
env_file:
- .env
environment:
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_DATABASE}
ports:
- "6000:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test:
[
"CMD-SHELL",
'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -q || exit 1',
]
interval: 5s
timeout: 5s
retries: 5
profiles: ["infra"]

redis:
hostname: redis
container_name: redis
image: redis:7-alpine
restart: always
ports:
- "7000:6379"
command: redis-server --save 60 1 --loglevel notice
volumes:
- redis_data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
profiles: ["infra"]

volumes:
postgres_data:
redis_data:

networks:
backend:
name: task-tracker-gateway
19 changes: 14 additions & 5 deletions libs/bootstrap/src/setups/cors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,22 @@ export function setupCors(app: NestFastifyApplication, origins: string[]) {
return callback(null, true);
}

const { hostname } = new URL(origin);
try {
const { hostname } = new URL(origin);
const allowedHostnames = origins.map((o) => new URL(o).hostname);

if (origins.some((o) => hostname === o || hostname.endsWith(`.${o}`))) {
callback(null, origin);
}
if (
allowedHostnames.some(
(allowed) => hostname === allowed || hostname.endsWith(`.${allowed}`),
)
) {
return callback(null, origin);
}

callback(new Error('Not allowed by CORS'), false);
callback(new Error('Not allowed by CORS'), false);
} catch (e) {
callback(new Error('Invalid origin format'), false);
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
Expand Down
5 changes: 4 additions & 1 deletion libs/bootstrap/src/setups/swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { cleanupOpenApiDoc } from 'nestjs-zod';
import type { NestFastifyApplication } from '@nestjs/platform-fastify';
import type { SwaggerOptions } from '../interfaces';
import { SWAGGER_DEFAULTS } from '../configs/swagger';
import { GlobalErrorResponse } from 'src/shared/error/schema';

export async function setupSwagger(app: NestFastifyApplication, options: SwaggerOptions = {}) {
const { title, description, version, path, server } = {
Expand All @@ -22,7 +23,9 @@ export async function setupSwagger(app: NestFastifyApplication, options: Swagger
if (stage) builder.addServer(`https://api.${stage}`, 'Staging');
if (domain) builder.addServer(`https://api.${domain}`, 'Production');

const document = SwaggerModule.createDocument(app, builder.build());
const document = SwaggerModule.createDocument(app, builder.build(), {
extraModels: [GlobalErrorResponse.Output],
});

SwaggerModule.setup(path, app, cleanupOpenApiDoc(document), {
jsonDocumentUrl: `${path}/s/json`,
Expand Down
Loading
Loading