refactor(repo): переход на pnpm monorepo с shadcn/ui и Fastify+Drizzle

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>
This commit is contained in:
DenozordecandCursor committed 2026-06-26 13:42:05 +07:00
1 parent 8408155be6
commit 6fbd1a9113
202 files changed
+16734 -12145

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
import { queryClient } from '../lib/queryClient'
import { api } from '../lib/api-client'
export const snapshotKeys = {
all: ['snapshot'] as const,
}
export const snapshotQueryOptions = () => ({
queryKey: snapshotKeys.all,
queryFn: () => api.fetchData(),
staleTime: 30_000,
})
export const ratesKeys = {
all: ['rates'] as const,
}
export const ratesQueryOptions = (ratesUrl?: string) => ({
queryKey: ratesKeys.all,
queryFn: async () => {
if (!ratesUrl) return null
const proxyUrl = `/api/rates-proxy?url=${encodeURIComponent(ratesUrl)}`
try {
const res = await fetch(proxyUrl)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
return await res.json()
} catch {
const direct = await fetch(ratesUrl)
if (!direct.ok) throw new Error(`HTTP ${direct.status}`)
return await direct.json()
}
},
enabled: Boolean(ratesUrl),
})
export const projectsKeys = {
suggest: (q: string) => ['projects', 'suggest', q] as const,
}
export const projectsSuggestQueryOptions = (q: string) => ({
queryKey: projectsKeys.suggest(q),
queryFn: () => api.fetchProjectSuggestions(q),
enabled: q.length >= 2,
})
export type SnapshotFromQuery = Awaited<ReturnType<typeof api.fetchData>>
export { queryClient }