ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
RusoFácilapp — сайт для обучения русскому языку Сайт для испаноговорящих студентов из Мексики: курсы русского языка от уровня A1 до B2, интерфейс на трёх языках (испанский, русский, английский), платная подписка (Stripe) и личный кабинет студента с прогрессом по урокам. • Раздел 1–2 — как запустить сайт на своём компьютере (нужен один раз). • Раздел 3 — как редактировать тексты, уроки и цены без программирования (для преподавателя/контент-менеджера). • Раздел 4–6 — команды проверки, переменные окружения и деплой (для разработчика).查看完整 README ↗
Сайт для испаноговорящих студентов из Мексики: курсы русского языка от уровня A1 до B2, интерфейс на трёх языках (испанский, русский, английский), платная подписка (Stripe) и личный кабинет студента с прогрессом по урокам.
Это руководство написано для двух аудиторий:
Node.js версии 20 или новее. Проверить, установлен ли он:
node -v
Если команда не найдена — самый простой способ поставить Node.js через nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# закройте и снова откройте терминал, затем:
nvm install --lts
Больше ничего устанавливать вручную не нужно — все остальные зависимости (Next.js, база данных, Stripe SDK) ставятся одной командой на следующем шаге.
# 1. Установить зависимости (один раз, займёт 1–2 минуты)
npm install
# 2. Скопировать файл с переменными окружения
cp .env.example .env
# 3. Сгенерировать секрет для входа и вписать его в .env
# (без этого шага вход и подписка не заработают — см. раздел 5)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# скопируйте, что выведет команда, и вставьте в .env вместо SESSION_SECRET=""
# 4. Создать локальную базу данных (SQLite-файл dev.db)
npx prisma db push
# 5. Назначить себя владельцем сайта (доступ к панели администратора)
# подставьте свою почту — той же почтой нужно будет войти на сайте
npm run db:set-owner -- [email protected]
# 6. Запустить сайт
npm run dev
После этого сайт открывается на http://localhost:3000 (Next.js сам подставит другой порт, например 3001, если 3000 занят — смотрите, что написано в терминале после запуска).
По умолчанию .env работает в «демо-режиме»: платежи не уходят в настоящий
Stripe, а подписка активируется сразу же после нажатия кнопки — это удобно
для тестирования и для локальной демонстрации сайта. Как подключить настоящий
Stripe — см. раздел 5. Переменные окружения.
Каждый следующий раз для запуска достаточно одной команды:
npm run dev
(Шаг 1 нужно повторить, только если вы удалили папку node_modules; шаги
4–5 — если вы удалили файл dev.db, то есть база данных стала пустой.)
Все тексты, которые видит студент, вынесены в отдельные JSON-файлы —
их можно открыть и отредактировать в любом текстовом редакторе (даже в
Блокноте), не трогая код сайта. Главное правило работы с JSON:
Сохраняйте кавычки
"..."и запятые между строками как есть — если случайно удалить кавычку или запятую, сайт перестанет собираться. Если сомневаетесь — сделайте копию файла перед правкой.
После любого изменения в JSON-файлах сайт обновляется автоматически,
если он запущен через npm run dev — просто сохраните файл и обновите
страницу в браузере.
Файлы: src/dictionaries/es.json, src/dictionaries/ru.json,
src/dictionaries/en.json — по одному на каждый язык интерфейса
(испанский / русский / английский).
Внутри каждого файла есть, среди прочего:
"nav", "home", "footer" — тексты шапки, главной страницы, подвала;
"courses"."levels"."a1" (и a2, b1, b2) — заголовок, описание и
список названий уроков для каждого уровня. Чтобы переименовать урок
или изменить его описание — меняйте текст здесь;
"pricing" — тексты и цены тарифов:
"monthly": { "name": "Mensual", "price": "$249", "period": "/ mes", "cta": "Suscribirme" },
"annual": { "name": "Anual", "price": "$1,990", "period": "/ año", "cta": "Suscribirme", "badge": "Ahorra 33%" }
Чтобы поменять цену — отредактируйте значение "price". Отображаемая
цена — это просто текст (не связана напрямую с реальным биллингом), но
не забудьте поменять её во всех трёх файлах (es.json, ru.json,
en.json), иначе на разных языках сайта будут показаны разные цифры.
(Реальная сумма, которую спишет Stripe, настраивается отдельно — в самом
Stripe, через STRIPE_PRICE_MONTHLY / STRIPE_PRICE_ANNUAL, см. раздел 5.)
Структура одинаковая во всех трёх файлах — если добавляете новый уровень
вложенности текста в es.json, добавьте такой же ключ в ru.json и
en.json, иначе сайт покажет ошибку на этом языке.
Файл: src/lib/lessons/content.json.
Здесь хранится подробное содержание уроков — то, что студент видит на вкладках «Gramática / Vocabulario / Ejercicios» на странице урока. Весь этот текст всегда пишется на испанском (курс объясняет русский язык через сравнение с испанским), независимо от того, какой язык выбран в переключателе сайта.
Каждый урок — это один блок в файле, с ключом вида "a1-1" (уровень a1,
урок 1), "a1-2", "a2-1" и так далее — цифра соответствует номеру урока
в списке "lessons" того же уровня в файлах из раздела 3.1.
Пока что заполнены только уроки a1-1 и a1-2 — это готовый пример
формата. Для всех остальных уроков (которые уже видны в списке курса)
страница автоматически показывает заглушку «содержание в разработке», пока
для них не добавлен блок в этом файле.
Структура одного урока:
"a1-1": {
"grammar": {
"title": "El alfabeto cirílico y los sonidos del ruso",
"paragraphs": [
"Первый абзац объяснения грамматики.",
"Второй абзац — можно добавлять сколько угодно строк в этот список."
]
},
"vocabulary": [
{ "word": "привет", "transcription": "privét", "translation": "hola (informal)" }
],
"exercises": [ /* см. ниже */ ]
}
grammar.paragraphs — список абзацев текста (обычный текст, без
markdown-разметки — **жирный** или *курсив* отображены не будут).vocabulary — список слов: word (по-русски), transcription
(произношение латиницей), translation (перевод на испанский).Внутри "exercises" — список упражнений. У каждого упражнения обязательно
своё уникальное "id" (просто строка, использована как ключ, не показывается
студенту) и "type", определяющий тип упражнения:
1. Выбор варианта (multiple-choice)
{
"id": "a1-1-mc-3",
"type": "multiple-choice",
"prompt": "¿Qué significa 'спасибо'?",
"options": ["hola", "gracias", "sí", "no"],
"correctIndex": 1
}
correctIndex — номер правильного варианта в списке options, считая от
нуля (0 — первый вариант, 1 — второй, и так далее).
2. Вставка пропущенной буквы/слова (fill-blank)
{
"id": "a1-1-fill-3",
"type": "fill-blank",
"before": "вод",
"after": "",
"answers": ["а"]
}
Студент видит before + поле для ввода + after (например, «вод[___]» →
нужно вписать «а»). В answers можно перечислить несколько вариантов
правильного ответа — регистр букв (заглавные/строчные) не важен.
3. Сопоставление пар (matching)
{
"id": "a1-1-matching-2",
"type": "matching",
"pairs": [
{ "left": "дом", "right": "casa" },
{ "left": "вода", "right": "agua" }
]
}
Студент видит список слов слева (left) и должен выбрать для каждого
правильный перевод из выпадающего списка (right).
src/lib/lessons/content.json."a1-2": { ... })
вместе с запятой перед ним."a1-3" —
номер должен совпадать с позицией названия урока в списке "lessons"
уровня a1 в src/dictionaries/es.json (и ru.json, en.json).Если после сохранения файла сайт показывает ошибку — скорее всего, в JSON пропущена запятая или кавычка. Хорошо помогает бесплатный онлайн-валидатор JSON (например, jsonlint.com) — можно вставить туда содержимое файла и проверить, где ошибка.
Важно: этот файл — только «встроенный пример по умолчанию». Если урок отредактирован через панель администратора (
/admin/lessons, см. раздел 3.4), сайт показывает версию из базы данных, а не из этого файла — правки вcontent.jsonдля такого урока перестанут быть видны, пока редактор не удалит правку через кнопку «Eliminar edición» / «Удалить правку». Для урока, который никто не редактировал через панель, всё работает как описано выше.
Всё остальное в папке src/ — это код сайта (файлы .ts и .tsx):
оформление страниц, логика подписки, защита уроков и т.д. Их менять без
знания программирования не стоит.
У сайта три роли:
| Роль | Права |
|---|---|
| owner (владелец) | Всё, что может admin, плюс раздел «Пользователи и роли»: назначение и снятие ролей у кого угодно, включая других администраторов. Владелец не может случайно снять роль владельца сама с себя, если она последняя в системе — сайт это запрещает. |
| admin (администратор) | Добавление/редактирование/удаление уроков, просмотр списка пользователей и подписок. Не видит раздел «Пользователи и роли» и не может ни выдавать/отменять подписки вручную, ни менять чьи-либо роли. |
| student (студент) | Обычный пользователь: личный кабинет и оплаченный контент. Роль по умолчанию для всех новых регистраций. |
Панель администратора находится на /admin (ссылка «Panel de administración»
появляется в шапке сайта у тех, кто вошёл как admin или owner). В ней три
раздела:
/admin/lessons) — список всех уроков всех уровней со статусом
(«Отредактировано» / «Есть пример» / «Нет содержания») и редактор с полем
JSON для грамматики/словаря/упражнений (тот же формат, что в разделе 3.2,
но правки здесь сохраняются в базу данных, а не в файл — это единственный
способ редактирования уроков, который переживает деплой на Vercel)./admin/subscriptions) — статус подписки каждого
пользователя; у владельца есть кнопки «Активировать на 30 дней» и
«Отменить» для ручного управления доступом без Stripe./admin/users, только для владельца) — смена
роли любого пользователя через выпадающий список.Как назначить владельца. Первый владелец назначается вручную — через скрипт, а не через интерфейс (иначе некому было бы выдать первую роль):
npm run db:set-owner -- [email protected]
Команда идемпотентна — её можно запускать повторно (например, на новой базе
данных после деплоя) или для смены владельца на другой email. Дальше этот
человек может назначать администраторов через /admin/users.
Как загрузить содержание уроков в базу данных массово. Если правите
src/lib/lessons/content.json напрямую (раздел 3.2) и хотите, чтобы эти же
версии оказались в БД (а не только в статическом файле-фолбэке), выполните:
npm run db:seed-lessons
Важно: команда перезаписывает в БД любой урок, чей ключ уже есть в
content.json — включая все текущие 32 урока. Если вы уже отредактировали
какой-то из этих 32 уроков через /admin/lessons и хотите сохранить эту
правку, не запускайте команду повторно для этого урока (либо сначала
обновите content.json тем же содержанием, прежде чем запускать).
Защита маршрутов. Доступ к /admin и ко всем API-маршрутам
/api/admin/* проверяется дважды независимо друг от друга: в
src/proxy.ts (до отрисовки страницы) и внутри каждого маршрута/страницы
(src/lib/admin-auth.ts). Это сделано специально, чтобы ошибка в одном
месте не открывала доступ посторонним — тот же принцип, что и у защиты
платных уроков.
Перед тем как выложить изменения на Vercel (или любой другой хостинг), запустите одну команду — она проверяет код, типы и то, что сайт вообще собирается:
npm run verify
Это эквивалент трёх шагов подряд:
| Команда | Что делает |
|---|---|
npm run lint | Проверяет код на ошибки и плохие практики (ESLint) |
npm run typecheck | Проверяет типы TypeScript без сборки (быстрее, чем полный build) |
npm run build | Собирает продакшн-версию сайта — если она падает, упадёт и деплой на Vercel |
Если вы правили только JSON-файлы из раздела 3 (тексты, уроки, цены),
запускать npm run verify не обязательно — эти файлы не участвуют в
проверке типов и почти никогда не ломают сборку (разве что из-за опечатки
в структуре JSON — в этом случае npm run build покажет, в какой строке
файла ошибка).
Если вы правили код (.ts / .tsx) — обязательно прогоните npm run verify
перед тем, как отправлять изменения в git / деплоить.
Файл .env (создаётся копированием .env.example, см. раздел 2) содержит:
| Переменная | Обязательна? | Назначение |
|---|---|---|
DATABASE_URL | да | Путь к локальной базе SQLite (file:./dev.db) |
SESSION_SECRET | да | Секрет для подписи cookie-сессии входа. Сгенерировать: openssl rand -hex 32 |
STRIPE_SECRET_KEY | нет | Секретный ключ Stripe. Пусто = демо-режим (см. ниже) |
STRIPE_WEBHOOK_SECRET | нет | Секрет для проверки подписи вебхуков Stripe |
STRIPE_PRICE_MONTHLY / STRIPE_PRICE_ANNUAL | нет | ID цен (Price ID) месячного/годового тарифа в Stripe |
Демо-режим (по умолчанию): если STRIPE_SECRET_KEY не задан, кнопка
«Suscribirme» на странице тарифов сразу активирует подписку в базе данных,
без обращения к настоящему Stripe. Это позволяет полностью протестировать
сайт (личный кабинет, доступ к урокам, отмену подписки) без создания
Stripe-аккаунта.
Реальный Stripe: чтобы принимать настоящие платежи, создайте аккаунт на
stripe.com, создайте два тарифа (Price) в разделе
Products, впишите их ID и секретные ключи в .env, а также настройте
вебхук в Stripe Dashboard на адрес <ваш-домен>/api/webhooks/stripe с
событиями checkout.session.completed, customer.subscription.updated,
customer.subscription.deleted, invoice.payment_failed.
.env (раздел 5).Важно про базу данных. Локально сайт использует SQLite — файл dev.db
на диске. На Vercel (как и на большинстве serverless-хостингов) файловая
система эфемерна: файл базы данных не сохраняется между запросами, поэтому
SQLite не подходит для продакшн-деплоя на Vercel как есть. Перед боевым
запуском на Vercel нужно:
DATABASE_URL в переменных окружения Vercel;src/lib/db.ts (сейчас там
@prisma/adapter-better-sqlite3) на адаптер, соответствующий выбранной
базе (например, @prisma/adapter-pg для Postgres) — это уже требует
участия разработчика.Пока этот шаг не сделан, деплой на Vercel будет работать для демонстрации интерфейса, но данные о пользователях/подписках/прогрессе не будут надёжно сохраняться между запросами.
src/
app/[lang]/ # страницы сайта (испанский/русский/английский)
courses/[level]/[lesson]/ # страница урока с вкладками и упражнениями
profile/ # личный кабинет студента
admin/ # панель администратора (уроки/подписки/роли, см. раздел 3.4)
pricing/, login/ # тарифы и вход
app/api/ # серверные обработчики (авторизация, checkout, вебхук Stripe)
api/admin/ # ручки панели администратора
components/ # переиспользуемые UI-компоненты
dictionaries/ # ← тексты интерфейса и цены (JSON, см. раздел 3.1)
lib/lessons/content.json # ← содержание уроков по умолчанию (JSON, см. раздел 3.2)
lib/roles.ts # роли (owner/admin/student) и проверки прав
lib/ # логика подписки, прогресса, авторизации
i18n/ # список поддерживаемых языков
proxy.ts # защита /courses/.../[lesson] и /admin на уровне запроса
prisma/schema.prisma # модели базы данных (пользователи, роли, подписки, уроки, прогресс)
prisma/set-owner.ts # скрипт назначения владельца (npm run db:set-owner)