Сервис автоматизации рассылки платёжных квитанций для бухгалтерии школы.
Бухгалтерский отдел школы ежемесячно формировал квитанции об оплате услуг вручную: вносил данные в шаблон PDF по одному ученику, печатал и передавал родителям. Около 300 квитанций в месяц. Сервис развёрнут и используется бухгалтерией с 2025 года.
Требовалось автоматизировать:
- Парсинг реестра зачислений из Excel (ФИО ученика, лицевой счёт, сумма, реквизиты организации)
- Сопоставление учеников с email-адресами родителей (отдельный Excel-файл)
- Генерацию персональных PDF-квитанций с QR-кодом для оплаты через СБП
- Массовую рассылку через SMTP с сохранением копий в папке «Отправленные» (IMAP)
Интерфейс — веб-страница, доступная бухгалтеру в браузере.
┌─────────────────────────────────────────────────────────┐
│ Browser (UI) │
│ HTML-страницы + multipart file upload │
└───────────────────────────┬─────────────────────────────┘
│ HTTP
┌───────────────────────────▼─────────────────────────────┐
│ Handler Layer │
│ MainHandler HistoryHandler SettingsHandler │
│ UIHandler APIClient │
│ │
│ (Gin framework, multipart parsing, response DTOs) │
└───────────────────────────┬─────────────────────────────┘
│ interfaces
┌───────────────────────────▼─────────────────────────────┐
│ Service Layer │
│ │
│ Manager │
│ │ ProcessPayersFile() │
│ │ ├── validate settings │
│ │ ├── store uploaded file │
│ │ ├── parse payers (XLS) │
│ │ ├── parse org (XLS) │
│ │ ├── record history │
│ │ ├── formPersonalReceipts() │
│ │ │ ├── prepareReceiptTemplate (XLS → PDF) │
│ │ │ ├── for each payer: generate QR + fill PDF │
│ │ │ └── map email → pdf path │
│ │ └── SendMails() │
│ │ │
│ ├── MailService (concurrent SMTP + IMAP store) │
│ ├── HistoryService (file history CRUD) │
│ └── SettingsService(email mappings, in-memory cache) │
└───────────────────────────┬─────────────────────────────┘
│ interfaces
┌───────────────────────────▼─────────────────────────────┐
│ Repository Layer │
│ HistoryRepository SettingsRepository │
│ PostgreSQL (pgx/v5) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────┐
│ Utility Packages │
│ pkg/pdf – PDF generation │
│ pkg/sender – SMTP + IMAP │
│ pkg/xls – Excel parsing │
│ pkg/qr – QR code (СБП) │
│ pkg/converter– Excel → PDF │
└─────────────────────────────────┘
| Компонент | Выбор | Обоснование |
|---|---|---|
| HTTP | Gin | Минимальные аллокации, встроенный multipart, удобный роутинг |
| Excel | excelize | Зрелая Go-библиотека с поддержкой .xls + .xlsx |
| pdft | Наложение текста и изображений на готовый PDF-шаблон без перегенерации | |
| QR | go-qrcode | Простой API; формат СБП-строки собирается вручную |
| SMTP | gomail | Вложения, MIME, TLS из коробки |
| IMAP | go-imap/v2 | Активно поддерживаемый Go IMAP-клиент; lazy connect + mutex для reuse |
| БД | PostgreSQL + pgx/v5 | История файлов и email-маппинги; pgx — без ORM, низкие накладные расходы |
| Логирование | zap | Структурированные логи, нет аллокаций в hot path |
| Метрики | Prometheus | Latency обработки файла и рассылки (histogram); счётчики успешных/упавших операций по типу (payers_file, emails_file); количество сгенерированных квитанций (gauge) |
| Рейт-лимитер | golang.org/x/time/rate | Token bucket 5 писем/сек; не перегружает SMTP-сервер школы |
| Слой | Покрытие | Метод |
|---|---|---|
| Repository | 84.6% | Интеграционные тесты (testcontainers — PostgreSQL поднимается автоматически) |
| Service | 66.2% | Unit с testify/mock; happy path ProcessPayersFile — E2E |
| Handler (бизнес-хэндлеры) | ~95% | Unit, httptest |
| Handler (весь пакет включая ui.go) | 51.7% | ui.go — HTML-рендеринг, не тестируется |
| pkg/sender | 40.7% | Unit; SendEmail с реальным SMTP — интеграционный |
| pkg/pdf | 22.8% | Unit (utils, layout); Canvas — интеграционный |
| pkg/xls | ~60% | Unit + интеграционные |
| pkg/qr | ~75% | Unit |
Canvas.Fill,GeneratePersonalReceipt,converter.ExcelToPdfпокрыты интеграционными тестами вpkg/pdf/integration/иtests/e2e/.
- Go 1.24+
- docker compose
cp .env.example .env
# Заполнить: DB_DSN, SMTP_HOST, SMTP_PORT, SMTP_EMAIL, SMTP_PASSWORD,
# IMAP_HOST, IMAP_PORT, IMAP_SENT_FOLDERdocker compose up --build
# Сервер на :8080# Unit-тесты (без Docker)
go test ./internal/handler/... ./internal/service/... \
./pkg/pdf/... ./pkg/sender/... ./pkg/qr/... ./pkg/xls/...
# Интеграционные — testcontainers поднимает PostgreSQL автоматически
go test ./internal/repository/... ./pkg/converter/... ./pkg/pdf/integration/...
# E2E — валидируют полный pipeline: Excel → PDF → QR → рассылка.
# Для запуска необходим реальный SMTP-аккаунт (см. .env.example)
go test ./tests/e2e/...
# Покрытие по слою
go test ./internal/handler/... -cover
go test ./internal/service/... -covere2e/testdata/— пример реестра зачислений и файла email-маппинга
cmd/app/ — точка входа
internal/
handler/ — HTTP-хэндлеры, UI, API-клиент
service/ — бизнес-логика (Manager, Mail, History, Settings)
repository/ — репозитории PostgreSQL
model/ — внутренние модели (Mail, Settings, File, пути)
mocks/ — testify-моки для unit-тестов
errs/ — типизированные ошибки (System/User/Validation)
metrics/ — Prometheus-метрики
pkg/
pdf/ — наложение данных на PDF-шаблон квитанции
sender/ — SMTP-рассылка + IMAP-хранение
xls/ — парсинг и редактирование Excel
qr/ — генерация QR-кода для СБП
converter/ — Excel → PDF через LibreOffice
model/ — публичные модели (Payer, Organization)
templates/ — HTML-шаблоны страниц
static/ — шрифты, CSS
e2e/testdata/ — тестовые Excel-файлы