Punch2027: Ogun PDP chieftain disowns lawyer, governorship bidThe Jerusalem PostMamdani, Paris already knows where 'globalize the intifada' ends up - commentInquirer2 alleged fixers nabbed over disorderly behavior in LTO central officeESPN DeportesMou: "Si yo fuese Vini hubiese forzado una salida en verano"ESPNJon Sumrall's cowboy hat, Auburn's caption tops trolls from Week 7 in college footballDaily MaverickWORLD FOOD DAY: Hundreds of protesters take on Parliament: ‘Wake up, the climate emergency is here!’Bollywood HungamaTiger Shroff safe after firing incident reported under Juhu Police StationColliderNetflix’s Next WWII Blockbuster Officially Arrives This MonthZDF heuteEntdecken Sie das ZDF-NachrichtenstudioWirtualna PolskaBronił swojego sklepu przed złodziejami. Wideo z Francji hitem sieciسكاي نيوز عربيةفيديو.. سيدة تتوسل لمنع نهب متجرها في فرنساObservador DesportoO "xadrez" que vai reconfigurar o BCE com a saída de Lagarde
The Daily Newsstand · Free, Always
Sunday, October 18, 2026

Возвращение в прошлое, которого у нас ещё не было

Translate

Интернет когда-то выглядел иначе. До бесконечных лент, рекомендательных алгоритмов и личных брендов существовали BBS, локальные сети, IRC, форумы и имиджборды. Пользователь приходил туда не ради собственного профиля, а ради темы, разговора или случайной встречи с незнакомым человеком.

У этих систем было много ограничений. Соединение могло быть медленным, интерфейс — текстовым, а навигация — целиком клавиатурной. Но именно ограничения часто делали общение более прямым. На экране не было десятка уведомлений, автовоспроизводящегося видео и алгоритма, который решал, что показать следующим.

Я сделал попытку вернуть это ощущение, не копируя технические проблемы
прошлого, написав публичную анонимная борду, основной клиент которой работает прямо
в современном терминале.

Проект открытый, каждый может развернуть его на своем сервере и погрузиться в ностальгию. Так же он развернут на моем VPS — все подробности в статье, ссылка на исходный код прикреплена.

Midnight Commander стал языком интерфейса

Внешне Bord напоминает Midnight Commander. Слева находится список досок, справа — каталог тредов или посты открытого обсуждения.

Двухпанельный интерфейс хорошо подходит для иерархии «доска → тред → пост». Пользователь одновременно видит контекст и содержимое, а основные действия всегда остаются на экране.

TUI поддерживает:

  • управление клавиатурой и мышью;

  • полноэкранную адаптивную компоновку;

  • узкие и широкие терминалы;

  • темы classic, amber, green и mono;

  • поиск по каталогу и открытому треду;

  • просмотр длинного поста с прокруткой;

  • JPEG- и PNG-вложения;

  • inline-графику в совместимых терминалах;

  • открытие изображения системным приложением как fallback.

Скачать клиент можно на bord.pw. После распаковки он подключается одной командой:

bord --server https://bord.pw

Есть сборки для Linux, macOS и современного Windows Terminal на архитектурах AMD64 и ARM64.

На чём написан Bord

Проект реализован как Go-монорепозиторий и собирается в два основных бинарника:

  • bord — терминальный клиент;

  • bord-server — публичный API, хранилище и операторские команды.

Go выбран не только ради производительности. Он позволяет собирать автономные бинарники для разных операционных систем, удобно работать с конкурентными соединениями и обходиться без большого runtime-окружения на сервере

Клиент построен на экосистеме Charm:

  • Bubble Tea управляет состоянием TUI по архитектуре Model–Update–View;

  • Bubbles предоставляет готовые интерактивные компоненты, включая редактор;

  • Lip Gloss отвечает за цвета, размеры и оформление;

  • x/ansi помогает безопасно работать с шириной Unicode-текста и переносами.

Backend использует стандартный HTTP-стек Go, сгенерированные адаптеры OpenAPI и SQLite через pure-Go драйвер modernc.org/sqlite. Для сборки не нужна системная библиотека SQLite или C-компилятор.

Как устроен TUI

Bubble Tea основан на однонаправленном потоке данных. В упрощённом виде цикл выглядит так:

событие клавиатуры, мыши или сети ↓ Update ↓ новое состояние модели ↓ View ↓ новый кадр терминала

Модель хранит текущий экран, активную панель, выбранную доску, тред, пост, позиции прокрутки, состояние загрузки и черновик редактора. Сетевые запросы выполняются как команды Bubble Tea и возвращают типизированные сообщения обратно в цикл обновления.

Такой подход отделяет ввод от отображения. Один и тот же переход состояния можно вызвать клавишей, кликом по нижней панели или мышью. Поэтому мышь не имеет отдельной «параллельной» логики: она использует те же операции модели, что и клавиатура.

Текст перед выводом проходит санитарную обработку. Управляющие последовательности из пользовательской публикации не должны превращаться в команды терминалу, менять заголовок окна или обращаться к буферу обмена. Дополнительно рендер учитывает широкие символы, emoji и комбинируемые Unicode- последовательности.

HTTP хранит состояние, SSE сообщает об изменениях

Bord разделяет получение данных и уведомления:

  • обычный HTTP API является источником истины;

  • Server-Sent Events сообщает клиенту, что состояние изменилось;

  • после события клиент повторно читает нужный каталог или тред через HTTP.

