Frontend:
- apps/web (Vite+TS, TanStack Router/Query, shadcn/ui @cfdm/ui base-nova)
- 10 страниц в routes/_auth/, Recharts через shadcn Chart, lucide-react
- формы на RHF + Zod (FormSheet/FormField)
- удалены Tabler, Chart.js, react-router-dom
Backend (параллельный трек):
- apps/api (Fastify 5 + Drizzle + better-sqlite3)
- packages/db: Drizzle-схема и repositories по сущностям
- packages/shared: Zod-контракты
- роуты с валидацией и единым форматом ошибок { error: { code, message } }
- sync/backup — заглушки 501 (billmanager-адаптеры переносятся отдельно)
- legacy Express оставлен как runtime по умолчанию (RUNTIME=express)
Infra:
- Dockerfile multi-stage под pnpm workspaces
- .dockerignore и docker-compose обновлены под monorepo
Rules:
- удалены нерелевантные правила (rust, cloudflare, server/frontend-conventions)
- project-structure.mdc и AGENTS.md переписаны под monorepo
- frontend-shadcn.mdc, shadcn-ui-production.mdc, sqlite.mdc обновлены
Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.6 KiB
JavaScript
55 lines
1.6 KiB
JavaScript
/**
|
||
* Запуск синхронизации BILLmanager с записью в sync_log (для API и планировщика)
|
||
*/
|
||
|
||
import { getDb } from './db.js'
|
||
import { syncFromBillmanager } from './adapters/billmanager/index.js'
|
||
|
||
/**
|
||
* @param {object} account - строка provider_accounts
|
||
* @param {object} [opts] - { skipTariffs, skipVpsPayments }
|
||
* @returns {Promise<object>} результат syncFromBillmanager + ok, logId
|
||
*/
|
||
export async function runBillmanagerAccountSync(account, opts = {}) {
|
||
const db = getDb()
|
||
const logId = `sync-${account.id}-${Date.now()}`
|
||
db.prepare(`
|
||
INSERT INTO sync_log (id, accountId, startedAt, status)
|
||
VALUES (?, ?, ?, ?)
|
||
`).run(logId, account.id, new Date().toISOString(), 'running')
|
||
|
||
try {
|
||
const result = await syncFromBillmanager(account, db, opts)
|
||
const summaryPayload = {
|
||
...(result.syncSummary || {}),
|
||
vpsCount: result.vpsCount,
|
||
paymentsCount: result.paymentsCount,
|
||
tariffsCount: result.tariffsCount ?? 0,
|
||
}
|
||
db.prepare(`
|
||
UPDATE sync_log SET finishedAt=?, status=?, vpsCount=?, paymentsCount=?, summary=?
|
||
WHERE id=?
|
||
`).run(
|
||
new Date().toISOString(),
|
||
'ok',
|
||
result.vpsCount,
|
||
result.paymentsCount,
|
||
JSON.stringify(summaryPayload),
|
||
logId,
|
||
)
|
||
return { ok: true, logId, ...result }
|
||
} catch (err) {
|
||
db.prepare(`
|
||
UPDATE sync_log SET finishedAt=?, status=?, error=?, summary=?
|
||
WHERE id=?
|
||
`).run(
|
||
new Date().toISOString(),
|
||
'error',
|
||
err.message || 'Unknown error',
|
||
JSON.stringify({ error: err.message || 'Unknown error' }),
|
||
logId,
|
||
)
|
||
throw err
|
||
}
|
||
}
|