Skip to content
Open
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
44 changes: 43 additions & 1 deletion apps/api/src/api/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,45 @@ export const CategoryTrendEndpoint = api.stats.categoryTrend
.tags('stats')
.operationId('categoryTrend');

export const CashFlowForecastEndpoint = api.stats.cashFlowForecast
.authorize(PrincipalSchema)
.inject({
db: DbToken,
knex: KnexToken,
config: ConfigToken,
logger: LoggerToken
})
.summary('Cash-flow forecast')
.description(
'Returns the persisted daily cash-flow forecast, queueing generation when needed.'
)
.tags('stats')
.operationId('cashFlowForecast');

export const CashFlowForecastJobEndpoint = api.stats.cashFlowForecastJob
.authorize(PrincipalSchema)
.inject({
db: DbToken,
knex: KnexToken,
config: ConfigToken,
logger: LoggerToken
})
.summary('Start cash-flow forecast generation')
.description(
'Starts an asynchronous forecast generation job and returns a short-lived progress token.'
)
.tags('stats')
.operationId('startCashFlowForecastJob');

export const CashFlowForecastProgressEndpoint =
api.stats.cashFlowForecastProgress
.summary('Cash-flow forecast generation progress')
.description(
'Streams progress and the final stored forecast for a short-lived forecast job token.'
)
.tags('stats')
.operationId('cashFlowForecastProgress');

export const endpoints = {
auth: {
register: RegisterEndpoint,
Expand Down Expand Up @@ -503,6 +542,9 @@ export const endpoints = {
stats: {
overview: StatsOverviewEndpoint,
window: StatsWindowEndpoint,
categoryTrend: CategoryTrendEndpoint
categoryTrend: CategoryTrendEndpoint,
cashFlowForecast: CashFlowForecastEndpoint,
cashFlowForecastJob: CashFlowForecastJobEndpoint,
cashFlowForecastProgress: CashFlowForecastProgressEndpoint
}
};
8 changes: 7 additions & 1 deletion apps/api/src/api/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,16 @@ import {
transactionScanProgressHandler
} from './transaction-scans.js';
import {
cashFlowForecastHandler,
cashFlowForecastProgressHandler,
categoryTrendHandler,
createTransactionHandler,
dashboardSummaryHandler,
dashboardWindowHandler,
deleteTransactionHandler,
getTransactionScanImageHandler,
listTransactionsHandler,
startCashFlowForecastJobHandler,
statsOverviewHandler,
statsWindowHandler,
updateTransactionHandler
Expand Down Expand Up @@ -135,6 +138,9 @@ export const handlers = {
stats: {
overview: statsOverviewHandler,
window: statsWindowHandler,
categoryTrend: categoryTrendHandler
categoryTrend: categoryTrendHandler,
cashFlowForecast: cashFlowForecastHandler,
cashFlowForecastJob: startCashFlowForecastJobHandler,
cashFlowForecastProgress: cashFlowForecastProgressHandler
}
};
40 changes: 39 additions & 1 deletion apps/api/src/api/handlers/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { ActionResult, type Handler } from '@cleverbrush/server';
import {
ActionResult,
type Handler,
type SubscriptionHandler
} from '@cleverbrush/server';
import { cashFlowForecast } from '../../application/cash-flow-forecast.js';
import {
startCashFlowForecastJob,
subscribeCashFlowForecastJob
} from '../../application/cash-flow-forecast-jobs.js';
import {
categoryTrend,
createTransaction,
Expand All @@ -15,6 +24,9 @@ import {
} from '../../application/transactions.js';
import { TransactionCreated } from '../../log-templates.js';
import type {
CashFlowForecastEndpoint,
CashFlowForecastJobEndpoint,
CashFlowForecastProgressEndpoint,
CategoryTrendEndpoint,
CreateTransactionEndpoint,
DashboardSummaryEndpoint,
Expand Down Expand Up @@ -162,3 +174,29 @@ export const categoryTrendHandler: Handler<
throw err;
}
};

export const cashFlowForecastHandler: Handler<
typeof CashFlowForecastEndpoint
> = async ({ query, principal }, { db, knex, config, logger }) => {
return cashFlowForecast(db, knex, config, logger, principal.userId, query);
};

export const startCashFlowForecastJobHandler: Handler<
typeof CashFlowForecastJobEndpoint
> = async ({ body, principal }, { db, knex, config, logger }) => {
const job = startCashFlowForecastJob(
db,
knex,
config,
logger,
principal.userId,
body
);
return ActionResult.accepted(job);
};

export const cashFlowForecastProgressHandler: SubscriptionHandler<
typeof CashFlowForecastProgressEndpoint
> = async function* ({ query, signal }) {
yield* subscribeCashFlowForecastJob(query, signal);
};
Loading
Loading