Техническое задание и пошаговый план реализации
Версия 1.0 · Сентябрь 2026 Автор задачи: Акмал (Kungfuman, Худжанд) Назначение документа: исходник для работы с Claude Code и точка сборки для всех решений по продукту.
Документ состоит из трёх частей:
| Часть | Что внутри | Кому |
|---|---|---|
| I. Спецификация | Принципы, архитектура, модель данных, SQL-схема, RLS | Claude Code — контекст проекта |
| II. План этапов | 8 этапов с задачами, DoD и готовыми промптами | Тебе — порядок работы |
| III. Операционный контур | Юрлицо, платежи, видео, право | Тебе — идёт параллельно коду |
Важно. Не отдавай Claude Code весь файл целиком одним промптом. Положи его в репозиторий как
docs/SPEC.md, а работай задачами по одному этапу за раз. Как это организовать — раздел 12.
Пять правил, которые определяют все решения ниже. Если возникает спор — решает этот список.
Методика — это данные, а не контент. Семиуровневая программа описывается один раз как структура в базе: дисциплина → уровень → практика → критерий аттестации. Видео, тексты и занятия только ссылаются на неё. Каталог видео копируется за месяц. Структурированная методика с прогрессией и аттестацией — нет. Это главный актив платформы.
Офлайн и онлайн — два интерфейса к одному ядру. Не два продукта. Занятие в
парке Камоли Худжанди и урок онлайн-курса ссылаются на одну и ту же запись
practices. Ученик имеет один прогресс независимо от того, где занимался.
Мультитенантность с первого дня. Худжанд — это первая запись в таблице
schools, а не хардкод. Регион, валюта, язык, часовой пояс — поля, а не константы.
Добавление Москвы или Дубая позже не должно требовать миграции.
Мультиязычность с первого дня, наполнение — по мере надобности. Все
пользовательские тексты хранятся как JSONB {"ru": "...", "tg": "...", "en": "..."}.
Сегодня заполняется только ru. Переход на tg и en не потребует переписывания
схемы.
Запуск по очереди, архитектура — сразу общая. Одна база, одна авторизация, один репозиторий. Но релизы последовательные: сначала офлайн-контур на живой группе, потом онлайн. Курс, снятый до обкатки на людях, снимается вслепую.
| Роль | Кто | Основные права |
|---|---|---|
owner |
Акмал | Всё в своей школе + управление школами |
admin |
Администратор школы | Ученики, группы, расписание, платежи |
instructor |
Инструктор | Свои группы, посещаемость, аттестации |
student |
Ученик | Свой профиль, свой прогресс, свои платежи, купленные курсы |
guest |
Лид из WhatsApp | Публичный контент, превью-уроки |
Роль хранится в profiles.role и всегда проверяется на уровне БД через RLS, а не
только в UI.
| Слой | Выбор | Почему |
|---|---|---|
| Фронтенд | Next.js 15 (App Router) + TypeScript | SSR для SEO лендингов, один язык на весь стек |
| UI | Tailwind CSS + shadcn/ui | Быстро, темизируемо под чёрно-золотую айдентику Kungfuman |
| БД + Auth + Storage | Supabase (Postgres 15+) | RLS даёт безопасность на уровне данных; auth по телефону/OTP критичен для Таджикистана |
| Хостинг | Vercel | Нулевой девопс, edge-кэш |
| Видео (РФ/СНГ) | Kinescope | Скорость в РФ, защита от скачивания, подписанные ссылки |
| Видео (мир) | Bunny.net Stream | Дёшево, глобальный CDN |
| Business API (позже) / вручную на старте | Аудитория Худжанда уже там | |
| Аналитика | Plausible или Umami | Без cookie-баннеров, проще с GDPR |
Почему не готовый LMS (GetCourse, Teachable). Они закрывают онлайн-курсы, но не закрывают офлайн-операционку и, главное, не дают хранить методику как структуру. Ты потеряешь принцип №1. При этом на первые 2–3 месяца GetCourse допустим как костыль для продаж, пока строится своё — см. этап 3.
Почему не Unreal Engine. Твоя экспертиза в UE здесь не применяется до этапа 8. Веб-платформа — это CRUD и права доступа. UE-модуль разбора формы движения через видеоанализ — отдельный продукт, к которому имеет смысл идти после того, как наберётся база учеников и материала.
schools (Худжанд, Москва, ...)
│
├── profiles ──── student_health (защищённые данные)
│ │
│ ├── enrollments ──── attestations
│ │ │
│ │ └── practice_progress
│ │
│ ├── subscriptions ──── payments
│ └── lesson_progress
│
├── disciplines ──── levels ──── practices ──── practice_criteria
│ ▲ ▲
│ │ │
├── venues groups ──── sessions ──── attendance
│ │
├── courses ──── course_modules ──── lessons
│ │
├── media_assets ─────────────────────────┘
│
├── products ──── product_prices
└── leads
Файл: supabase/migrations/00001_core.sql (см. одноимённый файл в репозитории — там
хранится актуальная версия схемы; ниже приведён её обзор).
Перечисления (enums):
app_role — student, instructor, admin, ownersession_kind — offline, online_live, self_pacedattendance_status — registered, present, absent, late, cancelledenrollment_status — active, paused, completed, droppedsub_status — pending, active, paused, expired, cancelledpayment_status — pending, succeeded, failed, refundedpayment_provider — cash, alif, dc_wallet, korti_milli, yookassa, paddle, manualmedia_provider — kinescope, vk_video, bunny, youtube, supabaseproduct_kind — subscription, course, workshop, retreat, single_visitcontent_status — draft, review, published, archivedprogress_status — not_started, in_progress, completedlead_status — new, contacted, trial_booked, trial_attended, converted, lostТаблицы (26):
schools, profiles, student_healthdisciplines, levels, practices, practice_criteriaenrollments, attestations, practice_progressvenues, groups, sessions, session_practices, attendancemedia_assets, courses, course_modules, lessons, lesson_progressproducts, product_prices, subscriptions, paymentsleads, audit_logТочные определения колонок, индексы и ограничения — в файле миграции
supabase/migrations/00001_core.sql.
Файл: supabase/migrations/00002_functions.sql.
set_updated_at() — автообновление updated_at (триггеры на profiles,
practice_progress, lesson_progress).security definer с фиксированным search_path = public, pg_temp):
auth_school_id(), auth_role(), is_staff(), is_admin(),
has_course_access(p_course_id).consume_session_credit() — списание занятия с активного абонемента при отметке
присутствия (триггер trg_attendance_credit на attendance).Внимание: для RLS-хелперов
security definer+ фиксированныйsearch_pathобязательны.
Файл: supabase/migrations/00003_rls.sql.
Принцип: ученик видит только своё, персонал видит всю свою школу, чужие школы не видит никто.
RLS включается на всех 26 таблицах. Ключевые правила:
schools — своя школа читается участниками; правит только owner.profiles — сам себя (read/update без смены роли), персонал читает свою школу,
админ правит всё в школе.student_health — только сам ученик и персонал школы.disciplines/levels/practices/practice_criteria) — читают участники
школы (practices — только published или персонал), правит только админ.courses/modules/lessons публичны при published или доступе
через has_course_access(); превью-уроки открыты; правит админ. lesson_progress —
сам ученик, персонал читает.products/prices читаются активными; subscriptions/payments — ученик
видит своё, админ правит.leads — только персонал; audit_log — читает только админ.Проверить обязательно. После применения политик залогинься тестовым учеником и попробуй прочитать чужой профиль, чужие платежи и непревьюшный урок неоплаченного курса. Если что-то отдаётся — политика дырявая. Это единственный тест, который нельзя пропустить.
kungfuman-platform/
├── app/
│ ├── (public)/ # лендинги, публичные страницы школ
│ │ ├── page.tsx
│ │ ├── [school]/
│ │ └── courses/[slug]/
│ ├── (student)/ # кабинет ученика
│ │ ├── dashboard/
│ │ ├── schedule/
│ │ ├── progress/
│ │ └── learn/[courseSlug]/[lessonId]/
│ ├── (staff)/ # админка
│ │ ├── students/
│ │ ├── groups/
│ │ ├── sessions/
│ │ ├── attendance/[sessionId]/
│ │ ├── payments/
│ │ ├── curriculum/ # редактор методики
│ │ └── leads/
│ ├── api/
│ │ ├── webhooks/[provider]/
│ │ └── media/sign/
│ └── layout.tsx
├── components/
│ └── ui/ # shadcn
├── lib/
│ ├── supabase/ # server.ts, client.ts, middleware.ts
│ ├── domain/ # чистая бизнес-логика, без React
│ │ ├── curriculum.ts
│ │ ├── attendance.ts
│ │ ├── billing.ts
│ │ └── progress.ts
│ ├── i18n/
│ └── types/database.ts # сгенерировано supabase gen types
├── supabase/
│ ├── migrations/
│ └── seed/
├── docs/
│ ├── SPEC.md # этот документ
│ └── DECISIONS.md # журнал архитектурных решений
├── CLAUDE.md
└── tests/
Оценки в неделях даны для работы соло с Claude Code, ~15–20 часов в неделю. Если занят проектами по UE — умножай на 1.5.
Не код. Идёт параллельно всему остальному и является критическим путём.
Регистрация юрлица, открытие счёта и подключение эквайринга займут больше времени, чем ты напишешь MVP. Если начать это на этапе 3, платформа будет готова, а принимать деньги будет некуда.
Задачи:
kungfuman.academy или аналог), настроить почтуDoD: есть реквизиты, на которые можно принять первый платёж от ученика в Худжанде.
Цель: база данных, авторизация, оболочка приложения. Ни одной бизнес-фичи.
Задачи:
npx create-next-app + TypeScript + Tailwind + shadcn/ui00001–00003supabase gen types typescript --local > lib/types/database.tsprofiles при регистрации нового пользователяstudent →
(student), остальные → (staff))ownert(jsonb, locale) с фолбэком на ruDoD:
Цель: твои 7 уровней перенесены в базу и редактируются через интерфейс. Это фундамент всего дальнейшего.
Задачи:
(staff)/curriculum: дисциплины → уровни → практики → критерииDoD: заходишь в админку и видишь всю свою методику как структуру. Можешь добавить практику за 30 секунд.
Цель: перестать вести учёт в тетради и в WhatsApp.
Задачи:
venues): набережная Сырдарьи, парк Камоли Худжандиsessions из расписания группы на 4 недели вперёд (cron через
Supabase Edge Function или кнопка в админке)session_practices)DoD: проводишь реальное утреннее занятие и отмечаешь всех через телефон, не открывая тетрадь.
Цель: абонементы и учёт платежей.
Задачи:
consume_session_credit уже в схеме)Не делать на этом этапе: автоматическую онлайн-оплату. При 50 учениках ручное подтверждение занимает 5 минут в день, а интеграция эквайринга — неделю. Автоматизируй, когда станет больно.
DoD: видишь, кто заплатил, у кого сколько занятий осталось, и кто пропал.
Цель: ученик перестаёт спрашивать «а когда занятие» в WhatsApp.
Задачи:
lead. Заменяет твою ссылку
wa.me, но WhatsApp остаётся как кнопкаDoD: ученик ставит иконку на телефон и видит своё расписание и прогресс.
Цель: первый продаваемый онлайн-продукт.
Задачи:
api/media/sign —
никогда не отдавать прямой URL видео клиентуpractice_idlesson_progress, обновление раз в 15 секунд)has_course_access()Что снимать первым. Курс на базе уровня 1 Цигун, уже обкатанного на живой группе с этапа 3. У тебя к этому моменту есть: понимание, где люди спотыкаются, реальные вопросы учеников, и отснятый материал с утренних занятий.
DoD: курс опубликован, куплен, пройден одним реальным человеком не из твоего окружения.
Цель: вторая школа и второй язык без переписывания кода.
Задачи:
/[locale]/..., определение локали по домену/гео/выборуtg (таджикский) для публичных страниц Худжанда — сильный сигнал доверия
локальноen для международных страницproduct_prices.region)DoD: открываешь сайт с российского IP — видишь рубли и РФ-контур; с таджикского — сомони.
Идеи, к которым имеет смысл возвращаться только когда база наберётся:
Дисклеймер: это не юридическая и не бухгалтерская консультация. Ниже — карта вопросов, которые надо задать специалисту, а не готовое решение. Всё требует проверки на месте.
| Рынок | Что нужно проверить |
|---|---|
| Таджикистан | ИП, местный эквайринг (Алиф, DC, Корти Милли). Самый быстрый путь, начинать с него. |
| РФ | Режим самозанятости (НПД) доступен гражданам РФ и стран ЕАЭС; Таджикистан в ЕАЭС не входит, поэтому этот вариант скорее закрыт без гражданства РФ. Реалистичный путь — ИП в РФ, что имеет требования по резидентству и налогам. Обязательно уточнить у бухгалтера. |
| РФ, данные | ФЗ-152 требует хранить персональные данные россиян на серверах в РФ. При работе на российскую аудиторию это может означать отдельный инстанс БД в РФ. Уточнить у юриста, попадает ли твой сценарий под требование. |
| Мир | Stripe не поддерживает Таджикистан. Merchant-of-record сервисы (Paddle, Lemon Squeezy) принимают платежи от твоего имени и решают вопрос налогов, но имеют свои списки допустимых стран для выплат. Проверить актуальные условия до этапа 7. |
Вывод для архитектуры: заложи в схему возможность двух инстансов БД (TJ и RU) с
общим кодом. Поле schools.country_code и разделение по тенантам это уже позволяют. Не
реализуй заранее, но не мешай себе.
Файл CLAUDE.md в корне репозитория содержит незыблемые правила, стек, команды и стиль
(см. корень репозитория).
Порядок работы.
Правильно:
docs/SPEC.md разделы 4.2 и 4.4. Реализуй этап 3, задачу 1:
площадки (venues). CRUD-экраны в (staff)/venues.»Неправильно:
Правила гигиены.
pnpm typecheck — не коммитишь.DECISIONS.md. Каждый раз, когда отходишь от спеки — записываешь почему. Через три
месяца не вспомнишь.lib/domain/ с тестами, потом
отдельно экран поверх неё. Тогда переделка интерфейса не ломает бизнес-правила.Неделя 1
00001–00003 примененыНеделя 2
Неделя 3
Неделя 4
Последний пункт — единственная настоящая метрика первого месяца. Всё остальное можно переделать.
| Риск | Как проявится | Что делать |
|---|---|---|
| Строишь вместо того, чтобы преподавать | Через 3 месяца отличная платформа и та же группа из 12 человек | Жёсткий таймбокс: 15 часов в неделю на код, не больше |
| Онлайн-курс до обкатки офлайн | Снят курс, который не продаётся | Не начинать этап 6 раньше, чем уровень 1 пройдут 20 живых человек |
| Платёжный контур не готов к запуску | Продукт есть, деньги принять нечем | Этап 0 стартует сегодня, а не когда код будет готов |
| Переусложнение схемы | Полгода на архитектуру, ноль пользователей | Схема выше — потолок. Новые таблицы только под подтверждённую потребность |
| Выгорание на соло-разработке | Проект замирает на этапе 4 | После этапа 5 рассмотреть подрядчика на фронтенд. Ядро и методика остаются у тебя |
Документ живой. По мере реализации обновляй разделы 4 и 11 — они устареют первыми.