FourCast: отчет по архитектуре и MVP Фокус: точные данные, бесплатная эксплуатация, эскалация сложных чеков

Короткое резюме

FourCast должен быть не просто OCR-ботом, а контролируемой очередью чеков: каждый чек либо строго обработан, либо немедленно отмечен как требующий локальной или ручной проверки.

Версия отчета: 2026-07-21
Рекомендация Worker + Apps Script Cloudflare Worker принимает Telegram webhook, Apps Script делает Drive, OCR, Sheets и Telegram ответы.
Главный принцип Нет тихих потерь Если товар не распознан или сумма не сходится, чек не попадает в статистику без проверки.
Реальность OCR 100% cloud auto нельзя обещать Drive OCR хорош для MVP, но обязательны local worker и review-flow для сложных чеков.

Что строим первым: рабочую цепочку Telegram photo/document -> очередь -> Drive original -> Sheets row -> Drive OCR -> parser -> validation -> результат в Telegram.

Что откладываем: автопробуждение ПК, LLM-категоризацию, красивые графики после каждого чека, универсальный парсер всех магазинов мира.

Цель и жесткие правила данных

Цель MVP - ежедневно отправлять чеки в Telegram и получать точную семейную статистику без ручного ввода, но с честной эскалацией всех сомнительных случаев.

Целевой пользовательский сценарий

1

Вы или жена отправляете чек

Лучше отправлять как файл/document, если чек длинный, смазанный или важный. Обычное photo тоже поддерживается.

2

Webhook принимает событие

Система проверяет секрет, канал или группу, message_id и кладет чек в очередь без тяжелого OCR.

3

Processor сохраняет оригинал

Фото сохраняется в Drive, в Sheets создается или обновляется idempotent receipt row.

4

OCR, parser и validation

Drive OCR извлекает текст, merchant-specific parser извлекает товары, validation проверяет сумму и полноту.

5

Telegram сообщает результат

Если чек надежный, он включается в статистику. Если нет, вы сразу видите причину и следующий шаг.

Непереговорные правила

  • 1Статистика считает только статусы processed и human_verified.
  • 2Любая сумма хранится в центах как integer, не float.
  • 3Если позиции не найдены, чек уходит в needs_local_processing.
  • 4Если сумма позиций не сходится с total, чек уходит в needs_review.
  • 5Повторный webhook не создает дубль: receipt_id = chat_id + message_id.
  • 6LLM может помогать с категорией, но финальные суммы проверяются кодом.

Интерактивная блок-схема

Нажимайте на узлы схемы: справа появится назначение шага, что хранится, какие ошибки ловим и почему это важно.

Кликабельная схема
Telegram photo/document Cloudflare Worker secret + fast 200 Queue retries + buffer Apps Script processor trigger Sheets Inbox idempotent row Google Drive original photo Drive OCR Google Doc text Parser merchant rules Validation sum + completeness Local Worker PaddleOCR/Tesseract Receipts + Items source of truth Summary computed from data Telegram result/status Human Review manual correction Alerts needs action Audit Log Errors sheet

Варианты архитектуры

Ниже сравнение трех практических вариантов. Для вашей цели я рекомендую вариант B: он остается бесплатным, но закрывает безопасность webhook и устойчивость к пикам.

Apps Script only

Самый простой путь: Telegram webhook указывает прямо на Web App URL Apps Script. Secret передается в URL, проверяется chat_id и message_id.

Компромисс Apps Script плохо подходит для проверки Telegram secret header, а doPost должен завершиться быстро.

Когда выбирать: если нужен самый короткий путь к первому прототипу и вы готовы принять более слабую защиту публичного webhook.

Cloudflare Worker + Queue + Apps Script

Worker проверяет Telegram header secret, ограничивает вход, кладет update в очередь и отвечает Telegram быстро. Apps Script обрабатывает задачу отдельно.

Рекомендовано Бесплатно для вашего объема, безопаснее и устойчивее, чем прямой Apps Script webhook.

Почему это лучший MVP: вы не заводите VPS, не платите за Cloud Run, но получаете нормальный gateway и очередь.

Local worker как fallback

Домашний ПК не обрабатывает каждый чек. Он подключается только для статусов needs_local_processing, когда Drive OCR или parser не смогли доказать полноту.

