Files
markclean-doc/changelog.md
T
2026-09-26 14:53:34 +03:00

20 KiB
Raw Blame History

[0.4.6-beta] - 2026-09-26

Добавлено

  • Email Anonymization on Delete: Полное обезличивание PII при удалении аккаунта — email заменяется на HMAC-SHA256 хеш, registration_ip обнуляется, password_hash очищается. Соответствует требованиям GDPR (право на забвение).
  • Re-registration Prevention: Защита от повторной регистрации с тем же email после удаления аккаунта. При удалении email хешируется через utils.HashIdentifierWithKey() с секретным ключом приложения, при регистрации проверяется наличие хеша в базе.
  • GetByEmailIncludingDeleted: Новый метод в UserRepository для поиска пользователей по email или его хешу, включая удалённые записи (без фильтра deleted_at IS NULL).
  • PII Cleanup: При удалении аккаунта также обнуляется registration_ip для полного удаления персональных данных из базы.
  • Register Validation: Добавлена проверка на наличие удалённого аккаунта с тем же email через поиск хеша в базе. Возвращается новая ошибка ErrEmailPreviouslyDeleted с HTTP 403 Forbidden.
  • Frontend i18n: Добавлены переводы для новой ошибки email_previously_deleted (RU/EN) с объяснением причины блокировки регистрации.

Изменено

  • DeleteAccount Flow: Переписан процесс удаления аккаунта — теперь email хешируется перед сохранением в БД вместо конкатенации 'deleted_' || id || '_' || email.
  • UserRepository Interface: Расширен интерфейс — добавлен метод GetByEmailIncludingDeleted(ctx, emailOrHash) для поддержки поиска по хешу.
  • Error Handling: Новый тип ошибки ErrEmailPreviouslyDeleted с понятным сообщением для пользователя: "This email was previously used for a deleted account and cannot be reused".

Безопасность

  • HMAC-SHA256: Используется криптографически стойкий HMAC с секретным ключом приложения (cfg.App.Secret) для хеширования email. Без знания секрета невозможно восстановить оригинальный email из хеша.
  • No PII Leaks: В случае утечки базы данных злоумышленник получит только необратимые хеши вместо реальных email-адресов удалённых пользователей.
  • Abuse Prevention: Невозможно обойти лимиты или получить приветственные бонусы повторно через цикл "удаление → регистрация".

[0.4.5-beta] - 2026-09-25

