Skip to content
Merged
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
11 changes: 11 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules
dist
.git
.github
infrastructure
*.log
.env
.env.*
test
coverage
README.md
2 changes: 2 additions & 0 deletions .github/workflows/api-dev.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Legacy Azure deploy — will be removed after DFX server migration cutover.
# New deploy pipeline: dfx-api-dev.yaml (Docker + SSH to dfxdev).
name: API DEV CI/CD

on:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/api-prd.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Legacy Azure deploy — will be removed after DFX server migration cutover.
# New deploy pipeline: dfx-api-prd.yaml (Docker + SSH to dfxprd).
name: API PRD CI/CD

on:
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/dfx-api-dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: DFX API DEV CI/CD

on:
# Auto-deploy is disabled until the DFX server migration cutover.
# The API still runs on Azure (see api-dev.yaml). Server-side prerequisites
# (deploy.sh dfx-api case, authorized_keys, compose) are not yet in place,
# so every develop push failed at the SSH deploy step. Re-add the push
# trigger when the migration goes live.
workflow_dispatch:

env:
DOCKER_TAGS: dfxswiss/dfx-api:beta

permissions:
contents: read

jobs:
build-and-deploy:
name: Build and deploy to DEV
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

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

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ env.DOCKER_TAGS }}
platforms: linux/arm64

- name: Install cloudflared
run: |
curl -fsSL https://github.com/cloudflare/cloudflared/releases/download/2025.4.0/cloudflared-linux-arm64 -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared

- name: Deploy
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_DEV_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
echo "${{ secrets.DEPLOY_DEV_SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
ssh -i ~/.ssh/deploy_key \
-o ProxyCommand="cloudflared access ssh --hostname ${{ secrets.DEPLOY_DEV_HOST }}" \
${{ secrets.DEPLOY_DEV_USER }}@${{ secrets.DEPLOY_DEV_HOST }} \
"dfx-api"
57 changes: 57 additions & 0 deletions .github/workflows/dfx-api-prd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: DFX API PRD CI/CD

on:
# Auto-deploy is disabled until the DFX server migration cutover.
# The API still runs on Azure (see api-prd.yaml). Server-side prerequisites
# (deploy.sh dfx-api case, authorized_keys, compose) are not yet in place,
# so every main push failed at the SSH deploy step. Re-add the push
# trigger when the migration goes live.
workflow_dispatch:

env:
DOCKER_TAGS: dfxswiss/dfx-api:latest

permissions:
contents: read

jobs:
build-and-deploy:
name: Build and deploy to PRD
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

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

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ env.DOCKER_TAGS }}
platforms: linux/arm64

- name: Install cloudflared
run: |
curl -fsSL https://github.com/cloudflare/cloudflared/releases/download/2025.4.0/cloudflared-linux-arm64 -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared

- name: Deploy
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_PRD_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
echo "${{ secrets.DEPLOY_PRD_SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
ssh -i ~/.ssh/deploy_key \
-o ProxyCommand="cloudflared access ssh --hostname ${{ secrets.DEPLOY_PRD_HOST }}" \
${{ secrets.DEPLOY_PRD_USER }}@${{ secrets.DEPLOY_PRD_HOST }} \
"dfx-api"
45 changes: 35 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
FROM node:latest AS builder
WORKDIR /app
COPY ./package.json ./
RUN npm install
COPY . .
# Multi-stage build for the dfx-api NestJS service.
#
# Built and pushed by .github/workflows/dfx-api-{dev,prd}.yaml as
# dfxswiss/dfx-api:{beta,latest} (linux/arm64).

FROM node:20-alpine AS builder

# node-gyp needs Python + a C/C++ toolchain to build native modules
RUN apk add --no-cache python3 make g++

USER node
WORKDIR /home/node

ADD --chown=node:node package.json .
ADD --chown=node:node package-lock.json .
RUN npm ci

ADD --chown=node:node . .
RUN npm run build
# Drop dev deps in-place after the build so the runtime stage can copy
# the already-compiled native modules without needing python3 + g++.
RUN npm prune --omit=dev


FROM node:20-alpine

USER node
WORKDIR /home/node

COPY --from=builder /home/node/package.json /home/node/package-lock.json ./
COPY --from=builder /home/node/node_modules ./node_modules
COPY --from=builder /home/node/dist ./dist
COPY --from=builder /home/node/migration ./migration

EXPOSE 3000

FROM node:latest
WORKDIR /app
COPY --from=builder /app ./
EXPOSE 3000:3000
CMD [ "npm", "run", "start" ]
CMD ["node", "dist/main.js"]
26 changes: 26 additions & 0 deletions migration/1780349782017-AddAccountMergeProcessingStartedAt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @typedef {import('typeorm').MigrationInterface} MigrationInterface
* @typedef {import('typeorm').QueryRunner} QueryRunner
*/

/**
* @class
* @implements {MigrationInterface}
*/
module.exports = class AddAccountMergeProcessingStartedAt1780349782017 {
name = 'AddAccountMergeProcessingStartedAt1780349782017'

/**
* @param {QueryRunner} queryRunner
*/
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "account_merge" ADD "processingStartedAt" TIMESTAMP`);
}

/**
* @param {QueryRunner} queryRunner
*/
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "account_merge" DROP COLUMN "processingStartedAt"`);
}
}
9 changes: 5 additions & 4 deletions src/subdomains/generic/kyc/controllers/kyc.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import { KycLevelDto, KycSessionDto, KycStepBase } from '../dto/output/kyc-info.
import { MergedDto } from '../dto/output/kyc-merged.dto';
import { Setup2faDto } from '../dto/output/setup-2fa.dto';
import { SumSubWebhookResult } from '../dto/sum-sub.dto';
import { KycContinueQueryDto, KycQueryDto } from '../dto/input/kyc-query.dto';
import { KycStepName } from '../enums/kyc-step-name.enum';
import { ReviewStatus } from '../enums/review-status.enum';
import { SumsubService } from '../services/integration/sum-sub.service';
Expand Down Expand Up @@ -119,8 +120,8 @@ export class KycController {
@Get()
@ApiOkResponse({ type: KycLevelDto })
@ApiUnauthorizedResponse(MergedResponse)
async getKycLevel(@Headers(CodeHeaderName) code: string): Promise<KycLevelDto> {
return this.kycService.getInfo(code);
async getKycLevel(@Headers(CodeHeaderName) code: string, @Query() query: KycQueryDto): Promise<KycLevelDto> {
return this.kycService.getInfo(code, query.context);
}

@Put()
Expand All @@ -131,9 +132,9 @@ export class KycController {
async continueKyc(
@Headers(CodeHeaderName) code: string,
@RealIP() ip: string,
@Query('autoStep') autoStep?: string,
@Query() query: KycContinueQueryDto,
): Promise<KycSessionDto> {
return this.kycService.continue(code, ip, autoStep !== 'false');
return this.kycService.continue(code, ip, query.autoStep !== 'false', query.context);
}

@Get('countries')
Expand Down
16 changes: 16 additions & 0 deletions src/subdomains/generic/kyc/dto/input/kyc-query.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsEnum, IsOptional } from 'class-validator';
import { KycContext } from '../../enums/kyc.enum';

export class KycQueryDto {
@ApiPropertyOptional({ enum: KycContext, description: 'KYC context to filter required steps per flow' })
@IsOptional()
@IsEnum(KycContext)
context?: KycContext;
}

export class KycContinueQueryDto extends KycQueryDto {
@ApiPropertyOptional()
@IsOptional()
autoStep?: string;
}
Loading
Loading