Как создать новое приложение на основе шаблона
Каноническое руководство — для людей и для Claude. DemoAppCore — это исходный код самой методики: каждое новое приложение компании «Один плюс один» начинается как его копия.
1 · Начало работы
- Копируем структуру решения:
DataAccessLayer,BusinessLogicLayer,UIи веб-приложение (на базеDemoApp). - DAL и UI копируются байт в байт — это канон, и менять их под отдельный проект запрещено. Нужна общая правка? Сначала здесь, в шаблоне.
- Имя проекта, namespace, логотип и заголовок меняются только в самом приложении.
- У каждого приложения свой порт разработки (launchSettings) — порты между проектами не дублируются.
- Есть готовый автоматический скил:
new-app-from-demoappcore.
2 · Новая сущность (BLL)
public class Invoice : Record
{
[Column(Size = 300)]
public override string Description { get; set; }
[Column] public double Amount { get; set; }
[Column] public DateTime Issued { get; set; }
[Column] public bool IsPaid { get; set; }
}
- Таблица создаётся и обновляется сама в
SetupAsync— никакого SQL и никаких миграций. - Имена таблиц — в единственном числе.
DateTime.MinValue= дата отсутствует. - Сущность, за которой нет реальной таблицы (демо, отображение):
[Table(Ignore = true)]. - Начальные данные (seed): переопределение
CreateAsyncв сущности (как вSettings).
3 · Экран управления
// DemoApp/Tables/InvoicesTable.cs
public class InvoicesTable : TableMakerEx<Invoice>
{
public InvoicesTable()
{
this["Description"].HeaderText = "Описание";
this["Amount"].HeaderText = "Сумма";
this["IsPaid"].HeaderText = "Оплачено";
this["IsPaid"].Filterable = true;
}
}
// Pages/Invoices.html
<h1>Счета</h1>
<div id="InvoicesTable" class="table"></div>
// Code/App.cs
public ReturnDetails Invoices() => AdminPage("Invoices");
// Pages/Main.html — кнопка в меню
<input type="button" id="Invoices" value="Счета" />
Это полноценный экран: таблица, сортировка, фильтрация, форма, экспорт. Без JS и без SQL.
4 · Страницы без таблицы
- Страница = HTML-файл в
wwwroot/Pages+ метод вApp, который возвращаетReturnDetails. - Кнопка вызывает метод по своему
id— без onclick и без новой конечной точки. - Параметры со страницы приходят в
Data(словарь); ответ сервера может передать html, popUp, script или наполнение списков. - Файлы
Pages/закрыты для прямого обращения из браузера — они отдаются только черезButtonClicked. - Состояние приложения (свойства
App) сохраняется между вызовами — в зашифрованном и сжатом виде на стороне клиента.
5 · Контент, SEO и многоязычность
- Страница контента = запись (
ContentPage), а не файл: человекопонятный адрес, H1, отдельный title, описание, изображение для соцсетей и структурированные данные. Редактируется на экране «Страницы контента». - Серверный рендеринг каждой публичной страницы (
Code/Seo.cs): уже первый ответ содержит контент и полный<head>. Панель управления остаётся SPA и получаетnoindex. - Новый экран, который должен попасть в индекс: добавьте его в
Seo.PublicMethodsи задайте емуPageMetaвPageMeta.Screens. Экран панели управления — вAdminMethods. - Сохранённые и вычисляемые метаданные проходят через единый интерфейс —
IPageMeta. Динамически созданная страница строитPageMeta.For("/…").Titled(…)во время выполнения. - Любое изменение адреса требует записи в «Перенаправлениях» (
PageRedirect), иначе каждая внешняя ссылка молча ломается. Старый числовой адрес (/Page@41) остаётся рабочим навсегда. sitemap.xmlиrobots.txtстроятся из данных сами; элементы интерфейса переводятся токенами ({текст}⇐Word), а объёмные тексты пишутся отдельной записью для каждого языка.- slug всегда на английском, строчными буквами и через дефис. Язык по умолчанию — в корне, остальные языки под
/en/; тегиhreflangвыводятся сами из общегоIdentify. - В продакшене заполните
SiteBaseUrlв настройках — на нём держатся canonical и карта сайта.
6 · Обязательные правила кода
- reuse-first: перед любой разработкой проверяем, что уже есть в
Util, DAL и UI. - Только асинхронно: синхронных обращений к базе данных нет; async доходит до самого контроллера.
- Точечное обновление:
UpdatePropertiesAsync("Col"), а не полное сохранение. - Оформление только в CSS, размеры в
rem; изменили CSS/JS ⇐ поднимите?v=. - Settings — в базе данных, а не в appsettings; база данных для разработки = localhost/SQLite.
- Поля не на иврите (электронная почта, телефон) —
LTR. - Фоновые задачи обязаны допускать возобновление (resumable).
7 · Перед сдачей работы
- Чистая сборка — без единого оставшегося предупреждения.
- code-review по diff + второе мнение (Gemini).
- Настоящая дымовая проверка в браузере — весь сценарий целиком, а не только компиляция.
- commit в SVN с содержательным сообщением; файлы .md тоже попадают в репозиторий.
- Развёртывание: переносимая папка (self-contained); в PROD — только с явного разрешения.