Позже Запуск через Windows Task Scheduler при старте ПК или по расписанию.

Роль ПК: не основная инфраструктура 24/7, а усилитель качества для сложных чеков и способ не терять товары.

Нажмите на заголовок таблицы для сортировки
Вариант Стоимость Плюсы Минусы Рекомендация
Apps Script only 0 EUR Самый быстрый старт, меньше компонентов. Слабее webhook security, нет нормальной внешней очереди. Можно для прототипа
Cloudflare Worker + Queue 0 EUR при вашем объеме Быстрый ответ Telegram, secret header, retries, буфер. Нужно настроить еще один сервис. Лучший MVP
Local worker 0 EUR, когда ПК включен Сильнее OCR, можно использовать PaddleOCR/Tesseract/Qwen-VL. Не 24/7, нужен мониторинг last_seen и безопасный доступ. Fallback
VPS до 5 EUR 3-5 EUR/мес Полный контроль, worker 24/7, проще Python pipeline. Операционное сопровождение, обновления, секреты, мониторинг. Не нужен для MVP

Ресурсы, доступы и секреты

Этот список нужен, чтобы команда не начала писать код без понимания, какие аккаунты, ключи и лимиты реально участвуют в системе.

Ресурс Что хранит или делает Где настраивается Критичность Замечание
Telegram Bot Получает update, отправляет статусы и отчеты. BotFather, channel/group permissions. Critical Token не хранить в коде и не писать в Sheets.
Telegram private group Семейный интерфейс для вас и жены. Telegram app. Important Группа удобнее канала для команд и sender attribution.
Cloudflare Worker Webhook gateway, проверка secret header, быстрый ответ. Cloudflare dashboard или Wrangler. Critical Рекомендованный бесплатный gateway.
Cloudflare Queue Буфер webhook events, retries, защита Apps Script. Cloudflare dashboard. Important Можно заменить Sheets Inbox, но очередь лучше.
Apps Script Drive, OCR, Sheets, parser orchestration. script.google.com, clasp из repo. Critical Использовать PropertiesService для секретов.
Google Drive Оригиналы чеков, OCR docs, reports, failed assets. Google Drive folders. Critical Нужна стабильная folder structure.
Google Sheets Receipts, Items, Errors, Settings, Summary. Spreadsheet FourCast Ledger. Critical Source of truth: Receipts + Items.
Windows PC worker Сильный OCR и parser fallback. Task Scheduler, Python venv. Optional Подключать после cloud MVP.
Секреты в Apps Script Properties
TELEGRAM_BOT_TOKEN=***
TELEGRAM_ALLOWED_CHAT_ID=-1001234567890
WEBHOOK_SHARED_SECRET=***
SPREADSHEET_ID=***
DRIVE_ROOT_FOLDER_ID=***
CLOUDFLARE_WORKER_SHARED_SECRET=***
Telegram webhook через Worker
https://api.telegram.org/bot<BOT_TOKEN>/setWebhook
  ?url=https://fourcast-webhook.example.workers.dev/telegram
  &secret_token=<LONG_RANDOM_SECRET>

Google Sheets schema

Разделение важно: Receipts и Items - источник истины, Summary - производная таблица или формулы. Это защищает от расхождений при retry и reprocess.

Receipts
ПолеТипНазначение
receipt_idstringchat_id + message_id. Главный ключ идемпотентности.
telegram_chat_id, telegram_message_idstring/intИсточник Telegram события.
telegram_file_id, file_unique_idstringСкачивание и дедупликация файла.
received_at_utc, updated_at, processed_atdatetimeАудит и мониторинг задержек.
status, status_reasonenum/stringТекущее состояние и короткая причина.
include_in_statsbooleanИстинно только для processed/human_verified.
merchant, receipt_date, currencystring/dateНормализованные данные чека.
total_centsintegerИтоговая сумма без float-ошибок.
photo_drive_file_id, ocr_doc_idstringСвязь с Drive.
parser_version, confidencestring/numberПовторная обработка после улучшения parser.
validation_errors_jsonjson textМашиночитаемые причины review/local fallback.
Items
ПолеТипНазначение
item_idstringreceipt_id + item_index.
receipt_idstringСвязь с Receipts.
item_indexintegerПорядок в чеке.
raw_item_namestringКак OCR увидел позицию.
normalized_item_namestringНормализованное имя для аналитики.
quantity, unitnumber/stringКоличество и единица: tk, kg, l.
unit_price_centsintegerЦена за единицу, если найдена.
line_total_centsintegerСумма строки.
discount_centsintegerСкидка по позиции, отрицательное число.
categorystringКатегория, сначала rules/dictionary, позже AI.
confidence, flags_jsonnumber/jsonПричины сомнений parser.
Errors, Settings, Summary

