2026-05-16 15:38:28 -05:00
|
|
|
'use strict';
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
import type { Db } from '../types/db';
|
|
|
|
|
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
const { getDb } = require('../db/database.cts');
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const { accountingActiveSql } = require('./paymentAccountingService.cts');
|
|
|
|
|
// Aggregation output re-typed by the client; branding adds friction (Dollars|null
|
|
|
|
|
// through many .filter/.sort/arith) without much safety here → plain require (any).
|
2026-07-05 13:44:04 -05:00
|
|
|
const { sumMoney, fromCents } = require('../utils/money.mts');
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const { resolveDueDate } = require('./statusService.cts');
|
|
|
|
|
|
|
|
|
|
// Dynamic better-sqlite3 rows / request query.
|
|
|
|
|
type Row = Record<string, any>;
|
|
|
|
|
|
|
|
|
|
interface MonthInfo { year: number; month: number; key: string; label: string; start: string; end: string }
|
|
|
|
|
interface ParsedQuery {
|
|
|
|
|
year: number;
|
|
|
|
|
month: number;
|
|
|
|
|
months: number;
|
|
|
|
|
categoryId: number | null;
|
|
|
|
|
billId: number | null;
|
|
|
|
|
includeInactive: boolean;
|
|
|
|
|
includeSkipped: boolean;
|
|
|
|
|
}
|
|
|
|
|
interface QueryError { error: string }
|
|
|
|
|
interface BillWhereOpts { userId: number; categoryId: number | null; billId: number | null; includeInactive: boolean }
|
2026-05-16 15:38:28 -05:00
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function parseInteger(value: unknown, fallback: number | null): number | null {
|
2026-05-16 15:38:28 -05:00
|
|
|
if (value === undefined || value === null || value === '') return fallback;
|
|
|
|
|
const parsed = Number(value);
|
|
|
|
|
return Number.isInteger(parsed) ? parsed : NaN;
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function monthKey(year: number, month: number): string {
|
2026-05-16 15:38:28 -05:00
|
|
|
return `${year}-${String(month).padStart(2, '0')}`;
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function monthLabel(year: number, month: number): string {
|
2026-05-16 15:38:28 -05:00
|
|
|
return new Date(Date.UTC(year, month - 1, 1)).toLocaleString('en-US', {
|
|
|
|
|
month: 'short',
|
|
|
|
|
year: '2-digit',
|
|
|
|
|
timeZone: 'UTC',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function addMonths(year: number, month: number, delta: number): { year: number; month: number } {
|
2026-05-16 15:38:28 -05:00
|
|
|
const date = new Date(Date.UTC(year, month - 1 + delta, 1));
|
|
|
|
|
return { year: date.getUTCFullYear(), month: date.getUTCMonth() + 1 };
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function monthEndDate(year: number, month: number): string {
|
2026-05-16 15:38:28 -05:00
|
|
|
const day = new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
|
|
|
return `${monthKey(year, month)}-${String(day).padStart(2, '0')}`;
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function buildMonths(endYear: number, endMonth: number, count: number): MonthInfo[] {
|
2026-05-16 15:38:28 -05:00
|
|
|
return Array.from({ length: count }, (_, index) => {
|
|
|
|
|
const value = addMonths(endYear, endMonth, index - count + 1);
|
|
|
|
|
return {
|
|
|
|
|
...value,
|
|
|
|
|
key: monthKey(value.year, value.month),
|
|
|
|
|
label: monthLabel(value.year, value.month),
|
|
|
|
|
start: `${monthKey(value.year, value.month)}-01`,
|
|
|
|
|
end: monthEndDate(value.year, value.month),
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function validateSummaryQuery(query: Row, now: Date = new Date()): ParsedQuery | QueryError {
|
2026-05-16 15:38:28 -05:00
|
|
|
const year = parseInteger(query.year, now.getFullYear());
|
|
|
|
|
const month = parseInteger(query.month, now.getMonth() + 1);
|
|
|
|
|
const months = parseInteger(query.months, 12);
|
|
|
|
|
const categoryId = parseInteger(query.category_id, null);
|
|
|
|
|
const billId = parseInteger(query.bill_id, null);
|
|
|
|
|
const includeInactive = query.include_inactive === 'true';
|
|
|
|
|
const includeSkipped = query.include_skipped !== 'false';
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
if (!Number.isInteger(year) || year! < 2000 || year! > 2100) {
|
2026-05-16 15:38:28 -05:00
|
|
|
return { error: 'year must be a 4-digit integer between 2000 and 2100' };
|
|
|
|
|
}
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
if (!Number.isInteger(month) || month! < 1 || month! > 12) {
|
2026-05-16 15:38:28 -05:00
|
|
|
return { error: 'month must be an integer between 1 and 12' };
|
|
|
|
|
}
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
if (!Number.isInteger(months) || months! < 1 || months! > 36) {
|
2026-05-16 15:38:28 -05:00
|
|
|
return { error: 'months must be an integer between 1 and 36' };
|
|
|
|
|
}
|
|
|
|
|
if (categoryId !== null && (!Number.isInteger(categoryId) || categoryId < 1)) {
|
|
|
|
|
return { error: 'category_id must be a positive integer' };
|
|
|
|
|
}
|
|
|
|
|
if (billId !== null && (!Number.isInteger(billId) || billId < 1)) {
|
|
|
|
|
return { error: 'bill_id must be a positive integer' };
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
return { year, month, months, categoryId, billId, includeInactive, includeSkipped } as ParsedQuery;
|
2026-05-16 15:38:28 -05:00
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function isMonthInPast(year: number, month: number): boolean {
|
2026-05-16 15:38:28 -05:00
|
|
|
const now = new Date();
|
|
|
|
|
const currentMonthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
|
|
|
const targetMonthStart = new Date(year, month - 1, 1);
|
|
|
|
|
return targetMonthStart < currentMonthStart;
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function buildBillWhere({ userId, categoryId, billId, includeInactive }: BillWhereOpts): { where: string; params: any[] } {
|
2026-05-16 15:38:28 -05:00
|
|
|
const clauses = ['b.user_id = ?', 'b.deleted_at IS NULL'];
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const params: any[] = [userId];
|
2026-05-16 15:38:28 -05:00
|
|
|
if (!includeInactive) clauses.push('b.active = 1');
|
|
|
|
|
if (categoryId) {
|
|
|
|
|
clauses.push('b.category_id = ?');
|
|
|
|
|
params.push(categoryId);
|
|
|
|
|
}
|
|
|
|
|
if (billId) {
|
|
|
|
|
clauses.push('b.id = ?');
|
|
|
|
|
params.push(billId);
|
|
|
|
|
}
|
|
|
|
|
return { where: clauses.join(' AND '), params };
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function emptySummary(parsed: ParsedQuery, rangeMonths: MonthInfo[], startDate: string, endDate: string, categories: any[]) {
|
2026-05-16 15:38:28 -05:00
|
|
|
return {
|
|
|
|
|
range: { year: parsed.year, month: parsed.month, months: parsed.months, start: startDate, end: endDate },
|
|
|
|
|
filters: {
|
|
|
|
|
category_id: parsed.categoryId,
|
|
|
|
|
bill_id: parsed.billId,
|
|
|
|
|
include_inactive: parsed.includeInactive,
|
|
|
|
|
include_skipped: parsed.includeSkipped,
|
|
|
|
|
},
|
|
|
|
|
categories,
|
|
|
|
|
bills: [],
|
|
|
|
|
monthly_spending: [],
|
|
|
|
|
expected_vs_actual: [],
|
|
|
|
|
category_spend: [],
|
|
|
|
|
heatmap: { months: rangeMonths.map(({ key, label, year, month }) => ({ key, label, year, month })), rows: [] },
|
|
|
|
|
generated_at: new Date().toISOString(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
function getAnalyticsSummary(userId: number, query: Row = {}) {
|
2026-05-16 15:38:28 -05:00
|
|
|
const parsed = validateSummaryQuery(query);
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
if ('error' in parsed) return parsed;
|
2026-05-16 15:38:28 -05:00
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const db: Db = getDb();
|
2026-05-16 15:38:28 -05:00
|
|
|
const rangeMonths = buildMonths(parsed.year, parsed.month, parsed.months);
|
|
|
|
|
const startDate = rangeMonths[0].start;
|
|
|
|
|
const endDate = rangeMonths[rangeMonths.length - 1].end;
|
|
|
|
|
const billWhere = buildBillWhere({ ...parsed, userId });
|
|
|
|
|
|
|
|
|
|
const categories = db.prepare(`
|
|
|
|
|
SELECT id, name
|
|
|
|
|
FROM categories
|
|
|
|
|
WHERE user_id = ?
|
|
|
|
|
AND deleted_at IS NULL
|
|
|
|
|
ORDER BY name COLLATE NOCASE
|
|
|
|
|
`).all(userId);
|
|
|
|
|
|
|
|
|
|
const bills = db.prepare(`
|
|
|
|
|
SELECT b.id, b.name, b.category_id, b.expected_amount, b.active, b.created_at,
|
2026-07-02 21:23:37 -05:00
|
|
|
b.due_day, b.billing_cycle, b.cycle_type, b.cycle_day,
|
2026-05-16 15:38:28 -05:00
|
|
|
c.name AS category_name
|
|
|
|
|
FROM bills b
|
|
|
|
|
LEFT JOIN categories c ON c.id = b.category_id AND c.user_id = b.user_id AND c.deleted_at IS NULL
|
|
|
|
|
WHERE ${billWhere.where}
|
|
|
|
|
ORDER BY b.name COLLATE NOCASE
|
|
|
|
|
`).all(...billWhere.params);
|
|
|
|
|
|
|
|
|
|
if (!bills.length) {
|
|
|
|
|
return emptySummary(parsed, rangeMonths, startDate, endDate, categories);
|
|
|
|
|
}
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const billIds = bills.map((b: Row) => b.id);
|
2026-05-16 15:38:28 -05:00
|
|
|
const placeholders = billIds.map(() => '?').join(',');
|
|
|
|
|
|
|
|
|
|
const paymentRows = db.prepare(`
|
|
|
|
|
SELECT p.bill_id,
|
|
|
|
|
substr(p.paid_date, 1, 7) AS month_key,
|
|
|
|
|
SUM(p.amount) AS total
|
|
|
|
|
FROM payments p
|
|
|
|
|
JOIN bills b ON b.id = p.bill_id
|
|
|
|
|
WHERE b.user_id = ?
|
|
|
|
|
AND b.deleted_at IS NULL
|
|
|
|
|
AND p.bill_id IN (${placeholders})
|
|
|
|
|
AND p.paid_date BETWEEN ? AND ?
|
|
|
|
|
AND p.deleted_at IS NULL
|
2026-06-07 01:05:48 -05:00
|
|
|
AND ${accountingActiveSql('p')}
|
2026-05-16 15:38:28 -05:00
|
|
|
GROUP BY p.bill_id, substr(p.paid_date, 1, 7)
|
|
|
|
|
`).all(userId, ...billIds, startDate, endDate);
|
|
|
|
|
|
|
|
|
|
const stateRows = db.prepare(`
|
|
|
|
|
SELECT m.bill_id, m.year, m.month, m.actual_amount, m.is_skipped
|
|
|
|
|
FROM monthly_bill_state m
|
|
|
|
|
JOIN bills b ON b.id = m.bill_id
|
|
|
|
|
WHERE b.user_id = ?
|
|
|
|
|
AND b.deleted_at IS NULL
|
|
|
|
|
AND m.bill_id IN (${placeholders})
|
|
|
|
|
AND (m.year * 100 + m.month) BETWEEN ? AND ?
|
|
|
|
|
`).all(
|
|
|
|
|
userId,
|
|
|
|
|
...billIds,
|
|
|
|
|
rangeMonths[0].year * 100 + rangeMonths[0].month,
|
|
|
|
|
rangeMonths[rangeMonths.length - 1].year * 100 + rangeMonths[rangeMonths.length - 1].month,
|
|
|
|
|
);
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const paymentByBillMonth = new Map<string, number>(paymentRows.map((row: Row) => [`${row.bill_id}:${row.month_key}`, Number(row.total) || 0]));
|
|
|
|
|
const stateByBillMonth = new Map<string, any>(stateRows.map((row: Row) => [`${row.bill_id}:${monthKey(row.year, row.month)}`, row]));
|
2026-05-16 15:38:28 -05:00
|
|
|
|
|
|
|
|
const monthly_spending = rangeMonths.map(m => {
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const total = sumMoney(bills, (bill: Row) => paymentByBillMonth.get(`${bill.id}:${m.key}`) || 0);
|
2026-06-11 20:12:31 -05:00
|
|
|
return { month: m.key, label: m.label, total: fromCents(total) };
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
}).filter((row: Row) => row.total > 0);
|
2026-05-16 15:38:28 -05:00
|
|
|
|
|
|
|
|
const expected_vs_actual = rangeMonths.map(m => {
|
2026-07-02 21:23:37 -05:00
|
|
|
const [mYear, mMonth] = m.key.split('-').map(Number);
|
2026-05-16 15:38:28 -05:00
|
|
|
let expected = 0;
|
|
|
|
|
let actual = 0;
|
|
|
|
|
let skipped_count = 0;
|
|
|
|
|
for (const bill of bills) {
|
|
|
|
|
const state = stateByBillMonth.get(`${bill.id}:${m.key}`);
|
|
|
|
|
const skipped = !!state?.is_skipped;
|
|
|
|
|
if (skipped) skipped_count += 1;
|
|
|
|
|
if (!skipped || parsed.includeSkipped) {
|
|
|
|
|
actual += paymentByBillMonth.get(`${bill.id}:${m.key}`) || 0;
|
|
|
|
|
}
|
2026-07-02 21:23:37 -05:00
|
|
|
// QA-B5-01 family: only add "expected" in months the bill actually occurs,
|
|
|
|
|
// so annual / off-month quarterly bills don't inflate the expected line
|
|
|
|
|
// every month (matches the Tracker / Summary occurrence gate).
|
|
|
|
|
if (!skipped && resolveDueDate(bill, mYear, mMonth)) {
|
2026-05-16 15:38:28 -05:00
|
|
|
expected += state?.actual_amount ?? bill.expected_amount ?? 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
month: m.key,
|
|
|
|
|
label: m.label,
|
2026-06-11 20:12:31 -05:00
|
|
|
expected: fromCents(expected),
|
|
|
|
|
actual: fromCents(actual),
|
2026-05-16 15:38:28 -05:00
|
|
|
skipped_count,
|
|
|
|
|
};
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
}).filter((row: Row) => row.expected > 0 || row.actual > 0 || row.skipped_count > 0);
|
2026-05-16 15:38:28 -05:00
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const categoryMap = new Map<string, any>();
|
2026-05-16 15:38:28 -05:00
|
|
|
for (const bill of bills) {
|
|
|
|
|
const categoryId = bill.category_id || null;
|
|
|
|
|
const key = categoryId == null ? 'uncategorized' : String(categoryId);
|
|
|
|
|
const existing = categoryMap.get(key) || {
|
|
|
|
|
category_id: categoryId,
|
|
|
|
|
category_name: bill.category_name || 'Uncategorized',
|
|
|
|
|
total: 0,
|
|
|
|
|
};
|
|
|
|
|
for (const m of rangeMonths) {
|
|
|
|
|
existing.total += paymentByBillMonth.get(`${bill.id}:${m.key}`) || 0;
|
|
|
|
|
}
|
|
|
|
|
categoryMap.set(key, existing);
|
|
|
|
|
}
|
|
|
|
|
const category_spend = Array.from(categoryMap.values())
|
2026-06-11 20:12:31 -05:00
|
|
|
.map(row => ({ ...row, total: fromCents(row.total) }))
|
2026-05-16 15:38:28 -05:00
|
|
|
.filter(row => row.total > 0)
|
|
|
|
|
.sort((a, b) => b.total - a.total);
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
const heatmapRows = bills.map((bill: Row) => {
|
2026-05-16 15:38:28 -05:00
|
|
|
const cells = rangeMonths.map(m => {
|
|
|
|
|
const paid = (paymentByBillMonth.get(`${bill.id}:${m.key}`) || 0) > 0;
|
|
|
|
|
const state = stateByBillMonth.get(`${bill.id}:${m.key}`);
|
|
|
|
|
const skipped = !!state?.is_skipped;
|
|
|
|
|
let status = 'no_data';
|
|
|
|
|
if (skipped) status = 'skipped';
|
|
|
|
|
else if (paid) status = 'paid';
|
|
|
|
|
else if (isMonthInPast(m.year, m.month)) status = 'missed';
|
|
|
|
|
return {
|
|
|
|
|
month: m.key,
|
|
|
|
|
label: m.label,
|
|
|
|
|
status,
|
2026-06-11 20:12:31 -05:00
|
|
|
amount_paid: fromCents(paymentByBillMonth.get(`${bill.id}:${m.key}`) || 0),
|
2026-05-16 15:38:28 -05:00
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
return {
|
|
|
|
|
bill_id: bill.id,
|
|
|
|
|
bill_name: bill.name,
|
|
|
|
|
category_name: bill.category_name || 'Uncategorized',
|
|
|
|
|
active: !!bill.active,
|
|
|
|
|
cells: parsed.includeSkipped ? cells : cells.filter(cell => cell.status !== 'skipped'),
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
range: { year: parsed.year, month: parsed.month, months: parsed.months, start: startDate, end: endDate },
|
|
|
|
|
filters: {
|
|
|
|
|
category_id: parsed.categoryId,
|
|
|
|
|
bill_id: parsed.billId,
|
|
|
|
|
include_inactive: parsed.includeInactive,
|
|
|
|
|
include_skipped: parsed.includeSkipped,
|
|
|
|
|
},
|
|
|
|
|
categories,
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
bills: bills.map((b: Row) => ({
|
2026-05-16 15:38:28 -05:00
|
|
|
id: b.id,
|
|
|
|
|
name: b.name,
|
|
|
|
|
category_id: b.category_id,
|
|
|
|
|
category_name: b.category_name || 'Uncategorized',
|
|
|
|
|
active: !!b.active,
|
|
|
|
|
})),
|
|
|
|
|
monthly_spending,
|
|
|
|
|
expected_vs_actual,
|
|
|
|
|
category_spend,
|
|
|
|
|
heatmap: {
|
|
|
|
|
months: rangeMonths.map(({ key, label, year, month }) => ({ key, label, year, month })),
|
|
|
|
|
rows: heatmapRows,
|
|
|
|
|
},
|
|
|
|
|
generated_at: new Date().toISOString(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
|
addMonths,
|
|
|
|
|
buildMonths,
|
|
|
|
|
getAnalyticsSummary,
|
|
|
|
|
monthEndDate,
|
|
|
|
|
monthKey,
|
|
|
|
|
monthLabel,
|
|
|
|
|
validateSummaryQuery,
|
|
|
|
|
};
|