fix: make backend local verification safe

This commit is contained in:
2026-08-23 21:21:17 +03:00
parent fee4f8c8e6
commit 71d57d60bc
9 changed files with 70 additions and 12 deletions
+1
View File
@@ -0,0 +1 @@
22
+11 -2
View File
@@ -7,11 +7,20 @@ NestJS API WealthLedger. Все функциональные изменения
## Проверка
```bash
npm ci
npm run lint
npm test
npm run build
npm run typecheck:app
npm run typecheck:test
```
Node 22 обязателен. `npm run lint` и `npm run lint:check` не изменяют
versioned-файлы; `npm run lint:fix` — явная записывающая команда. Текущий
`npm run test:e2e` временно не является надёжным gate: WL-P2-05 отложен из-за
Prisma schema-engine failure; статус и trigger пересмотра указаны в
`../docs/development/audit-remediation.md`.
Для read-only сверки runtime OpenAPI с frontend snapshot под Node 22 запускать
из workspace `bash specs/scripts/verify-runtime-openapi.sh`.
## Границы
- Публичный HTTP API версионируется как `/api/v1`; OpenAPI из backend - источник контракта для frontend.
+20 -5
View File
@@ -21,16 +21,31 @@
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## Description
## WealthLedger backend
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
## Project setup
NestJS API WealthLedger. Требуется Node 22. Перед первой локальной проверкой
установите зависимости строго из lockfile:
```bash
$ npm install
npm ci
```
Проверки, не изменяющие исходники:
```bash
npm run lint
npm run typecheck:app
npm run typecheck:test
```
Для явного исправления форматирования используйте `npm run lint:fix`.
`npm run test:e2e` пока не является надёжным local gate: Prisma 7.9.1
останавливает migration до Jest; запись WL-P2-05 в
`../docs/development/audit-remediation.md` фиксирует rationale и trigger
пересмотра.
## Запуск приложения
## Compile and run the project
```bash
+8 -1
View File
@@ -5,6 +5,9 @@
"author": "",
"private": true,
"license": "UNLICENSED",
"engines": {
"node": "22.x"
},
"scripts": {
"build": "prisma generate && nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
@@ -12,7 +15,11 @@
"start:dev": "NODE_ENV=development nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/src/main.js",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"lint": "npm run lint:check",
"lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\" --max-warnings=0",
"lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"typecheck:app": "tsc --project tsconfig.typecheck.app.json",
"typecheck:test": "tsc --project tsconfig.typecheck.test.json",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
+4 -1
View File
@@ -5,6 +5,7 @@ jest.mock('../prisma/prisma.service', () => ({
}));
import { TbankConnectionService } from './tbank-connection.service';
import type { TbankClient } from './tbank.client';
describe('TbankConnectionService', () => {
const prisma = {
@@ -17,7 +18,9 @@ describe('TbankConnectionService', () => {
const config = {
getOrThrow: jest.fn(() => 'MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY='),
};
const tbank = { validateToken: jest.fn() };
const tbank: jest.Mocked<Pick<TbankClient, 'validateToken'>> = {
validateToken: jest.fn(),
};
const portfolio = { invalidate: jest.fn() };
const service = new TbankConnectionService(
prisma as never,
+4 -2
View File
@@ -1,4 +1,4 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Environment } from '../config/env.validation';
import { PrismaService } from '../prisma/prisma.service';
@@ -6,6 +6,8 @@ import { TbankClient } from './tbank.client';
import { TbankCrypto } from './tbank.crypto';
import { PortfolioService } from './portfolio.service';
type TbankTokenValidator = Pick<TbankClient, 'validateToken'>;
@Injectable()
export class TbankConnectionService {
private readonly crypto: TbankCrypto;
@@ -13,7 +15,7 @@ export class TbankConnectionService {
constructor(
private readonly prisma: PrismaService,
config: ConfigService<Environment, true>,
private readonly tbank: TbankClient,
@Inject(TbankClient) private readonly tbank: TbankTokenValidator,
private readonly portfolio: PortfolioService,
) {
this.crypto = TbankCrypto.fromBase64(
+4 -1
View File
@@ -37,7 +37,10 @@ const instrumentCacheTtlMs = 24 * 60 * 60_000;
@Injectable()
export class UpcomingEventsService {
private readonly crypto: TbankCrypto;
private readonly dividendCache = new Map<string, CachedEntry<TbankDividend[]>>();
private readonly dividendCache = new Map<
string,
CachedEntry<TbankDividend[]>
>();
private readonly instrumentCache = new Map<
string,
CachedEntry<TbankInstrument | null>
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"incremental": false,
"noEmit": true
},
"include": ["src/**/*.ts"],
"exclude": ["src/**/*.spec.ts", "test", "node_modules", "dist"]
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"incremental": false,
"noEmit": true
},
"include": ["src/**/*.ts", "test/**/*.ts"],
"exclude": ["node_modules", "dist"]
}