fix: surface durable hourly attempt in accounts and income meta (WealthLedger/backend#58)
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 17s
Backend verify / verify (push) Failing after 7m31s

This commit was merged in pull request #92.
This commit is contained in:
2026-10-14 18:00:20 +03:00
parent b90cedd580
commit 14bcb9da5f
6 changed files with 80 additions and 4 deletions
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
import { investmentResourceMeta } from '../investment-resource.mapper';
import { PortfolioService } from '../portfolio/portfolio.api';
import { TbankSyncRepository } from '../tbank-sync/tbank-sync.repository';
import { hourlyAttempt, TbankSyncRepository } from '../tbank-sync/tbank-sync.repository';
import { BrokerageAccountDto, BrokerageAccountsResourceDto } from './brokerage-account.dto';
@Injectable()
@@ -61,6 +61,7 @@ export class BrokerageAccountsService {
: null,
freshForMs: 3_600_000,
work: null,
lastAttempt: hourlyAttempt(hourly, ['membership', 'portfolio']),
dependencies: saved.accounts.map((account) => account.meta),
}),
sync: hourly
@@ -98,6 +98,7 @@ export class IncomeAnalyticsService {
work: work.id
? { id: work.id, state: work.state, errorCode: work.errorCode }
: null,
lastAttempt: current.meta.lastAttempt,
coverage: current.meta.coverage,
dependencies,
}),
@@ -435,6 +435,7 @@ export class BrokerageOperationsService {
saved = await this.repository.readPage(input);
}
const now = new Date();
const hourly = await this.hourlySync.hourly(userId);
const membership = investmentResourceMeta({
resourceKey: 'accounts/membership',
dataRevision: String(saved?.connection.membershipRevision ?? MISSING_MEMBERSHIP_REVISION),
@@ -503,6 +504,7 @@ export class BrokerageOperationsService {
fetchedAt,
freshForMs: plan.intervals.some((range) => range.stale) ? STALE_FRESHNESS_MS : Infinity,
work,
lastAttempt: hourlyAttempt(hourly, 'operations', accountId === 'all' ? undefined : accountId),
dependencies: [membership],
coverage: {
requested: targets.map(serialize),
@@ -43,16 +43,17 @@ type HourlyAttempt = {
export function hourlyAttempt(
hourly: HourlyAttempt | null,
section: HourlySection['section'],
section: HourlySection['section'] | readonly HourlySection['section'][],
accountId?: string,
): InvestmentAttemptDto {
if (!hourly) {
return { state: 'none', startedAt: null, finishedAt: null, problems: [] };
}
const sections = Array.isArray(section) ? section : [section];
const problems = hourly.sections
.filter(
(entry) =>
entry.section === section &&
sections.includes(entry.section) &&
(accountId === undefined || entry.accountId === accountId),
)
.map((entry) => ({