Errors: receipt_id, stage, error_code, message, payload_excerpt, created_at.

Settings: key, value, description. Здесь хранить не секреты, а настройки parser, merchant aliases, thresholds.

Daily/Monthly Summary: считать из Receipts + Items. Не обновлять вручную как источник истины.

Структура репозитория и Apps Script

Главный риск Apps Script-проектов - весь код в одном файле без тестов. Parser должен быть отделен от Google APIs, чтобы его можно было гонять на fixtures локально.

Рекомендуемая структура GitHub repo
apps-script/
  appsscript.json
  src/
    00_config.gs
    01_secrets.gs
    10_webhook_adapter.gs
    20_telegram_client.gs
    30_sheet_store.gs
    40_drive_store.gs
    50_ocr_drive.gs
    60_parser_core.gs
    61_parser_maxima.gs
    62_parser_rimi.gs
    70_validation.gs
    80_summary.gs
    90_triggers.gs
cloudflare-worker/
  src/index.ts
  wrangler.toml
local-worker/
  fourcast_worker/
  pyproject.toml
tests/
  fixtures/ocr/
  parser/
docs/
  architecture.md
  deployment.md
  runbook.md

Принципы кодовой архитектуры

  • 1Google APIs в adapter слоях, бизнес-логика отдельно.
  • 2Parser pure function: OCR text -> parsed receipt + flags.
  • 3Validation pure function: parsed receipt -> decision.
  • 4Sheet writes идемпотентные: reprocess заменяет items для receipt_id.
  • 5Все внешние вызовы с retry, timeout и error logging.
  • 6Fixtures обязательны до подключения второго магазина.

Parser strategy для чеков Эстонии

Не делайте один универсальный regex. Начните с одного магазина, соберите fixtures, потом расширяйте правила по merchant.

Phase 1: Normalize

Чистим OCR: пробелы, decimal comma, похожие символы, мусорные строки, переносы имени товара.

OCR text hygiene

Phase 2: Merchant parser

Maxima, Rimi, Selver, Prisma, Lidl, Coop получают отдельные правила item-section и total-section.

Доказуемая точность

Phase 3: Reconcile

Складываем товары, скидки, pant/deposit, округления. Если total не сходится, чек не processed.

Strict validation
ЭлементЧто ищемРискРешение
MerchantMaxima/Rimi/Selver aliases, registrikood, address.OCR портит название.Alias dictionary + fuzzy matching.
Datedd.mm.yyyy, yyyy-mm-dd, time рядом.Дата печати или loyalty block.Prefer purchase timestamp near receipt header/footer.
TotalKOKKU, SUMMA, TASUDA, TOTAL.Есть subtotal, card payment, VAT total.Merchant-specific total labels.
Itemsname, qty, unit, unit price, line total.Multi-line names and discounts.Right-to-left numeric parsing + line stitching.
Discountssoodustus, allahindlus, campaign rows.Скидка отдельной строкой.Attach to previous item or global adjustment.
Pant/depositpant, tagatis, bottle deposit.Может быть отдельной позицией.Keep as item or adjustment by merchant rule.

Validation strategy

Validation - это gatekeeper статистики. Она не должна быть мягкой: лучше сразу сказать, что чек требует действия, чем тихо исказить месяц.

Условия processed

  • 1Найден merchant.
  • 2Найдена дата покупки.
  • 3Найден total в EUR или корректно обработана foreign currency.
  • 4Найдена хотя бы одна item line.
  • 5Каждая item line имеет name и line_total_cents.
  • 6sum(items + discounts + adjustments) == total с tolerance 1-2 cents.

Decision matrix