Добавлено

  • ConvertOptions: Четыре новые опции конвертации для гибкой настройки вывода:
    • include_title — добавляет заголовок страницы как H1 (# Title) в начало документа
    • include_frontmatter — добавляет YAML-шапку с метаданными (title, source, bytes, tokens)
    • strip_images — удаляет все <img> теги из результата
    • strip_links — удаляет <a> теги, сохраняя текст ссылок
  • Two-Level Cache Architecture: Двухуровневая система кэширования для экономии кредитов и снижения нагрузки:
    • Уровень 1 — Raw HTML: сырой HTML кэшируется на 30 минут (ключ: convert:html:{normalized_url})
    • Уровень 2 — Final Markdown: финальный результат кэшируется на 5 минут (ключ: convert:result:{url}:{params_hash})
    • Хэш параметров (SHA-256) обеспечивает уникальный ключ для каждой комбинации опций
  • Smart Credit Deduction: Кредиты списываются только при реальном HTTP-запросе к внешнему сайту. При попадании в любой уровень кэша — конвертация бесплатна.
  • Frontend Conversion Options: UI-контролы для всех 4 опций конвертации:
    • Чекбоксы Include Title, Include Frontmatter, Strip Images, Strip Links
    • Опции передаются в API через POST /api/convert в теле запроса
    • Состояние опций сохраняется между конвертациями в рамках сессии
  • CachedHTML DTO: Новая структура dto.CachedHTML для хранения сырого HTML с метаданными (html, title, fetched_at) в Redis.

Изменено

  • ConverterService: Полная переработка метода ConvertURLToMarkdown():
    • ШАГ 1: Проверка кэша финального результата (URL + параметры)
    • ШАГ 2: Проверка кэша сырого HTML (только URL)
    • ШАГ 3: Readability-парсинг выполняется один раз для обоих сценариев (кэш и свежий fetch)
    • ШАГ 4: Конвертация HTML→Markdown с учётом текущих опций
    • ШАГ 5: Списание кредитов только если fromCache == false (реальный fetch)
    • ШАГ 6: Сохранение результата в оба уровня кэша
  • API Contract: Тело запроса POST /api/convert расширено — добавлены опциональные поля:
    {
      "url": "https://example.com",
      "include_title": true,
      "include_frontmatter": false,
      "strip_images": false,
      "strip_links": false
    }
    
  • Cache Key Generation: Ключ кэша финального результата теперь включает хэш параметров — изменение любой опции генерирует новый ключ, не перезаписывая предыдущие результаты.
  • Readability Optimization: Устранён дубль вызова readability.FromReader() — парсинг основного контента и извлечение заголовка выполняются строго один раз, независимо от источника HTML (кэш или fetch).

Производительность

  • Credit Savings: Повторная конвертация того же URL с другими опциями не списывает кредиты — сырой HTML берётся из кэша, конвертируется заново бесплатно.
  • Reduced External Requests: При попадании в HTML-кэш (TTL 30 мин) внешний HTTP-запрос не выполняется — экономия времени (30+ секунд) и снижение нагрузки на целевые сайты.
  • Single Readability Pass: Оптимизация CPU — readability вызывается один раз вместо двух при свежем fetch.
  • Compact Cache Keys: Хэш параметров (8 байт SHA-256 → 16 hex-символов) вместо полной сериализации опций — компактные ключи Redis.

UX Улучшения

  • Instant Re-conversion: При изменении опций (например, включение strip_images) результат появляется мгновенно — HTML уже в кэше, нужна только быстрая конвертация.
  • No Surprise Charges: Пользователь может экспериментировать с опциями для одного URL без страха потратить кредиты — списание происходит только при первом fetch.
  • Flexible Output: Пользователь настраивает формат вывода под свои нужды:
    • Для LLM: strip_images: true + strip_links: true — чистый текст без мусора
    • Для документации: include_frontmatter: true — метаданные для статических генераторов
    • Для быстрого чтения: include_title: true — заголовок сразу виден

Сценарии кэширования

Сценарий Result Cache HTML Cache Fetch Кредиты Readability
Первый запрос ❌ ❌ ✅ −1 1×
Повтор с теми же опциями ✅ ✅ ❌ 0 0×
Повтор с другими опциями ❌ ✅ ❌ 0 1×
После истечения HTML cache (30 мин) ❌ ❌ ✅ −1 1×

[0.4.4-beta] - 2026-09-24

Добавлено

  • Smart History Deduplication: Умная дедупликация истории конвертаций — при повторной конвертации того же URL запись обновляется, а не создаётся дубликат. Добавлены поля count_usage (количество конвертаций) и updated_at (время последнего использования).
  • UPSERT Logic: Реализован UPSERT через ON CONFLICT (user_id, target_url) WHERE user_id IS NOT NULL — для авторизованных пользователей одна запись на URL, для анонимов допускаются дубликаты (их история не показывается в UI).
  • Partial Unique Index: Создан partial unique index idx_conversion_logs_user_url_unique на (user_id, target_url) с условием WHERE user_id IS NOT NULL для предотвращения дубликатов только для авторизованных пользователей.
  • Usage Counter: Счётчик count_usage автоматически инкрементируется при каждой повторной конвертации того же URL, позволяя видеть популярность страниц.
  • Smart Sorting: История теперь сортируется по updated_at DESC — недавно использованные URL всегда сверху списка, а не по времени первой конвертации.

Изменено

  • Database Schema: Добавлены колонки count_usage INT NOT NULL DEFAULT 1 и updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() в таблицу conversion_logs. Создан индекс idx_conversion_logs_user_updated для быстрой сортировки.
  • ConversionLog Domain: Добавлены поля CountUsage int и UpdatedAt time.Time в структуру domain.ConversionLog.
  • Repository Save Method: Переписан метод Save() в postgresConversionLogRepo — для авторизованных пользователей используется UPSERT с обновлением всех полей кроме id, user_id, target_url, created_at и инкрементом count_usage.
  • Repository ListByUserID: Изменена сортировка с ORDER BY created_at DESC на ORDER BY updated_at DESC для отображения недавно использованных URL сверху.
  • DTO HistoryItem: Добавлены поля CountUsage и UpdatedAt в dto.HistoryItem для отображения в UI.
  • Frontend HistoryDrawer: Обновлён компонент для отображения count_usage (badge с количеством конвертаций) и updated_at (время последнего использования вместо первого).

Производительность

  • Reduced Storage: Устранено бесконечное дублирование записей — один URL = одна запись для пользователя вместо N записей при N конвертациях.
  • Index Optimization: Partial unique index и индекс для сортировки по updated_at обеспечивают быстрые запросы даже при большом объёме данных.
  • Query Efficiency: UPSERT выполняется одним атомарным SQL-запросом вместо SELECT + INSERT/UPDATE, снижая нагрузку на БД.

UX Улучшения

  • Frontend: Добавлен логотип с анимацией при наведении курсором.
  • Recent First: Пользователь видит недавно использованные URL сверху списка, что упрощает доступ к часто конвертируемым страницам.
  • No Clutter: История не забивается дубликатами — чистый и понятный список уникальных URL с метаданными.

[0.4.3-beta] - 2026-09-23

Добавлено

  • Credit-Based Billing: Полная переработка биллинга — переход от подписок к системе кредитов. Платные кредиты не сгорают и не имеют срока действия, бесплатный дневной лимит (5 запросов/сутки) сбрасывается каждые 24 часа.
  • Priority Deduction Logic: Двухуровневое списание с приоритетом — сначала расходуются платные кредиты, затем бесплатный дневной лимит. Атомарные SQL-операции гарантируют корректность при конкурентных запросах.
  • Credit Packages: Три пакета кредитов для покупки — Старт (1 000 за 99 ₽), Оптимальный (3 000 за 199 ₽, −33%), Профи (8 000 за 399 ₽, −50%).
  • Billing API v2: Новые эндпоинты GET /api/billing/credits (баланс), GET /api/billing/packages (каталог пакетов), POST /api/billing/purchase (покупка).
  • Test Endpoints: Отладочные эндпоинты POST /api/billing/test/add-credits (+100 кредитов) и POST /api/billing/test/reset-daily (сброс дневного лимита) для упрощения разработки.
  • Skeleton Loaders: Плавные скелетон-загрузчики в QuotaBadge и UserDropdown при ожидании данных биллинга.
  • i18n Expansion: Новые ключи переводов (RU/EN) для кредитной системы: баланс кредитов, дневной лимит, пакеты, покупка, цена за запрос, процент выгоды.

Изменено

  • Database Schema: Удалены таблицы subscriptions и user_current_usage. Добавлена таблица user_credits (credits, daily_used, daily_reset_at) с CHECK-ограничениями и каскадным удалением.
  • Domain Layer: Полная замена Subscription/PlanLimits/UsageStats на UserCredits/CreditPackage/PackagesConfig с хелпер-методами (CanUseCredit, ShouldResetDaily, DeductCredit).
  • QuotaService: Переписан с нуля — убрана логика подписок и автопродления, добавлен автоматический сброс дневного лимита при проверке квоты (lazy reset через time.Since).
  • Frontend Billing Store: BillingStore теперь хранит CreditsResponse вместо SubscriptionResponse, оптимистичное обновление корректно обрабатывает приоритет (кредиты → дневной лимит).
  • QuotaBadge Component: Адаптивное отображение — ⚡ 1 234 при наличии кредитов, 📅 2/5 при использовании дневного лимита. Мини-прогресс-бар показывается только при отсутствии кредитов.
  • UserDropdown: Новый блок квоты с прогресс-баром дневного использования, таймером сброса и кнопкой «Купить кредиты» с градиентным стилем.
  • Pricing Page: Полная переработка — карточки пакетов вместо тарифных планов, отображение цены за запрос (в копейках), бейджи выгоды.
  • Error Handling: Обновлён HTTP 402 ответ quota_exceeded — сообщение теперь учитывает обе причины (нет кредитов + дневной лимит исчерпан).
  • Cache Strategy: Кэш баланса кредитов (TTL 5 мин) вместо кэша подписок (TTL 10 мин) — более агрессивная инвалидация для часто меняющихся данных.
  • Removed: Удалены устаревшие SubscriptionRepository, UsageRepository, feature flags инфраструктура, все эндпоинты тестового апгрейда планов.

[0.3.2-beta] - 2026-09-22

Добавлено

  • Billing & Subscriptions: Модуль управления тарифными планами (Free, Basic, Pro) с ежемесячными квотами и атомарным трекингом использования (usage tracking).
  • Auth & Security: Полноценный цикл аутентификации на HttpOnly cookies, сброс пароля по OTP на email и защита от брутфорса.
  • Rate Limiting: Многоуровневое ограничение запросов (суточное для анонимных пользователей, месячное по тарифам для авторизованных).
  • History & Logs: Пагинируемая история конвертаций в API и интерфейсе с разделением хранения логов и лимитов.
  • UX & Frontend Integration: Уведомления об исчерпании лимитов, модальные окна регистрации и повторное использование сохраненных URL.

Изменено

  • API v2: Переход бэкенда на новую версию архитектуры (Clean Architecture).
  • Database Architecture: Миграция хранилища на PostgreSQL (управление миграциями через Goose) и Redis для кэширования и лимитов.
  • CI/CD Pipeline: Автоматизация сборки Docker-образов и деплоя через приватный registry Gitea.

[0.2.1-alpha] - 2026-06-15

Добавлено

  • Базовый API конвертации HTML в чистый Markdown для LLM.
  • Поддержка первичного веб-интерфейса на SvelteKit.
  • Базовая обработка ошибок и первичная валидация входных URL.

[0.1.0-alpha] - 2026-03-01

Добавлено

  • Инициализация проекта MarkClean, MVP мотора конвертации текста.