Files
chronicle.nixg.ru/ROADMAP.md
T

514 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CHRONICLE ROADMAP
> **The Operating System for Technical Creators**
> Единая среда для создания, публикации и архивирования технического контента
---
## 🎯 Миссия
Решить проблему фрагментации цифровой идентичности технических авторов (разработчики, DevOps, IT-евангелисты) и дать им инструмент для работы с кодом в статьях без боли.
**Боль:** В рунете нет редактора лонгридов с нормальной подсветкой синтаксиса. Тех-блогеры мучаются между Telegram (нет подсветки), Хабром (закрытая платформа) и скриншотами кода (🤮).
**Решение:** Chronicle — редактор + кросс-постинг + архив на своём сайте.
---
## 🗺️ Дорожная карта
### **Фаза 0: Telegram Archiver (MVP)** ✅ (В РАБОТЕ)
**Цель:** Базовый архиватор Telegram-канала в Markdown для Hugo
- [x] **0.1** Парсинг Telegram-канала (API / MTProto) ✅ ВЫПОЛНЕНА
- [x] **0.2** Конвертация постов в Markdown (с сохранением форматирования) ✅ ВЫПОЛНЕНА
- [x] **0.3** Экспорт медиа (изображения, видео, документы) ✅ ВЫПОЛНЕНА
- [x] **0.4** Генерация структуры файлов для Hugo ✅ ВЫПОЛНЕНА
- [x] **0.5** Front-matter для каждого поста (дата, теги, ID) ✅ ВЫПОЛНЕНА
- [x] **0.6** Базовая дедупликация при повторном запуске ✅ ВЫПОЛНЕНА
- [x] **0.7** Извлечение тегов из постов (#хэштеги) и добавление во front-matter ✅ ВЫПОЛНЕНА
- [x] **0.8** Обработка медиа: встраивание в Markdown для Hugo (image shortcode, video) ✅ ВЫПОЛНЕНА
- [ ] **0.9** Сохранение прямых ссылок на посты (для репостов и оригиналов)
- [ ] **0.10** Исправление бага: посты без index.md (только медиа в папке)
- [ ] **0.11** Конвертация видео-кружков и .bin файлов в нормальный формат (mp4)
- [ ] **0.12** Отчёт о неуспешно скачанных файлах (таймаут/размер) + список URL для дозагрузки
- [ ] **0.13** Корректная временная зона (GMT+3 Москва) вместо UTC
- [ ] **0.14** Прямые ссылки на скачивание файлов в front-matter (для дозагрузки)
- [ ] **0.15** Исправление: размер файла = 0 во front-matter (должен браться из Telegram)
- [ ] **0.16** Расширенный front-matter: ссылки на канал, автора, оригинальный пост
- [ ] **0.17** Многопоточное скачивание медиа (параллельные загрузки)
- [ ] **0.18** Валидация скачанных файлов (проверка целостности)
- [ ] **0.19** Очередь на скачивание: сбор URL → многопоточная загрузка
- [ ] **0.20** Аудио-файлы: длительность, waveform для Hugo (красивый плеер)
- [ ] **0.21** Resume: возобновление прерванной архивации (по последнему ID)
- [ ] **0.22** Формат тегов для Hugo: `tags: ["tag1", "tag2"]` вместо списка
- [ ] **0.23** Обработка трансляций (streaming messages) без текста
- [ ] **0.24** Голосовые сообщения: определение формата (ogg/mp3), метаданные
**Результат:** Консольная утилита, которая по ссылке на канал скачивает все посты в папку `content/posts/` для Hugo
**Критерий готовности:** Можно запустить на своём канале `dedinit` и получить работающий статический сайт
---
### **Фаза 1: Брендинг и запуск сайта** ⬜
**Цель:** Зарегистрировать бренд, запустить сайт-визитку
- [x] **1.1** DNS для `c7e.ru` настроен
- [ ] **1.2** SSL-сертификат (Caddy / Let's Encrypt)
- [ ] **1.3** Лендинг (1 экран):
- Заголовок + слоган
- Краткое описание идеи
- Email для связи / форма подписки на ранний доступ
- [ ] **1.4** GitHub репозиторий: `github.com/evgenystor/c7e` или `github.com/evgenystor/chronicle`
- [ ] **1.5** README.md с:
- ASCII-арт логотипом
- Описанием проекта
- Roadmap
- Инструкциями для контрибьюторов
**Результат:** `c7e.ru` — рабочая точка входа, есть куда направить первых пользователей
---
### **Фаза 2: Редактор с подсветкой кода** (Q2 2026)
**Цель:** Дать тех-блогерам редактор, в котором можно писать статьи с кодом
**Требования пользователя (2026-09-18):** отдельный модуль для встраивания в другие проекты
(VESTI — первый потребитель) + основа блогоплатформы chronicle:
- Блоки кода с кнопкой «Скопировать»
- Включение/выключение нумерации строк (копирование БЕЗ номеров)
- Подсветка синтаксиса по выбранному языку
- Выделение инлайн-команд в тексте (`` `cmd` ``)
- Живой предпросмотр + GFM
- [x] **2.1** Веб-редактор — как ОТДЕЛЬНЫЙ модуль (web component / npm-пакет / собственная сборка), встраивается в VESTI и другие проекты — **ПЕРЕНЕСЁН в /opt/md-editor (2026-09-20), реализуется там: web-компонент `<md-editor>` (CodeMirror 6, без npm)**
- [ ] ~~**2.2** Интеграция Monaco Editor (как в VS Code)~~ — **перенесено в /opt/md-editor** (2026-09-20: CodeMirror 6, не Monaco — ADR 0001)
- [ ] ~~**2.3** Поддержка языков: Python, JavaScript, Go, Rust, Bash, SQL~~ — **перенесено в /opt/md-editor** (2026-09-20: + Markdown, JSON, YAML, TOML, HTML, CSS)
- [ ] ~~**2.4** Темы оформления (светлая / тёмная)~~ — **перенесено в /opt/md-editor**
- [ ] ~~**2.5** Блоки кода с кнопкой «скопировать» + нумерация строк (toggle; копирование без номеров)~~ — **перенесено в /opt/md-editor**
- [ ] ~~**2.6** Markdown-режим + WYSIWYG превью~~ — **перенесено в /opt/md-editor** (web-компонент `<md-editor>`, живой предпросмотр + GFM)
- [ ] ~~**2.7** Сохранение черновиков (локально / в GitHub)~~ — **перенесено в /opt/md-editor** (черновики в localStorage)
- [ ] ~~**2.8** Drag-and-drop изображений~~ — **перенесено в /opt/md-editor**
**Результат:** Можно написать статью с кодом, и она будет выглядеть как в IDE
---
### **Фаза 3: Интеграция с архивом** (Q3 2026)
**Цель:** Объединить редактор и архив в единую систему
- [ ] **3.1** Написанное в редакторе → автоматически в архив (Markdown-файлы)
- [ ] **3.2** Импорт постов из Telegram (через Phase 0)
- [ ] **3.3** Редактирование старых постов из архива
- [ ] **3.4** Поиск по всему контенту (full-text)
- [ ] **3.5** Теги и категории
- [ ] **3.6** Версионность постов (как Git: история изменений, откат)
**Результат:** Весь контент в одном месте, можно редактировать и искать
---
### **Фаза 4: Публикация и кросс-постинг** (Q4 2026)
**Цель:** Публикация в несколько соцсетей одной кнопкой
- [ ] **4.1** Интеграция с Telegram Bot API (публикация в канал)
- [ ] **4.2** Интеграция с VK API
- [ ] **4.3** Интеграция с Habr API (или парсинг формы)
- [ ] **4.4** Интеграция с Medium API
- [ ] **4.5** Календарь публикаций
- [ ] **4.6** Отложенные посты (очередь)
- [ ] **4.7** Адаптация контента под платформы:
- Telegram: коротко, без сложных блоков
- Habr: полная версия с кодом
- VK: адаптированный текст
- [ ] **4.8** Превью: как пост будет выглядеть на каждой платформе
**Результат:** Написал один раз → опубликовал везде с адаптацией
---
### **Фаза 5: Аналитика и экосистема** (Q1-Q2 2027)
**Цель:** Превратить Chronicle в полноценную платформу
- [ ] **5.1** Сбор статистики по платформам (просмотры, реакции, комментарии)
- [ ] **5.2** Аналитика вовлеченности
- [ ] **5.3** Лучшее время для постов (рекомендации)
- [ ] **5.4** Сбор комментариев с платформ обратно в Chronicle
- [ ] **5.5** Командная работа (несколько авторов)
- [ ] **5.6** API для разработчиков
- [ ] **5.7** Мобильное приложение (черновики, заметки)
- [ ] **5.8** White-label решения для брендов
**Результат:** Полноценная операционная система для технического креатора
---
## 💰 Монетизация
| План | Цена | Что включает |
|------|------|--------------|
| **Free** | $0 | 1 соцсеть (Telegram), базовый архив, редактор |
| **Pro** | $9/мес | До 3 соцсетей, календарь, базовая аналитика |
| **Creator** | $19/мес | До 10 соцсетей, приоритетная поддержка, API |
| **Team** | $49/мес | Командная работа, общий архив, white-label |
**Дополнительно:**
- White-label сайты: $299 разово
- Хостинг сайта: $5/мес (опционально)
- API доступ: $29/мес
---
## 📊 Метрики успеха
| Фаза | Метрика | Цель |
|------|---------|------|
| Phase 0 | Каналов архивировано | 10+ |
| Phase 1 | Посетителей на c7e.ru | 100+ за первый месяц |
| Phase 2 | Активных редакторов | 50+ |
| Phase 4 | Публикаций в день | 100+ |
| Phase 5 | Платящих пользователей | 500+ |
---
## 📝 Детали задач Фазы 0
### Задача 0.7: Извлечение тегов (#хэштеги)
**Проблема:** В Telegram теги — это просто текст с `#`. Для Hugo нужно извлечь их и добавить во front-matter.
**Реализация:**
- Парсинг текста поста на наличие `#хэштегов` (regex: `#[\wа-яА-ЯёЁ\d_]+`)
- Извлечение в список `tags: [tag1, tag2, tag3]`
- Добавление во front-matter:
```yaml
---
message_id: 1044
date: 2026-03-05T18:05:47+00:00
author: Дед in АйТи
tags: [linux, debian, usermod, sudo]
---
```
- Удаление хэштегов из текста поста (опционально)
**Результат:** Hugo сможет генерировать страницу `/tags/linux/` со списком всех постов с этим тегом.
---
### Задача 0.8: Обработка медиа для Hugo
**Проблема:** Hugo имеет свои shortcodes для встраивания медиа. Нужно использовать их вместо стандартного Markdown.
**Hugo shortcodes для медиа:**
**Изображения:**
```markdown
{{< figure src="photo.jpg" alt="Описание" title="Заголовок" >}}
```
**Видео:**
```markdown
{{< video src="video.mp4" >}}
```
**Аудио:**
```markdown
{{< audio src="audio.mp3" >}}
```
**Документы:**
```markdown
{{< download-file href="document.pdf" title="Скачать PDF" >}}
```
**Реализация:**
- При генерации `index.md` проверять тип медиа
- Вместо `![caption](file.jpg)` использовать Hugo shortcodes
- Для изображений: извлекать `alt`, `title` из caption
- Для видео/аудио: определять формат и подбирать shortcode
**Пример выходного файла:**
```markdown
---
message_id: 1042
date: 2026-03-05T07:09:24+00:00
author: Дед in АйТи
media_files:
- filename: photo_20260305_070924.jpg
type: photo
caption: "Скриншот конфига"
---
{{< figure src="photo_20260305_070924.jpg" alt="Скриншот конфига" >}}
Текст поста...
```
**Альтернатива:** Оставить стандартный Markdown `![]()` — Hugo тоже его понимает. Shortcodes дают больше контроля (lightbox, подписи, размеры).
---
## 📝 Найденные проблемы при полном тестировании (992 поста)
### Задача 0.9: Прямые ссылки на посты
**Проблема:** При скачивании репоста сохраняется название канала и ID поста, но нет прямой ссылки на оригинал.
**Реализация:**
- Для репостов: `original_post_url: https://t.me/channel_name/12345`
- Для канала: `channel_url: https://t.me/dedinit`
- Сохранять в front-matter для каждой записи
**Пример:**
```yaml
---
message_id: 1015
repost_from: 987
repost_channel: "Some Channel"
original_post_url: "https://t.me/somechannel/987"
channel_url: "https://t.me/dedinit/1015"
---
```
---
### Задача 0.10: Посты без index.md
**Проблема:** Пост 987 — в папке только mp3 файл, index.md отсутствует.
**Причина:** Вероятно, ошибка при записи файла или пост был удалён/изменён.
**Решение:**
- Проверять наличие index.md после записи
- Создавать минимальный front-matter даже если текст пуст
- Логировать ошибки записи
---
### Задача 0.11: Видео-кружки и .bin файлы
**Проблема:** Пост 988 — видео-кружок сохранился как `.bin` файл.
**Причина:** Telethon не определяет расширение для video_note.
**Решение:**
- Определять тип по MIME (video/mp4 для кружков)
- Переименовывать `.bin` → `.mp4` после скачивания
- Опционально: конвертировать в нормальное видео через ffmpeg
---
### Задача 0.12: Отчёт о неуспешно скачанных файлах
**Проблема:** Файлы по таймауту или размеру пропускаются, но не сохраняется информация для последующей дозагрузки.
**Реализация:**
- Создавать `2big2get.md` (уже есть) + `to_download_later.md`
- Сохранять прямые ссылки на файлы: `https://t.me/dedinit/123/file.mp4`
- Добавить команду для дозагрузки: `python run_archiver.py --resume-downloads to_download_later.md`
---
### Задача 0.13: Временная зона (GMT+3 Москва)
**Проблема:** `date: '2026-01-18T08:11:24+00:00'` — UTC вместо Москвы (GMT+3).
**Пост был в 11:11 по Москве, а указано 08:11 UTC.**
**Решение:**
- Определять часовой пояс канала/автора
- Конвертировать время: `date.astimezone(timezone('Europe/Moscow'))`
- Сохранять с правильным offset: `+03:00`
---
### Задача 0.14: Прямые ссылки на файлы
**Проблема:** При таймауте нет ссылки для последующей загрузки.
**Решение:**
- Telethon может получить прямую ссылку: `await client.download_media(..., file=file_path)` → сохранить URL
- Добавлять во front-matter: `download_url: "https://..."`
- Для дозагрузки использовать список URL
---
### Задача 0.15: Размер файла = 0 во front-matter
**Проблема:** `size: 0` вместо реального размера.
**Причина:** Размер не проставляется после скачивания.
**Решение:**
- Брать размер из атрибутов Telegram: `doc.size`
- Либо проверять размер файла после записи: `Path(filepath).stat().st_size`
---
### Задача 0.16: Расширенный front-matter
**Проблема:** Нет ссылок на канал, автора, оригинальный пост.
**Текущий front-matter:**
```yaml
author: Дед in АйТи
```
**Нужно:**
```yaml
author: Дед in АйТи
author_username: "@dedinit"
channel_title: "Дед in АйТи"
channel_username: "@dedinit"
channel_url: "https://t.me/dedinit"
post_url: "https://t.me/dedinit/1234"
original_post_url: "https://t.me/otherchannel/987" # для репостов
```
---
### Задача 0.17: Многопоточное скачивание медиа
**Идея:** Скачивать медиафайлы параллельно (5-10 потоков).
**Оценка:**
- Telethon поддерживает `asyncio.gather()` для параллельных загрузок
- Ограничение: Telegram может блокировать при слишком частых запросах
- Реалистично: 3-5 одновременных загрузок
**План:**
- Создать очередь на скачивание
- Запускать 3-5 корутин параллельно
- Соблюдать rate limits (паузы между запросами)
---
### Задача 0.18: Валидация скачанных файлов
**Проблема:** Файл 618 — голосовуха 384 КБ, но нет проверки целостности.
**Решение:**
- Проверять размер после скачивания (сравнить с ожидаемым)
- Проверять заголовки файлов (magic bytes)
- Логировать битые файлы в `corrupted.md`
---
### Задача 0.19: Очередь на скачивание + многопоточность
**Идея:** Разделить на 2 прохода:
1. Сбор всех URL файлов (быстро)
2. Многопоточная загрузка по списку
**План:**
- Первый проход: собрать все `download_url`
- Сохранить в `queue.json`
- Второй проход: загружать параллельно (3-5 потоков)
- Resume: продолжать с места обрыва
---
### Задача 0.20: Аудио-файлы для Hugo
**Проблема:** Голосовые сообщения без метаданных (длительность, waveform).
**Вопросы:**
- Нужна ли длительность во front-matter? (`duration: 45` секунд)
- Как отобразить waveform в Hugo?
**Решение:**
- Извлекать длительность из атрибутов Telegram: `doc.attributes.duration`
- Для waveform: использовать Hugo shortcode с JS-библиотекой (wavesurfer.js)
- Пример: `{{< audio-player src="file.ogg" waveform="true" >}}`
---
### Задача 0.21: Resume прерванной архивации
**Проблема:** 2 часа на 1000 постов — при обрыве начинать заново.
**Решение:**
- Сохранять последний обработанный ID: `last_message_id: 992`
- Команда: `python run_archiver.py --resume`
- Пропускать уже скачанные посты (дедупликация по ID)
---
### Задача 0.22: Формат тегов для Hugo
**Проблема:** Сейчас:
```yaml
tags:
- 1с
- debian
```
Hugo предпочитает:
```yaml
tags: ["1с", "debian", "postgres"]
```
**Решение:**
- Изменить формат вывода YAML
- Протестировать оба варианта в Hugo
---
### Задача 0.23: Обработка трансляций
**Проблема:** Посты 122, 120 — трансляции без текста, только метаданные.
**Вопросы:**
- Что приходит от Telegram для streaming messages?
- Можно ли извлечь длительность, участников, тему?
**Решение:**
- Изучить `message.media` для трансляций
- Сохранять метаданные во front-matter
- Создавать index.md с информацией о трансляции
---
### Задача 0.24: Голосовые сообщения
**Проблема:** Голосовухи скачиваются как `.bin` или `.ogg`.
**Вопросы:**
- Как определить формат (ogg/mp3)?
- Нужны ли метаданные (длительность, размер)?
**Решение:**
- Определять по MIME: `audio/ogg` → `.ogg`, `audio/mp3` → `.mp3`
- Извлекать длительность из атрибутов
- Сохранять во front-matter: `duration: 45, size: 127359`
---
## 🚀 Ближайшие шаги (эта неделя)
- [x] **1.1** DNS для `c7e.ru` настроен
- [ ] **1.2** SSL-сертификат (Caddy)
- [ ] **1.4** GitHub репозиторий
- [ ] **1.5** README.md с ASCII-логотипом
- [ ] **1.3** Лендинг (1 экран) на `c7e.ru`
- [ ] **0.1** Начать Phase 0: парсинг Telegram
---
## 📝 История изменений
| Дата | Изменение |
|------|-----------|
| 19 февраля 2026 | Создан документ ROADMAP.md |
---
*Документ создан на основе диалога о проекте Telegram Archiver и его эволюции в Chronicle.*