СитуацияСтатусДействие
OCR short/noisyneeds_local_processingЛокальный worker или ручная проверка.
Total missingneeds_reviewНе включать в статистику.
Items missingneeds_local_processingЗапустить сильный OCR.
Sum mismatchneeds_reviewПоказать diff и фото.
All checks passedprocessedЗаписать Items и обновить summary.

Порядок реализации

План построен так, чтобы уже на раннем этапе получить end-to-end цепочку и не тратить месяц на универсальный parser до появления реальных OCR fixtures.

01

Подготовить repo и окружение

Склонировать GitHub в C:\FourCast\ai-workspace, добавить apps-script, cloudflare-worker, tests, docs.

02

Создать Google Drive и Sheets

Family Ledger/receipts/YYYY-MM, ocr_docs, reports, failed. Создать Receipts, Items, Errors, Settings.

03

Webhook gateway

Cloudflare Worker проверяет Telegram secret header и allowed route, кладет update в Queue.

04

Apps Script queue processor

Сохраняет original photo/document, создает idempotent receipt row, отправляет "чек принят".

05

Drive OCR

Создает Google Doc из изображения, извлекает raw text, сохраняет ссылку и текстовый artifact.

06

Maxima parser

Покрыть 10-20 реальных чеков fixture-тестами до перехода к другим магазинам.

07

Validation gate

Суммы в центах, tolerance, flags, статусы processed/needs_local_processing/needs_review.

08

Telegram UX

/status, /review, /summary_today, /summary_month, понятные сообщения об ошибках.

09

Local worker

Python worker берет needs_local_processing и запускает PaddleOCR/Tesseract при включенном ПК.

10

Графики по запросу

Apps Script Charts Service или Sheets charts, только по командам, не после каждого чека.

Домашний ПК и локальная обработка

ПК не должен быть обязательной частью happy path. Его роль - спасать сложные чеки, когда облако не смогло доказать полноту.

Когда подключать ПК

  • 1Drive OCR вернул слишком короткий или мусорный текст.
  • 2Не найдены позиции товаров.
  • 3Не найден total.
  • 4Сумма позиций не сходится с total.
  • 5Parser выставил low confidence.

Рекомендованный старт

Windows Task Scheduler запускает worker при входе в систему и каждые 10-15 минут, пока ПК включен. Worker пишет local_worker_last_seen_at в Settings.

Wake-on-LAN через интернет, port forwarding и smart plug лучше отложить до момента, когда cloud MVP стабилен.

Telegram команды и ответы

Команды должны быть короткими, предсказуемыми и показывать не только суммы, но и наличие незакрытых чеков.

КомандаОтвет
/statusСостояние system health, pending queue, local worker last seen, needs_review count.
/reviewСписок чеков, которые не включены в статистику, с причинами.
/summary_todayИтог за сегодня только по processed/human_verified.
/summary_monthИтог за месяц, количество чеков, warnings.
/chart_todayPNG chart по категориям или магазинам за день.
/chart_monthPNG chart по категориям, магазинам, динамике дней.
Пример успешного ответа
Чек обработан
Магазин: Maxima
Дата: 2026-07-21
Итого: 23.41 EUR
Позиций: 8
Сегодня: 74.20 EUR
За месяц: 612.80 EUR

Риски и конкретные меры

Это список мест, где проект обычно ломается. Его стоит использовать как архитектурный review checklist перед реализацией.

РискСерьезностьПочему опасноМера
Тяжелая работа в webhookHighTelegram retry, дубли, потеря UX.Webhook только queue/inbox, OCR отдельно.
Нет idempotencyHighДубли чеков и завышенная статистика.receipt_id + LockService + upsert.
Float для денегHighОшибки округления и mismatch.Все суммы в integer cents.
Один regex parserHighСломается на первом другом магазине.Merchant-specific parsers + fixtures.
Summary как источник истиныMediumRetry/reprocess создают расхождения.Summary пересчитывать из Receipts + Items.
Сжатые Telegram фотоMediumOCR теряет мелкий текст.Поддержать document/image и подсказки пользователю.
Секреты в коде или SheetsHighКомпрометация бота и данных.PropertiesService, Worker secrets, no logs.
Нет local fallbackMediumСложные чеки будут висеть без решения.Python worker для needs_local_processing.

Чеклист запуска

Отмечайте пункты по мере выполнения. Состояние сохраняется в браузере локально.