django.moscow — Сервисный лендинг с дизайн-системой
Production-ready лендинг с автогенерацией цветовых палитр, кастомными ESLint-правилами и строгой FSD-архитектурой. Создал дизайн-систему нового уровня для масштабируемых проектов.
Оглавление
Контекст
Запустил новый сервис по поддержке Django-проектов и нужен был лендинг. Но не просто «страничка», а полноценная платформа для экспериментов с дизайн-системами и архитектурными паттернами. Результат — production-ready проект с автогенерацией цветовых токенов, кастомными линтерами и FSD-архитектурой.
Живой пример: django.moscow
Проект стал sandbox'ом для отработки продвинутых техник: автоматическая генерация дизайн-токенов, кастомные ESLint-правила, строгое соблюдение FSD. Всё, что работает здесь, переношу в коммерческие проекты.
Дизайн-система нового уровня
Трёхслойная токенизация
Создал систему, где цвета генерируются автоматически из конфига:
- Палитры (tokens.css) — 8 цветовых палитр с оттенками 50-950, генерируются из базовых цветов через chroma-js в LCH-пространстве
- Семантика (semantic.css) — контекстные токены (
background,foreground,surface,text-*,link) - Tailwind-маппинг (theme-mapping.css) — прозрачная интеграция с утилитами (
bg-surface,text-foreground)
// palette.config.json
{
"primary": { "base": "#7e102e" }
}npm run colors:generate
# → Генерирует полную палитру: primary-50...primary-950
# → Автоматически настраивает dark-режим (инверсия шкалы)
# → Мапит на Tailwind-классыАвтоматическая поддержка тем
Темы работают через data-theme атрибут, а не классы:
:root {
--background: var(--color-gray-50);
--foreground: var(--color-gray-900);
}
[data-theme="dark"] {
--background: var(--color-gray-950);
--foreground: var(--color-gray-50);
}Кастомный ESLint плагин
Написал собственный ESLint-плагин для запрета хардкод-цветов:
// ❌ Запрещено
<div className="bg-blue-500 text-zinc-900" />
// ✅ Разрешено
<div className="bg-primary-500 text-foreground" />Плагин анализирует:
- Tailwind-классы в JSX (
className,class) - Встроенные стили (
style) - CSS-файлы через Stylelint
Результат: 100% использование дизайн-токенов, ноль «магических» цветов в коде.
Архитектура: FSD с границами
Применил строгое Feature-Sliced Design с автоматической проверкой границ:
src/
├── app/ # Next.js App Router, провайдеры, глобальные стили
├── processes/ # Бизнес-процессы (checkout, onboarding)
├── widgets/ # Крупные UI-блоки (header, footer, hero)
├── features/ # Пользовательские сценарии (theme-toggle, filters)
├── entities/ # Доменные сущности (user, post, order)
└── shared/ # UI-примитивы, утилиты, конфигПравила импортов (enforced by ESLint):
features→ может импортитьentities,sharedfeatures→ НЕ может импортитьwidgets,processes- Нарушение = ошибка сборки
ESLint не прощает ошибок: попытка импортировать виджет в фичу = красная сборка. Это жёсткий контроль, но он окупается в долгосрочной перспективе.
Технологический стек
Next.js 16 + React 19
Использовал самые свежие версии для тестирования новых возможностей:
- Server Components по умолчанию
- Server Actions для форм
- Streaming и Suspense
- Оптимизированная сборка Turbopack (в dev-режиме)
Tailwind CSS v4
Новая версия с inline-конфигом прямо в CSS:
@theme inline {
--color-primary: var(--primary);
--color-foreground: var(--foreground);
}Никаких tailwind.config.js — всё в CSS, нативно и быстро.
shadcn/ui интеграция
Настроил components.json для работы с FSD:
npx shadcn@latest add button
# → Устанавливается в src/shared/ui/
# → Интегрируется с дизайн-токенами
# → Готов к использованиюКонтент и SEO
MDX-блог с валидацией
- Все посты в MDX с frontmatter
- Zod-схема для валидации метаданных
- Автоматическая проверка в pre-push hook
- Отдельный скрипт для CI/CD:
npm run blog:validate
Полная SEO-оптимизация
- JSON-LD structured data (Organization, WebSite, Service)
- Динамический sitemap
- robots.txt
- Open Graph и Twitter Cards
- Canonical URLs
const jsonLd = {
"@context": "https://schema.org",
"@type": "Service",
name: "Поддержка и разработка Django",
provider: { "@id": "https://django.moscow/#organization" },
};Production-ready инфраструктура
PM2 в кластерном режиме
// ecosystem.config.js
{
name: 'django-moscow',
instances: 'max', // Все CPU-ядра
exec_mode: 'cluster', // Кластер для zero-downtime
autorestart: true, // Авто-рестарт при падении
max_memory_restart: '1G', // Рестарт при превышении памяти
}Zero-downtime deploys:
pm2 reload django-moscow # Рестарт без простояGit hooks для качества
- pre-commit: ESLint + Stylelint (блокирует коммит при ошибках)
- pre-push: Валидация MDX-постов (блокирует push при невалидных данных)
Результаты
Уроки и находки
Автогенерация токенов = масштабируемость
Добавить новый цвет в дизайн-систему теперь — это изменить 1 строку в JSON и запустить скрипт. Раньше — ручная работа на час.
Кастомные ESLint-правила окупаются
Первые 2 дня ругался на «назойливый линтер». Через неделю — радовался отсутствию вопросов типа «почему у кнопки не тот цвет в dark mode?».
FSD с границами ≠ бюрократия
Строгие правила импортов кажутся избыточными на старте. Через месяц разработки понимаешь, что это единственный способ не превратить проект в спагетти.
django.moscow стал полигоном для техник, которые теперь применяю во всех проектах: автогенерация дизайн-токенов, кастомные линтеры, строгий FSD. Результат — предсказуемый, масштабируемый и приятный в поддержке код.
Что дальше
- RSS/Atom feed для блога
- Автогенерация OG-изображений для постов
- Lighthouse CI в pipeline
- A/B тесты на лендинге
- Расширение дизайн-системы: spacing, typography, shadows
Похожие материалы
Проекты с похожими технологиями и задачами
PassWave — Генератор и хранилище паролей
Минималистичный PWA: генерирует крепкие пароли, шифрует всё на клиенте, синхронизируется по желанию. Сделал MVP за 2 недели — и оставил как есть: быстро, безопасно, без излишеств.
- Next.js 16
- React 19
- TypeScript
- Supabase
- PWA
- +1
Slot-Me.ru — Платформа бронирования встреч
Cal.com для русского рынка: от архитектуры до production. FastAPI + React, FSD, OAuth, календари, email, 196 тестов.
- FastAPI
- React
- PostgreSQL
- Redis
- TypeScript
- +3
Система управления Евразийским экономическим форумом молодежи (ШОС)
Госзаказ на управление масштабным международным мероприятием: 12 кураторов, 72 координатора, 5000+ участников. Технически справились, психологически чуть не сгорели. Урок о том, что госконтракты требуют не только технологий, но и работы с людьми.
- Python
- Django
- PostgreSQL
- JavaScript
- jQuery
- +1