Initial SFERA platform baseline

This commit is contained in:
2026-05-16 19:03:49 +03:00
commit 3b845c8fce
282 changed files with 55045 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
# Codex Instructions for SFERA
Путь проекта для Windows-команд: `R:\codex\SFERA`.
Диск `R:` смонтирован на `\\nas\MST`; используй `R:\codex\SFERA` вместо UNC-пути `\\nas\MST\codex\SFERA`, чтобы Windows/Node/Next не упирались в ограничения сетевого current directory.
Всегда читай:
1. `docs/design-system.md`
2. `docs/component-architecture.md`
3. `docs/codex-ui-guidelines.md`
Перед созданием UI:
- определи бизнес-сущность
- выбери стандартный page pattern
- проверь наличие базовых компонентов
- не создавай новый UI primitive, если есть shadcn/ui компонент
- делай маленькие файлы
После создания UI:
- добавь loading/error/empty states
- проверь accessibility
- проверь responsive
- проверь TypeScript
- добавь комментарии только там, где они реально помогают
+47
View File
@@ -0,0 +1,47 @@
---
description: SFERA UI rules
globs:
- "src/**/*.tsx"
- "src/**/*.ts"
alwaysApply: true
---
# SFERA UI Rules
Use:
- Next.js
- React
- TypeScript
- Tailwind
- shadcn/ui
- lucide-react
- TanStack Table
- Zod
- React Hook Form
Do not use:
- Bootstrap
- random colors
- inline styles
- huge components
- business logic inside JSX
Every page must include:
- loading state
- error state
- empty state
- permission state where applicable
Visual style:
- enterprise
- minimal
- rounded-2xl
- soft shadows
- clear hierarchy
- dark/light ready
AI actions must show:
- selected model
- token usage
- project/user limits
- audit log entry
+8
View File
@@ -0,0 +1,8 @@
.git
.pytest_cache
.venv
**/__pycache__
**/*.pyc
frontend/sfera-web/.next
frontend/sfera-web/node_modules
rust/target
+24
View File
@@ -0,0 +1,24 @@
SFERA_ENV=local
SFERA_LOG_LEVEL=INFO
# Optional: path to compiled Rust BSL parser executable.
# Windows example: rust\target\debug\bsl-parser.exe
SFERA_BSL_PARSER=
POSTGRES_DSN=postgresql://sfera:sfera@localhost:5432/sfera
NEO4J_URI=bolt://docker-test.cin.su:17687
NEO4J_USER=neo4j
NEO4J_PASSWORD=password
QDRANT_URL=http://localhost:6333
REDIS_URL=redis://localhost:6379/0
# Optional local 1C/EDT imports. Do not store infobase passwords here.
RUNTIME_ADAPTER_MODE=mock
RUNTIME_ADAPTER_URL=http://localhost:8010
ONEC_DESIGNER_PATH=C:\Program Files\1cv8\8.5.1.1150\bin\1cv8.exe
SFERA_EDT_PROJECTS_PATH=C:\EDT\projects
SFERA_UPO_EDT_PATH=C:\EDT\projects\iFCM-UPO\upo\src
SFERA_UPO_INFOBASE='Srvr="192.168.200.95";Ref="upo";'
# Optional official 1C documentation access. Put real credentials only in .env.local.
SFERA_ITS_URL=https://its.1c.ru/db/v838doc#browse:13:-1:7
SFERA_ITS_USERNAME=<set locally>
SFERA_ITS_PASSWORD=<set locally>
+23
View File
@@ -0,0 +1,23 @@
name: CI
on:
push:
pull_request:
jobs:
python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uv sync --all-packages
- run: uv run ruff check .
- run: uv run mypy packages services || true
- run: uv run pytest packages/sir/tests
rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cd rust && cargo test
+23
View File
@@ -0,0 +1,23 @@
.venv/
__pycache__/
*.egg-info/
.pytest_cache/
.mypy_cache/
.ruff_cache/
target/
node_modules/
.next/
*.tsbuildinfo
.env
.env.local
.env.*.local
.sfera/
tmp/
tmp-*/
api_server_diag.py
*.pyc
*.log
*smoke-debug.png
.DS_Store
.idea/
.vscode/
+20
View File
@@ -0,0 +1,20 @@
# AGENTS.md instructions for SFERA
## Shared Test Docker Host
- Test and stand verification must be done on the shared Docker host, not on a local Docker Engine.
- Use SSH alias `test-docker` / `docker-test`.
- Host: `docker-test.cin.su` (`192.168.200.61`).
- SSH user: `test`.
- Preferred Docker endpoint when Docker CLI is available: `ssh://test-docker`.
- Deploy both backend/server services and frontend services on `docker-test` for integrated testing.
- Portainer: `http://docker-test.cin.su:9000/`, user `admin`.
- Do not store the password in repositories or project files; use an SSH key for persistent access.
## Local Workspace Path
- The project is available locally at `Z:\codex\SFERA`.
- `Z:\codex\SFERA` is a mapped network folder for `\\nas\MST\codex\SFERA`.
- Prefer `Z:\codex\SFERA` for Windows tooling and frontend commands.
- Do not fall back to UNC current directories for npm/cmd workflows; Windows `cmd.exe` does not support UNC current directories reliably.
+72
View File
@@ -0,0 +1,72 @@
# Codex Instructions for SFERA
Ты реализуешь SFERA по шагам. Не перескакивай к AI и UI, пока не работает semantic core.
## Абсолютные правила
1. Не писать autonomous code generation до готового SIR + parser + graph.
2. Каждый parser bug превращать в golden fixture.
3. Не писать напрямую в Neo4j вне `projection-engine`.
4. Все изменения в будущем должны быть связаны с task/session/user, но в Phase 1 можно оставить placeholders.
5. Русский UI и команды по умолчанию, но должен быть выбор английского интерфейса/команд; internal models — English.
6. BSL parser обязан поддерживать смешанный русский/английский синтаксис 1С в одном тексте.
7. Любые integration/security/agent слои делать только после core.
## Test stand and workspace
- Тестирование интегрированного проекта проводить на `docker-test` / `test-docker`, а не на локальном Docker Engine.
- На `docker-test` разворачивать обе части: backend/server services и frontend.
- Docker endpoint: `ssh://test-docker`.
- Host: `docker-test.cin.su` (`192.168.200.61`), SSH user: `test`.
- Portainer: `http://docker-test.cin.su:9000/`, user `admin`; пароль не сохранять в репозитории и проектных файлах.
- Локальный рабочий путь проекта: `Z:\codex\SFERA`.
- `Z:\codex\SFERA` — подмонтированная сетевая папка `\\nas\MST\codex\SFERA`.
- Для Windows/npm/frontend команд использовать `Z:\codex\SFERA`, не UNC current directory.
## Frontend contract
Перед любым изменением frontend:
1. Прочитать `docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md`.
2. Прочитать `docs/frontend/SFERA_IDE_UI_CONTRACT.md`.
3. Если меняется дерево 1С - прочитать `docs/frontend/SFERA_METADATA_TREE_CONTRACT.md`.
4. Если меняются настройки проекта - прочитать `docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md`.
5. Если контракт устарел - сначала обновить контракт, затем код.
6. Все UI-изменения фиксировать в `docs/frontend/SFERA_FRONTEND_CHANGELOG.md`.
Не ломать принятую модель: SFERA = metadata-first semantic configurator for 1C, основной экран = IDE последнего проекта, проект выбирается сверху, левая панель = дерево текущего проекта, основная конфигурация и расширения = configuration-like roots одного уровня, центр = рабочая область, правая панель = контекстные свойства, низ = открытые объекты, tools и status.
Для 1C-specific поведения использовать official 1C docs через ITS/v8.1c.ru/1C DN или локальные knowledge packs. ITS credentials брать только из `.env.local`; реальные credentials не коммитить, не писать в markdown/Dockerfile и не выводить в logs.
## Текущий приоритет
Реализовать Phase 1:
```text
packages/sir
rust/crates/bsl-parser
packages/semantic-kernel
packages/projection-engine
packages/incremental-indexer
```
## Стиль кода
- Python 3.12+.
- Pydantic v2.
- Async где есть IO.
- Rust parser сначала простой и детерминированный.
- Тесты обязательны.
- Минимальная магия.
## Definition of Done Phase 1
```text
1. BSL procedures extracted.
2. Calls extracted.
3. Queries extracted.
4. Writes extracted.
5. SIR snapshot validates.
6. Neo4j projection works.
7. Incremental update works on changed file.
```
+95
View File
@@ -0,0 +1,95 @@
# SFERA — полный анализ проекта для Codex
## Что строим
SFERA — серверная semantic SDLC платформа для 1С:
- semantic graph 1С-конфигурации;
- полноценная IDE-среда для ручной и AI-assisted разработки 1С;
- object-level versioning вместо обязательного Git;
- task-linked изменения;
- review/impact/runtime intelligence;
- knowledge-aware AI, который умеет анализировать, писать и изменять 1С-код и metadata;
- агенты EPF/CFE;
- marketplace/download center;
- многопользовательская серверная консоль.
## Продуктовая формула
```text
SIR + Lineage + Object Versioning + Runtime Overlay + Knowledge Base + Collaboration
```
Расширенная формула продукта:
```text
Semantic Core + 1C IDE + AI Pair Programmer + Object/Form Designer + Guarded Apply
```
## Что не делаем в начале
- автоприменение изменений в production;
- автономное применение AI-изменений без preview/diff/approval;
- полный live debugger;
- сложную marketplace-экосистему;
- heavy frontend до ядра.
## IDE и authoring стратегия
SFERA должна уметь всё, что ожидается от современной IDE для 1С, но опираясь на semantic graph и структуру конфигурации:
- ручное редактирование BSL-кода с подсветкой, диагностикой, навигацией, поиском ссылок и refactoring;
- AI autocomplete и продолжение кода с учётом текущей процедуры, локальных переменных, параметров, доступных реквизитов, табличных частей, форм, команд, ролей и связей объекта;
- AI generation для процедур, функций, обработчиков команд, запросов, движений регистров и безопасных шаблонов 1С;
- создание и изменение объектов 1С: документы, справочники, регистры, общие модули, реквизиты, табличные части, команды, формы и отчёты;
- visual/object designer для metadata, форм, команд, реквизитов, табличных частей и отчётов;
- preview/diff всех изменений перед применением;
- guarded apply: проверка impact, прав, privacy, review findings, style rules и AI policy до записи изменений;
- AI объясняет, почему предлагает именно такой код, какие объекты будут затронуты и какие риски есть.
## Что берём из 1С Конфигуратора
SFERA не копирует старый интерфейс Конфигуратора, но сохраняет его сильную рабочую модель, знакомую 1С-разработчикам:
- дерево конфигурации как основной навигатор по метаданным, модулям, формам, реквизитам, командам, ролям и регистрам;
- отдельные рабочие режимы для модуля, формы, реквизитов/табличных частей, команд, свойств, событий и обработчиков;
- вкладки открытых объектов и быстрый переход между модулем объекта, модулем формы, дизайнером формы, свойствами и событиями;
- правый инспектор свойств/событий, который меняет содержимое по выбранному объекту или элементу формы;
- нижние панели проблем, ссылок, output, preview, diff и статуса выполнения;
- поиск по дереву, объектам, процедурам, событиям, формам и документации.
Поверх этой модели SFERA добавляет то, чего нет в классическом Конфигураторе как единой среды:
- object-level версии и rollback для каждого изменения;
- semantic diff, impact analysis и guarded apply перед записью;
- документацию проекта, vendor/BSP docs, базу знаний, паттерны команды и историю решений прямо в IDE;
- обучение и подсказки для разработчиков по текущему объекту, коду и стандартам команды;
- AI pair programmer, который умеет читать контекст 1С, писать код, создавать объекты/формы/отчёты и объяснять риски;
- task/session binding, audit trail, права доступа, privacy policy и учёт AI token/cost impact.
## Первый технический proof
```text
BSL file
Rust parser
SIR Snapshot
Neo4j graph
find_callers / find_callees
```
## Языковая стратегия
- UI по умолчанию русский.
- В интерфейсе и командах русский язык используется по умолчанию.
- Пользователь должен иметь возможность выбрать английский язык интерфейса и английский вариант написания команд.
- Внутренний код/модели — английский.
- BSL parser обязан понимать русские и английские ключевые слова: `Процедура/Procedure`, `Функция/Function`, `КонецПроцедуры/EndProcedure` и т.д.
- В одном BSL-тексте 1С допустима смесь русских и английских ключевых слов/команд; SFERA обязана это поддерживать.
## Git strategy
Git не является обязательным source of truth. История SFERA хранится в Semantic Object Version Store. Git — только optional import/export adapter.
+726
View File
@@ -0,0 +1,726 @@
# SFERA Platform
**SFERA — Semantic Operating Platform for 1C Ecosystems**
SFERA — enterprise semantic platform для анализа, понимания, индексирования, визуализации и AI-оркестрации экосистем 1С.
SFERA также является современной IDE/authoring-средой для 1С: пользователь должен уметь вручную писать код, создавать и менять объекты, формы, команды и отчёты, а AI должен помогать как pair programmer, который видит текущий код, metadata, связи объектов, доступные переменные и правила платформы.
Платформа строит детерминированное semantic core ядро поверх:
- 1C BSL
- XML metadata
- CF/CFE
- integrations
- access topology
- UI semantics
- scheduled jobs
- object dependencies
- runtime graph
SFERA проектируется как:
```text
Enterprise AI Operating System
for 1C ecosystems
```
---
# Core Philosophy
```text
Semantic truth first.
AI later.
```
AI не является источником истины.
Сначала:
- deterministic parsing
- semantic graph
- metadata topology
- impact analysis
- dependency resolution
- integration discovery
- access analysis
И только потом:
- AI copilots
- AI review
- AI reasoning
- AI onboarding
- AI architecture analysis
- AI migration planning
---
# High-Level Architecture
```text
1C BSL/XML/CF/CFE
Rust BSL Parser
SIR Snapshot
Semantic Kernel
Neo4j Semantic Graph
Incremental Indexing
Impact Analysis
AI Operating Layer
```
---
# Main Goals
## Semantic Understanding of 1C
SFERA должна понимать:
- объекты 1С
- формы
- команды
- реквизиты
- табличные части
- роли
- права доступа
- BSL dependencies
- integrations
- scheduled jobs
- runtime topology
- object impact
- UI semantics
---
## 1C IDE and Authoring
SFERA должна давать возможности современной IDE для 1С:
- BSL editor: подсветка, диагностика, folding, outline, go to definition, find references, rename, extract method и безопасные refactoring actions.
- Semantic autocomplete: продолжение кода с учётом текущей процедуры, параметров, локальных переменных, реквизитов объекта, табличных частей, форм, команд, ролей, интеграций и доступных методов 1С.
- AI pair programmer: генерация процедур, функций, запросов, обработчиков команд, движений регистров, проверок заполнения и обработчиков форм.
- Object designer: создание и изменение документов, справочников, регистров, общих модулей, реквизитов, табличных частей, команд и форм.
- Form/report designer: работа с формами, элементами, командами, обработчиками и отчётами в visual/object-oriented интерфейсе.
- Diff/preview/apply: любое AI- или ручное изменение проходит через preview, semantic diff, impact analysis, review и подтверждение.
- Context-aware hints: подсказки не просто по словам, а по текущему объекту 1С, доступным данным, связям, query/write context и runtime/knowledge facts.
AI не ограничивается анализом. Он должен уметь писать код и предлагать структурные изменения, но SFERA обязана показывать последствия и держать контроль применения у пользователя.
---
## Enterprise AI Layer
Поверх semantic graph строится AI operating layer:
- AI code completion
- AI code generation
- AI object/form/report generation
- AI guarded refactoring
- AI code review
- AI impact analysis
- AI onboarding
- AI architecture assistant
- AI dependency explorer
- AI migration assistant
- AI semantic search
- AI documentation generation
- AI risk analysis
- AI integration analysis
AI должен работать поверх semantic truth: перед предложением кода он учитывает текущий BSL-контекст, AST/SIR, metadata object, форму, доступные реквизиты, табличные части, команды, роли, запросы, регистры, интеграции, knowledge records и privacy policy.
---
## 1C Knowledge Coverage
`GET /projects/{project_id}/knowledge/schema-coverage` показывает покрытие knowledge-records для документов, справочников, реквизитов и табличных частей.
`GET /projects/{project_id}/review` добавляет INFO `Missing 1C schema knowledge`, если узел схемы 1С не связан ни с одной knowledge-записью.
`POST /knowledge/packs` импортирует BSP/vendor documentation pack как набор `KnowledgeRecord` с тегами `pack:{pack_id}` и `vendor:{vendor}`. `GET /knowledge/packs` показывает установленные пакеты знаний.
`GET /projects/{project_id}/patterns` выполняет детерминированный pattern mining по SIR: повторяющиеся чтения таблиц, записи таблиц и совпадающие read/write формы процедур.
## 1C Ownership
`POST /projects/{project_id}/comments` добавляет обсуждение к `target_id` внутри проекта, а `GET /projects/{project_id}/comments/{target_id}` возвращает комментарии по конкретному объекту, задаче или lineage.
`POST /projects/{project_id}/ownership` назначает ответственного на 1С-объект по `lineage_id`.
`GET /projects/{project_id}/objects/ownership/{object_name}` возвращает владельцев документа, справочника, регистра, общего модуля и других корневых объектов 1С.
`GET /projects/{project_id}/review` добавляет INFO `Missing 1C object owner` для 1С-объектов без назначенного владельца, а `GET /projects/{project_id}/report` включает `ownership_count`, `unowned_object_count` и `unowned_objects`.
## 1C Privacy
`POST /projects/{project_id}/privacy/markers` назначает privacy-классификацию на `lineage_id`: `PUBLIC`, `INTERNAL`, `CONFIDENTIAL`, `PERSONAL_DATA`, `SECRET`.
`GET /projects/{project_id}/objects/privacy/{object_name}` возвращает privacy-маркеры самого 1С-объекта и его прямых реквизитов/табличных частей/форм.
`GET /projects/{project_id}/review` добавляет INFO `Unclassified sensitive 1C field` для реквизитов с чувствительными именами вроде ИНН, паспорт, телефон, email, адрес, если они ещё не классифицированы.
## AI Usage Governance
`POST /ai/usage` записывает факт AI-действия: проект, пользователь, модель, операция, prompt/completion токены и стоимость.
`GET /ai/usage/summary` агрегирует AI usage по проекту, пользователю, модели и операции. `GET /ai/policy` показывает текущий token limit и остаток для пользователя.
`GET /projects/{project_id}/report` включает `ai_usage_request_count`, `ai_usage_total_tokens` и `ai_usage_cost`.
`POST /projects/{project_id}/ai/answer-policy` проверяет, можно ли отвечать на AI-вопрос по выбранному 1С-контексту: учитывает token budget, knowledge records, privacy markers и запрет external model calls.
---
# Monorepo Structure
```text
sfera-platform/
packages/
bsl-parser-rs/
sir/
semantic-kernel/
neo4j-projection/
indexing/
integrations/
api/
ai/
frontend/
sfera-web/
docs/
architecture/
frontend/
operations/
ai/
prompts/
.codex/
.cursor/
```
---
# Technology Stack
## Backend
```text
Python
FastAPI
Rust
Neo4j
PostgreSQL
Pydantic
NetworkX
asyncio
uv
```
## Frontend
```text
Next.js
React
TypeScript
Tailwind CSS
shadcn/ui
TanStack Table
TanStack Query
Zustand
Framer Motion
Recharts / ECharts
```
## AI Layer
```text
OpenAI-compatible APIs
Local LLM support
Multi-model routing
AI policy engine
AI audit system
Context orchestration
Token accounting
Semantic AI routing
```
---
# Quick Start
## Environment
```bash
cp .env.example .env
uv sync --all-packages
```
## Run tests
```bash
pytest packages/sir/tests
```
## Run Rust parser
```bash
cargo run -p bsl-parser -- ../tests/golden/english_module.bsl
```
---
# Development Philosophy
SFERA строится как:
```text
Deterministic semantic platform first.
AI-enhanced operating system second.
```
Главный приоритет:
- reproducibility
- deterministic parsing
- semantic correctness
- graph consistency
- auditability
- incremental scalability
---
# Semantic Intermediate Representation (SIR)
Rust parser возвращает deterministic JSON contract:
```json
{
"procedures": [],
"calls": [],
"queries": [],
"writes": [],
"diagnostics": []
}
```
SIR является semantic truth snapshot проекта.
---
# Supported 1C Metadata
## Core metadata objects
```text
Catalog
Document
Register
CommonModule
ExchangePlan
ScheduledJob
BusinessProcess
Task
Role
Form
Command
Attribute
TabularSection
Element
```
---
# Semantic Graph Relations
## Main graph relations
```text
CALLS
WRITES
READS
USES_INTEGRATION
HANDLES
CONTAINS
HAS_FORM
HAS_COMMAND
HAS_ATTRIBUTE
HAS_TABULAR_SECTION
HAS_ROLE
HAS_ELEMENT
RUNS
GRANTS_ACCESS
```
---
# Object Impact Analysis
SFERA умеет строить object-level impact:
- реквизиты
- табличные части
- формы
- команды
- BSL handlers
- registers
- integrations
- scheduled jobs
- roles/access
- UI semantics
- cross-module dependencies
---
# Incremental Indexing
SFERA поддерживает incremental semantic updates.
Изменение:
- `.bsl`
- `.xml`
- metadata object
- forms
- handlers
перестраивает только affected semantic graph sections.
---
# Neo4j Projection
Semantic graph может быть выгружен в Neo4j:
```text
SIR Snapshot
Neo4j Projection
Cypher Queries
Graph Analytics
```
---
# Integration Topology
SFERA извлекает integrations из:
- HTTPConnection
- HTTPСоединение
- WSProxy
- FTPConnection
- COMObject
- ExchangePlan
- URL strings
- external services
---
# Scheduled Jobs
Регламентные задания индексируются как runtime semantic graph:
```text
ScheduledJob
RUNS
Procedure
```
---
# Access Model
Для ролей 1С извлекаются:
- object permissions
- rights
- grants
- access topology
Graph relation:
```text
Role GRANTS_ACCESS Object
```
---
# UI Semantics
SFERA анализирует UI layer:
- forms
- commands
- command handlers
- form elements
- UI actions
- BSL bindings
---
# API Examples
## Object impact
```text
GET /projects/{project_id}/objects/impact/{object_name}
```
## UI semantics
```text
GET /projects/{project_id}/objects/ui/{object_name}
```
## Integrations
```text
GET /projects/{project_id}/integrations
```
## Scheduled jobs
```text
GET /projects/{project_id}/jobs/scheduled
```
## Access graph
```text
GET /projects/{project_id}/access/roles/{role_name}/objects
```
---
# Frontend Philosophy
SFERA UI — не обычная CRM.
Интерфейс должен ощущаться как:
- Linear
- Stripe Dashboard
- Notion
- Attio
- Plane
- Enterprise AI Workspace
---
# Frontend Stack
```text
Next.js
React
TypeScript
Tailwind CSS
shadcn/ui
TanStack Table
Framer Motion
```
---
# Enterprise UI Principles
## Main principles
- clean enterprise minimalism
- dark/light mode
- modular workspace
- AI-native UX
- semantic navigation
- adaptive layouts
- contextual side panels
- command palette
- realtime analytics
---
# AI-Assisted Development
Проект проектируется для работы через:
- Codex
- Cursor
- v0
- AI code review
- AI UI generation
- AI semantic assistants
---
# Codex Workflow
В репозитории присутствуют:
```text
.codex/
.cursor/
docs/design-system.md
docs/component-architecture.md
docs/codex-ui-guidelines.md
prompts/
```
Codex обязан:
- соблюдать architecture rules
- соблюдать design system
- генерировать production-ready TypeScript
- использовать reusable components
- учитывать AI limits/audit/token usage
---
# Frontend Design System
Frontend design system основан на:
```text
Tailwind CSS
shadcn/ui
Radix UI
Design Tokens
Enterprise Layout Rules
```
Основной принцип:
```text
Enterprise AI Operating System
instead of legacy CRM UI
```
---
# AI Operating Layer
Будущие AI возможности:
- AI semantic copilots
- AI impact prediction
- AI migration planning
- AI documentation generation
- AI integration analysis
- AI security review
- AI onboarding assistant
- AI dependency graph reasoning
- AI runtime diagnostics
- AI topology explorer
---
# Infrastructure
Docker Engine локально для development stand не обязателен.
Общий infrastructure host:
```text
docker-test
test-docker
```
Infrastructure documentation:
```text
docs/operations/STAND_RUNBOOK.md
```
---
# First Demo Target
```bsl
Процедура Проведение()
ПроверитьОстатки();
Движения.ОстаткиТоваров.Записать();
КонецПроцедуры
```
Expected semantic graph:
```text
Проведение CALLS ПроверитьОстатки
Проведение WRITES РегистрНакопления.ОстаткиТоваров
```
---
# Long-Term Vision
SFERA — это не просто analyzer.
Цель проекта:
```text
Semantic Operating System
for enterprise 1C ecosystems
```
Где:
- semantic graph
- runtime topology
- integrations
- access model
- UI semantics
- AI reasoning
- enterprise workflows
- impact analysis
становятся единой operating platform.
---
# Core Principles
```text
Deterministic.
Semantic.
Incremental.
Observable.
AI-Ready.
Enterprise-Scale.
```
---
# Future Roadmap
## Phase 1
- Rust parser
- SIR
- semantic graph
- Neo4j projection
- incremental indexing
## Phase 2
- semantic APIs
- integrations topology
- access graph
- UI semantics
## Phase 3
- enterprise frontend
- AI copilots
- semantic search
- AI review
## Phase 4
- distributed indexing
- multi-project graph
- semantic federation
- AI orchestration
- autonomous semantic agents
+21
View File
@@ -0,0 +1,21 @@
# 1C Metadata Object Catalog
This catalog is the product source of truth for the 1C metadata tree. It is backed by the official EDT mdclass metamodel and exposed by `/metadata/catalog`.
Primary sources:
- EDT mdclass package: https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/package-summary.html
- EDT HTTPService: https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/HTTPService.html
- 1C HTTP services guide: https://1c-dn.com/1c_enterprise/http_services/
Root configuration objects are maintained in `packages/one-c-normalizer/src/one_c_normalizer/metadata_catalog.py` as `METADATA_TYPE_SPECS` plus descriptions in `METADATA_TYPE_DESCRIPTIONS`.
Child metadata elements are maintained in the same module as `METADATA_CHILD_OBJECT_SPECS`.
Important documented structures:
- HTTP service: HTTP service -> URL templates -> methods -> module.
- Web service: Web service -> operations -> parameters -> module.
- Integration service: Integration service -> channels -> messages -> module.
- Registers: register -> dimensions -> resources -> requisites -> forms -> commands -> templates -> rights -> record set/manager modules.
- Catalogs/plans/documents: object -> requisites -> tabular sections -> forms -> commands -> templates -> rights -> modules, with type-specific groups such as movements or predefined data.
+411
View File
@@ -0,0 +1,411 @@
# Структура объектов метаданных 1С для дерева SFERA
Дата фиксации: 2026-05-09.
Назначение документа: единая опорная модель для загрузчика метаданных из 1С и дерева SFERA IDE. Реальные объекты, имена и состав узлов должны приходить из выгрузки конфигурации 1С/SIR. В коде интерфейса допустимо хранить только типы объектов, правила группировки, иконки и шаблоны подчинённых узлов.
## Источники
- 1C:Enterprise 8.3.23 Developer Guide, "Configuration objects": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.2._Configuration_objects/
- 1C:Enterprise 8.3.23 Developer Guide, "The concept of configuration": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.1._The_concept_of__configuration_/
- 1C:Enterprise 8.3.23 Developer Guide, "Modules": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.5._Modules/
- 1C:Enterprise 8.3.23 Developer Guide, "Common attributes": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_5._Configuration_objects/5.3.__Common__configuration_branch/5.3.5._Common_attributes/
- 1C:Enterprise 8.3.23 Developer Guide, "Functional options": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_5._Configuration_objects/5.3.__Common__configuration_branch/5.3.10._Functional_options_and_functional_option_parameters/
- 1C:Enterprise 8.3.23 Developer Guide, "Commands": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_6._Command_interface/6.2._Global_command_interface_structure/6.2.2._Commands/
- 1C:Enterprise 8.3.23 Developer Guide, "Templates": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.6._Templates/
Отдельной публичной документации `1C:Enterprise 8.5 Developer Guide` на kb.1ci.com при проверке не найдено. До появления официальной ветки 8.5 используем модель 8.3 как базовую и оставляем место под версионные отличия.
## Принципы дерева
1. В Designer/Конфигураторе типы объектов метаданных сгруппированы в дереве конфигурации.
2. Объект метаданных описывает структуру и поведение, но не хранит конкретные пользовательские данные.
3. Внутри объектов есть подчинённые объекты: реквизиты, табличные части, формы, команды, макеты, модули, измерения, ресурсы, права и т.д.
4. SFERA не должна создавать плоский список. Дерево строится по типу объекта и подчинённым коллекциям.
5. Узел `Задачи 1С` внутри конфигуратора является типом метаданных 1С. Узел `Задачи` верхнего уровня SFERA является системой разработки.
## Корневые ветки конфигурации
```text
Конфигурация
├── Общие
├── Константы
├── Справочники
├── Документы
├── Журналы документов
├── Перечисления
├── Отчеты
├── Обработки
├── Планы видов характеристик
├── Планы счетов
├── Планы видов расчета
├── Регистры сведений
├── Регистры накопления
├── Регистры бухгалтерии
├── Регистры расчета
├── Бизнес-процессы
├── Задачи
├── Внешние источники данных
└── Расширения конфигурации
```
## Ветка "Общие"
```text
Общие
├── Подсистемы
├── Общие модули
├── Параметры сеанса
├── Роли
├── Общие реквизиты
├── Планы обмена
├── Критерии отбора
├── Подписки на события
├── Регламентные задания
├── Функциональные опции
├── Параметры функциональных опций
├── Определяемые типы
├── Хранилища настроек
├── Общие команды
├── Группы команд
├── Общие формы
├── Общие макеты
├── Общие картинки
├── XDTO-пакеты
├── Web-сервисы
├── HTTP-сервисы
├── WS-ссылки
├── WebSocket-клиенты
├── Сервисы интеграции
├── Цвета палитры
├── Элементы стиля
├── Стили
└── Языки
```
## Шаблоны подчинённых узлов
### Справочник
```text
Справочники
└── <ИмяСправочника>
├── Реквизиты
├── Табличные части
│ └── <ИмяТабличнойЧасти>
│ ├── Реквизиты
│ └── Индексы
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
├── Права
├── Предопределенные данные
└── SFERA: Версии / Проверки / Инциденты / Знания
```
### Документ
```text
Документы
└── <ИмяДокумента>
├── Реквизиты
├── Табличные части
│ └── <ИмяТабличнойЧасти>
│ ├── Реквизиты
│ └── Индексы
├── Формы
├── Команды
├── Макеты
├── Движения
│ ├── Регистры сведений
│ ├── Регистры накопления
│ ├── Регистры бухгалтерии
│ └── Регистры расчета
├── Последовательности
├── Нумераторы
├── Модуль объекта
├── Модуль менеджера
├── Права
└── SFERA: Версии / Проверки / Инциденты / Знания
```
### Журнал документов
```text
Журналы документов
└── <ИмяЖурнала>
├── Графы
├── Формы
├── Команды
├── Макеты
├── Модуль менеджера
└── Права
```
### Перечисление
```text
Перечисления
└── <ИмяПеречисления>
├── Значения
├── Формы
├── Команды
├── Макеты
├── Модуль менеджера
└── Права
```
### Отчет
```text
Отчеты
└── <ИмяОтчета>
├── СКД
│ ├── Наборы данных
│ ├── Запросы
│ ├── Поля
│ ├── Ресурсы
│ ├── Группировки
│ ├── Отборы
│ └── Варианты
├── Реквизиты
├── Табличные части
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
└── Права
```
### Обработка
```text
Обработки
└── <ИмяОбработки>
├── Реквизиты
├── Табличные части
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
└── Права
```
### План видов характеристик
```text
Планы видов характеристик
└── <ИмяПВХ>
├── Реквизиты
├── Табличные части
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
├── Предопределенные данные
└── Права
```
### План счетов
```text
Планы счетов
└── <ИмяПланаСчетов>
├── Признаки учета
├── Признаки учета субконто
├── Табличные части
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
├── Предопределенные данные
└── Права
```
### План видов расчета
```text
Планы видов расчета
└── <ИмяПВР>
├── Реквизиты
├── Табличные части
├── Вытесняющие виды расчета
├── Ведущие виды расчета
├── Базовые виды расчета
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
└── Права
```
### Регистр сведений
```text
Регистры сведений
└── <ИмяРегистра>
├── Измерения
├── Ресурсы
├── Реквизиты
├── Формы
├── Команды
├── Макеты
├── Модуль набора записей
├── Модуль менеджера
├── Кто пишет
├── Кто читает
└── Права
```
### Регистр накопления
```text
Регистры накопления
└── <ИмяРегистра>
├── Измерения
├── Ресурсы
├── Реквизиты
├── Формы
├── Команды
├── Макеты
├── Модуль набора записей
├── Модуль менеджера
├── Кто пишет
├── Кто читает
└── Права
```
### Регистр бухгалтерии
```text
Регистры бухгалтерии
└── <ИмяРегистра>
├── Измерения
├── Ресурсы
├── Реквизиты
├── Признаки учета
├── Признаки учета субконто
├── Формы
├── Команды
├── Макеты
├── Модуль набора записей
├── Модуль менеджера
└── Права
```
### Регистр расчета
```text
Регистры расчета
└── <ИмяРегистра>
├── Измерения
├── Ресурсы
├── Реквизиты
├── Перерасчеты
├── Формы
├── Команды
├── Макеты
├── Модуль набора записей
├── Модуль менеджера
└── Права
```
### Бизнес-процесс
```text
Бизнес-процессы
└── <ИмяБизнесПроцесса>
├── Реквизиты
├── Табличные части
├── Карта маршрута
├── Точки маршрута
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
└── Права
```
### Задача 1С
```text
Задачи
└── <ИмяЗадачи>
├── Реквизиты
├── Табличные части
├── Адресация
├── Формы
├── Команды
├── Макеты
├── Модуль объекта
├── Модуль менеджера
└── Права
```
### Внешний источник данных
```text
Внешние источники данных
└── <ИмяИсточника>
├── Таблицы
│ └── <ИмяТаблицы>
│ └── Поля
├── Кубы
├── Функции
├── Формы
├── Команды
└── Макеты
```
## Универсальные подчинённые узлы
Эти узлы могут встречаться у разных типов объектов. Загрузчик должен брать фактический состав из 1С, а не создавать все узлы всегда.
- `Реквизиты`
- `Табличные части`
- `Формы`
- `Команды`
- `Макеты`
- `Модуль объекта`
- `Модуль менеджера`
- `Модуль набора записей`
- `Права`
- `Предопределенные данные`
- `Измерения`
- `Ресурсы`
- `Графы`
- `Значения`
- `Перерасчеты`
- `Движения`
- `Адресация`
- `СКД`
- `URL-шаблоны`
- `Методы`
- `Контракты`
- `Обработчики`
## Правило для SFERA
Загрузчик метаданных должен сохранять:
- `metadata_type`: тип объекта 1С;
- `name`: имя объекта из конфигурации;
- `synonym`: синоним;
- `qualified_name`: полное имя вида `Документ.Имя`, `Справочник.Имя.Форма.ФормаЭлемента`;
- `parent`: родительский узел;
- `children`: подчинённые коллекции;
- `module_kind`: тип модуля, если узел является модулем;
- `rights`: права/ограничения доступа;
- `extension_origin`: основная конфигурация или расширение;
- `version_origin`: снимок/версия/задача;
- `sfera_overlays`: проверки, инциденты, знания, владельцы, runtime-события.
UI-дерево обязано строиться из этой структуры. Любые демонстрационные имена объектов должны быть заменены данными из SIR после подключения реального загрузчика.
+46
View File
@@ -0,0 +1,46 @@
# Codex Instructions for SFERA Docs
## Frontend Contract Rules
Перед любым изменением frontend:
1. Прочитать `docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md`.
2. Прочитать `docs/frontend/SFERA_IDE_UI_CONTRACT.md`.
3. Если меняется дерево 1С - прочитать `docs/frontend/SFERA_METADATA_TREE_CONTRACT.md`.
4. Если меняются настройки проекта - прочитать `docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md`.
5. Если контракт устарел - сначала обновить контракт, затем код.
6. Все UI-изменения фиксировать в `docs/frontend/SFERA_FRONTEND_CHANGELOG.md`.
Frontend SFERA нельзя переводить в dashboard, CRM или файловый редактор. Принятая модель сохраняется:
- SFERA = metadata-first semantic configurator for 1C;
- основной экран = IDE последнего проекта;
- проект выбирается сверху;
- левая панель = дерево текущего проекта;
- основная конфигурация и расширения = configuration-like roots одного уровня;
- центр = рабочая область;
- правая панель = контекстные свойства;
- низ = открытые объекты, tools и status.
Для 1C-specific поведения использовать официальную документацию:
- ITS;
- v8.1c.ru;
- 1C DN;
- локальные knowledge packs.
ITS credentials передаются только через `.env.local`:
```dotenv
SFERA_ITS_URL=<ITS_URL>
SFERA_ITS_USERNAME=<ITS_USERNAME>
SFERA_ITS_PASSWORD=<ITS_PASSWORD>
```
Запрещено:
- хранить реальные ITS credentials в репозитории;
- писать реальные логины или пароли в markdown;
- писать реальные логины или пароли в Dockerfile;
- выводить реальные логины или пароли в logs;
- коммитить `.env.local` и `.env.*.local`.
+104
View File
@@ -0,0 +1,104 @@
# Architecture Index
## Core
- SIR
- Rust Parser
- `rust/crates/bsl-parser`
- JSON CLI contract: `cargo run -p bsl-parser -- <module.bsl>`
- output sections: `procedures`, `calls`, `queries`, `writes`, `diagnostics`
- Semantic Kernel
- Projection Engine
- Incremental Indexer
- project-level delta rebuild for 1C `.bsl` and `.xml`
- preserves metadata object links and object-level impact consistency
- refreshes Neo4j projection after incremental updates for already-projected projects
- Impact Engine
- routine-level impact
- 1C object-level impact from metadata owner to attributes/tabular sections/tabular section columns/modules/routines/tables/writes/forms/commands/command handlers
- role access included in object impact
- in-memory and Neo4j API surfaces
## 1C Native
- Designer CLI adapter primary
- EDT optional
- EPF/CFE agent later
- XML metadata extraction
- Catalog / Document / Register / CommonModule
- ExchangePlan / ScheduledJob / BusinessProcess / Task / Role
- Form / Command / Attribute / TabularSection / Element
- Role rights as `GRANTS_ACCESS` edges
- metadata object `CONTAINS` BSL module links from 1C export paths
- Form commands linked to BSL handlers with `HANDLES`
- Object-scoped UI API for 1C forms, commands, elements, and handlers
- Scheduled jobs linked to routines with `RUNS`
- Integration topology from BSL and XML ExchangePlan metadata
- BSL integrations as `INTEGRATION_ENDPOINT` nodes and `USES_INTEGRATION` edges
## Versioning
- Semantic Object Store primary
- Git optional adapter
## Knowledge
- Global / Workspace / Project / Session scopes
- Knowledge packs
- BSP/vendor documentation pack import
- pack/vendor metadata enrichment for records
- Vendor configs
- BSP detection
- 1C schema knowledge coverage
- review findings for schema nodes without knowledge records
- Pattern mining
- repeated table read/write patterns
- repeated routine IO shapes
## Collaboration
- Users / workspaces / projects
- Tasks / active task context / change sessions
- Comments / discussions
- project comments API
- target-scoped discussion lookup
- Activity feed
- 1C object ownership
- project ownership API
- object-scoped owner lookup
- persisted ownership assignments
## Governance
- RBAC
- 1C role rights graph
- object -> roles access API
- role -> objects access API
- project report security summary
- review warnings for objects without role access
- Integration governance
- project report integration counters
- review findings for outbound external integration endpoints
- Schema governance
- project report counters for attributes, tabular sections, columns, and empty tabular sections
- review findings for tabular sections without columns
- review hints for tabular sections without common subject columns
- UI governance
- review findings for form commands with missing BSL handlers
- Ownership governance
- project report ownership counters
- review findings for 1C objects without an assigned owner
- Privacy modes
- Privacy classification
- project privacy marker API
- object-scoped privacy lookup
- review hints for sensitive 1C fields without classification
- project report privacy counters
- AI governance
- answer policy gate for knowledge context, privacy markers, token budget, and external model calls
- AI usage governance
- AI usage event API
- project/user/model/operation usage summaries
- token limit policy endpoint
- project report AI usage counters
- Token usage limits
## Operations
- Jobs / workers / queues
- Admin console
- Observability
- Marketplace/download center
+72
View File
@@ -0,0 +1,72 @@
# Codex UI Guidelines для SFERA
## Роль Codex
Codex должен работать как senior frontend engineer + product designer.
Он обязан:
- соблюдать design system
- использовать русский язык интерфейса и команд по умолчанию
- предусматривать выбор английского языка интерфейса
- не генерировать случайные стили
- переиспользовать компоненты
- писать TypeScript
- не ломать архитектуру
- добавлять loading/error/empty states
- учитывать права доступа
- думать о масштабируемости IDE/authoring-среды для 1С
## Перед генерацией экрана Codex должен определить
1. Какая 1С-сущность или IDE-сущность?
2. Какие действия доступны пользователю?
3. Какие статусы есть?
4. Какие поля обязательные?
5. Нужен ли editor, designer, graph, table, inspector или diff?
6. Нужен ли AI Copilot?
7. Нужны ли права доступа?
8. Нужна ли история изменений?
9. Нужна ли интеграция с внешним источником?
10. Нужно ли preview/diff/apply для изменения 1С-кода или metadata?
## Запреты
Codex НЕ должен:
- использовать inline styles
- создавать хаотичные цвета
- использовать Bootstrap
- делать огромный компонент на 1000 строк
- хранить business logic в JSX
- игнорировать loading states
- игнорировать empty states
- генерировать mock API без явной пометки
- смешивать entity-компоненты и базовый UI
## Обязательные states
Каждый экран должен иметь:
- loading
- error
- empty
- success
- permission denied
- dirty form / unsaved changes
- semantic diff / preview
- guarded apply result
## UI quality checklist
Перед финалом Codex обязан проверить:
- интерфейс адаптивный
- все кнопки имеют понятный action
- статусы представлены Badge
- опасные действия требуют confirmation
- таблицы имеют фильтры
- формы валидируются через Zod
- редактор/дизайнер имеет problems panel и состояние несохранённых изменений
- дата/время форматируются единообразно
- AI действия показывают token/cost impact
- AI-подсказки учитывают текущий BSL-код, объект 1С, переменные, реквизиты, формы и связи
- есть audit trail для важных действий
+34
View File
@@ -0,0 +1,34 @@
# SPRINT 1 — SIR Core
## Цель
Создать `packages/sir`.
## Files
- `enums.py`
- `source_ref.py`
- `lineage.py`
- `nodes.py`
- `edges.py`
- `diagnostics.py`
- `references.py`
- `snapshot.py`
- `delta.py`
- `validation.py`
- `serialization.py`
- `hashing.py`
## DoD
```bash
pytest packages/sir/tests
```
Должно проходить:
- snapshot validation ok;
- dangling edge detected;
- serialization roundtrip;
- snapshot hash deterministic;
- diagnostics/unresolved references serializable.
+27
View File
@@ -0,0 +1,27 @@
# SPRINT 2 — Rust BSL Parser MVP
## Цель
`rust/crates/bsl-parser` должен возвращать `ParsedSemanticUnit`:
- procedures;
- functions;
- calls;
- queries;
- query tables;
- writes;
- diagnostics.
## Важное
Поддержать RU/EN keywords.
## MVP ограничение
Можно начать с deterministic line-based parser. Позже заменить на полноценный lexer/parser.
## DoD
```bash
cd rust && cargo test
```
@@ -0,0 +1,27 @@
# SPRINT 3 — Semantic Kernel
## Цель
`packages/semantic-kernel` конвертирует parsed result в SIR snapshot.
## Вход
`.bsl` файлы.
## Выход
`SirSnapshot` с nodes/edges:
- MODULE;
- PROCEDURE/FUNCTION;
- QUERY;
- TABLE/REGISTER;
- DECLARES;
- CALLS;
- OWNS_QUERY;
- READS_TABLE;
- WRITES.
## DoD
`index_project(path)` возвращает валидный snapshot.
+17
View File
@@ -0,0 +1,17 @@
# SPRINT 4 — Neo4j Projection
## Цель
`SirSnapshot → Neo4j graph`.
## Queries
- find procedures;
- find callers;
- find callees;
- find query tables;
- find writes.
## Rule
Only `projection-engine` can mutate Neo4j.
+13
View File
@@ -0,0 +1,13 @@
# SPRINT 5 — Incremental Indexer
## Цель
Изменился один `.bsl` файл — пересобираем только fragment и применяем delta.
## Components
- source hash;
- change detector;
- SirDelta builder;
- snapshot transition;
- projection delta.
+167
View File
@@ -0,0 +1,167 @@
# Component Architecture
## Рекомендуемая структура
```txt
src/
app/
(auth)/
(workspace)/
dashboard/
projects/
objects/
graph/
editor/
designer/
review/
impact/
knowledge/
integrations/
jobs/
ai/
settings/
components/
ui/
layout/
data-table/
editor/
designer/
graph/
command/
ai/
entities/
one-c-projects/
one-c-objects/
bsl-modules/
forms/
reports/
roles/
features/
one-c-projects/
semantic-graph/
bsl-editor/
object-designer/
form-designer/
report-designer/
impact-analysis/
review/
ai-authoring/
ai-usage/
integrations/
scheduled-jobs/
lib/
api/
auth/
permissions/
validators/
formatters/
one-c/
store/
styles/
```
## Правило разделения
### `components/ui`
Только базовые shadcn-like компоненты:
- Button
- Input
- Dialog
- Drawer
- Badge
- Card
- Tabs
### `components/editor`
IDE primitives:
- BslEditor
- ProblemsPanel
- ReferencesPanel
- OutlinePanel
- SemanticDiffView
- CompletionList
### `components/designer`
Object/form/report designer primitives:
- ObjectTree
- MetadataInspector
- FormCanvas
- FormElementPalette
- PropertiesInspector
- ReportDesigner
### `components/entities`
Переиспользуемые 1С entity-компоненты:
- OneCProjectCard
- OneCObjectBadge
- ObjectKindBadge
- RoleAccessBadge
- ReviewSeverityBadge
- SnapshotStatusBadge
### `features`
Полные feature-модули:
- список 1С-проектов
- дерево конфигурации
- карточка объекта 1С
- BSL editor workspace
- дизайнер формы
- дизайнер отчёта
- semantic graph
- impact analysis
- AI authoring panel
- AI usage dashboard
## Data Table стандарт
Каждая таблица должна иметь:
- search
- filters
- saved views
- column visibility
- sorting
- pagination / virtualization
- row actions
- bulk actions
- export
- audit-friendly row details
## IDE Page Standard
Каждая IDE-страница строится по шаблону:
```txt
PageHeader
Toolbar
ObjectTree
PrimaryEditorOrDesigner
RightInspector
ProblemsPanel
SemanticDiffPreview
AIAssistantContext
```
## Naming conventions
```txt
OneCProjectList
OneCObjectTree
BslEditorWorkspace
BslCompletionPanel
FormDesignerCanvas
MetadataPropertiesInspector
SemanticDiffPreview
AiAuthoringPanel
```
Не использовать абстрактные имена вроде:
- MainTable
- CustomCard
- ModalWindow
- BigForm
+207
View File
@@ -0,0 +1,207 @@
# Design System SFERA
## UI концепция
**SFERA — Enterprise AI Operating System**
Интерфейс должен ощущаться как:
- Linear
- Stripe Dashboard
- Notion
- Attio
- ClickUp 3.0
- Plane
- VS Code / JetBrains IDE для authoring-сценариев 1С
SFERA не CRM. Основной UI — это современная IDE/операционная среда для 1С: semantic workspace, редактор кода, дерево объектов, дизайнер форм/отчётов, инспектор свойств, diff/preview/apply и AI-помощник.
Классический 1С Конфигуратор используется как reference workflow, а не как visual style. Мы берём рабочие паттерны 1С-разработчика: дерево конфигурации, вкладки объектов, модуль/форма/свойства/события, правый инспектор, нижние панели диагностики и поиск. Визуально это должно быть современно, плотно, спокойно и удобно для долгой работы.
## Визуальный стиль
- чистый enterprise minimalism
- dark/light режим
- спокойные нейтральные цвета
- акцентный цвет для действий
- cards with soft shadows
- rounded-2xl
- минимальный glassmorphism только для важных overlay
- плотная, но не перегруженная информационная сетка
## Layout principles
### Главная структура
```txt
AppShell
├── Sidebar
├── Topbar
├── CommandPalette
├── Workspace
│ ├── PageHeader
│ ├── Toolbar
│ ├── ContentGrid
│ └── RightInspector
├── EditorWorkspace
│ ├── ObjectTree
│ ├── WorkspaceModeBar
│ ├── CodeEditor
│ ├── FormDesigner
│ ├── PropertiesInspector
│ ├── EventsInspector
│ ├── VersionsPanel
│ ├── DocumentationPanel
│ ├── KnowledgePanel
│ ├── LearningPanel
│ ├── ProblemsPanel
│ └── SemanticDiff
└── AI Copilot Panel
```
## Основные зоны
### Sidebar
- Dashboard
- Проекты 1С
- Объекты 1С
- Редактор BSL
- Дизайнер объектов
- Дизайнер форм
- Отчёты
- Семантический граф
- Impact analysis
- Review
- Знания
- AI
- Интеграции
- Регламентные задания
- Настройки
### Topbar
- поиск
- command palette
- быстрые действия
- уведомления
- профиль
- переключение проекта/организации
### Right Inspector
Контекстная панель для:
- объекта 1С
- процедуры или функции
- формы, команды или элемента формы
- реквизита или табличной части
- отчёта
- AI анализа
- истории изменений
- связанных сущностей
## Компонентные правила
### Карточки
- `rounded-2xl`
- `border`
- `bg-card`
- `shadow-sm`
- padding минимум `p-4`
### Таблицы
- sticky header
- фильтры
- saved views
- быстрый поиск
- column visibility
- bulk actions
- inline status badge
- row details через drawer/inspector
### Формы
- разделять на logical sections
- использовать progressive disclosure
- показывать validation inline
- сохранять drafts
- audit trail для важных изменений
## Цветовые токены
```txt
background
foreground
card
card-foreground
muted
muted-foreground
border
input
primary
primary-foreground
secondary
destructive
warning
success
info
```
## Статусы
### Задача
```txt
Новая
В работе
На проверке
Выполнена
Отменена
Просрочена
```
### Сделка
```txt
Активна
Неактивна
На бординге
Ожидает документов
Приостановлена
Закрыта
```
### Терминал
```txt
Подключен
Не подключен
Отключен банком
Ошибка настройки
```
## AI UX
AI должен быть не отдельной страницей, а частью workflow:
- AI Copilot справа
- подсказки в карточках
- inline completion в BSL editor
- context-aware suggestions по текущим переменным, реквизитам, табличным частям, форме и объекту 1С
- генерация кода, объектов, форм, команд и отчётов через preview/diff/apply
- объяснение текущего кода и структуры объекта
- генерация безопасных изменений 1С
- продолжение кода по текущему контексту
- объяснение изменений
- статистика токенов и лимитов
## Knowledge, Docs, Training UX
SFERA должна показывать знания рядом с местом работы, а не прятать их в отдельную wiki:
- документация объекта, формы, отчёта и бизнес-правила доступны из IDE-контекста;
- база знаний связывается с lineage объекта, процедурами, запросами и событиями формы;
- training/onboarding показывает рекомендации по текущему коду, стандартам команды и типовым ошибкам;
- AI отвечает только с учётом доступных знаний, прав и privacy policy;
- history/versions объясняют, почему объект менялся, какими задачами и решениями это было связано.
+81
View File
@@ -0,0 +1,81 @@
# Frontend Stack для SFERA
## Core
```txt
Next.js
React
TypeScript
Tailwind CSS
shadcn/ui
Radix UI
lucide-react
```
## Data layer
```txt
TanStack Query
Zustand
Zod
React Hook Form
```
## Tables / Grids
```txt
TanStack Table
TanStack Virtual
```
Использовать для:
- 1С-проектов
- объектов 1С
- процедур и функций
- форм и команд
- ролей и прав
- review findings
- журналов изменений
- AI usage статистики
- лимитов
- интеграций
## Charts
```txt
Recharts
Apache ECharts
```
Для простых dashboard — Recharts.
Для тяжелой аналитики и сложных графиков — ECharts.
## Animations
```txt
Framer Motion
```
Использовать аккуратно:
- открытие панелей
- command palette
- sidebar
- drawer
- карточки задач
- state transitions
## UI generation tools
```txt
v0 by Vercel
shadcn/ui
shadcn/studio
Cursor
Codex
```
## Почему не Ant Design / Bootstrap
Ant Design подходит для быстрых корпоративных систем, но SFERA должна выглядеть как современный AI enterprise workspace, а не как старая админка.
Bootstrap и старые admin templates не использовать как основу.
+391
View File
@@ -0,0 +1,391 @@
# SFERA Frontend Changelog
## Правило
Каждое изменение frontend должно фиксироваться здесь.
Формат:
```text
Дата:
Автор/Codex task:
Что изменено:
Какие файлы:
Затронутые экраны:
Изменен ли UI contract:
Нужны ли новые smoke tests:
```
## Записи
### 2026-05-11
Initial UI contract created.
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Корневой маршрут frontend переведен на IDE последнего проекта; существующий экран настройки проекта вынесен на `/project-settings`; Top Project Bar дополнен настройками проекта, созданием проекта, уведомлениями и профилем; smoke-тесты обновлены под IDE-first модель и новый route настроек проекта.
Какие файлы: `frontend/sfera-web/src/app/page.tsx`, `frontend/sfera-web/src/app/project-settings/page.tsx`, `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/lib/i18n.ts`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: основной вход frontend, IDE workspace, project settings
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, HTML smoke покрывает redirect `/` -> IDE и доступность `/project-settings`
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Fallback metadata tree приведен к контрактной модели: проект содержит top-level `Основная конфигурация`, `Расширение: <Имя>`, `SFERA`, `Среды`; расширение использует тот же configuration-like каркас без fake-объектов.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: IDE workspace, левая панель metadata tree
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, HTML smoke проверяет ключевые top-level узлы левой панели
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Server-side metadata tree приведен к той же top-level модели для lazy/large-project режима; пути раскрытия теперь идут через `main-configuration`, а lazy tree сохраняет раскрытие `Основная конфигурация`.
Какие файлы: `services/api-server/src/api_server/main.py`, `services/api-server/tests/test_api.py`, `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
Затронутые экраны: IDE workspace, lazy metadata tree
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, API tests покрывают структуру, HTML smoke покрывает видимые top-level узлы
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Project Settings sidebar переименован из wizard в контрактный экран настроек, добавлен список разделов настроек, AI policy и ITS/documentation access с безопасными env placeholders без реальных credentials; default privacy для нового fallback проекта изменен на `METADATA_ONLY`.
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/src/app/project-settings/page.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: Project Settings, Top Project Bar, Import Center
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, HTML smoke проверяет Project Settings и ITS env placeholders
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Lazy metadata tree получил полный маппинг contract-first иконок на существующие 1C SVG assets, чтобы top-level проект, основная конфигурация, ветки metadata, группы макетов/событий/движений, бизнес-процессы, задачи и внешние источники не ссылались на отсутствующие файлы.
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
Затронутые экраны: IDE workspace, lazy metadata tree
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, существующий editor smoke покрывает lazy metadata tree shell
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Lazy metadata tree очищен от старого `dashboard` route variant; все переходы из дерева теперь строятся напрямую на `/editor`, включая SFERA overview как `mode=overview`.
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`, `frontend/sfera-web/src/components/editor/ide-workspace.tsx`
Затронутые экраны: IDE workspace, lazy metadata tree
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, существующий editor smoke покрывает IDE route
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: `/project-settings` закреплен как экран Project Settings при любом статусе проекта; INDEXED-проект больше не подменяет настройки старым workbench, поэтому настройки проекта остаются доступны из Top Project Bar по контракту.
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, project setup smoke обновлен под contract-first Project Settings route
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: IDE workspace получил contract-first управление панелями: левая навигация сворачивается и меняет ширину, правая Context Inspector и нижняя tool panel сворачиваются, добавлены горячие клавиши `Alt+1`, `Alt+2`, `Alt+3`, `Ctrl+Tab`, `Ctrl+Shift+Tab`, `Ctrl+W`.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: IDE workspace, Left Navigation Panel, Main Workspace, Right Context Inspector, Bottom Tool Panel, Open Objects Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, editor smoke расширен проверкой contract layout markers
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Runtime smoke расширен интерактивной проверкой contract controls: `Alt+1`, `Alt+2`, `Alt+3` скрывают соответствующие панели, rail/buttons возвращают их, `Ctrl+Tab` и `Ctrl+Shift+Tab` переключают открытые объекты; после переходов между editor modes нижняя tool panel сворачивается для focused editor workflows.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, панель открытых объектов, левая/правая/нижняя панели
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, runtime smoke обновлен
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Open Objects Bar получил fallback-набор IDE tabs (`Обзор`, `Модуль`, `Форма`, `TASK-123`) для пустого или минимального metadata tree, чтобы workspace сохранял contract-first модель переключаемых открытых объектов.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, Open Objects Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, runtime smoke проверяет минимум два переключаемых объекта
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: IDE workspace убран жесткий `min-h-[760px]`, из-за которого нижняя tool panel и fixed status bar могли перекрывать рабочую область и перехватывать клики в metadata editor на невысоких viewport.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`
Затронутые экраны: IDE workspace, Main Workspace, Bottom Tool Panel, Status Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, runtime smoke ловит перекрытие кликов
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Top Project Bar получил настоящий global search input; IDE workspace обрабатывает `Ctrl+K` для фокуса глобального поиска и `F5` для запуска проверки с открытием bottom tool panel и статусом запуска.
Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: Top Project Bar, IDE workspace, Bottom Tool Panel
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, runtime smoke расширен проверкой `Ctrl+K` и `F5`
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Fallback Left Navigation Panel получил поиск по дереву, фильтры `Все / 1C / SFERA / Среды`, отдельный scroll marker и сохранение раскрытия веток через `localStorage`.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, Left Navigation Panel
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой поиска/фильтров fallback tree
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Open Objects Bar получил pin/close controls, `Ctrl+W` закрывает активный незакрепленный объект, состояние закрытых и закрепленных объектов сохраняется в `localStorage` и восстанавливается для проекта.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, Open Objects Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой pin/close/persist поведения
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Open Objects Bar поднят над рабочей областью (`z-index`) и сделан `shrink-0`, чтобы Monaco/editor canvas не перекрывал pin/close controls и не перехватывал клики.
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`
Затронутые экраны: IDE workspace, Open Objects Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, runtime smoke ловит перекрытие кликов
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Project Settings получил недостающие контрактные секции `Пользователи и доступ`, `Интеграции задач`, `Docker/runtime adapter`, `Audit`, `Backup/restore`; sidebar anchors обновлены под эти секции, без хранения credentials.
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, существующие smoke расширены проверкой полного набора settings sections
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Status Bar приведен к полному набору контрактных индикаторов, добавлен `Current user`, стабильные `data-status-item` markers и горизонтальный overflow для узких viewport.
Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, Status Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой status markers
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Источники структуры 1С дополнены `REFERENCE_CONFIGURATION` end-to-end: backend import source registry/preflight, frontend selector/action button/source configurator и smoke checks.
Какие файлы: `services/api-server/src/api_server/main.py`, `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings, Import Center
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, существующие smoke расширены проверкой reference configuration source
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Metadata tree дополнен контрактными configuration-like roots для context/reference источников: при `CONTEXT_ONLY` добавляется `Context-only configuration`, при `REFERENCE_CONFIGURATION` добавляется `Reference configuration` с тем же каркасом веток, что у основной конфигурации/расширений.
Какие файлы: `services/api-server/src/api_server/main.py`, `services/api-server/tests/test_api.py`
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy/server data)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, покрыто API tests для metadata tree response
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: В `LazyMetadataTree` добавлен настоящий virtual scroll для списка видимых узлов (viewport-based windowing с overscan), чтобы левая панель масштабировалась на больших деревьях без полной отрисовки всех root-level элементов.
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, существующий `smoke:editor` проходит; typecheck зеленый
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Runtime smoke расширен проверкой контрактного scroll-контейнера левой панели (`data-virtual-scroll` для lazy tree или `data-fallback-tree-scroll` для fallback tree), чтобы регресс virtual scroll ловился автоматически.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, левая панель metadata tree
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: API test coverage дерева метаданных расширено для `CONTEXT_CONFIGURATION`: добавлен тест, подтверждающий появление `Context-only configuration` как configuration-like root с контрактным набором первых веток (`Сведения`, `Общие`, `Константы`).
Какие файлы: `services/api-server/tests/test_api.py`
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, покрыто API tests
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: В `LazyMetadataTree` добавлены контрактные фильтры левой панели (`Все / 1C / SFERA / Среды`) для lazy/server режима, чтобы поведение фильтрации было единым с fallback tree.
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, существующий runtime smoke проходит; typecheck зеленый
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Runtime smoke расширен проверкой lazy-tree фильтров: при наличии `data-lazy-tree-filter` тест переключает `SFERA`/`All` и подтверждает доступность узла `SFERA`, чтобы зафиксировать поведение новых фильтров.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Project Settings runtime smoke усилен проверкой отображения `.env.local` в секции `ITS/documentation access`, чтобы policy "credentials only via .env.local" оставалась закрепленной на UI-уровне.
Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings (`ITS/documentation access`)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: HTML smoke (`smoke:editor`) усилен контрактными маркерами Top Project Bar на корневом IDE-экране: добавлены проверки `Компания`, `Среда`, `Задача`, `Ctrl+K`, `API доступен`, `Агент онлайн`.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: основной IDE экран, Top Project Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: HTML smoke для `/project-settings` расширен security-маркерами секции `ITS/documentation access`: добавлены проверки `.env.local` и placeholder `&lt;set locally&gt;` вместе с `SFERA_ITS_USERNAME`.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: Project Settings (`ITS/documentation access`)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Добавлен защитный API-тест на metadata tree: для обычных источников (`XML_DUMP`) в корне проекта не должны появляться contract-only roots `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION`.
Какие файлы: `services/api-server/tests/test_api.py`
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, покрыто API tests
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Runtime smoke расширен проверкой горячей клавиши `Ctrl+W`: тест выбирает немодульный открытый объект (если доступен), закрывает его через `Ctrl+W` и проверяет, что tab удален без runtime ошибок; сценарий стабилизирован возвратом к module-tab при необходимости.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, Open Objects Bar, горячие клавиши
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: ITS security-policy smoke-покрытие расширено: в HTML smoke добавлены `SFERA_ITS_URL`/`SFERA_ITS_PASSWORD`, в runtime smoke `Project Settings` добавлены проверки `SFERA_ITS_URL`, `SFERA_ITS_PASSWORD` и presence примера ITS URL через `input[value*='its.1c.ru/db/v838doc']`.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings (`ITS/documentation access`)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:project-setup`
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: HTML smoke расширен англоязычной проверкой корневого IDE-экрана (`lang=en`) для Top Project Bar: `Workspace`, `Env`, `Task`, `Ctrl+K`, `API online`, `Agent online`.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: основной IDE экран, Top Project Bar (EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Добавлен API-тест порядка top-level узлов metadata tree: при `CONTEXT_ONLY` и `REFERENCE_CONFIGURATION` соответствующие configuration-like roots должны располагаться перед `SFERA` в корне проекта.
Какие файлы: `services/api-server/tests/test_api.py`
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, покрыто API tests
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: Runtime smoke расширен проверкой восстановления `Open Objects Bar` после перезагрузки: тест сохраняет состояние закрытых/закрепленных табов, делает `page.reload`, подтверждает сохранность `localStorage` и проверяет, что закрытый таб снова скрыт после применения состояния.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, Open Objects Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
Дата: 2026-05-11
Автор/Codex task: Codex
Что изменено: API tests для `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION` расширены проверкой lazy-режима (`object_limit_per_branch=0`): условные configuration-like roots должны присутствовать не только в полном, но и в lazy metadata tree response.
Какие файлы: `services/api-server/tests/test_api.py`
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, покрыто API tests
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: API-тест порядка корневых узлов расширен и на lazy metadata tree: для `CONTEXT_ONLY` и `REFERENCE_CONFIGURATION` условные configuration-like roots должны располагаться перед `SFERA` как в полном, так и в lazy-ответе (`object_limit_per_branch=0`).
Какие файлы: `services/api-server/tests/test_api.py`
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, покрыто API tests
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: Runtime smoke расширен проверкой состава `Bottom Tool Panel`: тест подтверждает видимость вкладок `Проблемы`, `Semantic diff`, `Вывод`, `История`, `Тесты`, `AI` после открытия нижней панели.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: IDE workspace, Bottom Tool Panel
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: HTML smoke расширен англоязычной проверкой `Project Settings` (`lang=en`): закреплены `Project Settings`, `Import Center`, `Task/session policy`, `Docker/runtime adapter`, `ITS/documentation access`, `Audit`, `Backup/restore` и ITS env placeholders.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: Project Settings (EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: Защитный API-тест для обычных источников (`XML_DUMP`) расширен и на lazy metadata tree: `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION` не должны появляться в корне ни полного, ни lazy-ответа.
Какие файлы: `services/api-server/tests/test_api.py`
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, покрыто API tests
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: Runtime smoke `Project Settings` расширен англоязычным сценарием (`lang=en`): подтверждаются `Task/session policy`, `Docker/runtime adapter`, `ITS/documentation access`, `Audit`, `Backup/restore` и ITS env placeholders на реальном интерактивном экране.
Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings (EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: Runtime smoke IDE расширен англоязычным сценарием (`lang=en`) для Top Project Bar и status bar; дополнительно smoke фиксирован на desktop viewport `1680x1050`, чтобы контрактные desktop-элементы вроде `Task` проверялись в реальном видимом layout.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: основной IDE экран, Top Project Bar, Status Bar (EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий editor runtime smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: EN runtime smoke `Project Settings` расширен проверкой `REFERENCE_CONFIGURATION` и кнопки `Reference config`, чтобы import/source contract был закреплен и в английском интерактивном сценарии.
Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings (EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: EN runtime smoke IDE расширен проверкой `Bottom Tool Panel`: в английском сценарии подтверждаются вкладки `Problems`, `Semantic diff`, `Output`, `Change history`, `Tests`, `AI`.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: основной IDE экран, Bottom Tool Panel (EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий editor runtime smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: Кнопки действий `Project Settings` получили стабильный маркер `data-import-action=<SOURCE>:<mode>`; runtime smoke переведен на этот маркер и EN-сценарий теперь интерактивно запускает `Source preflight`, а не зависит от русского текста кнопки.
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings, Import Center (RU/EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: HTML smoke для `Project Settings` (RU/EN) расширен проверкой стабильных action markers `data-import-action="REFERENCE_CONFIGURATION:import"` и `data-import-action="XML_DUMP:check"`, чтобы import actions ловились быстрым контуром без Playwright.
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
Затронутые экраны: Project Settings, Import Center (RU/EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: `Top Project Bar` получил стабильные `data-*` маркеры для logo, selectors, actions, status badges, language switcher и profile button; `Badge` обновлен с passthrough `HTMLAttributes`, чтобы `data-*` атрибуты доходили до DOM. HTML и runtime smoke IDE переведены на эти маркеры. Дополнительно runtime smoke после reload явно возвращается на module-tab перед проверкой Monaco.
Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/components/ui/badge.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
Затронутые экраны: основной IDE экран, Top Project Bar, Open Objects Bar
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:editor:runtime`
Дата: 2026-05-12
Автор/Codex task: Codex
Что изменено: `Project Settings` секции получили стабильный маркер `data-settings-section`; HTML и runtime smoke переведены на него для ключевых разделов `task-session-policy`, `docker-runtime-adapter`, `its-documentation-access` в RU/EN сценариях.
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
Затронутые экраны: Project Settings (RU/EN UI)
Изменен ли UI contract: нет
Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:project-setup`
@@ -0,0 +1,35 @@
# SFERA Frontend Product Contract
SFERA - это серверная semantic IDE-платформа для 1С, а не dashboard, CRM или файловый редактор.
## Главная модель
- Проект выбирается в верхней панели.
- Пользователь долго работает внутри одного проекта.
- Основной экран - IDE workspace последнего проекта.
- Если проекта нет - пустой workspace с выбором или созданием проекта.
- Левая панель - навигация по текущему проекту.
- Центр - рабочая область.
- Правая панель - контекстные свойства.
- Нижняя зона - открытые объекты, служебные панели и status bar.
## Product Principles
SFERA должна быть metadata-first: в 1С дерево объектов конфигурации представляет прикладное решение как древовидную структуру логически связанных объектов.
Расширения являются configuration-like структурами: расширение похоже на обычную конфигурацию и тоже представляется деревом объектов.
Формы - visual-first: формы 1С предназначены для просмотра и редактирования данных и могут принадлежать объектам конфигурации или быть общими.
Окно объекта конфигурации в 1С предназначено для редактирования свойств, управления подчиненными объектами и настройки взаимодействия объектов. SFERA должна расширять эту модель, а не заменять ее dashboard-карточками.
## Official 1C Documentation
При проектировании 1C-specific поведения использовать официальные источники:
- ITS;
- v8.1c.ru;
- 1C DN;
- локальные knowledge packs.
ITS credentials нельзя хранить в документации или репозитории. Доступ передается только через `.env.local`.
+152
View File
@@ -0,0 +1,152 @@
# SFERA IDE UI Contract
## 1. Основной экран
После входа открывается:
- последний проект пользователя;
- либо пустой IDE shell, если проекта нет.
Проект выбирается только в верхней панели.
Запрещено:
- показывать список проектов в левой панели;
- делать dashboard главным экраном;
- показывать fake-данные без импортированного проекта.
## 2. Главный Layout
Экран состоит из:
```text
Top Project Bar
Left Navigation Panel
Main Workspace
Right Context Inspector
Open Objects Bar
Bottom Tool Panel
Status Bar
```
## 3. Top Project Bar
Содержит:
- SFERA logo;
- Workspace selector;
- Project selector;
- Project settings button;
- Create project button;
- Environment selector;
- Active task selector;
- Global search;
- Agent/API status;
- Notifications;
- Language;
- User profile.
Пример:
```text
SFERA | Workspace v | Project v | Настройки | + Проект | Env v | Task v | Search...
```
## 4. Левая Панель
Левая панель - навигация текущего проекта.
Она содержит:
```text
Проект: ERP Demo
├── Основная конфигурация
├── Расширение: <Имя>
├── Расширение: <Имя>
├── SFERA
└── Среды
```
Левая панель должна:
- сворачиваться;
- менять ширину;
- поддерживать поиск;
- поддерживать фильтры;
- поддерживать lazy loading;
- поддерживать virtual scroll;
- сохранять состояние раскрытия узлов.
## 5. Центр
Центр - основная рабочая область.
Там открываются:
- Object Workspace;
- Code Workspace;
- Form Designer;
- Report Designer;
- СКД Designer;
- Layout Designer;
- Project Settings;
- Task Workspace;
- Review Workspace;
- Runtime Workspace;
- Knowledge Workspace.
## 6. Правая Панель
Правая панель - Context Inspector.
Она показывает свойства выбранного объекта, элемента формы, процедуры, задачи, отчета, регистра, расширения.
Она не является навигацией.
## 7. Open Objects Bar
Внизу отображается панель открытых объектов:
```text
[Документ.ЗаказКлиента] [ФормаДокумента] [Модуль объекта] [TASK-123]
```
Поддерживает:
- быстрое переключение;
- закрытие;
- закрепление;
- восстановление после перезагрузки.
## 8. Bottom Tool Panel
Сворачиваемая служебная панель:
- Проблемы;
- Semantic diff;
- Вывод;
- История;
- Тесты;
- AI.
## 9. Status Bar
- Snapshot;
- Agent;
- Parser;
- Diagnostics;
- Active Task;
- Privacy;
- AI tokens;
- Current user.
## 10. Горячие Клавиши
- `Alt+1` - левая панель;
- `Alt+2` - правая панель;
- `Alt+3` - нижняя панель;
- `Ctrl+Tab` - следующий открытый объект;
- `Ctrl+Shift+Tab` - предыдущий объект;
- `Ctrl+W` - закрыть текущий объект;
- `Ctrl+K` - глобальный поиск;
- `F5` - запустить проверку.
@@ -0,0 +1,301 @@
# SFERA Metadata Tree Contract
## 1. Верхний Уровень
```text
Проект
├── Основная конфигурация
├── Расширение: <name>
├── Расширение: <name>
├── SFERA
└── Среды
```
## 2. ConfigurationLikeRoot
Один компонент используется для:
- основной конфигурации;
- расширений;
- context-only конфигураций;
- reference конфигураций.
Типы:
- `MAIN_CONFIGURATION`;
- `EXTENSION`;
- `CONTEXT_CONFIGURATION`;
- `REFERENCE_CONFIGURATION`.
## 3. Структура ConfigurationLikeRoot
- Сведения;
- Общие;
- Константы;
- Справочники;
- Документы;
- Журналы документов;
- Перечисления;
- Отчеты;
- Обработки;
- Планы видов характеристик;
- Планы счетов;
- Планы видов расчета;
- Регистры сведений;
- Регистры накопления;
- Регистры бухгалтерии;
- Регистры расчета;
- Бизнес-процессы;
- Задачи 1С;
- Внешние источники данных.
## 4. Узел "Общие"
- Подсистемы;
- Общие модули;
- Параметры сеанса;
- Роли;
- Общие реквизиты;
- Планы обмена;
- Критерии отбора;
- Подписки на события;
- Регламентные задания;
- Боты;
- Функциональные опции;
- Параметры функциональных опций;
- Определяемые типы;
- Хранилища настроек;
- Общие команды;
- Группы команд;
- Общие формы;
- Общие макеты;
- Общие картинки;
- XDTO-пакеты;
- Web-сервисы;
- HTTP-сервисы;
- WS-ссылки;
- WebSocket-клиенты;
- Сервисы интеграции;
- Цвета палитры;
- Элементы стиля;
- Стили;
- Языки.
## 5. Object Tree Templates
### Справочник
- Обзор;
- Свойства;
- Реквизиты;
- Табличные части;
- Формы;
- Команды;
- Макеты;
- Модуль объекта;
- Модуль менеджера;
- Права;
- Данные;
- Где используется;
- Кто читает;
- Кто записывает;
- Версии;
- Проверки.
### Документ
- Обзор;
- Свойства;
- Реквизиты;
- Табличные части;
- Формы;
- Команды;
- Макеты;
- Движения;
- Модуль объекта;
- Модуль менеджера;
- Права;
- Данные;
- Где используется;
- Кто создает;
- Кто проводит;
- Версии;
- Проверки.
### Регистр Сведений
- Обзор;
- Свойства;
- Измерения;
- Ресурсы;
- Реквизиты;
- Формы;
- Команды;
- Макеты;
- Модуль набора записей;
- Модуль менеджера;
- Права;
- Данные;
- Кто читает;
- Кто записывает;
- Версии;
- Проверки.
### Регистр Накопления
- Обзор;
- Свойства;
- Измерения;
- Ресурсы;
- Реквизиты;
- Формы;
- Команды;
- Макеты;
- Модуль набора записей;
- Модуль менеджера;
- Права;
- Данные;
- Кто читает;
- Кто записывает;
- Документы-регистраторы;
- Версии;
- Проверки.
### Отчет
- Обзор;
- Свойства;
- СКД;
- Формы;
- Команды;
- Макеты;
- Модуль объекта;
- Права;
- Данные;
- Версии;
- Проверки.
### Обработка
- Обзор;
- Свойства;
- Формы;
- Команды;
- Макеты;
- Модуль объекта;
- Права;
- Данные;
- Интеграции;
- Версии;
- Проверки.
### Общий Модуль
- Обзор;
- Свойства;
- Процедуры;
- Функции;
- Экспортные методы;
- Запросы;
- Записи;
- Вызовы;
- Кто вызывает;
- Транзакции;
- Runtime;
- Версии;
- Проверки.
### Форма
- Дизайнер формы;
- Свойства;
- Реквизиты формы;
- Элементы;
- Команды;
- События;
- Модуль формы;
- Связи с объектом;
- Данные;
- Версии;
- Проверки.
### Роль
- Обзор;
- Свойства;
- Права на объекты;
- Права на реквизиты;
- Права на табличные части;
- RLS;
- Унаследованные права;
- Отличия от default rights;
- Пользователи с ролью;
- Проверки безопасности;
- Версии;
- Данные.
### HTTP-Сервис
- Обзор;
- Свойства;
- URL-шаблоны;
- Методы;
- Обработчики;
- Контракты JSON;
- Безопасность;
- Runtime;
- Тестовые запросы;
- Версии;
- Проверки.
### План Обмена
- Обзор;
- Свойства;
- Узлы;
- Состав обмена;
- Авторегистрация;
- Правила регистрации;
- Формы;
- Команды;
- Модуль объекта;
- Модуль менеджера;
- Runtime;
- Данные;
- Версии;
- Проверки.
### Регламентное Задание
- Обзор;
- Свойства;
- Расписание;
- Обработчик;
- Параметры;
- Runtime;
- Связанные интеграции;
- Версии;
- Проверки.
## 6. Узел "Данные"
Узел "Данные" добавляется к объектам, где это применимо.
Режимы:
- `METADATA_ONLY`;
- `SANITIZED_SAMPLE`;
- `TEST_DATA`;
- `FULL_DATA`.
По умолчанию:
- `METADATA_ONLY`.
Правила:
- `FULL_DATA` только по RBAC;
- `FULL_DATA` всегда audit logged;
- AI не получает данные без explicit approval;
- данные привязаны к environment;
- данные маскируются по умолчанию.
@@ -0,0 +1,194 @@
# SFERA Project Settings Contract
## 1. Назначение
Настройки проекта - один из главных экранов SFERA.
Открывается из Top Project Bar через кнопку рядом с Project selector.
## 2. Разделы Настроек
```text
Основные сведения
Источники структуры 1С
Импорт конфигурации
Среды
Агенты
Расширения
Knowledge sources
Privacy
AI policy
Task/session policy
Пользователи и доступ
Интеграции задач
Docker/runtime adapter
ITS/documentation access
Audit
Backup/restore
```
## 3. Основные Сведения
Поля:
- Название проекта;
- Код проекта;
- Описание;
- Workspace;
- Владелец;
- Тип проекта;
- Язык интерфейса;
- Язык кода 1С по умолчанию: русский / английский;
- Версия платформы;
- Режим совместимости.
## 4. Источники Структуры 1С
Поддерживаемые источники:
- `.cf` файл;
- `.cfe` файл;
- XML dump;
- Live infobase через Designer CLI;
- EPF agent snapshot;
- CFE agent snapshot;
- EDT project;
- Архив выгрузки;
- BSL/XML file tree;
- Context-only configuration;
- Reference configuration.
Для каждого источника:
- тип;
- статус;
- последний импорт;
- последняя ошибка;
- версия платформы;
- режим совместимости;
- количество объектов;
- количество модулей;
- количество форм;
- количество расширений.
## 5. Среды
- Dev;
- Test;
- Stage;
- Prod.
Для среды:
- тип;
- подключение;
- агент;
- источник данных;
- privacy mode;
- разрешение data preview;
- версия платформы;
- активные расширения.
## 6. Агенты
- EPF agent;
- CFE agent;
- runtime agent;
- diagnostic agent.
Поля:
- agent id;
- version;
- environment;
- last heartbeat;
- status;
- compatibility;
- download/update.
## 7. Расширения
Таблица:
- имя;
- версия;
- назначение;
- активно;
- безопасный режим;
- защита от опасных действий;
- область действия;
- источник;
- последний import;
- статус применимости.
Действия:
- загрузить `.cfe`;
- получить из live base;
- обновить snapshot;
- проверить применимость;
- сравнить с основной конфигурацией;
- построить effective configuration.
## 8. ITS/Documentation Access
Документация 1С используется для проверки 1С-specific поведения.
Источники:
- ITS;
- v8.1c.ru;
- 1C DN;
- локальные knowledge packs.
ITS credentials нельзя хранить в репозитории.
Использовать только переменные окружения:
```dotenv
SFERA_ITS_URL=<ITS_URL>
SFERA_ITS_USERNAME=<ITS_USERNAME>
SFERA_ITS_PASSWORD=<ITS_PASSWORD>
```
Локальный файл:
```text
.env.local
```
Пример для локальной настройки:
```dotenv
SFERA_ITS_URL=https://its.1c.ru/db/v838doc#browse:13:-1:7
SFERA_ITS_USERNAME=<set locally>
SFERA_ITS_PASSWORD=<set locally>
```
Запрещено:
- коммитить логин или пароль;
- писать логин или пароль в markdown;
- писать логин или пароль в Dockerfile;
- выводить логин или пароль в logs.
## 9. Privacy
- `METADATA_ONLY`;
- `SANITIZED_SAMPLE`;
- `TEST_DATA`;
- `FULL_DATA`.
По умолчанию:
- `METADATA_ONLY`.
## 10. Task/Session Policy
- `STRICT`;
- `SOFT`;
- `LOCAL_DEV`.
Enterprise default:
- `STRICT`.
+282
View File
@@ -0,0 +1,282 @@
# SFERA Stand Runbook
## Network API
- API: `http://192.168.200.60:8000`
- Swagger: `http://192.168.200.60:8000/docs`
- Health: `GET /health`
- Summary: `GET /admin/summary`
## Docker
This OS runs inside a VM. Do not install or use a local Docker Engine here.
Use the shared Docker host for Docker/integration stands:
```bash
docker -H ssh://test-docker ps
```
Shared host:
- SSH alias: `test-docker` / `docker-test`
- Host: `docker-test.cin.su`
- User: `test`
Integrated SFERA testing must be deployed on `docker-test`, including both backend/server
services and the frontend service. Do not fall back to local Docker Engine for project testing.
## Neo4j
Neo4j runs on `docker-test` as container `sfera-neo4j`.
- Browser: `http://docker-test.cin.su:17474`
- Bolt: `bolt://docker-test.cin.su:17687`
- User: `neo4j`
- Password: `password`
API uses:
```text
NEO4J_URI=bolt://docker-test.cin.su:17687
NEO4J_USER=neo4j
NEO4J_PASSWORD=password
```
## Rust BSL Parser
Build the parser locally:
```bash
cd rust
cargo build -p bsl-parser
```
API indexing consumes the Rust JSON contract automatically when the built parser is found at
`rust\target\debug\bsl-parser.exe`. To force a specific parser binary, set:
```text
SFERA_BSL_PARSER=rust\target\debug\bsl-parser.exe
```
If no parser binary is configured or auto-discovered, `semantic-kernel` uses the built-in Python parser fallback.
## Runtime Adapter / 1C Access
`sfera-runtime-adapter` is a separate container/service. It must stay separate from `sfera-api`.
Modes:
```text
RUNTIME_ADAPTER_MODE=mock
RUNTIME_ADAPTER_MODE=local_1c
RUNTIME_ADAPTER_MODE=remote_worker
```
`mock` is the default Docker mode and does not require a 1C platform inside Linux containers. `local_1c` can normalize EDT/XML/file-tree sources without executing Designer. For `.cf`, `.cfe`, archive, and live infobase sources it first returns a safe `designer_dump_planned` response unless execution is explicitly enabled on a trusted worker.
Platform discovery:
- Set `ONEC_DESIGNER_PATH` when the worker has a known Designer CLI path.
- If it is empty, runtime-adapter tries common install roots such as `C:\Program Files\1cv8\*\bin\1cv8.exe`.
- Set `ONEC_DISABLE_AUTO_DISCOVERY=true` to turn discovery off in tests.
- Check `GET /runtime/platform` for `platform_found`, `designer_path`, `discovered_paths`, capabilities, and diagnostics.
Credentials rule:
- Do not store live 1C credentials in repository files, compose files, docs, fixtures, or logs.
- Use `credentials_ref` such as `runtime://prompt/live-upo` or a real vault reference.
- Runtime dump plans redact password-like keys in connection strings before returning diagnostics.
Useful local checks, without storing secrets:
```powershell
Test-Path "C:\EDT\projects\iFCM-UPO"
Invoke-WebRequest -UseBasicParsing -Uri "http://192.168.200.95/upo/ru_RU/" -TimeoutSec 10
Get-ChildItem "C:\Program Files\1cv8","C:\Program Files (x86)\1cv8" -Recurse -Filter 1cv8.exe -ErrorAction SilentlyContinue
```
## Smoke Flow
```bash
POST /projects/demo/index
POST /projects/{project_id}/incremental/file
POST /projects/demo/graph/neo4j/project
GET /projects/demo/graph/neo4j/callees/Проведение
GET /projects/demo/graph/neo4j/writes/Проведение
GET /projects/{project_id}/objects/impact/{object_name}
GET /projects/{project_id}/objects/attributes/{object_name}
GET /projects/{project_id}/objects/schema/{object_name}
GET /projects/{project_id}/objects/tabular-sections/{object_name}
GET /projects/{project_id}/objects/tabular-sections/{object_name}/columns
GET /projects/{project_id}/objects/ui/{object_name}
GET /projects/{project_id}/graph/neo4j/objects/attributes/{object_name}
GET /projects/{project_id}/graph/neo4j/objects/schema/{object_name}
GET /projects/{project_id}/graph/neo4j/objects/tabular-sections/{object_name}
GET /projects/{project_id}/graph/neo4j/objects/tabular-sections/{object_name}/columns
GET /projects/{project_id}/graph/neo4j/objects/impact/{object_name}
GET /projects/{project_id}/graph/neo4j/objects/ui/{object_name}
GET /projects/{project_id}/access/objects/{object_name}/roles
GET /projects/{project_id}/access/roles/{role_name}/objects
GET /projects/{project_id}/jobs/scheduled
GET /projects/{project_id}/integrations
GET /projects/{project_id}/graph/neo4j/integrations
GET /projects/{project_id}/graph/neo4j/integrations/{integration_name}/modules
GET /projects/{project_id}/graph/neo4j/access/objects/{object_name}/roles
GET /projects/{project_id}/graph/neo4j/access/roles/{role_name}/objects
POST /knowledge/packs
GET /knowledge/packs
GET /projects/{project_id}/knowledge/schema-coverage
GET /projects/{project_id}/patterns
POST /projects/{project_id}/comments
GET /projects/{project_id}/comments
GET /projects/{project_id}/comments/{target_id}
POST /projects/{project_id}/ownership
GET /projects/{project_id}/ownership
GET /projects/{project_id}/objects/ownership/{object_name}
POST /projects/{project_id}/privacy/markers
GET /projects/{project_id}/privacy/markers
GET /projects/{project_id}/objects/privacy/{object_name}
POST /ai/usage
GET /ai/usage
GET /ai/usage/summary
GET /ai/policy
POST /projects/{project_id}/ai/answer-policy
GET /projects/{project_id}/review
GET /projects/{project_id}/report
GET /graph/neo4j/status
```
## Frontend
Frontend app:
```text
Z:\codex\SFERA\frontend\sfera-web
```
Use the mapped `Z:` drive. It points to `\\nas\MST` and avoids Windows tooling issues with UNC current directories:
```bat
cd /d Z:\codex\SFERA\frontend\sfera-web
npm run dev
```
Always run frontend `npm` commands from the mapped `Z:` drive. Do not use `\\nas\MST\...` as the current directory: Windows `cmd.exe` does not support UNC current directories and falls back to `C:\Windows`, which makes npm scripts fail with missing `package.json`.
Default URL:
```text
http://192.168.200.60:3000
```
Editor direct links:
```text
http://192.168.200.60:3000/editor?project=demo&mode=module
http://192.168.200.60:3000/editor?project=demo&mode=form
http://192.168.200.60:3000/editor?project=demo&mode=events
http://192.168.200.60:3000/editor?project=demo&mode=learning
```
Lightweight frontend smoke check against the running stand:
```bat
cd /d Z:\codex\SFERA\frontend\sfera-web
npm run smoke:editor
```
Browser runtime smoke check against the running stand:
```bat
cd /d Z:\codex\SFERA\frontend\sfera-web
npm run smoke:editor:runtime
```
Project Setup / Import Center runtime smoke check against the running stand:
```bat
cd /d Z:\codex\SFERA\frontend\sfera-web
npm run smoke:project-setup
```
Full editor smoke check:
```bat
cd /d Z:\codex\SFERA\frontend\sfera-web
npm run smoke:editor:all
```
Override the checked frontend URL when needed:
```bat
set SFERA_WEB_URL=http://docker-test.cin.su:3000
npm run smoke:editor:all
```
`smoke:editor` checks server-rendered HTML for the overview and editor modes and retries briefly while a freshly started stand settles. `smoke:editor:runtime` launches the installed Chrome/Edge through `playwright-core`, catches browser runtime errors, verifies Monaco in module mode, opens the Versions tab, clicks a version row, checks full version payload details, and exercises metadata draft preview/apply through the API. `smoke:project-setup` prepares the `default` project through the web API proxy, verifies the new Project Setup / IDE Shell route, and saves a metadata draft to workspace history. Set `SFERA_BROWSER_PATH` if Chrome/Edge is installed in a non-standard location.
Docker health smoke can include the Project Setup browser smoke:
```powershell
.\scripts\smoke-test-docker.ps1 `
-ApiUrl http://docker-test.cin.su:8000 `
-WebUrl http://docker-test.cin.su:3000 `
-Neo4jUrl http://docker-test.cin.su:7474 `
-QdrantUrl http://docker-test.cin.su:6333 `
-ObjectStorageUrl http://docker-test.cin.su:9000 `
-IncludeProjectSetupSmoke
```
The frontend resolves the API endpoint in this order:
1. `SFERA_API_URL`
2. `NEXT_PUBLIC_SFERA_API_URL`
3. the current panel host with API port `8000`
Examples:
```text
http://192.168.200.60:3000 -> http://192.168.200.60:8000
http://docker-test.cin.su:3000 -> http://docker-test.cin.su:8000
http://127.0.0.1:3001 -> http://localhost:8000
```
If the API moves to another address or port, set:
```text
SFERA_API_URL=http://api-host:8080
```
If only the derived API port changes, set:
```text
SFERA_API_PORT=8080
```
Do not use `127.0.0.1:8000` as the panel default, because browsers are normally opened from another computer in the LAN. Full Docker stands should run on `docker-test`; local mode is only for the current API + Next.js development loop without a local Docker Engine.
Browser-side editor actions call the API directly, so API CORS must allow the panel origin. By default the API allows localhost, LAN `192.168.*.*` origins, and `docker-test.cin.su`. Override with `SFERA_CORS_ORIGIN_REGEX` only when the stand moves to a different trusted host pattern.
Expected demo projection:
```text
nodes: 5
edges: 6
```
After a project has been projected once to Neo4j, `POST /projects/{project_id}/incremental/file` automatically applies the SIR delta to that project's Neo4j graph. Check `neo4j_projected` / `neo4j_error` in the response.
Object impact includes 1C role access when XML contains role rights, for example `Role -> Right object="Документ.ЗаказПокупателя"`.
Knowledge packs are stored in `knowledge_packs`; importing a BSP/vendor pack also persists enriched `knowledge` records with `pack:{pack_id}` and `vendor:{vendor}` tags for search and coverage.
Pattern mining is available via `GET /projects/{project_id}/patterns?min_support=2` and reports repeated table reads/writes and repeated routine read/write shapes.
Ownership is stored in `collaboration_ownership` and is scoped by project + target lineage. Project review reports `Missing 1C object owner` for root 1C objects without an assigned owner; project report includes ownership and unowned-object counters.
Privacy markers are stored in `privacy_markers` and are scoped by project + target lineage. Review reports `Unclassified sensitive 1C field` for likely sensitive 1C attributes such as ИНН, паспорт, телефон, email, адрес when no privacy classification exists.
AI usage records are stored in `ai_usage`. Use `GET /ai/usage/summary?project_id=...` for dashboard counters and `GET /ai/policy?user_id=...` before AI actions to show token limits and remaining allowance.
AI answer policy is available via `POST /projects/{project_id}/ai/answer-policy`. It does not generate an answer; it returns `allowed`, blocking reasons, warnings, matching knowledge records, privacy markers, and remaining token budget.
+167
View File
@@ -0,0 +1,167 @@
# SFERA Completion Plan
Дата аудита: 2026-05-10.
Этот план фиксирует путь к завершению SFERA как продукта. Он не подменяет
`IMPLEMENTATION_ORDER.md`, а добавляет проверяемые критерии готовности и текущий статус.
## Текущее состояние
SFERA уже содержит рабочий backend/API, Rust BSL parser, SIR, semantic kernel,
projection/incremental контур, runtime/governance/knowledge/collaboration пакеты и Next.js IDE.
Текущая проверенная база:
- Python/API tests: `161 passed`.
- Rust tests: `14 passed`.
- Frontend `typecheck`: passed.
- Frontend production `next build`: passed.
- Editor smoke: passed.
- Editor runtime smoke: passed.
## Definition Of Done
Проект считается завершённым для production-ready milestone, когда выполнены все пункты:
1. Все фазы из `IMPLEMENTATION_ORDER.md` имеют deterministic implementation без placeholder/stub.
2. Все parser bugs покрыты golden fixtures.
3. SIR snapshot validates для BSL/XML metadata projects.
4. Projection and incremental update pass against in-memory and Neo4j-compatible contracts.
5. API exposes project, semantic, governance, knowledge, collaboration and IDE workflows.
6. Frontend builds production bundle and passes editor smoke/runtime checks.
7. Stand runbook is executable on local/NAS and shared Docker host.
8. A single verification command can reproduce core/backend/Rust/frontend checks.
## Phase Plan
### Phase 1 — Semantic Core
Status: mostly complete.
Completed:
- `packages/sir`.
- `rust/crates/bsl-parser`.
- Rust `query-parser` foundation.
- Rust `semantic-engine` foundation.
- `packages/semantic-kernel`.
- `packages/projection-engine`.
- `packages/incremental-indexer`.
- Golden fixtures for mixed RU/EN syntax, calls, queries, writes, object writes and recordset writes.
- Same-module routine resolution priority for duplicate routine names.
- SIR diagnostics for malformed BSL routine/query boundaries.
- Incremental diagnostic refresh for changed BSL fragments.
- Routine `Экспорт` / `Export` flags preserved in SIR node attributes.
- BSL control-flow fixture for calls/writes inside loops and try/except blocks.
- Form event handler links from XML metadata to BSL routines.
Remaining:
- Keep parser and XML fixtures expanding as new 1C export patterns are encountered.
### Phase 2 — Object Runtime
Status: implemented with tests, needs broader fixtures.
Completed:
- XML metadata fixtures preserve register dimensions/resources as SIR attributes.
- Semantic versioning classifies object rename/move/update changes.
- Object impact includes form event handlers and their register writes.
- XML fixtures cover child-element forms, commands and role rights.
- Query intelligence reports register read/write dependencies.
- Transaction topology groups routines by written register target.
- Object impact can include scheduled-job integration endpoints from the owning module.
Remaining:
- Add more impact/review fixtures for object-level dependency edge cases as new patterns are found.
### Phase 3 — Runtime Intelligence
Status: implemented with tests, needs integration depth.
Remaining:
- Expand transaction/query intelligence with register movement patterns.
- Connect UI semantics to editor panels and review findings.
- Add scheduled job and integration cross-links to impact reports.
### Phase 4 — Knowledge System
Status: implemented with tests.
Remaining:
- Add import fixtures for larger BSP/vendor packs.
- Add coverage reports by metadata subtree.
### Phase 5 — Collaboration
Status: implemented with tests.
Remaining:
- Enforce task/session binding for mutations outside Phase 1 placeholders.
- Add UI flow coverage for comments/ownership/activity.
### Phase 6 — Governance/Operations
Status: implemented with tests.
Remaining:
- Verify full stand runbook on `test-docker`.
- Add backup/restore and migration smoke checks.
### Phase 7 — 1C IDE / Authoring
Status: working Next.js IDE exists and passes smoke; advanced authoring remains product work.
Completed:
- Backend and typed frontend API client for symbol search, go to definition and find references.
Remaining:
- Wire editor actions for go to definition, find references and symbol search into IDE panels.
- Complete semantic autocomplete from SIR + metadata context.
- Complete guarded apply with preview, semantic diff, impact, review, RBAC/privacy and version record.
- Complete object/form/report designer flows.
- Add browser smoke for key authoring flows.
### AI Layer
Status: intentionally gated until semantic truth is stronger.
Remaining:
- Add answer/generation policy enforcement to every AI-facing endpoint.
- Add prompt/context builders over SIR, metadata, knowledge, privacy and task/session.
- Add preview-only AI code generation and guarded apply workflow.
## Execution Order From Here
1. Keep all current green checks green with `scripts/check_all.ps1`.
2. Finish Phase 1 hardening fixtures and diagnostics.
3. Expand Phase 2/3 fixtures around metadata, impact, query and runtime topology.
4. Finish guarded apply and object-level authoring API.
5. Finish IDE authoring UI and smoke coverage.
6. Add AI pair-programmer only after guarded apply is deterministic.
7. Verify full stand on local/NAS and shared Docker host.
## Verification
Use:
```powershell
.\scripts\check_all.ps1
```
Expected checks:
- `cargo test && cargo build -p bsl-parser`
- `uv run pytest`
- `npm run typecheck`
- `next build`
- optional frontend smoke checks when API/frontend stand is running.
+123
View File
@@ -0,0 +1,123 @@
# Реальный порядок реализации
## Phase 1 — Semantic Core
1. `packages/sir`
2. `rust/crates/bsl-parser`
- deterministic BSL parser;
- JSON CLI contract for Python semantic-kernel integration.
3. `packages/semantic-kernel`
- current Python parser remains compatible;
- consumes Rust parser JSON as canonical BSL parse source when the CLI is configured or auto-discovered;
- metadata object to BSL module links via `CONTAINS`.
4. `packages/projection-engine`
5. `packages/incremental-indexer`
## Phase 2 — Object Runtime
1. `packages/one-c-normalizer`
- BSL source normalization;
- XML metadata extraction for core 1C objects.
2. `packages/semantic-versioning`
3. `packages/semantic-search`
4. `packages/impact-engine`
5. `packages/review-engine`
## Phase 3 — Runtime Intelligence
1. `runtime-overlays`
2. `transaction-topology`
3. `query-intelligence`
4. `ui-semantics`
5. `integration-topology`
6. `job-topology`
## Phase 4 — Knowledge System
1. global/workspace/project knowledge; ✅
2. BSP/vendor docs; ✅
3. pattern mining; ✅
4. knowledge coverage; ✅
5. AI answer policy. ✅
## Phase 5 — Collaboration
1. users/workspaces/projects; ✅
2. tasks/sessions; ✅
3. comments/discussions; ✅
4. activity feed; ✅
5. ownership. ✅
## Phase 6 — Governance/Operations
RBAC ✅, privacy ✅, AI usage ✅, jobs ✅, observability ✅, reports ✅, marketplace ✅, licensing ✅, admin ✅.
## Phase 7 — 1C IDE / Authoring
Reference workflow: берём лучшие рабочие паттерны 1С Конфигуратора, но реализуем их как современную AI IDE. Обязательны дерево конфигурации, вкладки открытых объектов, режимы модуль/форма/свойства/события, инспектор, нижние панели проблем/output/diff и быстрый поиск. Дополнительно SFERA должна объединять версии, документацию, знания, обучение, audit и guarded apply.
1. BSL editor foundation:
- syntax highlighting;
- diagnostics;
- outline;
- go to definition;
- find references;
- symbol search.
2. Semantic autocomplete:
- current procedure/function context;
- local variables and parameters;
- object attributes;
- tabular sections and columns;
- form elements and commands;
- known 1C platform APIs;
- mixed Russian/English 1C syntax.
3. AI pair programmer:
- code continuation;
- procedure/function generation;
- query generation;
- register movement generation;
- command/form handler generation;
- explanation of proposed code.
4. 1C object designer:
- create/update document/catalog/register/common module metadata;
- create/update attributes and tabular sections;
- create/update commands, forms, form elements and reports.
5. Semantic diff and guarded apply:
- preview every manual or AI change;
- impact analysis before apply;
- review findings before apply;
- privacy/RBAC checks;
- object-level version record;
- rollback point.
6. IDE-grade UX:
- editor workspace;
- object tree;
- mode bar: module/form/properties/events/versions/docs/knowledge/training;
- properties inspector;
- form/report designer;
- terminal/command palette;
- AI assistant panel;
- problems/references/output panels.
7. Documentation/knowledge/training inside IDE:
- docs linked to objects, forms, reports, events and routines;
- project/vendor/BSP knowledge available next to the code;
- team patterns, decisions and examples surfaced by current context;
- learning hints for the selected object and available variables;
- search across code, metadata, docs, versions and discussions.
## Frontend/UI Gate
Перед началом UI-этапа перечитать и применить актуальные требования:
- `docs/design-system.md`
- `docs/codex-ui-guidelines.md`
- `docs/ui-ux-roadmap.md`
- `docs/component-architecture.md`
- `docs/frontend-stack.md`
- `prompts/system-frontend-architect.md`
- `prompts/ui-generation-prompt.md`
Ключевой принцип: SFERA UI должен ощущаться как современная Enterprise AI IDE / Operating System для 1С, а не legacy CRM. Каждый экран обязан иметь AppShell-compatible layout, loading/error/empty/permission states, адаптивность, права доступа, audit trail для важных действий, таблицы с фильтрами/saved views/bulk actions и AI token/cost impact для AI-действий. Для authoring-экранов обязательны editor/object tree/properties inspector/problems/diff/preview/apply states.
Язык UI/команд: русский по умолчанию, но каждый пользовательский экран должен иметь выбор английского интерфейса. Команды в интерфейсе также проектируются с русским вариантом по умолчанию и английским вариантом как доступным режимом. 1С-код может смешивать русские и английские ключевые слова в одном тексте; parser/review/UI не должны считать это ошибкой.
+96
View File
@@ -0,0 +1,96 @@
# UI/UX Roadmap SFERA
SFERA UI — это современная IDE/операционная среда для 1С, а не CRM.
Для authoring-экранов 1С Конфигуратор является источником сильных workflow-паттернов: дерево конфигурации, вкладки открытых объектов, режимы модуль/форма/свойства/события, правый инспектор и нижние панели. SFERA не повторяет legacy-внешний вид, а переносит эти паттерны в современную AI IDE.
## Этап 1 — Foundation
- AppShell
- Sidebar
- Topbar
- theme tokens
- auth layout
- workspace layout
- command palette
- базовый 1С dashboard
- permissions scaffold
- audit trail scaffold
## Этап 2 — 1С Semantic Workspace
- дерево проектов 1С
- дерево объектов конфигурации
- SIR snapshots
- semantic graph view
- object details inspector
- impact analysis
- review findings
- knowledge coverage
- роли и права 1С
- privacy markers
## Этап 3 — IDE Workspace
- BSL code editor
- рабочие режимы: модуль, форма, свойства, события, версии, документация, знания, обучение
- подсветка синтаксиса
- diagnostics/problems panel
- outline
- go to definition
- find references
- rename/refactor preview
- semantic search
- command palette для IDE-действий
## Этап 4 — AI Pair Programmer
- inline code completion
- продолжение BSL-кода по текущему контексту
- подсказки по доступным переменным, параметрам, реквизитам, табличным частям и формам
- генерация процедур, функций, запросов и движений регистров
- генерация обработчиков команд и форм
- объяснение предложенного кода
- token/cost impact перед AI-действием
- AI decision audit
- объяснение текущих переменных, доступных реквизитов, событий формы и связанных объектов перед генерацией
## Этап 5 — Object/Form/Report Designer
- создание и изменение документов, справочников, регистров и общих модулей
- создание реквизитов и табличных частей
- создание команд
- visual form designer
- form elements inspector
- command handler binding
- report designer
- metadata diff
## Этап 5.5 — Documentation, Knowledge, Training
- документация объекта и формы рядом с редактором
- связь знаний с lineage, процедурами, запросами, событиями и задачами
- командные паттерны и стандарты кодирования 1С
- обучение разработчика на текущем объекте: что можно безопасно написать, какие переменные доступны, какие риски есть
- поиск по документации, базе знаний, версиям, обсуждениям и изменениям
## Этап 6 — Guarded Apply
- preview всех изменений
- semantic diff
- impact analysis до применения
- review до применения
- RBAC/privacy checks
- object-level version record
- task/session binding
- rollback point
## Этап 7 — Runtime And Operations
- регламентные задания
- интеграции
- runtime overlays
- operations jobs
- observability
- marketplace/download center
- license/admin panels
+49
View File
@@ -0,0 +1,49 @@
# VSCode / Cursor Extensions
## Обязательно
```txt
Tailwind CSS IntelliSense
ESLint
Prettier
Pretty TypeScript Errors
Error Lens
GitLens
```
## Для UI
```txt
shadcn/studio
v0 integration / paste workflow
Figma for VS Code
Iconify IntelliSense
```
## Для качества кода
```txt
SonarLint
Import Cost
TypeScript Importer
Path Intellisense
```
## Для AI workflow
```txt
Cursor
GitHub Copilot
Continue
Codeium / Windsurf, если используется отдельно
```
## Рекомендация
Основной UI генерировать через:
```txt
v0 → вставка в проект → Codex refactor → Cursor review
```
Codex не должен генерировать финальный UI без design system rules.
+13
View File
@@ -0,0 +1,13 @@
Процедура Проведение()
ПроверитьОстатки();
Движения.ОстаткиТоваров.Записать();
КонецПроцедуры
Процедура ПроверитьОстатки()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
Остатки.Номенклатура
ИЗ
РегистрНакопления.ОстаткиТоваров КАК Остатки";
КонецПроцедуры
+71
View File
@@ -0,0 +1,71 @@
# SFERA Web
Next.js frontend for the SFERA 1C semantic workspace.
## Run On This NAS Workspace
Use the mapped `R:` drive. It points to `\\nas\MST` and avoids Windows tooling issues with UNC current directories.
```bat
cd /d R:\codex\SFERA\frontend\sfera-web
npm run dev
```
Do not run `npm` from the UNC path `\\nas\MST\...`. Windows starts `cmd.exe` in `C:\Windows` for UNC current directories, so package scripts cannot find `package.json`.
The app resolves the API endpoint in this order:
1. `SFERA_API_URL`
2. `NEXT_PUBLIC_SFERA_API_URL`
3. the current panel host with API port `8000`
Examples:
- `http://192.168.200.60:3000` -> `http://192.168.200.60:8000`
- `http://docker-test.cin.su:3000` -> `http://docker-test.cin.su:8000`
- `http://127.0.0.1:3001` -> `http://localhost:8000`
If the stand moves to another API port, set:
```text
SFERA_API_URL=http://api-host:8080
```
You can also override only the derived port:
```text
SFERA_API_PORT=8080
```
## Checks
```bat
cd /d R:\codex\SFERA\frontend\sfera-web
node_modules\.bin\tsc.cmd -p tsconfig.json --noEmit
node_modules\.bin\next.cmd build
npm run smoke:editor
npm run smoke:editor:runtime
npm run smoke:project-setup
```
`npm run smoke:editor` checks the running stand URL. By default it uses `http://192.168.200.60:3000` and verifies that the overview stays a dashboard while editor modes open directly:
- `mode=module`
- `mode=form`
- `mode=events`
- `mode=learning`
Use `SFERA_WEB_URL` to point the smoke check at another host or port. The HTML smoke retries each page briefly while a freshly started stand settles.
`npm run smoke:editor:runtime` opens the running editor in an installed Chrome/Edge through `playwright-core`. It catches browser runtime failures such as Monaco `Runtime TypeError`, verifies that Monaco renders in `mode=module`, opens `mode=versions`, clicks a version row, checks full version payload details, and exercises metadata draft preview/apply through the API.
`npm run smoke:project-setup` checks the new Project Setup / Import Center flow. It prepares the `default` project through the web API proxy, verifies that the indexed Project IDE Shell opens, and exercises metadata draft preview/save to workspace history.
By default the runtime smoke uses the installed Chrome/Edge paths on this Windows stand. Override when needed:
```text
SFERA_BROWSER_PATH=C:\Path\To\chrome.exe
SFERA_WEB_URL=http://docker-test.cin.su:3000
```
Use `npm run smoke:editor:all` to run both the HTML smoke and browser runtime smoke. Browser-side editor actions require API CORS for the panel origin; the API allows LAN panel origins, localhost, and `docker-test.cin.su` by default. The Project Setup smoke uses the Next.js `/api/sfera/...` proxy and therefore also verifies frontend-to-backend routing.
+6
View File
@@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+6
View File
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true
};
export default nextConfig;
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
{
"name": "sfera-web",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --hostname 0.0.0.0 --port 3000",
"build": "next build",
"start": "next start --hostname 0.0.0.0 --port 3000",
"lint": "next lint",
"smoke:editor": "node scripts/smoke-editor-modes.mjs",
"smoke:editor:all": "npm run smoke:editor && npm run smoke:editor:runtime",
"smoke:editor:runtime": "node scripts/smoke-editor-runtime.mjs",
"smoke:project-setup": "node scripts/smoke-project-setup.mjs",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@monaco-editor/react": "^4.7.0",
"@tanstack/react-table": "^8.21.3",
"clsx": "^2.1.1",
"lucide-react": "^0.468.0",
"monaco-editor": "^0.55.1",
"next": "^15.0.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^2.5.5",
"zod": "^3.24.1",
"zustand": "^5.0.2"
},
"devDependencies": {
"@types/node": "^22.10.2",
"@types/react": "^19.0.1",
"@types/react-dom": "^19.0.2",
"autoprefixer": "^10.4.20",
"eslint": "^9.16.0",
"eslint-config-next": "^15.0.4",
"playwright-core": "^1.59.1",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2"
}
}
+8
View File
@@ -0,0 +1,8 @@
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};
export default config;
@@ -0,0 +1,25 @@
The MIT License (MIT)
=====================
Copyright © 2026 Andrew Ponomarev
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,9 @@
1C-like metadata icons
======================
Source: MetadataViewer1C by Andrew Ponomarev
Repository: https://github.com/asweetand-a11y/MetadataViewer1C
License: MIT, see LICENSE.MetadataViewer1C.md
These SVGs are used as a visually similar open-source icon set for SFERA's 1C metadata tree.
They are not extracted from the 1C:Enterprise Configurator executable or distribution.
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M20.95 31.95 35.4 17.5l-2.15-2.15-12.3 12.3L15 21.7l-2.15 2.15ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24.5 21.7h3v-4.2h4.2v-3h-4.2v-4.2h-3v4.2h-4.2v3h4.2Zm-4.2 7.8h11.4v-3H20.3ZM13 40q-1.2 0-2.1-.9-.9-.9-.9-2.1V5q0-1.2.9-2.1.9-.9 2.1-.9h17.4L42 13.6V37q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h26V14.9L28.9 5H13v32Zm-6 9q-1.2 0-2.1-.9Q4 44.2 4 43V12.05h3V43h24.9v3Zm6-9V5v32Z"/>
</svg>

After

Width:  |  Height:  |  Size: 506 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M32 22q.85 0 1.425-.575Q34 20.85 34 20q0-.85-.575-1.425Q32.85 18 32 18q-.85 0-1.425.575Q30 19.15 30 20q0 .85.575 1.425Q31.15 22 32 22Zm-16-5h10v-3H16ZM9 42q-1.7-5.7-3.35-11.375Q4 24.95 4 19q0-4.6 3.2-7.8T15 8h10q1.45-1.9 3.525-2.95Q30.6 4 33 4q1.25 0 2.125.875T36 7q0 .3-.075.6t-.175.55q-.2.55-.375 1.125T35.1 10.45L39.65 15H44v13.95l-5.65 1.85L35 42H24v-4h-4v4Zm2.25-3H17v-4h10v4h5.75l3.15-10.5 5.1-1.75V18h-2.6L32 11.6q.05-1.25.325-2.425Q32.6 8 32.9 6.8q-1.9.5-3.6 1.475-1.7.975-2.6 2.725H15q-3.3 0-5.65 2.35Q7 15.7 7 19q0 5.15 1.45 10.075Q9.9 34 11.25 39ZM24 22.9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 811 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M8 25.5v-3h32v3Z"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M31 44v-4.75L15.5 31.5H6v-11h8.75l6.25-7V4h11v11h-8.3L17 22.5v6.45l14 6.95V33h11v11Zm-7-32h5V7h-5ZM9 28.5h5v-5H9ZM34 41h5v-5h-5ZM26.5 9.5ZM11.5 26Zm25 12.5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 400 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M15.7 36.6h2.5v-4.4h4.4v-2.5h-4.4v-4.4h-2.5v4.4h-4.4v2.5h4.4Zm10.75-1.75H36.5V32.4H26.45Zm0-5.35H36.5V27H26.45Zm1.85-8.15 3.05-3.05 3.05 3.05 1.8-1.8-3.05-3.05 3.05-3.05-1.8-1.8-3.05 3.05-3.05-3.05-1.8 1.8 3.05 3.05-3.05 3.05Zm-16.25-3.6h9.8v-2.5h-9.8ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 629 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M6 42V6h36v36Zm3-25h30V9H9Zm11 11h8v-8h-8Zm0 11h8v-8h-8ZM9 28h8v-8H9Zm22 0h8v-8h-8ZM9 39h8v-8H9Zm22 0h8v-8h-8Z"/>
</svg>

After

Width:  |  Height:  |  Size: 354 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M14.5 40V13H4V8h26v5H19.5v27Zm18 0V23H26v-5h18v5h-6.5v17Z"/>
</svg>

After

Width:  |  Height:  |  Size: 301 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="m24 41.5-18-14 2.5-1.85L24 37.7l15.5-12.05L42 27.5Zm0-7.6-18-14 18-14 18 14Zm0-15.05Zm0 11.25 13.1-10.2L24 9.7 10.9 19.9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 365 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M15 33.7q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm0-8.2q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm0-8.2q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm6.6 16.4h12.2v-3H21.6Zm0-8.2h12.2v-3H21.6Zm0-8.2h12.2v-3H21.6ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 811 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M15.35 16.6q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm8.65 0q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm8.65 0q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 753 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M19.15 32.5 32.5 24l-13.35-8.5ZM24 44q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 24q0-4.15 1.575-7.8 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24 4q4.15 0 7.8 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm0-3q7.1 0 12.05-4.975Q41 31.05 41 24q0-7.1-4.95-12.05Q31.1 7 24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24 41Zm0-17Z"/>
</svg>

After

Width:  |  Height:  |  Size: 704 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M13.4 35.5q-3.1 0-5.25-2.15T6 28.1q0-3.1 2.15-5.25t5.25-2.15q3.1 0 5.25 2.15t2.15 5.25q0 3.1-2.15 5.25T13.4 35.5Zm0-3q1.85 0 3.125-1.275T17.8 28.1q0-1.85-1.275-3.125T13.4 23.7q-1.85 0-3.125 1.275T9 28.1q0 1.85 1.275 3.125T13.4 32.5Zm8.45-16.7q1.9 0 3.15-1.25t1.25-3.15q0-1.9-1.25-3.15T21.85 7q-1.9 0-3.15 1.25t-1.25 3.15q0 1.9 1.25 3.15t3.15 1.25Zm0 3q-3.1 0-5.25-2.15t-2.15-5.25q0-3.1 2.15-5.25T21.85 4q3.1 0 5.25 2.15t2.15 5.25q0 3.1-2.15 5.25t-5.25 2.15ZM34.6 39q1.9 0 3.15-1.25T39 34.6q0-1.9-1.25-3.15T34.6 30.2q-1.9 0-3.15 1.25T30.2 34.6q0 1.9 1.25 3.15T34.6 39Zm0 3q-3.1 0-5.25-2.15T27.2 34.6q0-3.1 2.15-5.25t5.25-2.15q3.1 0 5.25 2.15T42 34.6q0 3.1-2.15 5.25T34.6 42ZM21.85 11.4ZM13.4 28.1Zm21.2 6.5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 950 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M13.85 34.05H27.6v-3H13.85Zm0-8.55h20.3v-3h-20.3Zm0-8.55h20.3v-3h-20.3ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 448 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M6 6h16.5v16.5H6Zm3 2.95v9.4ZM25.5 6H42v16.5H25.5Zm4.15 2.95v9.4ZM6 25.5h16.5V42H6Zm3 4.05V39Zm23.25-4.05h3v6.75H42v3h-6.75V42h-3v-6.75H25.5v-3h6.75ZM28.5 9v10.5H39V9ZM9 9v10.5h10.5V9Zm0 19.5V39h10.5V28.5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 449 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="m14 42-2.15-2.15 4.3-4.3q-5.4.35-9.775-3.525T2 22q0-5.85 4.075-9.925Q10.15 8 16 8h6v3h-6q-4.55 0-7.775 3.225Q5 17.45 5 22q0 4.7 3.275 7.7t8.025 2.9l-4.45-4.45L14 26l8 8Zm12-2V26h18v14Zm0-18V8h18v14Zm3-3h12v-8H29Z"/>
</svg>

After

Width:  |  Height:  |  Size: 456 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M7 36q-1.2 0-2.1-.9Q4 34.2 4 33V15q0-1.15.9-2.075Q5.8 12 7 12h34q1.2 0 2.1.925.9.925.9 2.075v18q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h34V15h-6.5v9h-3v-9h-6v9h-3v-9h-6v9h-3v-9H7v18Zm6.5-9h3Zm9 0h3Zm9 0h3ZM24 24Z"/>
</svg>

After

Width:  |  Height:  |  Size: 445 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M15 16H2V0h8.621L15 4.379V16z" id="outline"/><path class="icon-vs-fg" d="M13 14H4V2h5v4h4v8zm-3-9V2.207L12.793 5H10z" id="iconFg"/><path class="icon-vs-bg" d="M3 1v14h11V4.793L10.207 1H3zm10 13H4V2h5v4h4v8zm-3-9V2.207L12.793 5H10z" id="iconBg"/></svg>

After

Width:  |  Height:  |  Size: 552 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M28.05 31V20h3.75l3.25 3.25V31Zm-3 3h13V22l-5-5h-8Zm-18 6q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Zm0-29v26h34V14H22.8l-3-3H7.05Zm0 0v26Z"/>
</svg>

After

Width:  |  Height:  |  Size: 488 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" viewBox="0 -960 960 960">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M120-80v-60h100v-30h-60v-60h60v-30H120v-60h160v90l-30 30 30 30v90H120Zm0-280v-150h100v-30H120v-60h160v150H180v30h100v60H120Zm60-280v-180h-60v-60h120v240h-60Zm189 431v-60h471v60H369Zm0-243v-60h471v60H369Zm0-243v-60h471v60H369Z"/>
</svg>

After

Width:  |  Height:  |  Size: 494 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24 42v-3.55l10.8-10.8 3.55 3.55L27.55 42ZM6 31.5v-3h15v3Zm34.5-2.45-3.55-3.55 1.45-1.45q.4-.4 1.05-.4t1.05.4l1.45 1.45q.4.4.4 1.05t-.4 1.05ZM6 23.25v-3h23.5v3ZM6 15v-3h23.5v3Z"/>
</svg>

After

Width:  |  Height:  |  Size: 420 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M11 44q-1.2 0-2.1-.9Q8 42.2 8 41V7q0-1.2.9-2.1Q9.8 4 11 4h17l12 12v7.8h-3V18H26V7H11v34h15v3Zm0-3V7v34Zm26.8-11.15 1.4 1.4-8.2 8.2V42h2.55l8.2-8.2 1.4 1.4-8.8 8.8H29v-5.35Zm5.35 5.35-5.35-5.35 3.05-3.05q.45-.45 1.05-.45.6 0 1.05.45l3.25 3.25q.45.45.45 1.05 0 .6-.45 1.05Z"/>
</svg>

After

Width:  |  Height:  |  Size: 515 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M28.5 40v-3h6q1.05 0 1.775-.725Q37 35.55 37 34.5v-5q0-1.85 1.125-3.3 1.125-1.45 2.875-2v-.4q-1.75-.5-2.875-1.975T37 18.5v-5q0-1.05-.725-1.775Q35.55 11 34.5 11h-6V8h6q2.3 0 3.9 1.6t1.6 3.9v5q0 1.05.725 1.775Q41.45 21 42.5 21H44v6h-1.5q-1.05 0-1.775.725Q40 28.45 40 29.5v5q0 2.3-1.6 3.9T34.5 40Zm-15 0q-2.3 0-3.9-1.6T8 34.5v-5q0-1.05-.725-1.775Q6.55 27 5.5 27H4v-6h1.5q1.05 0 1.775-.725Q8 19.55 8 18.5v-5q0-2.3 1.6-3.9T13.5 8h6v3h-6q-1.05 0-1.775.725Q11 12.45 11 13.5v5q0 1.85-1.125 3.325T7 23.8v.4q1.75.55 2.875 2T11 29.5v5q0 1.05.725 1.775Q12.45 37 13.5 37h6v3Z"/>
</svg>

After

Width:  |  Height:  |  Size: 805 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M19.95 42 22 27.9h-7.3q-.55 0-.8-.5t0-.95L26.15 6h2.05l-2.05 14.05h7.2q.55 0 .825.5.275.5.025.95L22 42Z"/>
</svg>

After

Width:  |  Height:  |  Size: 347 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M8.35 40v-3h6.5l-.75-.6q-3.2-2.55-4.65-5.55-1.45-3-1.45-6.7 0-5.3 3.125-9.525Q14.25 10.4 19.35 8.8v3.1q-3.75 1.45-6.05 4.825T11 24.15q0 3.15 1.175 5.475 1.175 2.325 3.175 4.025l1.5 1.05v-6.2h3V40Zm20.35-.75V36.1q3.8-1.45 6.05-4.825T37 23.85q0-2.4-1.175-4.875T32.75 14.6l-1.45-1.3v6.2h-3V8h11.5v3h-6.55l.75.7q3 2.8 4.5 6t1.5 6.15q0 5.3-3.1 9.55-3.1 4.25-8.2 5.85Z"/>
</svg>

After

Width:  |  Height:  |  Size: 606 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="m24.5 28.85 11.4-11.4-2.1-2.05-9.25 9.3-4.85-4.85-2.1 2.1ZM13 38q-1.2 0-2.1-.9-.9-.9-.9-2.1V7q0-1.2.9-2.1.9-.9 2.1-.9h28q1.2 0 2.1.9.9.9.9 2.1v28q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h28V7H13v28Zm-6 9q-1.2 0-2.1-.9Q4 42.2 4 41V10h3v31h31v3Zm6-37v28V7Z"/>
</svg>

After

Width:  |  Height:  |  Size: 486 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24 22q-8.05 0-13.025-2.45T6 14q0-3.15 4.975-5.575Q15.95 6 24 6t13.025 2.425Q42 10.85 42 14q0 3.1-4.975 5.55Q32.05 22 24 22Zm0 10q-7.3 0-12.65-2.2Q6 27.6 6 24.5v-5q0 1.95 1.875 3.375t4.65 2.35q2.775.925 5.9 1.35Q21.55 27 24 27q2.5 0 5.6-.425 3.1-.425 5.875-1.325 2.775-.9 4.65-2.325Q42 21.5 42 19.5v5q0 3.1-5.35 5.3Q31.3 32 24 32Zm0 10q-7.3 0-12.65-2.2Q6 37.6 6 34.5v-5q0 1.95 1.875 3.375t4.65 2.35q2.775.925 5.9 1.35Q21.55 37 24 37q2.5 0 5.6-.425 3.1-.425 5.875-1.325 2.775-.9 4.65-2.325Q42 31.5 42 29.5v5q0 3.1-5.35 5.3Q31.3 42 24 42Z"/>
</svg>

After

Width:  |  Height:  |  Size: 780 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M22 40q-.85 0-1.425-.575Q20 38.85 20 38V26L8.05 10.75q-.7-.85-.2-1.8Q8.35 8 9.4 8h29.2q1.05 0 1.55.95t-.2 1.8L28 26v12q0 .85-.575 1.425Q26.85 40 26 40Zm2-13.8L36 11H12Zm0 0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 417 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M7.05 40q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Zm0-29v26h34V14H22.8l-3-3H7.05Zm0 0v26Z"/>
</svg>

After

Width:  |  Height:  |  Size: 439 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M8 38v-3h19.3v3Zm0-8.3v-3h32v3Zm0-8.35v-3h32v3ZM8 13v-3h32v3Z"/>
</svg>

After

Width:  |  Height:  |  Size: 305 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24 44q-4.2 0-7.85-1.575Q12.5 40.85 9.8 38.15q-2.7-2.7-4.25-6.375Q4 28.1 4 23.9t1.55-7.825Q7.1 12.45 9.8 9.75t6.35-4.225Q19.8 4 24 4q4.2 0 7.85 1.525Q35.5 7.05 38.2 9.75q2.7 2.7 4.25 6.325Q44 19.7 44 23.9t-1.55 7.875Q40.9 35.45 38.2 38.15t-6.35 4.275Q28.2 44 24 44Zm0-2.9q1.75-1.8 2.925-4.125Q28.1 34.65 28.85 31.45H19.2q.7 3 1.875 5.4Q22.25 39.25 24 41.1Zm-4.25-.6q-1.25-1.9-2.15-4.1-.9-2.2-1.5-4.95H8.6Q10.5 35 13 37.025q2.5 2.025 6.75 3.475Zm8.55-.05q3.6-1.15 6.475-3.45 2.875-2.3 4.625-5.55h-7.45q-.65 2.7-1.525 4.9-.875 2.2-2.125 4.1Zm-20.7-12h7.95q-.15-1.35-.175-2.425-.025-1.075-.025-2.125 0-1.25.05-2.225.05-.975.2-2.175h-8q-.35 1.2-.475 2.15T7 23.9q0 1.3.125 2.325.125 1.025.475 2.225Zm11.05 0H29.4q.2-1.55.25-2.525.05-.975.05-2.025 0-1-.05-1.925T29.4 19.5H18.65q-.2 1.55-.25 2.475-.05.925-.05 1.925 0 1.05.05 2.025.05.975.25 2.525Zm13.75 0h8q.35-1.2.475-2.225Q41 25.2 41 23.9q0-1.3-.125-2.25T40.4 19.5h-7.95q.15 1.75.2 2.675.05.925.05 1.725 0 1.1-.075 2.075-.075.975-.225 2.475Zm-.5-11.95h7.5q-1.65-3.45-4.525-5.75Q32 8.45 28.25 7.5q1.25 1.85 2.125 4t1.525 5Zm-12.7 0h9.7q-.55-2.65-1.85-5.125T24 7q-1.6 1.35-2.7 3.55-1.1 2.2-2.1 5.95Zm-10.6 0h7.55q.55-2.7 1.4-4.825.85-2.125 2.15-4.125-3.75.95-6.55 3.2T8.6 16.5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M4 39.5v-31h40v31Zm3-21.65h6.25V11.5H7Zm9.25 0h6.25V11.5h-6.25Zm9.25 0h6.25V11.5H25.5Zm9.25 0H41V11.5h-6.25Zm0 9.35H41v-6.35h-6.25Zm-9.25 0h6.25v-6.35H25.5Zm-9.25 0h6.25v-6.35h-6.25Zm-3-6.35H7v6.35h6.25Zm21.5 15.65H41v-6.3h-6.25Zm-9.25 0h6.25v-6.3H25.5Zm-9.25 0h6.25v-6.3h-6.25ZM7 36.5h6.25v-6.3H7Z"/>
</svg>

After

Width:  |  Height:  |  Size: 542 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M12.55 40q-4.4 0-7.475-3.075Q2 33.85 2 29.45q0-3.9 2.5-6.85 2.5-2.95 6.35-3.55 1-4.85 4.7-7.925T24.1 8.05q5.6 0 9.45 4.075Q37.4 16.2 37.4 21.9v1.2q3.6-.1 6.1 2.325Q46 27.85 46 31.55q0 3.45-2.5 5.95T37.55 40Zm0-3h25q2.25 0 3.85-1.6t1.6-3.85q0-2.25-1.6-3.85t-3.85-1.6H34.4v-4.2q0-4.55-3.05-7.7-3.05-3.15-7.45-3.15t-7.475 3.15q-3.075 3.15-3.075 7.7h-.95q-3.1 0-5.25 2.175T5 29.45q0 3.15 2.2 5.35Q9.4 37 12.55 37ZM33 15V4h11v11Zm5-5h5V5h-5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 680 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M34 36q-4.95 0-8.475-3.525Q22 28.95 22 24q0-4.95 3.525-8.475Q29.05 12 34 12q4.95 0 8.475 3.525Q46 19.05 46 24q0 4.95-3.525 8.475Q38.95 36 34 36Z"/>
</svg>

After

Width:  |  Height:  |  Size: 389 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/>
</svg>

After

Width:  |  Height:  |  Size: 472 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M8 40V18h7v22Zm12.5 0V8h7v32ZM33 40V26h7v14Z"/>
</svg>

After

Width:  |  Height:  |  Size: 288 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="m22.4 39.65-11-6.45q-.7-.4-1.075-1.1-.375-.7-.375-1.5V17.75q0-.8.375-1.5t1.075-1.1L22.45 8.6q.7-.4 1.55-.4.85 0 1.55.4l11.05 6.55q.7.4 1.075 1.1.375.7.375 1.5V30.6q0 .8-.4 1.5t-1.1 1.1L25.4 39.65q-.7.4-1.5.4t-1.5-.4Zm.1-3.45V25L13 19.55V30.5Zm3 0 9.55-5.7V19.55L25.5 25ZM2 11.45V7.6q0-2.35 1.625-3.975T7.6 2h3.85v3H7.6q-1.1 0-1.85.75T5 7.6v3.85ZM7.6 46q-2.35 0-3.975-1.625T2 40.4v-3.85h3v3.85q0 1.1.75 1.85T7.6 43h3.85v3Zm28.95-.2v-3h3.85q1.1 0 1.85-.75T43 40.2v-3.85h3v3.85q0 2.35-1.625 3.975T40.4 45.8ZM43 11.45V7.6q0-1.1-.75-1.85T40.4 5h-3.85V2h3.85q2.35 0 3.975 1.625T46 7.6v3.85ZM24 22.3l9.5-5.5-9.5-5.45-9.5 5.45Zm0 1.25Zm0-1.25Zm1.5 2.7Zm-3 0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 894 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M14 27.4q-1.4 0-2.4-1t-1-2.4q0-1.4 1-2.4t2.4-1q1.4 0 2.4 1t1 2.4q0 1.4-1 2.4t-2.4 1Zm0 8.6q-5 0-8.5-3.5T2 24q0-5 3.5-8.5T14 12q3.6 0 6.3 1.7 2.7 1.7 4.25 5.15h17.8L48 24.5l-8.35 7.65-4.4-3.2-4.4 3.2-3.75-3h-2.55q-1.25 3-3.925 4.925Q17.95 36 14 36Zm0-3q2.9 0 5.35-1.925 2.45-1.925 3.15-4.925h5.7l2.7 2.25 4.4-3.15 4.1 3.1 4.25-3.95-2.55-2.55H22.5q-.6-2.8-3-4.825Q17.1 15 14 15q-3.75 0-6.375 2.625T5 24q0 3.75 2.625 6.375T14 33Z"/>
</svg>

After

Width:  |  Height:  |  Size: 670 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24 38q5.85 0 9.925-4.075Q38 29.85 38 24q0-5.85-4.075-9.925Q29.85 10 24 10v14l-9.55 10q1.85 1.95 4.35 2.975Q21.3 38 24 38Zm0 6q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 24q0-4.15 1.575-7.8 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24 4q4.15 0 7.8 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm0-3q7.1 0 12.05-4.975Q41 31.05 41 24q0-7.1-4.95-12.05Q31.1 7 24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24 41Zm0-17Z"/>
</svg>

After

Width:  |  Height:  |  Size: 793 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M120-280v-60h560v60H120Zm80-170v-60h560v60H200Zm80-170v-60h560v60H280Z"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24 29.25 18.75 24 24 18.75 29.25 24Zm-4.25-14.7L15.6 10.4 24 2l8.4 8.4-4.15 4.15L24 10.3ZM10.4 32.4 2 24l8.4-8.4 4.15 4.15L10.3 24l4.25 4.25Zm27.2 0-4.15-4.15L37.7 24l-4.25-4.25 4.15-4.15L46 24ZM24 46l-8.4-8.4 4.15-4.15L24 37.7l4.25-4.25 4.15 4.15Z"/>
</svg>

After

Width:  |  Height:  |  Size: 493 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M603-160h56v-83l102-24q21-5 43.5-11.5T827-299q0-8-8-14.5T792-326q-38-11-58-34t-18-49q2-21 19.5-37.5T785-474q28-10 41.5-22.5T840-526q0-20-17-30.5t-37-3.5q-6 2-12.5 3t-12.5 1q-26 0-43.5-20T700-625q0-26 13.5-47.5T727-720q0-17-14.5-28.5T677-760q-29 0-40.5 12.5T625-700q0 17 1.5 33t1.5 33q0 45-16 66t-50 21q-11 0-23-3t-23-3q-6 0-9.5 2.5T503-543q0 10 12 20t23 19q26 23 38 44t12 42q0 27-19.5 46T521-353q-11 0-21-2t-21-3q-28-2-43 5t-15 21q0 14 13 23t38 13l131 21v115Zm-450 40-73-33 200-440 73 33-200 440Zm370 40v-128l-57-8q-55-8-89.5-39.5T342-329q0-48 39.5-80.5T476-439q5 0 8.5.5t7.5 1.5q-8-8-15-14.5T464-465q-20-22-29-40.5t-9-37.5q0-38 21.5-62.5T504-630q7 0 19 .5t26 2.5q2-20 0-41t-2-41q0-63 34-97t97-34q56 0 93.5 32t36.5 78q0 23-8 45t-18 43q5-1 10.5-1.5t10.5-.5q48 0 82.5 34.5T920-525q0 43-30.5 77.5T818-402q7 2 13 4t12 5q29 14 47 39.5t18 55.5q0 38-33.5 66.5T779-188l-40 10v98H523ZM138-537q-29-29-43.5-65.5T80-679q0-84 58-142.5T280-880q40 0 76.5 15t65.5 44l-56 56q-17-17-39.5-26t-46.5-9q-50 0-85 35t-35 85q0 24 9 46.5t26 39.5l-57 57Zm493 128Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M8 46V35h5v-5.5H8v-11h5V13H8V2h13v11h-5v5.5h5v4h8v-4h13v11H29v-4h-8v4h-5V35h5v11Zm3-3h7v-5h-7Zm0-16.5h7v-5h-7Zm21 0h7v-5h-7ZM11 10h7V5h-7Zm3.5-2.5Zm0 16.5Zm21 0Zm-21 16.5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 415 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M7 37h9.35V11H7v26Zm12.35 0h9.3V11h-9.3v26Zm12.3 0H41V11h-9.35v26ZM7 40q-1.2 0-2.1-.9Q4 38.2 4 37V11q0-1.2.9-2.1Q5.8 8 7 8h34q1.2 0 2.1.9.9.9.9 2.1v26q0 1.2-.9 2.1-.9.9-2.1.9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 419 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M11.1 37.3 4 30.2l2.1-2.1 5 4.95 8.95-8.95 2.1 2.15Zm0-16L4 14.2l2.1-2.1 5 4.95 8.95-8.95 2.1 2.15ZM26 33.5v-3h18v3Zm0-16v-3h18v3Z"/>
</svg>

After

Width:  |  Height:  |  Size: 374 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M13 33h13v-3H13Zm19 0h3V15h-3Zm-19-7.5h13v-3H13Zm0-7.5h13v-3H13ZM6.6 42q-1.2 0-2.1-.9-.9-.9-.9-2.1V9q0-1.2.9-2.1.9-.9 2.1-.9h34.8q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h34.8V9H6.6v30Zm0 0V9v30Z"/>
</svg>

After

Width:  |  Height:  |  Size: 452 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24 44q-4.2 0-7.85-1.575Q12.5 40.85 9.8 38.15q-2.7-2.7-4.25-6.375Q4 28.1 4 23.9t1.55-7.825Q7.1 12.45 9.8 9.75t6.35-4.225Q19.8 4 24 4q1.15 0 2.275.125T28.5 4.5v10.4q-.7-2.25-1.85-4.275Q25.5 8.6 24 7q-1.6 1.35-2.7 3.55-1.1 2.2-2.1 5.95h9.3v3h-9.85q-.2 1.55-.25 2.475-.05.925-.05 1.925 0 1.05.05 2.025.05.975.25 2.525H29.4q.2-1.55.25-2.525.05-.975.05-2.025 0-1-.05-1.925T29.4 19.5h3.05q.15 1.75.2 2.675.05.925.05 1.725 0 1.1-.075 2.075-.075.975-.225 2.475h8q.35-1.2.475-2.225Q41 25.2 41 23.9q0-1.3-.125-2.25T40.4 19.5h3.15q.25 1.05.35 2.15.1 1.1.1 2.25 0 4.2-1.55 7.875T38.2 38.15q-2.7 2.7-6.35 4.275Q28.2 44 24 44ZM7.6 28.45h7.95q-.15-1.35-.175-2.425-.025-1.075-.025-2.125 0-1.25.05-2.225.05-.975.2-2.175h-8q-.35 1.2-.475 2.15T7 23.9q0 1.3.125 2.325.125 1.025.475 2.225ZM19.75 40.5q-1.25-1.9-2.15-4.1-.9-2.2-1.5-4.95H8.6Q10.5 35 13 37.025q2.5 2.025 6.75 3.475ZM8.6 16.5h7.55q.55-2.7 1.4-4.825.85-2.125 2.15-4.125-3.75.95-6.55 3.2T8.6 16.5ZM24 41.1q1.75-1.8 2.925-4.125Q28.1 34.65 28.85 31.45H19.2q.7 3 1.875 5.4Q22.25 39.25 24 41.1Zm4.3-.65q3.6-1.15 6.475-3.45 2.875-2.3 4.625-5.55h-7.45q-.65 2.7-1.525 4.9-.875 2.2-2.125 4.1ZM33 15V4h11v11Zm5-5h5V5h-5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M12.55 40q-4.4 0-7.475-3.075Q2 33.85 2 29.45q0-3.9 2.5-6.85 2.5-2.95 6.35-3.55 1-4.85 4.7-7.925T24.1 8.05q5.6 0 9.45 4.075Q37.4 16.2 37.4 21.9v1.2q3.6-.1 6.1 2.325Q46 27.85 46 31.55q0 3.45-2.5 5.95T37.55 40Zm0-3h25q2.25 0 3.85-1.6t1.6-3.85q0-2.25-1.6-3.85t-3.85-1.6H34.4v-4.2q0-4.55-3.05-7.7-3.05-3.15-7.45-3.15t-7.475 3.15q-3.075 3.15-3.075 7.7h-.95q-3.1 0-5.25 2.175T5 29.45q0 3.15 2.2 5.35Q9.4 37 12.55 37ZM24 24Z"/>
</svg>

After

Width:  |  Height:  |  Size: 661 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M24 44q-3.3 0-6.525-1.2-3.225-1.2-5.775-3.15-2.55-1.95-4.125-4.4Q6 32.8 6 30.25v-5l6.75 5.05-2.9 2.9q1.55 2.9 5.3 5.175T22.5 40.9V21.5H16v-3h6.5v-3.7q-1.9-.7-2.95-2.1-1.05-1.4-1.05-3.2 0-2.3 1.625-3.9T24 4q2.3 0 3.9 1.6t1.6 3.9q0 1.8-1.05 3.2-1.05 1.4-2.95 2.1v3.7H32v3h-6.5v19.4q3.6-.25 7.35-2.525 3.75-2.275 5.3-5.175l-2.9-2.9L42 25.25v5q0 2.55-1.575 5t-4.125 4.4q-2.55 1.95-5.775 3.15Q27.3 44 24 44Zm0-32q1.05 0 1.775-.75.725-.75.725-1.75 0-1.05-.725-1.775Q25.05 7 24 7q-1 0-1.75.725T21.5 9.5q0 1 .75 1.75T24 12Z"/>
</svg>

After

Width:  |  Height:  |  Size: 759 B

@@ -0,0 +1,165 @@
const baseUrl = process.env.SFERA_WEB_URL ?? "http://192.168.200.60:3000";
const projectId = process.env.SFERA_PROJECT_ID ?? "demo";
const routine = encodeURIComponent(process.env.SFERA_ROUTINE ?? "Проведение");
const attempts = Number(process.env.SFERA_SMOKE_ATTEMPTS ?? "5");
const checks = [
{
name: "root opens IDE workspace",
url: `${baseUrl}/?lang=ru&project=${projectId}`,
mustInclude: [
"SFERA",
"data-top-project-bar",
"data-top-bar-logo",
"data-top-bar-selector=\"workspace\"",
"data-top-bar-selector=\"project\"",
"data-top-bar-selector=\"environment\"",
"data-top-bar-selector=\"active-task\"",
"data-top-bar-action=\"project-settings\"",
"data-top-bar-action=\"create-project\"",
"data-top-bar-badge=\"api-status\"",
"data-top-bar-badge=\"agent-status\"",
"data-top-bar-language",
"data-top-bar-button=\"profile\"",
"Ctrl+K",
"data-status-bar",
"data-status-item=\"current-user\""
],
mustNotInclude: ["Открыть в редакторе"]
},
{
name: "root opens IDE workspace (en)",
url: `${baseUrl}/?lang=en&project=${projectId}`,
mustInclude: [
"SFERA",
"data-top-project-bar",
"data-top-bar-logo",
"data-top-bar-selector=\"workspace\"",
"data-top-bar-selector=\"project\"",
"data-top-bar-selector=\"environment\"",
"data-top-bar-selector=\"active-task\"",
"data-top-bar-action=\"project-settings\"",
"data-top-bar-action=\"create-project\"",
"data-top-bar-badge=\"api-status\"",
"data-top-bar-badge=\"agent-status\"",
"data-top-bar-language",
"data-top-bar-button=\"profile\"",
"Ctrl+K",
"data-status-bar",
"data-status-item=\"current-user\""
],
mustNotInclude: ["Open in editor"]
},
{
name: "project settings route",
url: `${baseUrl}/project-settings`,
mustInclude: [
"Project Settings",
"Import Center",
"REFERENCE_CONFIGURATION",
"Reference config",
"data-import-action=\"REFERENCE_CONFIGURATION:import\"",
"data-import-action=\"XML_DUMP:check\"",
"data-settings-section=\"docker-runtime-adapter\"",
"data-settings-section=\"its-documentation-access\"",
"Пользователи и доступ",
"Интеграции задач",
"Docker/runtime adapter",
"ITS/documentation access",
"Audit",
"Backup/restore",
"SFERA_ITS_URL",
"SFERA_ITS_USERNAME",
"SFERA_ITS_PASSWORD",
"https://its.1c.ru/db/v838doc#browse:13:-1:7",
".env.local",
"&lt;set locally&gt;"
],
mustNotInclude: ["Открыть в редакторе"]
},
{
name: "project settings route (en)",
url: `${baseUrl}/project-settings?lang=en`,
mustInclude: [
"Project Settings",
"Import Center",
"REFERENCE_CONFIGURATION",
"Reference config",
"data-import-action=\"REFERENCE_CONFIGURATION:import\"",
"data-import-action=\"XML_DUMP:check\"",
"data-settings-section=\"task-session-policy\"",
"data-settings-section=\"docker-runtime-adapter\"",
"data-settings-section=\"its-documentation-access\"",
"Task/session policy",
"Docker/runtime adapter",
"ITS/documentation access",
"Audit",
"Backup/restore",
"SFERA_ITS_URL",
"SFERA_ITS_USERNAME",
"SFERA_ITS_PASSWORD",
".env.local",
"&lt;set locally&gt;"
],
mustNotInclude: ["Open in editor"]
},
{
name: "module mode",
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=module&routine=${routine}`,
mustInclude: ["data-ide-workspace", "data-left-navigation-panel", "data-right-context-inspector", "data-open-objects-bar", "data-open-document-pin", "data-open-document-close", "data-fallback-tree-search", "data-fallback-tree-filters", "Alt+1 Alt+2 Alt+3", "Редактор BSL", "Код модуля не загружен", "Выберите реальный модуль", "Основная конфигурация", "Расширение: &lt;Имя&gt;", "SFERA", "Среды"]
},
{
name: "form mode",
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=form&routine=${routine}`,
mustInclude: ["Дизайнер формы", "Провести и закрыть", "Товары"]
},
{
name: "events mode",
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=events&routine=${routine}`,
mustInclude: ["Инспектор событий", "ПриСозданииНаСервере", "ПередЗаписью"]
},
{
name: "learning mode",
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=learning&routine=${routine}`,
mustInclude: ["Обучение", "переменные доступны", "стандарты команды"]
}
];
for (const check of checks) {
let lastError;
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
await runCheck(check);
console.log(`ok ${check.name}`);
lastError = undefined;
break;
} catch (error) {
lastError = error;
if (attempt < attempts) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
}
if (lastError) {
throw lastError;
}
}
async function runCheck(check) {
const response = await fetch(check.url, { headers: { Accept: "text/html" } });
if (!response.ok) {
throw new Error(`${check.name}: ${response.status} ${response.statusText}`);
}
const html = await response.text();
for (const expected of check.mustInclude ?? []) {
if (!html.includes(expected)) {
throw new Error(`${check.name}: missing "${expected}"`);
}
}
for (const forbidden of check.mustNotInclude ?? []) {
if (html.includes(forbidden)) {
throw new Error(`${check.name}: unexpected "${forbidden}"`);
}
}
}
@@ -0,0 +1,292 @@
import { chromium } from "playwright-core";
import { existsSync } from "node:fs";
const baseUrl = process.env.SFERA_WEB_URL ?? "http://192.168.200.60:3000";
const projectId = process.env.SFERA_PROJECT_ID ?? "demo";
const uniqueSuffix = Date.now().toString(36);
const browserPath =
process.env.SFERA_BROWSER_PATH ??
[
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"
].find((path) => existsSync(path));
if (!browserPath) {
throw new Error("No installed Chrome or Edge browser found. Set SFERA_BROWSER_PATH.");
}
const runtimeErrors = [];
const browser = await chromium.launch({
executablePath: browserPath,
headless: true
});
function assertNoFatalRuntimeErrors(stage) {
const fatalErrors = runtimeErrors.filter((message) => {
return (
message.includes("Runtime TypeError") ||
message.includes("Cannot read properties") ||
message.includes("Unhandled Runtime Error")
);
});
if (fatalErrors.length > 0) {
throw new Error(`${stage} failed:\n${fatalErrors.join("\n")}`);
}
}
async function collapseBottomPanelIfOpen(page) {
if ((await page.locator("[data-bottom-tool-panel]").count()) > 0) {
await page.keyboard.press("Alt+3");
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 });
}
}
try {
const page = await browser.newPage();
await page.setViewportSize({ width: 1680, height: 1050 });
page.on("pageerror", (error) => {
runtimeErrors.push(`pageerror: ${error.message}`);
});
page.on("console", (message) => {
if (message.type() === "error") {
runtimeErrors.push(`console: ${message.text()}`);
}
});
const response = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=module`, {
waitUntil: "load",
timeout: 60000
});
if (!response?.ok()) {
throw new Error(`editor runtime smoke: ${response?.status()} ${response?.statusText()}`);
}
await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 });
await page.getByRole("heading", { name: "Семантический diff" }).waitFor({ state: "visible", timeout: 15000 });
for (const marker of ["snapshot", "agent", "parser", "diagnostics", "active-task", "privacy", "ai-tokens", "current-user"]) {
await page.locator(`[data-status-item="${marker}"]`).waitFor({ state: "visible", timeout: 15000 });
}
await page.locator("[data-global-search-input]").waitFor({ state: "visible", timeout: 15000 });
await page.keyboard.press("Control+K");
const globalSearchFocused = await page.locator("[data-global-search-input]").evaluate((input) => document.activeElement === input);
if (!globalSearchFocused) {
throw new Error("Ctrl+K did not focus global search");
}
await page.evaluate(() => {
window.dispatchEvent(new KeyboardEvent("keydown", { key: "F5", bubbles: true, cancelable: true }));
});
await page.locator("[data-run-check-status]").waitFor({ state: "visible", timeout: 15000 });
await page.locator("[data-left-navigation-panel]").waitFor({ state: "visible", timeout: 15000 });
const hasVirtualScrollContainer =
(await page.locator("[data-virtual-scroll]").count()) > 0 ||
(await page.locator("[data-fallback-tree-scroll]").count()) > 0;
if (!hasVirtualScrollContainer) {
throw new Error("Left navigation panel has no virtual/fallback scroll container marker");
}
await page.locator("[data-right-context-inspector]").waitFor({ state: "visible", timeout: 15000 });
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 });
for (const tabName of ["Проблемы", "Semantic diff", "Вывод", "История", "Тесты", "AI"]) {
await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 });
}
await page.locator("[data-fallback-tree-search-input]").fill("SFERA");
await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 });
await page.locator("[data-fallback-tree-search-input]").fill("");
await page.locator("[data-fallback-tree-filter='sfera']").click();
await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 });
await page.locator("[data-fallback-tree-filter='all']").click();
const lazyFilterCount = await page.locator("[data-lazy-tree-filter]").count();
if (lazyFilterCount > 0) {
await page.locator("[data-lazy-tree-filter='sfera']").click();
await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 });
await page.locator("[data-lazy-tree-filter='all']").click();
}
await page.keyboard.press("Alt+1");
await page.locator("[data-left-navigation-panel]").waitFor({ state: "detached", timeout: 15000 });
await page.locator("[data-panel-rail]").first().click();
await page.locator("[data-left-navigation-panel]").waitFor({ state: "visible", timeout: 15000 });
await page.keyboard.press("Alt+2");
await page.locator("[data-right-context-inspector]").waitFor({ state: "detached", timeout: 15000 });
await page.locator("[data-panel-rail]").last().click();
await page.locator("[data-right-context-inspector]").waitFor({ state: "visible", timeout: 15000 });
await page.keyboard.press("Alt+3");
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 });
await page.getByRole("button", { name: "Нижняя панель" }).click();
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 });
await page.keyboard.press("Alt+3");
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 });
const activeDocumentBeforeNext = await page.locator('[data-open-document][aria-pressed="true"]').first().getAttribute("data-open-document");
const openDocumentCount = await page.locator("[data-open-document]").count();
if (openDocumentCount < 2) {
throw new Error("Open Objects Bar has fewer than two switchable objects");
}
await page.evaluate(() => {
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", ctrlKey: true, bubbles: true, cancelable: true }));
});
const activeDocumentAfterNext = await page.locator('[data-open-document][aria-pressed="true"]').first().getAttribute("data-open-document");
if (!activeDocumentAfterNext || activeDocumentAfterNext === activeDocumentBeforeNext) {
throw new Error("Ctrl+Tab did not switch the active open object");
}
await page.evaluate(() => {
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", ctrlKey: true, shiftKey: true, bubbles: true, cancelable: true }));
});
await page.locator(`[data-open-document="${activeDocumentBeforeNext}"][aria-pressed="true"]`).waitFor({ state: "visible", timeout: 15000 });
await page.locator(`[data-open-document-pin="${activeDocumentAfterNext}"]`).click();
const pinnedCloseButton = page.locator(`[data-open-document-close="${activeDocumentAfterNext}"]`);
if (!(await pinnedCloseButton.isDisabled())) {
throw new Error("Pinned open object close button is not disabled");
}
await page.locator(`[data-open-document-pin="${activeDocumentAfterNext}"]`).click();
await pinnedCloseButton.click();
await page.locator(`[data-open-document="${activeDocumentAfterNext}"]`).waitFor({ state: "detached", timeout: 15000 });
const ctrlWCandidate = await page.evaluate(() => {
const buttons = Array.from(document.querySelectorAll<HTMLElement>("[data-open-document]"));
const candidate = buttons.find((button) => button.getAttribute("data-open-document-mode") !== "module");
return candidate?.getAttribute("data-open-document") ?? null;
});
if (ctrlWCandidate) {
const targetTab = page.locator(`[data-open-document="${ctrlWCandidate}"]`);
await targetTab.click();
await page.evaluate(() => {
window.dispatchEvent(new KeyboardEvent("keydown", { key: "w", ctrlKey: true, bubbles: true, cancelable: true }));
});
await targetTab.waitFor({ state: "detached", timeout: 15000 });
const moduleTabs = page.locator('[data-open-document-mode="module"]');
const moduleTabCount = await moduleTabs.count();
if (moduleTabCount > 0) {
await moduleTabs.first().click();
}
}
const openObjectsState = await page.evaluate((storageKey) => window.localStorage.getItem(storageKey), `sfera.open-objects.${projectId}`);
if (!openObjectsState?.includes(activeDocumentAfterNext)) {
throw new Error("Open Objects Bar state was not persisted");
}
await page.reload({ waitUntil: "load", timeout: 60000 });
await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 });
const restoredState = await page.evaluate((storageKey) => window.localStorage.getItem(storageKey), `sfera.open-objects.${projectId}`);
if (restoredState !== openObjectsState) {
throw new Error("Open Objects Bar state was not restored after reload");
}
await page.locator(`[data-open-document="${activeDocumentAfterNext}"]`).waitFor({ state: "detached", timeout: 15000 });
const restoredModuleTabs = page.locator('[data-open-document-mode="module"]');
if ((await restoredModuleTabs.count()) > 0) {
await restoredModuleTabs.first().click();
}
await page.locator(".monaco-editor").waitFor({ state: "visible", timeout: 15000 });
await page.locator("#symbol-search-input").fill("Проверить");
await page.locator("#symbol-search-input").press("Enter");
await page.locator("[data-symbol-result]").first().waitFor({ state: "visible", timeout: 15000 });
await page.locator('button[data-editor-action="find-usages"]').click();
await page.locator("[data-symbol-references]").waitFor({ state: "visible", timeout: 15000 });
const applyButton = page.locator('button[data-editor-action="apply-to-sfera"]');
await applyButton.waitFor({ state: "visible", timeout: 15000 });
if (await applyButton.isEnabled()) {
await applyButton.click();
await page.getByText("Записано в SFERA").waitFor({ state: "visible", timeout: 15000 });
}
assertNoFatalRuntimeErrors("editor module runtime smoke");
const versionsResponse = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=versions`, {
waitUntil: "load",
timeout: 60000
});
if (!versionsResponse?.ok()) {
throw new Error(`editor versions runtime smoke: ${versionsResponse?.status()} ${versionsResponse?.statusText()}`);
}
await page.getByRole("heading", { name: "Версии" }).waitFor({ state: "visible", timeout: 15000 });
await collapseBottomPanelIfOpen(page);
await page.getByText("Линия версий").first().waitFor({ state: "visible", timeout: 15000 });
const versionButtons = page.locator("button[data-version-id]");
const versionButtonCount = await versionButtons.count();
if (versionButtonCount > 0) {
await versionButtons.first().click();
await page.getByText("Полные данные").waitFor({ state: "visible", timeout: 15000 });
}
assertNoFatalRuntimeErrors("editor versions runtime smoke");
const rollbackButtons = page.locator('button[data-editor-action="rollback-plan"]');
const rollbackButtonCount = await rollbackButtons.count();
if (rollbackButtonCount > 0) {
await rollbackButtons.first().click();
await page.locator("[data-rollback-preview]").waitFor({ state: "visible", timeout: 15000 });
const applyRollbackButton = page.locator('button[data-editor-action="apply-rollback"]');
await applyRollbackButton.waitFor({ state: "visible", timeout: 15000 });
if (await applyRollbackButton.isEnabled()) {
await applyRollbackButton.click();
await page.locator("[data-rollback-apply-message]").waitFor({ state: "visible", timeout: 15000 });
}
}
assertNoFatalRuntimeErrors("editor rollback runtime smoke");
const metadataResponse = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=properties`, {
waitUntil: "load",
timeout: 60000
});
if (!metadataResponse?.ok()) {
throw new Error(`editor metadata runtime smoke: ${metadataResponse?.status()} ${metadataResponse?.statusText()}`);
}
await page.getByRole("heading", { name: "Свойства" }).waitFor({ state: "visible", timeout: 15000 });
await collapseBottomPanelIfOpen(page);
await page.getByLabel("Имя объекта").fill(`АвтоОбъект${uniqueSuffix}`);
await page.getByLabel("Синоним").fill(`Авто объект ${uniqueSuffix}`);
const addAttributeButton = page.locator('button[data-editor-action="add-metadata-attribute"]');
await addAttributeButton.waitFor({ state: "visible", timeout: 15000 });
await addAttributeButton.click();
await page.getByRole("textbox", { name: "Имя реквизита" }).nth(1).fill("Комментарий");
await page.getByRole("textbox", { name: "Тип" }).nth(1).fill("Строка250");
const addFormButton = page.locator('button[data-editor-action="add-metadata-form"]');
await addFormButton.waitFor({ state: "visible", timeout: 15000 });
await addFormButton.click();
await page.getByRole("textbox", { name: "Имя формы" }).last().fill(`ФормаВыбора${uniqueSuffix}`);
const addCommandButton = page.locator('button[data-editor-action="add-metadata-command"]');
await addCommandButton.waitFor({ state: "visible", timeout: 15000 });
await addCommandButton.click();
await page.getByRole("textbox", { name: "Имя команды" }).last().fill(`Отправить${uniqueSuffix}`);
await page.getByRole("textbox", { name: "Обработчик" }).last().fill(`Отправить${uniqueSuffix}Команда`);
const metadataButton = page.locator('button[data-editor-action="apply-metadata-object"]');
await metadataButton.waitFor({ state: "visible", timeout: 15000 });
if (await metadataButton.isEnabled()) {
await metadataButton.click();
const draftMessage = page.locator("[data-metadata-draft-message]");
await draftMessage.waitFor({ state: "visible", timeout: 15000 });
try {
await page.locator("[data-metadata-draft-preview]").waitFor({ state: "visible", timeout: 15000 });
} catch (error) {
throw new Error(`metadata draft preview did not appear: ${await draftMessage.textContent()}`);
}
}
assertNoFatalRuntimeErrors("editor metadata runtime smoke");
const englishResponse = await page.goto(`${baseUrl}/editor?lang=en&project=${encodeURIComponent(projectId)}&mode=module`, {
waitUntil: "load",
timeout: 60000
});
if (!englishResponse?.ok()) {
throw new Error(`editor english runtime smoke: ${englishResponse?.status()} ${englishResponse?.statusText()}`);
}
await page.getByRole("heading", { name: "BSL Editor" }).waitFor({ state: "visible", timeout: 15000 });
await page.locator("[data-top-project-bar]").waitFor({ state: "visible", timeout: 15000 });
for (const selector of ["workspace", "project", "environment", "active-task"]) {
await page.locator(`[data-top-bar-selector="${selector}"]`).waitFor({ state: "visible", timeout: 15000 });
}
for (const action of ["project-settings", "create-project"]) {
await page.locator(`[data-top-bar-action="${action}"]`).waitFor({ state: "visible", timeout: 15000 });
}
for (const badge of ["api-status", "agent-status"]) {
await page.locator(`[data-top-bar-badge="${badge}"]`).waitFor({ state: "visible", timeout: 15000 });
}
await page.locator("[data-top-bar-language]").waitFor({ state: "visible", timeout: 15000 });
await page.locator('[data-top-bar-button="profile"]').waitFor({ state: "visible", timeout: 15000 });
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 });
for (const tabName of ["Problems", "Semantic diff", "Output", "Change history", "Tests", "AI"]) {
await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 });
}
for (const statusMarker of ["snapshot", "agent", "parser", "diagnostics", "active-task", "privacy", "ai-tokens", "current-user"]) {
await page.locator(`[data-status-item="${statusMarker}"]`).waitFor({ state: "visible", timeout: 15000 });
}
assertNoFatalRuntimeErrors("editor english runtime smoke");
console.log("ok editor runtime");
} finally {
await browser.close();
}
@@ -0,0 +1,152 @@
import { chromium } from "playwright-core";
import { existsSync } from "node:fs";
const baseUrl = process.env.SFERA_WEB_URL ?? "http://localhost:3000";
const projectId = process.env.SFERA_PROJECT_ID ?? "default";
const browserPath =
process.env.SFERA_BROWSER_PATH ??
[
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"
].find((path) => existsSync(path));
if (!browserPath) {
throw new Error("No installed Chrome or Edge browser found. Set SFERA_BROWSER_PATH.");
}
await prepareIndexedProject();
const runtimeErrors = [];
const browser = await chromium.launch({
executablePath: browserPath,
headless: true
});
try {
const page = await browser.newPage();
page.on("pageerror", (error) => {
runtimeErrors.push(`pageerror: ${error.message}`);
});
page.on("console", (message) => {
if (message.type() === "error") {
runtimeErrors.push(`console: ${message.text()}`);
}
});
const response = await page.goto(`${baseUrl}/project-settings`, { waitUntil: "load", timeout: 60000 });
if (!response?.ok()) {
throw new Error(`project setup smoke: ${response?.status()} ${response?.statusText()}`);
}
await page.locator("[data-project-import-center]").waitFor({ state: "visible", timeout: 15000 });
await page.getByRole("heading", { name: "Project Settings" }).waitFor({ state: "visible", timeout: 15000 });
for (const section of ["Пользователи и доступ", "Интеграции задач", "Docker/runtime adapter", "Audit", "Backup/restore"]) {
await page.getByText(section).first().waitFor({ state: "visible", timeout: 15000 });
}
for (const sectionMarker of ["docker-runtime-adapter", "its-documentation-access"]) {
await page.locator(`[data-settings-section="${sectionMarker}"]`).waitFor({ state: "visible", timeout: 15000 });
}
await page.getByText("ITS/documentation access").first().waitFor({ state: "visible", timeout: 15000 });
await page.getByText("SFERA_ITS_URL").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("SFERA_ITS_USERNAME").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("SFERA_ITS_PASSWORD").waitFor({ state: "visible", timeout: 15000 });
await page.locator("input[value*='its.1c.ru/db/v838doc']").first().waitFor({ state: "visible", timeout: 15000 });
await page.getByText(".env.local").first().waitFor({ state: "visible", timeout: 15000 });
await page.locator("input[value='<set locally>']").first().waitFor({ state: "visible", timeout: 15000 });
await page.locator("select").filter({ hasText: "REFERENCE_CONFIGURATION" }).first().waitFor({ state: "visible", timeout: 15000 });
await page.getByRole("button", { name: /Reference config/ }).waitFor({ state: "visible", timeout: 15000 });
const hasMetadataOnlyPrivacy = await page.locator("select").evaluateAll((selects) => {
return selects.some((select) => select.value === "METADATA_ONLY" || [...select.options].some((option) => option.value === "METADATA_ONLY"));
});
if (!hasMetadataOnlyPrivacy) {
throw new Error("project setup smoke: missing METADATA_ONLY privacy mode");
}
await page.getByText("Project Setup / Import Center").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("Режим работы с конфигурацией 1С").waitFor({ state: "visible", timeout: 15000 });
await page.locator('[data-import-mode="FULL_REPLACE"]').waitFor({ state: "visible", timeout: 15000 });
await page.locator('[data-run-import-mode="SYNC_PREVIEW"]').click();
const importMode = await page.evaluate(() => window.localStorage.getItem("sfera.import.mode"));
if (importMode !== "SYNC_PREVIEW") {
throw new Error(`project setup smoke: import mode was not persisted, got ${importMode}`);
}
await page.locator('[data-run-import-mode="FULL_REPLACE"]').click();
await page.locator("[data-import-validation-panel]").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("Не заполнен путь к источнику").waitFor({ state: "visible", timeout: 15000 });
await page.locator('input[placeholder*="/mnt/share/project"]').fill("/tmp/nonexistent-smoke-import");
await page.locator('[data-run-import-mode="FULL_REPLACE"]').click();
await page.getByText("Подтвердите полное обновление").waitFor({ state: "visible", timeout: 15000 });
await page.getByRole("button", { name: "Отмена" }).click();
await page.locator('[data-run-import-mode="SYNC_PREVIEW"]').click();
await page.locator('[data-import-action="XML_DUMP:check"]').click();
await page.locator("[data-import-check-panel]").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("Source preflight").waitFor({ state: "visible", timeout: 15000 });
const englishResponse = await page.goto(`${baseUrl}/project-settings?lang=en`, { waitUntil: "load", timeout: 60000 });
if (!englishResponse?.ok()) {
throw new Error(`project setup smoke (en): ${englishResponse?.status()} ${englishResponse?.statusText()}`);
}
await page.getByRole("heading", { name: "Project Settings" }).waitFor({ state: "visible", timeout: 15000 });
for (const section of ["Task/session policy", "Docker/runtime adapter", "ITS/documentation access", "Audit", "Backup/restore"]) {
await page.getByText(section).first().waitFor({ state: "visible", timeout: 15000 });
}
for (const sectionMarker of ["task-session-policy", "docker-runtime-adapter", "its-documentation-access"]) {
await page.locator(`[data-settings-section="${sectionMarker}"]`).waitFor({ state: "visible", timeout: 15000 });
}
await page.locator("select").filter({ hasText: "REFERENCE_CONFIGURATION" }).first().waitFor({ state: "visible", timeout: 15000 });
await page.getByRole("button", { name: /Reference config/ }).waitFor({ state: "visible", timeout: 15000 });
await page.getByText("SFERA_ITS_URL").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("SFERA_ITS_USERNAME").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("SFERA_ITS_PASSWORD").waitFor({ state: "visible", timeout: 15000 });
await page.getByText(".env.local").first().waitFor({ state: "visible", timeout: 15000 });
await page.locator("input[value='<set locally>']").first().waitFor({ state: "visible", timeout: 15000 });
await page.locator('[data-import-action="XML_DUMP:check"]').click();
await page.locator("[data-import-check-panel]").waitFor({ state: "visible", timeout: 15000 });
await page.getByText("Source preflight").waitFor({ state: "visible", timeout: 15000 });
assertNoFatalRuntimeErrors();
console.log("ok project setup runtime");
} finally {
await browser.close();
}
async function prepareIndexedProject() {
await postJson(`/api/sfera/projects/${encodeURIComponent(projectId)}/settings`, {
name: "SFERA Smoke Project",
structure_source: "XML_DUMP",
platform_version: "8.3.24",
compatibility_mode: "8.3.20"
});
await postJson(`/api/sfera/projects/${encodeURIComponent(projectId)}/imports/XML_DUMP`, {
source: "XML_DUMP",
metadata: {
platform_version: "8.3.24",
compatibility_mode: "8.3.20"
}
});
}
async function postJson(path, body) {
const response = await fetch(`${baseUrl}${path}`, {
method: "POST",
headers: { Accept: "application/json", "Content-Type": "application/json" },
body: JSON.stringify(body)
});
if (!response.ok) {
throw new Error(`${path}: ${response.status} ${await response.text()}`);
}
return response.json();
}
function assertNoFatalRuntimeErrors() {
const fatalErrors = runtimeErrors.filter((message) => {
return (
message.includes("Runtime TypeError") ||
message.includes("Cannot read properties") ||
message.includes("Unhandled Runtime Error")
);
});
if (fatalErrors.length > 0) {
throw new Error(`project setup runtime smoke failed:\n${fatalErrors.join("\n")}`);
}
}
@@ -0,0 +1,79 @@
import { resolveApiUrl } from "@/lib/api";
type RouteContext = {
params: Promise<{ path: string[] }>;
};
export async function GET(request: Request, context: RouteContext) {
return proxy(request, context);
}
export async function POST(request: Request, context: RouteContext) {
return proxy(request, context);
}
export async function PUT(request: Request, context: RouteContext) {
return proxy(request, context);
}
export async function PATCH(request: Request, context: RouteContext) {
return proxy(request, context);
}
export async function DELETE(request: Request, context: RouteContext) {
return proxy(request, context);
}
export async function OPTIONS(request: Request, context: RouteContext) {
return proxy(request, context);
}
export async function HEAD(request: Request, context: RouteContext) {
return proxy(request, context);
}
async function proxy(request: Request, context: RouteContext) {
const { path } = await context.params;
const apiUrl = resolveApiUrl(request.headers.get("host"));
const sourceUrl = new URL(request.url);
const target = `${apiUrl}/${path.join("/")}${sourceUrl.search}`;
const method = request.method;
const hasBody = method !== "GET" && method !== "HEAD" && request.body !== null;
const body = hasBody ? await request.arrayBuffer() : undefined;
const contentType = request.headers.get("Content-Type");
const accept = request.headers.get("Accept") ?? "application/json";
const publicHost = request.headers.get("x-forwarded-host") ?? request.headers.get("host");
const publicProto = request.headers.get("x-forwarded-proto") ?? "http";
const publicOrigin = publicHost ? `${publicProto}://${publicHost}` : sourceUrl.origin;
const headers: Record<string, string> = {
Accept: accept,
"X-Sfera-Public-Origin": publicOrigin
};
if (hasBody) {
headers["Content-Type"] = contentType ?? "application/json";
}
const response = await fetch(target, {
method,
cache: "no-store",
headers,
body
});
const responseHeaders: Record<string, string> = {
"Content-Type": response.headers.get("Content-Type") ?? "application/json"
};
const contentDisposition = response.headers.get("Content-Disposition");
if (contentDisposition) {
responseHeaders["Content-Disposition"] = contentDisposition;
}
const cacheControl = response.headers.get("Cache-Control");
if (cacheControl) {
responseHeaders["Cache-Control"] = cacheControl;
}
return new Response(response.body, {
status: response.status,
headers: responseHeaders
});
}
+113
View File
@@ -0,0 +1,113 @@
import { AlertTriangle } from "lucide-react";
import { headers } from "next/headers";
import { IdeWorkspace } from "@/components/editor/ide-workspace";
import { AppShell } from "@/components/layout/app-shell";
import { Card } from "@/components/ui/card";
import {
getApiHealth,
getProjects,
getProjectWorkspaceData,
resolveApiUrl,
type ProjectSummary
} from "@/lib/api";
import { messages, normalizeLanguage, type UiLanguage } from "@/lib/i18n";
export default async function EditorPage({
searchParams
}: Readonly<{
searchParams?: Promise<{ lang?: string; mode?: string; project?: string; routine?: string }>;
}>) {
const params = await searchParams;
const language = normalizeLanguage(params?.lang);
const requestHeaders = await headers();
const apiUrl = resolveApiUrl(requestHeaders.get("host"));
const bootstrap = await loadEditorBootstrap(apiUrl, language, params?.project);
const projectData =
bootstrap.status === "ok" && bootstrap.projectId ? await getProjectWorkspaceData(bootstrap.projectId, apiUrl, params?.routine, params?.mode) : null;
return (
<AppShell
apiStatus={bootstrap.status}
language={language}
projectId={bootstrap.status === "ok" ? bootstrap.projectId : undefined}
projectOptions={bootstrap.status === "ok" ? bootstrap.projects : []}
>
<main className="pb-8">
{bootstrap.status === "error" ? (
<ErrorState language={language} message={bootstrap.error} />
) : projectData ? (
<IdeWorkspace
key={projectData.projectId}
data={projectData}
initialMode={params?.mode}
language={language}
routineName={params?.routine}
/>
) : (
<ErrorState language={language} message={messages[language].noProjectDataDescription} />
)}
</main>
</AppShell>
);
}
async function loadEditorBootstrap(apiUrl: string, language: UiLanguage, projectId?: string): Promise<
| { status: "ok"; projectId: string | undefined; projects: ProjectSummary[] }
| { status: "error"; error: string }
> {
try {
const [projectsResponse] = await Promise.all([getProjects(apiUrl), getApiHealth(apiUrl)]);
const projects = uniqueProjects(projectsResponse);
return { status: "ok", projectId: projectId || pickDefaultProject(projectsResponse), projects };
} catch (error) {
return {
status: "error",
error: error instanceof Error ? error.message : messages[language].unknownApiError
};
}
}
function ErrorState({
message,
language
}: Readonly<{
message: string;
language: UiLanguage;
}>) {
const t = messages[language];
return (
<div className="mx-auto flex min-h-[70vh] max-w-xl items-center justify-center">
<Card className="w-full">
<div className="flex items-start gap-3">
<AlertTriangle className="mt-1 h-5 w-5 text-destructive" aria-hidden="true" />
<div>
<h1 className="text-base font-semibold">{t.apiUnavailable}</h1>
<p className="mt-2 text-sm leading-6 text-muted-foreground">{message}</p>
</div>
</div>
</Card>
</div>
);
}
function pickDefaultProject(projects: ProjectSummary[]) {
return (
projects.find((project) => project.project_id === "ifcm-upo")?.project_id ??
projects.find((project) => project.project_id !== "demo")?.project_id ??
projects.at(-1)?.project_id ??
projects.find((project) => project.project_id === "demo")?.project_id
);
}
function uniqueProjects(projects: ProjectSummary[]) {
const byId = new Map<string, ProjectSummary>();
for (const project of projects) {
const projectId = project.project_id.trim();
if (projectId) {
byId.set(projectId, { ...project, project_id: projectId, name: project.name || projectId });
}
}
return Array.from(byId.values()).sort((left, right) => (left.name || left.project_id).localeCompare(right.name || right.project_id, "ru"));
}
+70
View File
@@ -0,0 +1,70 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: 210 20% 98%;
--foreground: 222 47% 11%;
--card: 0 0% 100%;
--card-foreground: 222 47% 11%;
--muted: 210 17% 94%;
--muted-foreground: 215 16% 47%;
--border: 214 20% 88%;
--input: 214 20% 88%;
--primary: 198 93% 32%;
--primary-foreground: 0 0% 100%;
--secondary: 168 42% 39%;
--secondary-foreground: 0 0% 100%;
--destructive: 0 72% 45%;
--warning: 38 92% 48%;
--success: 142 54% 36%;
--info: 214 84% 56%;
}
.dark {
--background: 220 24% 10%;
--foreground: 210 20% 96%;
--card: 220 20% 14%;
--card-foreground: 210 20% 96%;
--muted: 220 16% 20%;
--muted-foreground: 215 15% 66%;
--border: 220 16% 24%;
--input: 220 16% 24%;
--primary: 194 80% 46%;
--primary-foreground: 0 0% 100%;
--secondary: 164 52% 43%;
--secondary-foreground: 0 0% 100%;
--destructive: 0 72% 51%;
--warning: 38 92% 52%;
--success: 142 54% 42%;
--info: 214 84% 62%;
}
* {
box-sizing: border-box;
}
html {
background: hsl(var(--background));
}
body {
min-height: 100vh;
margin: 0;
background: hsl(var(--background));
color: hsl(var(--foreground));
font-family:
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
letter-spacing: 0;
}
button,
input,
select,
textarea {
font: inherit;
}
::selection {
background: hsl(var(--primary) / 0.18);
}
@@ -0,0 +1,3 @@
export async function GET() {
return Response.json({ status: "ok", service: "sfera-web" });
}
+16
View File
@@ -0,0 +1,16 @@
import type { Metadata } from "next";
import type React from "react";
import "./globals.css";
export const metadata: Metadata = {
title: "SFERA",
description: "Semantic 1C operating workspace"
};
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="ru">
<body>{children}</body>
</html>
);
}
+22
View File
@@ -0,0 +1,22 @@
import { redirect } from "next/navigation";
export default async function HomePage({
searchParams
}: Readonly<{
searchParams?: Promise<{ lang?: string; mode?: string; project?: string; routine?: string }>;
}>) {
const params = await searchParams;
const nextParams = new URLSearchParams();
if (params?.lang === "en") {
nextParams.set("lang", "en");
}
for (const key of ["project", "mode", "routine"] as const) {
const value = params?.[key];
if (value) {
nextParams.set(key, value);
}
}
const suffix = nextParams.size > 0 ? `?${nextParams.toString()}` : "";
redirect(`/editor${suffix}`);
}

Some files were not shown because too many files have changed in this diff Show More