Это проще и надёжнее, чем передавать полную модель данных внутри непрерывного потока. Если SSE-соединение оборвалось, клиент переподключается и использует Last-Event-ID. Если история событий уже недоступна, сервер сообщает о reset, после чего клиент заново синхронизирует состояние.

На reverse proxy SSE вынесен в отдельную цепочку без буферизующего сжатия. Иначе небольшие события могли бы задерживаться до накопления достаточного объёма данных, и живое обновление перестало бы быть живым.

SQLite тоже осознанный выбор

Для централизованного MVP используется SQLite в режиме WAL. У такого решения есть практические преимущества:

  • один файл базы данных;

  • транзакции и внешние ключи;

  • простое резервное копирование;

  • отсутствие отдельного сервера СУБД;

  • предсказуемое обслуживание небольшого публичного проекта.

Изображения не складываются внутрь базы. SQLite хранит метаданные, состояния и ссылки, а нормализованные blobs находятся в файловом хранилище. Запись файла проходит через временный файл и атомарное перемещение, чтобы незавершённая загрузка не стала видимым вложением.

Репозиторий содержит миграции, проверку версии схемы, команды status/migrate, согласованное резервное копирование базы и blobs, а также проверку восстановления по SHA-256.

Анонимность

У Bord нет пользовательских аккаунтов, но это не означает, что сервер вообще не обрабатывает технические данные. Публичному сервису всё равно нужны защита от спама, rate limits, блокировки и расследование злоупотреблений.

Поэтому адрес клиента по умолчанию преобразуется в HMAC-SHA-256 индекс с серверным ключом. Такой индекс позволяет обнаруживать повторные злоупотребления, не сохраняя IP открытым текстом. Опциональное хранение исходного IP выключено; если оператор сознательно включает его, значение шифруется AES-256-GCM отдельным ключом и подпадает под ограниченный срок хранения.

Trusted proxy boundary настроена явно. Backend принимает forwarded-адрес только от известного reverse proxy, поэтому произвольный клиент не может просто подставить чужой X-Forwarded-For.

Сам клиент создаёт локальный случайный session secret. Для каждой публикации он также хранит delete capability — секрет, позволяющий позднее удалить собственный пост без аккаунта. Сервер получает стойкий verifier, а исходный delete secret остаётся в локальном конфигурационном файле пользователя с ограниченными правами.

Такая модель не делает человека невидимым для сети или закона. Она решает более конкретную задачу: сервису не требуется собирать профили, email и пароли только ради публикации текста.

Безопасная работа с изображениями

Загрузка файла — одна из самых опасных частей публичного сервиса. Bord принимает только JPEG и PNG, ограничивает размер тела запроса и параметры изображения, декодирует файл и создаёт нормализованную серверную копию.

Клиент никогда не строит shell-команду из имени вложения. Для внешнего просмотра используется системный opener с отдельными аргументами. HTTP-ответы изображений получают безопасные заголовки и предсказуемый Content-Type.

Контракт вместо JSON

Публичное API описано в api/openapi.yaml. Из контракта генерируется Go-клиент, а CI проверяет, что generated-код не расходится с исходной спецификацией.

Запросы на запись используют строгий JSON: неизвестные поля отклоняются. Для создания тредов и постов предусмотрен Idempotency-Key. Если сеть оборвалась после отправки, клиент может безопасно повторить запрос с тем же ключом, не создавая дубликат.

Отдельный management API предназначен только для операторов и не публикуется через внешний Caddy. Действия модераторов записываются в audit log.

Как проект развёрнут

Публичный экземпляр работает за Caddy с автоматическим TLS-сертификатом Let's Encrypt. Внешний reverse proxy принимает https://bord.pw, добавляет проверенные forwarded-заголовки и передаёт запрос во внутреннюю Docker-сеть.

Backend и внутренний edge не публикуют собственные порты в интернет. Для сайта включены HTTPS redirect, HSTS, Content Security Policy, запрет framing, nosniff и строгая referrer policy.

Сам landing полностью статический: HTML, CSS и небольшой JavaScript без frontend-фреймворка и внешнего CDN. Он показывает возможности проекта, выбирает архив для ОС и архитектуры и формирует команды установки.

Для альтернативного развёртывания в репозитории также есть systemd unit, Caddyfile, инструкции по установке, backup, restore, ротации ключей, retention и диагностике.

Выпуск

Проект собирается для шести клиентских платформ:

linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64

Release pipeline создаёт детерминированные .tar.gz и .zip архивы. Каждый архив содержит бинарник, инструкцию, MIT License и third-party notices. Рядом публикуется SHA256SUMS.

Возвращение в прошлое

Bord не пытается доказать, что старый интернет во всём был лучше. В нём было меньше удобства, меньше доступности и гораздо меньше встроенной безопасности.

Но у него была ценная идея: интерфейс может отойти в сторону и оставить человеку текст, тему и собеседников. Терминал хорошо напоминает об этом. Он ограничивает визуальный шум, поощряет клавиатурную навигацию и не пытается превратить каждое действие в метрику вовлечённости.

Под ретро-интерфейсом не обязана находиться ретро-архитектура. Там могут быть типизированные контракты, безопасная обработка медиа, шифрование, audit, идемпотентность, автоматические тесты и воспроизводимые релизы.

В этом и состоит идея Bord: вернуться не к старым ограничениям, а к старому ощущению прямого, необязательного и немного случайного разговора — используя инструменты, которых тогда ещё не существовало.

Попробовать: https://bord.pw
Исходный код: https://github.com/pavel-up-lab/bord

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.