mirror of
https://gitverse.ru/kpa39l/chronicle.nixg.ru.git
synced 2026-09-29 01:50:07 +00:00
514 lines
24 KiB
Markdown
514 lines
24 KiB
Markdown
# 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` проверять тип медиа
|
||
- Вместо `` использовать 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.*
|