Merge branch 'dev-web'

This commit is contained in:
Nick Shirokov
2026-02-22 18:53:06 +03:00
12 changed files with 1426 additions and 1 deletions
+62
View File
@@ -0,0 +1,62 @@
---
name: web-info
description: Статус Apache и веб-публикаций 1С — запущен ли сервер, какие базы опубликованы, ошибки. Используй когда пользователь спрашивает про статус веб-сервера, опубликованные базы, работает ли Apache
argument-hint: ""
allowed-tools:
- Bash
- Read
- Glob
---
# /web-info — Статус Apache и публикаций 1С
Показывает состояние Apache HTTP Server, список опубликованных баз и последние ошибки.
## Usage
```
/web-info
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
По умолчанию `tools/apache24` от корня проекта.
## Команда
```powershell
powershell.exe -NoProfile -File .claude/skills/web-info/scripts/web-info.ps1 <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
## Формат вывода
```
=== Apache Web Server ===
Status: Запущен (PID: 12345)
Path: C:\...\tools\apache24
Port: 8081
Module: C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll
=== Опубликованные базы ===
mydb http://localhost:8081/mydb File="C:\Bases\MyDB";
=== Последние ошибки ===
(пусто)
```
## Примеры
```powershell
# Статус по умолчанию
powershell.exe -NoProfile -File .claude/skills/web-info/scripts/web-info.ps1
# Указать путь к Apache
powershell.exe -NoProfile -File .claude/skills/web-info/scripts/web-info.ps1 -ApachePath "C:\tools\apache24"
```
@@ -0,0 +1,148 @@
# web-info v1.0 — Apache & 1C publication status
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
<#
.SYNOPSIS
Статус Apache и публикаций 1С
.DESCRIPTION
Показывает состояние Apache HTTP Server, список опубликованных баз
и последние ошибки из error.log.
.PARAMETER ApachePath
Корень Apache (по умолчанию tools\apache24)
.EXAMPLE
.\web-info.ps1
.EXAMPLE
.\web-info.ps1 -ApachePath "C:\tools\apache24"
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$ApachePath
)
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# --- Resolve ApachePath ---
if (-not $ApachePath) {
$projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
$ApachePath = Join-Path $projectRoot "tools\apache24"
}
# --- Check Apache installation ---
$httpdExe = Join-Path (Join-Path $ApachePath "bin") "httpd.exe"
Write-Host "=== Apache Web Server ===" -ForegroundColor Cyan
if (-not (Test-Path $httpdExe)) {
Write-Host "Status: Не установлен" -ForegroundColor Red
Write-Host "Path: $ApachePath (не найден)"
Write-Host ""
Write-Host "Используйте /web-publish для установки Apache." -ForegroundColor Yellow
exit 0
}
# --- Check process (only our Apache) ---
$httpdExeNorm = (Resolve-Path $httpdExe -ErrorAction SilentlyContinue).Path
$ourProc = Get-Process httpd -ErrorAction SilentlyContinue | Where-Object {
try { $_.Path -eq $httpdExeNorm } catch { $false }
}
$foreignProc = Get-Process httpd -ErrorAction SilentlyContinue | Where-Object {
try { $_.Path -ne $httpdExeNorm } catch { $true }
}
if ($ourProc) {
$pids = ($ourProc | ForEach-Object { $_.Id }) -join ", "
Write-Host "Status: Запущен (PID: $pids)" -ForegroundColor Green
} else {
Write-Host "Status: Остановлен" -ForegroundColor Yellow
}
if ($foreignProc) {
$fpid = ($foreignProc | Select-Object -First 1).Id
$fpath = try { ($foreignProc | Select-Object -First 1).Path } catch { "?" }
Write-Host "[WARN] Обнаружен сторонний Apache (PID: $fpid, $fpath)" -ForegroundColor Yellow
}
Write-Host "Path: $ApachePath"
# --- Parse httpd.conf ---
$confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
if (-not (Test-Path $confFile)) {
Write-Host "Config: httpd.conf не найден" -ForegroundColor Red
exit 0
}
$confContent = [System.IO.File]::ReadAllText($confFile)
# Extract port from global block
$port = ""
if ($confContent -match '(?m)^Listen\s+(\d+)') {
$port = $Matches[1]
}
Write-Host "Port: $port"
# Extract wsap24 path
if ($confContent -match 'LoadModule\s+_1cws_module\s+"([^"]+)"') {
Write-Host "Module: $($Matches[1])"
}
# --- Publications ---
Write-Host ""
Write-Host "=== Опубликованные базы ===" -ForegroundColor Cyan
$pubPattern = '# --- 1C Publication: (.+?) ---'
$pubMatches = [regex]::Matches($confContent, $pubPattern)
if ($pubMatches.Count -eq 0) {
Write-Host "(нет публикаций)" -ForegroundColor Yellow
} else {
foreach ($match in $pubMatches) {
$appName = $match.Groups[1].Value
# Read default.vrd for this publication
$vrdPath = Join-Path (Join-Path (Join-Path $ApachePath "publish") $appName) "default.vrd"
$ibInfo = ""
if (Test-Path $vrdPath) {
$vrdContent = [System.IO.File]::ReadAllText($vrdPath)
if ($vrdContent -match 'ib="([^"]*)"') {
$ibInfo = $Matches[1] -replace '&quot;','"'
}
}
# Detect published services
$svcTags = @()
if (Test-Path $vrdPath) {
if ($vrdContent -match '<ws\s') { $svcTags += "WS" }
if ($vrdContent -match '<httpServices\s') { $svcTags += "HTTP" }
if ($vrdContent -match 'enableStandardOdata\s*=\s*"true"') { $svcTags += "OData" }
}
$svcLabel = if ($svcTags.Count -gt 0) { " [" + ($svcTags -join " ") + "]" } else { "" }
$url = "http://localhost:$port/$appName"
Write-Host " $appName" -ForegroundColor White -NoNewline
Write-Host " $url" -ForegroundColor Gray -NoNewline
Write-Host " $ibInfo" -ForegroundColor DarkGray -NoNewline
Write-Host $svcLabel -ForegroundColor DarkCyan
}
}
# --- Error log ---
Write-Host ""
Write-Host "=== Последние ошибки ===" -ForegroundColor Cyan
$errorLog = Join-Path (Join-Path $ApachePath "logs") "error.log"
if (Test-Path $errorLog) {
$lines = Get-Content $errorLog -Tail 5 -ErrorAction SilentlyContinue
if ($lines -and $lines.Count -gt 0) {
foreach ($line in $lines) {
Write-Host " $line" -ForegroundColor DarkGray
}
} else {
Write-Host "(пусто)" -ForegroundColor Green
}
} else {
Write-Host "(нет файла)" -ForegroundColor Green
}
+101
View File
@@ -0,0 +1,101 @@
---
name: web-publish
description: Публикация информационной базы 1С через Apache. Используй когда пользователь просит опубликовать базу, сервисы, настроить веб-доступ, веб-клиент, открыть в браузере
argument-hint: "[database]"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /web-publish — Публикация 1С через Apache
Генерирует `default.vrd`, настраивает `httpd.conf` и запускает Apache HTTP Server для веб-доступа к информационной базе. При необходимости скачивает portable Apache. Идемпотентный — повторный вызов обновляет конфигурацию.
## Usage
```
/web-publish [database]
/web-publish dev
/web-publish dev --manual
/web-publish dev --port 9090
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта и разреши базу:
1. Если пользователь указал параметры подключения (путь, сервер) — используй напрямую
2. Если указал базу по имени — ищи по id / alias / name в `.v8-project.json`
3. Если не указал — сопоставь текущую ветку Git с `databases[].branches`
4. Если ветка не совпала — используй `default`
**ОБЯЗАТЕЛЬНО передавай все найденные параметры:**
- **`-V8Path`** — из `v8path` в `.v8-project.json`. Если не передать, скрипт автоопределит версию платформы, что может выбрать не ту версию
- **`-UserName`** — из поля `user` найденной записи базы (если есть)
- **`-Password`** — из поля `password` найденной записи базы (если есть)
- **`-ApachePath`** — из `webPath` в `.v8-project.json` (если есть)
Если файла `.v8-project.json` нет — предложи `/db-list add`.
## Команда
```powershell
powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (для wsap24.dll) |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
| `-UserName <имя>` | нет | Имя пользователя |
| `-Password <пароль>` | нет | Пароль |
| `-AppName <имя>` | нет | Имя публикации (по умолчанию из имени каталога базы) |
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
| `-Port <порт>` | нет | Порт (по умолчанию `8081`) |
| `-Manual` | нет | Не скачивать — только проверить и дать инструкцию |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
## Несколько пользователей одной базы
Повторный вызов с тем же AppName **заменяет** публикацию (идемпотентность). Это используется для:
- смены пользователя: «опубликуй под Ивановым» → тот же AppName, новый `-UserName`
- перезапуска после `/web-stop`: тот же вызов поднимает Apache обратно
Если пользователь просит **параллельную** публикацию под другим пользователем (для тестирования разных наборов прав), добавь суффикс к AppName:
- база `bpdemo`, пользователь `Иванов``-AppName bpdemo-ivanov`
- база `bpdemo`, пользователь `Admin``-AppName bpdemo-admin` (или просто `bpdemo`)
Ключевые слова: «ещё одну публикацию», «дополнительно», «параллельно», «под другим пользователем не убирая текущую».
## После выполнения
1. Сообщи URL-ы:
- Веб-клиент: `http://localhost:{Port}/{AppName}`
- OData: `http://localhost:{Port}/{AppName}/odata/standard.odata`
- HTTP-сервисы: `http://localhost:{Port}/{AppName}/hs/<RootUrl>/...`
- Web-сервисы: `http://localhost:{Port}/{AppName}/ws/<Имя>?wsdl`
2. Предложи открыть в браузере
3. Если нужно протестировать сервис — помоги составить запрос
4. Если база не зарегистрирована — предложи `/db-list add`
## Примеры
```powershell
# Файловая база
powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
# С явным именем публикации и портом
powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -AppName "mydb" -Port 9090
# Серверная база
powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret"
# Ручной режим (только инструкция)
powershell.exe -NoProfile -File .claude/skills/web-publish/scripts/web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -Manual
```
@@ -0,0 +1,373 @@
# web-publish v1.0 — Publish 1C infobase via Apache
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
<#
.SYNOPSIS
Публикация информационной базы 1С через Apache HTTP Server
.DESCRIPTION
Генерирует default.vrd и настраивает httpd.conf для веб-доступа
к информационной базе 1С. При необходимости скачивает portable Apache.
Идемпотентный — повторный вызов обновляет конфигурацию.
.PARAMETER V8Path
Путь к каталогу bin платформы (для wsap24.dll)
.PARAMETER InfoBasePath
Путь к файловой информационной базе
.PARAMETER InfoBaseServer
Сервер 1С (для серверной базы)
.PARAMETER InfoBaseRef
Имя базы на сервере
.PARAMETER UserName
Имя пользователя 1С
.PARAMETER Password
Пароль пользователя
.PARAMETER AppName
Имя публикации (по умолчанию из имени каталога базы)
.PARAMETER ApachePath
Корень Apache (по умолчанию tools\apache24)
.PARAMETER Port
Порт (по умолчанию 8081)
.PARAMETER Manual
Не скачивать Apache — только проверить и дать инструкцию
.EXAMPLE
.\web-publish.ps1 -InfoBasePath "C:\Bases\MyDB"
.EXAMPLE
.\web-publish.ps1 -InfoBasePath "C:\Bases\MyDB" -AppName "mydb" -Port 9090
.EXAMPLE
.\web-publish.ps1 -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -Manual
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$V8Path,
[Parameter(Mandatory=$false)]
[string]$InfoBasePath,
[Parameter(Mandatory=$false)]
[string]$InfoBaseServer,
[Parameter(Mandatory=$false)]
[string]$InfoBaseRef,
[Parameter(Mandatory=$false)]
[string]$UserName,
[Parameter(Mandatory=$false)]
[string]$Password,
[Parameter(Mandatory=$false)]
[string]$AppName,
[Parameter(Mandatory=$false)]
[string]$ApachePath,
[Parameter(Mandatory=$false)]
[int]$Port = 8081,
[Parameter(Mandatory=$false)]
[switch]$Manual
)
# --- Encoding ---
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# --- Resolve V8Path ---
if (-not $V8Path) {
$found = Get-ChildItem "C:\Program Files\1cv8\*\bin\1cv8.exe" -ErrorAction SilentlyContinue | Sort-Object FullName -Descending | Select-Object -First 1
if ($found) {
$V8Path = Split-Path $found.FullName -Parent
} else {
Write-Host "Error: платформа 1С не найдена. Укажите -V8Path" -ForegroundColor Red
exit 1
}
} elseif (Test-Path $V8Path -PathType Leaf) {
$V8Path = Split-Path $V8Path -Parent
}
# Validate wsap24.dll
$wsapDll = Join-Path $V8Path "wsap24.dll"
if (-not (Test-Path $wsapDll)) {
Write-Host "Error: wsap24.dll не найден в $V8Path" -ForegroundColor Red
exit 1
}
# --- Validate connection ---
if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) {
Write-Host "Error: укажите -InfoBasePath или -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red
exit 1
}
# --- Resolve ApachePath ---
if (-not $ApachePath) {
$projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
$ApachePath = Join-Path $projectRoot "tools\apache24"
}
# --- Check / Install Apache ---
$httpdExe = Join-Path (Join-Path $ApachePath "bin") "httpd.exe"
if (-not (Test-Path $httpdExe)) {
if ($Manual) {
Write-Host "Apache не найден: $ApachePath" -ForegroundColor Yellow
Write-Host ""
Write-Host "Установите Apache вручную:" -ForegroundColor Cyan
Write-Host " 1. Скачайте Apache Lounge (x64) с https://www.apachelounge.com/download/"
Write-Host " 2. Распакуйте содержимое Apache24\ в: $ApachePath"
Write-Host " 3. Запустите скрипт повторно"
exit 1
}
Write-Host "Apache не найден. Скачиваю..." -ForegroundColor Cyan
$zipUrl = "https://www.apachelounge.com/download/VS18/binaries/httpd-2.4.66-260131-Win64-VS18.zip"
$tmpZip = Join-Path $env:TEMP "apache24.zip"
$tmpDir = Join-Path $env:TEMP "apache24_extract"
try {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# WebClient works better than Invoke-WebRequest in PS 5.1 (handles redirects)
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($zipUrl, $tmpZip)
} catch {
Write-Host "Error: не удалось скачать Apache: $_" -ForegroundColor Red
Write-Host "Скачайте вручную: https://www.apachelounge.com/download/" -ForegroundColor Yellow
exit 1
}
Write-Host "Распаковка..."
if (Test-Path $tmpDir) { Remove-Item $tmpDir -Recurse -Force }
Expand-Archive -Path $tmpZip -DestinationPath $tmpDir -Force
# Move Apache24 contents up to ApachePath
$innerDir = Join-Path $tmpDir "Apache24"
if (-not (Test-Path $innerDir)) {
# Try to find Apache24 in nested folder
$innerDir = Get-ChildItem $tmpDir -Directory -Recurse -Filter "Apache24" | Select-Object -First 1
if ($innerDir) { $innerDir = $innerDir.FullName } else {
Write-Host "Error: каталог Apache24 не найден в архиве" -ForegroundColor Red
exit 1
}
}
if (-not (Test-Path $ApachePath)) {
New-Item -ItemType Directory -Path $ApachePath -Force | Out-Null
}
Copy-Item -Path (Join-Path $innerDir "*") -Destination $ApachePath -Recurse -Force
# Cleanup
Remove-Item $tmpZip -Force -ErrorAction SilentlyContinue
Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
# Patch ServerRoot in httpd.conf
$confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
if (Test-Path $confFile) {
$apachePathFwd = $ApachePath -replace '\\','/'
$confContent = [System.IO.File]::ReadAllText($confFile)
$confContent = $confContent -replace '(?m)^Define SRVROOT .*$', "Define SRVROOT `"$apachePathFwd`""
[System.IO.File]::WriteAllText($confFile, $confContent)
Write-Host "ServerRoot обновлён: $apachePathFwd" -ForegroundColor Green
}
Write-Host "Apache установлен: $ApachePath" -ForegroundColor Green
}
# --- Derive AppName ---
if (-not $AppName) {
if ($InfoBasePath) {
$AppName = (Split-Path $InfoBasePath -Leaf) -replace '[^\w]',''
} else {
$AppName = $InfoBaseRef -replace '[^\w]',''
}
$AppName = $AppName.ToLower()
}
$AppName = $AppName.ToLower()
if (-not $AppName) {
Write-Host "Error: не удалось определить имя публикации. Укажите -AppName" -ForegroundColor Red
exit 1
}
Write-Host "Публикация: $AppName" -ForegroundColor Cyan
# --- Create publish directory ---
$publishDir = Join-Path (Join-Path $ApachePath "publish") $AppName
if (-not (Test-Path $publishDir)) {
New-Item -ItemType Directory -Path $publishDir -Force | Out-Null
}
# --- Generate default.vrd ---
$vrdPath = Join-Path $publishDir "default.vrd"
$ibParts = @()
if ($InfoBaseServer -and $InfoBaseRef) {
$ibParts += "Srvr=&quot;$InfoBaseServer&quot;"
$ibParts += "Ref=&quot;$InfoBaseRef&quot;"
} else {
$ibParts += "File=&quot;$InfoBasePath&quot;"
}
if ($UserName) { $ibParts += "Usr=&quot;$UserName&quot;" }
if ($Password) { $ibParts += "Pwd=&quot;$Password&quot;" }
$ibString = ($ibParts -join ";") + ";"
$vrdContent = @"
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/$AppName"
ib="$ibString"
enableStandardOdata="true">
<ws pointEnableCommon="true"/>
<httpServices publishByDefault="true"/>
</point>
"@
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($vrdPath, $vrdContent, $utf8Bom)
Write-Host "default.vrd: $vrdPath" -ForegroundColor Green
# --- Update httpd.conf ---
$confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
if (-not (Test-Path $confFile)) {
Write-Host "Error: httpd.conf не найден: $confFile" -ForegroundColor Red
exit 1
}
$confContent = [System.IO.File]::ReadAllText($confFile)
$apachePathFwd = $ApachePath -replace '\\','/'
$wsapDllFwd = $wsapDll -replace '\\','/'
$publishDirFwd = $publishDir -replace '\\','/'
$vrdPathFwd = $vrdPath -replace '\\','/'
# --- Global block (Listen + LoadModule) ---
$globalMarkerStart = "# --- 1C: global ---"
$globalMarkerEnd = "# --- End: global ---"
$globalBlock = @"
$globalMarkerStart
Listen $Port
LoadModule _1cws_module "$wsapDllFwd"
$globalMarkerEnd
"@
if ($confContent -match [regex]::Escape($globalMarkerStart)) {
# Replace existing global block
$pattern = [regex]::Escape($globalMarkerStart) + '[\s\S]*?' + [regex]::Escape($globalMarkerEnd)
$confContent = [regex]::Replace($confContent, $pattern, $globalBlock)
} else {
# Comment out default Listen to avoid port conflict
$confContent = $confContent -replace '(?m)^(Listen\s+\d+)', '#$1 # commented by web-publish'
# Append global block
$confContent = $confContent.TrimEnd() + "`n`n" + $globalBlock + "`n"
}
# --- Publication block ---
$pubMarkerStart = "# --- 1C Publication: $AppName ---"
$pubMarkerEnd = "# --- End: $AppName ---"
$pubBlock = @"
$pubMarkerStart
Alias "/$AppName" "$publishDirFwd"
<Directory "$publishDirFwd">
AllowOverride All
Require all granted
SetHandler 1c-application
ManagedApplicationDescriptor "$vrdPathFwd"
</Directory>
$pubMarkerEnd
"@
if ($confContent -match [regex]::Escape($pubMarkerStart)) {
# Replace existing publication block
$pattern = [regex]::Escape($pubMarkerStart) + '[\s\S]*?' + [regex]::Escape($pubMarkerEnd)
$confContent = [regex]::Replace($confContent, $pattern, $pubBlock)
} else {
# Append publication block
$confContent = $confContent.TrimEnd() + "`n`n" + $pubBlock + "`n"
}
[System.IO.File]::WriteAllText($confFile, $confContent)
Write-Host "httpd.conf обновлён" -ForegroundColor Green
# --- Helper: filter httpd processes by our ApachePath ---
function Get-OurHttpd {
$httpdExeNorm = (Resolve-Path $httpdExe -ErrorAction SilentlyContinue).Path
Get-Process httpd -ErrorAction SilentlyContinue | Where-Object {
try { $_.Path -eq $httpdExeNorm } catch { $false }
}
}
# --- Check port availability ---
$portCheck = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue | Select-Object -First 1
if ($portCheck) {
$ourProc = Get-OurHttpd
if ($ourProc) {
# Our Apache holds the port — will restart
} else {
$holder = Get-Process -Id $portCheck.OwningProcess -ErrorAction SilentlyContinue
$holderName = if ($holder) { "$($holder.ProcessName) (PID: $($holder.Id))" } else { "PID $($portCheck.OwningProcess)" }
Write-Host "Error: порт $Port занят процессом $holderName" -ForegroundColor Red
Write-Host "Укажите другой порт: -Port 9090" -ForegroundColor Yellow
exit 1
}
}
# --- Start Apache if not running ---
$httpdProc = Get-OurHttpd
if ($httpdProc) {
Write-Host "Apache уже запущен (PID: $(($httpdProc | Select-Object -First 1).Id))" -ForegroundColor Yellow
Write-Host "Перезапуск для применения конфигурации..."
$httpdProc | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
} else {
# Check if a foreign httpd holds the port
$foreignHttpd = Get-Process httpd -ErrorAction SilentlyContinue
if ($foreignHttpd) {
Write-Host "[WARN] Обнаружен сторонний Apache (PID: $(($foreignHttpd | Select-Object -First 1).Id))" -ForegroundColor Yellow
Write-Host " Наш Apache: $httpdExe" -ForegroundColor Yellow
}
}
Write-Host "Запуск Apache..."
Start-Process -FilePath $httpdExe -WorkingDirectory $ApachePath -WindowStyle Hidden
Start-Sleep -Seconds 2
$httpdCheck = Get-OurHttpd
if ($httpdCheck) {
Write-Host "Apache запущен (PID: $(($httpdCheck | Select-Object -First 1).Id))" -ForegroundColor Green
} else {
Write-Host "Apache не удалось запустить" -ForegroundColor Red
# Run config test for diagnostics
$testResult = & $httpdExe -t 2>&1
if ($testResult) {
Write-Host "--- httpd -t ---" -ForegroundColor Yellow
$testResult | ForEach-Object { Write-Host " $_" }
}
$errorLog = Join-Path (Join-Path $ApachePath "logs") "error.log"
if (Test-Path $errorLog) {
Write-Host "--- error.log (последние 10 строк) ---" -ForegroundColor Yellow
Get-Content $errorLog -Tail 10
}
exit 1
}
# --- Result ---
Write-Host ""
Write-Host "=== Публикация готова ===" -ForegroundColor Green
Write-Host "URL: http://localhost:$Port/$AppName" -ForegroundColor Cyan
Write-Host "OData: http://localhost:$Port/$AppName/odata/standard.odata" -ForegroundColor Cyan
Write-Host "HTTP-сервисы: http://localhost:$Port/$AppName/hs/<RootUrl>/..." -ForegroundColor Cyan
Write-Host "Web-сервисы: http://localhost:$Port/$AppName/ws/<Имя>?wsdl" -ForegroundColor Cyan
+52
View File
@@ -0,0 +1,52 @@
---
name: web-stop
description: Остановка Apache HTTP Server. Используй когда пользователь просит остановить веб-сервер, Apache, прекратить веб-публикацию
argument-hint: ""
allowed-tools:
- Bash
- Read
- Glob
---
# /web-stop — Остановка Apache
Останавливает Apache HTTP Server. Публикации сохраняются — при следующем `/web-publish` сервер запустится снова.
## Usage
```
/web-stop
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
По умолчанию `tools/apache24` от корня проекта.
## Команда
```powershell
powershell.exe -NoProfile -File .claude/skills/web-stop/scripts/web-stop.ps1 <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
## После выполнения
Предложи пользователю:
- **Перезапуск** — `/web-publish <база>` (повторный вызов поднимет Apache с существующими публикациями)
- **Удаление публикаций** — `/web-unpublish <имя>` или `/web-unpublish --all`
## Примеры
```powershell
# Остановить Apache
powershell.exe -NoProfile -File .claude/skills/web-stop/scripts/web-stop.ps1
# С указанием пути
powershell.exe -NoProfile -File .claude/skills/web-stop/scripts/web-stop.ps1 -ApachePath "C:\tools\apache24"
```
@@ -0,0 +1,92 @@
# web-stop v1.0 — Stop Apache HTTP Server
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
<#
.SYNOPSIS
Остановка Apache HTTP Server
.DESCRIPTION
Останавливает Apache HTTP Server. Сначала пытается graceful shutdown,
при неудаче — принудительная остановка.
.PARAMETER ApachePath
Корень Apache (по умолчанию tools\apache24)
.EXAMPLE
.\web-stop.ps1
.EXAMPLE
.\web-stop.ps1 -ApachePath "C:\tools\apache24"
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$ApachePath
)
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# --- Resolve ApachePath ---
if (-not $ApachePath) {
$projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
$ApachePath = Join-Path $projectRoot "tools\apache24"
}
# --- Helper: filter httpd processes by our ApachePath ---
$httpdExe = Join-Path (Join-Path $ApachePath "bin") "httpd.exe"
$httpdExeNorm = (Resolve-Path $httpdExe -ErrorAction SilentlyContinue).Path
function Get-OurHttpd {
Get-Process httpd -ErrorAction SilentlyContinue | Where-Object {
try { $_.Path -eq $httpdExeNorm } catch { $false }
}
}
# --- Check process (only our Apache) ---
$httpdProc = Get-OurHttpd
if (-not $httpdProc) {
$foreign = Get-Process httpd -ErrorAction SilentlyContinue
if ($foreign) {
Write-Host "Наш Apache не запущен" -ForegroundColor Yellow
Write-Host "[WARN] Обнаружен сторонний Apache (PID: $(($foreign | Select-Object -First 1).Id))" -ForegroundColor Yellow
} else {
Write-Host "Apache не запущен" -ForegroundColor Yellow
}
exit 0
}
$pids = ($httpdProc | ForEach-Object { $_.Id }) -join ", "
Write-Host "Останавливаю Apache (PID: $pids)..."
# --- Stop our processes ---
$httpdProc | Stop-Process -Force -ErrorAction SilentlyContinue
# --- Wait for shutdown ---
$maxWait = 5
$elapsed = 0
while ($elapsed -lt $maxWait) {
Start-Sleep -Seconds 1
$elapsed++
$check = Get-OurHttpd
if (-not $check) {
Write-Host "Apache остановлен" -ForegroundColor Green
Write-Host "Публикации сохранены. Перезапуск: /web-publish <база> Удаление: /web-unpublish --all" -ForegroundColor Gray
exit 0
}
}
# --- Fallback: force kill ---
$remaining = Get-OurHttpd
if ($remaining) {
Write-Host "Принудительная остановка..." -ForegroundColor Yellow
$remaining | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
$final = Get-OurHttpd
if ($final) {
Write-Host "Error: не удалось остановить Apache" -ForegroundColor Red
exit 1
}
}
Write-Host "Apache остановлен" -ForegroundColor Green
Write-Host "Публикации сохранены. Перезапуск: /web-publish <база> Удаление: /web-unpublish --all" -ForegroundColor Gray
+62
View File
@@ -0,0 +1,62 @@
---
name: web-unpublish
description: Удаление веб-публикации 1С из Apache. Используй когда пользователь просит убрать публикацию, удалить веб-доступ к базе
argument-hint: "<appname | --all>"
allowed-tools:
- Bash
- Read
- Glob
- AskUserQuestion
---
# /web-unpublish — Удаление веб-публикации 1С из Apache
Удаляет блок публикации из `httpd.conf` и каталог `publish/{appname}` внутри Apache. Если других публикаций не осталось — удаляет глобальный блок 1C и останавливает Apache. С флагом `--all` удаляет все публикации разом.
> **Внимание:** этот навык управляет только веб-публикациями в Apache (блоки в `httpd.conf` + каталог `publish/`). Он **НЕ** удаляет каталоги проекта, `upload/`, базы данных или исходники.
## Usage
```
/web-unpublish <appname>
/web-unpublish bpdemo
/web-unpublish --all
```
## Параметры подключения
Прочитай `.v8-project.json` из корня проекта. Если задан `webPath` — используй как `-ApachePath`.
По умолчанию `tools/apache24` от корня проекта.
Если пользователь не указал `appname` и не указал `--all`, выполни `/web-info` чтобы показать список публикаций и спроси какую удалить.
Если пользователь просит удалить **все** публикации — используй `-All`.
## Команда
```powershell
powershell.exe -NoProfile -File .claude/skills/web-unpublish/scripts/web-unpublish.ps1 <параметры>
```
### Параметры скрипта
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-AppName <имя>` | * | Имя публикации |
| `-All` | * | Удалить все публикации |
| `-ApachePath <путь>` | нет | Корень Apache (по умолчанию `tools/apache24`) |
> `*` — нужен либо `-AppName`, либо `-All`
## Примеры
```powershell
# Удалить одну публикацию
powershell.exe -NoProfile -File .claude/skills/web-unpublish/scripts/web-unpublish.ps1 -AppName "bpdemo"
# Удалить все публикации
powershell.exe -NoProfile -File .claude/skills/web-unpublish/scripts/web-unpublish.ps1 -All
# С указанием пути
powershell.exe -NoProfile -File .claude/skills/web-unpublish/scripts/web-unpublish.ps1 -AppName "mydb" -ApachePath "C:\tools\apache24"
```
@@ -0,0 +1,159 @@
# web-unpublish v1.0 — Remove 1C web publication
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
<#
.SYNOPSIS
Удаление веб-публикации 1С из Apache
.DESCRIPTION
Удаляет маркерный блок из httpd.conf и каталог публикации.
Если Apache запущен — перезапускает для применения.
С флагом -All удаляет все публикации и останавливает Apache.
.PARAMETER AppName
Имя публикации (обязательный, если не указан -All)
.PARAMETER ApachePath
Корень Apache (по умолчанию tools\apache24)
.PARAMETER All
Удалить все публикации
.EXAMPLE
.\web-unpublish.ps1 -AppName "mydb"
.EXAMPLE
.\web-unpublish.ps1 -All
.EXAMPLE
.\web-unpublish.ps1 -AppName "bpdemo" -ApachePath "C:\tools\apache24"
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$AppName,
[Parameter(Mandatory=$false)]
[string]$ApachePath,
[Parameter(Mandatory=$false)]
[switch]$All
)
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# --- Resolve ApachePath ---
if (-not $ApachePath) {
$projectRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName
$ApachePath = Join-Path $projectRoot "tools\apache24"
}
# --- Validate params ---
if (-not $All -and -not $AppName) {
Write-Host "Error: укажите -AppName или -All" -ForegroundColor Red
exit 1
}
# --- Read httpd.conf ---
$confFile = Join-Path (Join-Path $ApachePath "conf") "httpd.conf"
if (-not (Test-Path $confFile)) {
Write-Host "Error: httpd.conf не найден: $confFile" -ForegroundColor Red
exit 1
}
$confContent = [System.IO.File]::ReadAllText($confFile)
# --- Helper: our httpd process ---
$httpdExe = Join-Path (Join-Path $ApachePath "bin") "httpd.exe"
$httpdExeNorm = (Resolve-Path $httpdExe -ErrorAction SilentlyContinue).Path
function Get-OurHttpd {
Get-Process httpd -ErrorAction SilentlyContinue | Where-Object {
try { $_.Path -eq $httpdExeNorm } catch { $false }
}
}
# --- Collect app names to remove ---
if ($All) {
$pubPattern = '# --- 1C Publication: (.+?) ---'
$pubMatches = [regex]::Matches($confContent, $pubPattern)
if ($pubMatches.Count -eq 0) {
Write-Host "Нет публикаций для удаления" -ForegroundColor Yellow
exit 0
}
$appNames = @()
foreach ($m in $pubMatches) { $appNames += $m.Groups[1].Value }
Write-Host "Удаление всех публикаций: $($appNames -join ', ')" -ForegroundColor Cyan
} else {
$appNames = @($AppName)
}
# --- Remove marker blocks ---
foreach ($name in $appNames) {
$pubMarkerStart = "# --- 1C Publication: $name ---"
$pubMarkerEnd = "# --- End: $name ---"
if ($confContent -match [regex]::Escape($pubMarkerStart)) {
$pattern = '\r?\n?' + [regex]::Escape($pubMarkerStart) + '[\s\S]*?' + [regex]::Escape($pubMarkerEnd) + '\r?\n?'
$confContent = [regex]::Replace($confContent, $pattern, "`n")
Write-Host "httpd.conf: блок публикации '$name' удалён" -ForegroundColor Green
} else {
Write-Host "Публикация '$name' не найдена в httpd.conf" -ForegroundColor Yellow
}
}
# --- Check if any publications remain; if not, remove global block ---
$remainingPubs = [regex]::Matches($confContent, '# --- 1C Publication: .+? ---')
if ($remainingPubs.Count -eq 0) {
$globalMarkerStart = "# --- 1C: global ---"
$globalMarkerEnd = "# --- End: global ---"
if ($confContent -match [regex]::Escape($globalMarkerStart)) {
$globalPattern = '\r?\n?' + [regex]::Escape($globalMarkerStart) + '[\s\S]*?' + [regex]::Escape($globalMarkerEnd) + '\r?\n?'
$confContent = [regex]::Replace($confContent, $globalPattern, "`n")
Write-Host "httpd.conf: глобальный блок 1C удалён (нет публикаций)" -ForegroundColor Green
}
}
[System.IO.File]::WriteAllText($confFile, $confContent)
# --- Remove publish directories ---
foreach ($name in $appNames) {
$publishDir = Join-Path (Join-Path $ApachePath "publish") $name
if (Test-Path $publishDir) {
Remove-Item $publishDir -Recurse -Force
Write-Host "Каталог удалён: $publishDir" -ForegroundColor Green
} else {
Write-Host "Каталог не найден: $publishDir" -ForegroundColor Yellow
}
}
# --- Restart/Stop Apache if running (only our instance) ---
$httpdProc = Get-OurHttpd
if ($httpdProc) {
if ($remainingPubs.Count -gt 0) {
Write-Host "Перезапуск Apache..."
$httpdProc | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
Start-Process -FilePath $httpdExe -WorkingDirectory $ApachePath -WindowStyle Hidden
Start-Sleep -Seconds 2
$check = Get-OurHttpd
if ($check) {
Write-Host "Apache перезапущен" -ForegroundColor Green
} else {
Write-Host "Error: Apache не удалось перезапустить" -ForegroundColor Red
exit 1
}
} else {
Write-Host "Публикаций не осталось — останавливаю Apache..."
$httpdProc | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
Write-Host "Apache остановлен" -ForegroundColor Green
}
}
Write-Host ""
if ($All) {
Write-Host "Все публикации удалены ($($appNames.Count) шт.)" -ForegroundColor Green
} else {
Write-Host "Публикация '$AppName' удалена" -ForegroundColor Green
}
+3
View File
@@ -13,5 +13,8 @@ test-tmp/
# Локальные настройки Claude Code
.claude/settings.local.json
# Инструменты (portable Apache и т.д.)
tools/
# Локальный реестр баз данных 1С
.v8-project.json
+9 -1
View File
@@ -34,6 +34,7 @@
| Подсистемы (Subsystem) | 4 навыка `/subsystem-*` | Анализ, создание, редактирование, валидация подсистем конфигурации | [Подробнее](docs/subsystem-guide.md) |
| Командный интерфейс (CI) | 2 навыка `/interface-*` | Редактирование и валидация CommandInterface.xml подсистем | [Подробнее](docs/subsystem-guide.md) |
| Базы данных (DB) | 9 навыков `/db-*` | Создание баз, загрузка/выгрузка конфигураций, обновление БД, загрузка из Git | [Подробнее](docs/db-guide.md) |
| Веб-публикация (Web) | 4 навыка `/web-*` | Публикация баз через Apache, статус, остановка, удаление публикаций | [Подробнее](docs/web-guide.md) |
| Утилиты | `/img-grid` | Наложение сетки на изображение для определения пропорций колонок | — |
## Требования
@@ -61,6 +62,7 @@
- [Подсистемы и командный интерфейс](docs/1c-subsystem-spec.md) — XML-формат подсистем, CommandInterface.xml, секции видимости/размещения/порядка
- [Корневая конфигурация](docs/1c-configuration-spec.md) — XML-формат Configuration.xml, ConfigDumpInfo.xml, Languages/, 44 типа ChildObjects
- [Расширения конфигурации (CFE)](docs/1c-extension-spec.md) — XML-формат выгрузки расширений конфигурации
- [Веб-публикация 1С](docs/web-spec.md) — VRD, httpd.conf, wsap24.dll, portable Apache
## Структура репозитория
@@ -127,6 +129,10 @@
├── db-update/ # Обновление конфигурации БД
├── db-run/ # Запуск 1С:Предприятие
├── db-load-git/ # Загрузка изменений из Git
├── web-publish/ # Публикация базы через Apache
├── web-info/ # Статус Apache и публикаций
├── web-stop/ # Остановка Apache
├── web-unpublish/ # Удаление публикации
└── img-grid/ # Сетка для анализа изображений
docs/
├── epf-guide.md # Гайд: внешние обработки и отчёты
@@ -139,6 +145,7 @@ docs/
├── cfe-guide.md # Гайд: расширения конфигурации (CFE)
├── subsystem-guide.md # Гайд: подсистемы и командный интерфейс
├── db-guide.md # Гайд: базы данных 1С
├── web-guide.md # Гайд: веб-публикация через Apache
├── 1c-epf-spec.md # Спецификация XML-формата (EPF)
├── 1c-erf-spec.md # Спецификация XML-формата (ERF)
├── 1c-form-spec.md # Спецификация управляемых форм
@@ -154,5 +161,6 @@ docs/
├── skd-dsl-spec.md # Спецификация SKD DSL
├── role-dsl-spec.md # Спецификация Role DSL
├── 1c-extension-spec.md # Спецификация расширений конфигурации (CFE)
── 1c-subsystem-spec.md # Спецификация подсистем и командного интерфейса
── 1c-subsystem-spec.md # Спецификация подсистем и командного интерфейса
└── web-spec.md # Спецификация веб-публикации (VRD, httpd.conf, Apache)
```
+164
View File
@@ -0,0 +1,164 @@
# Веб-публикация 1С
Навыки группы `/web-*` позволяют публиковать информационные базы 1С через Apache HTTP Server для доступа из браузера (веб-клиент). Это замыкает цикл разработки: правка исходников → загрузка → обновление БД → **открытие в браузере**.
## Навыки
| Навык | Скрипт | Описание |
|-------|:------:|----------|
| `/web-publish` | `.ps1` | Публикация базы (VRD + httpd.conf + запуск Apache) |
| `/web-info` | `.ps1` | Статус Apache и список публикаций |
| `/web-stop` | `.ps1` | Остановка Apache |
| `/web-unpublish` | `.ps1` | Удаление публикации (одной или всех `--all`) |
## Рабочий цикл
```
правки в исходниках → /db-load-xml → /db-update → /web-publish → браузер
/web-info ← статус |
/web-stop ← остановка|
/web-unpublish ← удаление
```
### Типичный цикл разработки
1. **Настройка**`/db-list add` зарегистрировать базу в `.v8-project.json`
2. **Загрузка**`/db-load-xml` загрузить конфигурацию
3. **Обновление**`/db-update` применить к БД
4. **Публикация**`/web-publish` опубликовать базу (при первом запуске скачает Apache)
5. **Проверка** — открыть `http://localhost:8081/{appname}` в браузере
6. **Правка** — изменить исходники
7. **Синхронизация**`/db-load-git` + `/db-update`
8. **Проверка** — обновить страницу в браузере
9. **Завершение**`/web-stop` остановить Apache
## Конфигурация `webPath` в `.v8-project.json`
Поле `webPath` указывает путь к каталогу Apache. Если не задано, используется `tools/apache24` от корня проекта.
```json
{
"v8path": "C:\\Program Files\\1cv8\\8.3.24.1691\\bin",
"webPath": "C:\\tools\\apache24",
"databases": [
{
"id": "dev",
"name": "Разработка",
"type": "file",
"path": "C:\\Bases\\MyApp_Dev",
"user": "Admin"
}
],
"default": "dev"
}
```
> `webPath` — опционально. Если не задан, все навыки `/web-*` ищут Apache в `tools/apache24`.
## Сценарии использования
### Опубликовать базу
```
> Опубликуй базу bp-demo
```
Claude вызовет `/web-publish bp-demo` → скачает Apache (если нет) → сгенерирует VRD → настроит httpd.conf → запустит Apache → выдаст URL.
### Проверить статус
```
> Что с веб-сервером?
```
Claude вызовет `/web-info` → покажет состояние Apache, порт, список публикаций, последние ошибки.
### Опубликовать на другом порту
```
> Опубликуй ERP на порту 9090
```
Claude вызовет `/web-publish erp --port 9090`.
### Сменить пользователя публикации
```
> Переключи публикацию bp-demo на пользователя Иванов
```
Claude вызовет `/web-publish bp-demo` с `-UserName "Иванов"` — перезапишет VRD с новым пользователем.
### Параллельные публикации под разными пользователями
```
> Добавь ещё одну публикацию bp-demo под Ивановым, Admin оставь
```
Claude вызовет `/web-publish bp-demo --appname bpdemo-ivanov --user Иванов` — создаст вторую публикацию. Обе будут доступны одновременно по разным URL.
### Остановить сервер
```
> Останови Apache
```
Claude вызовет `/web-stop`.
### Удалить публикацию
```
> Убери публикацию bpdemo
```
Claude вызовет `/web-unpublish bpdemo` → удалит блок из httpd.conf → удалит каталог → перезапустит Apache (если есть другие публикации).
### Удалить все публикации
```
> Удали все веб-публикации
```
Claude вызовет `/web-unpublish --all` → удалит все блоки из httpd.conf → удалит все каталоги → остановит Apache.
## Работа с сервисами
### Протестировать HTTP-сервис
```
> Вызови HTTP-сервис ОбменДанными метод ПолучитьСтатус
```
Claude составит curl/Invoke-WebRequest к `http://localhost:8081/appname/hs/exchange/status`
### Проверить OData
```
> Покажи список справочников через OData
```
Claude вызовет `http://localhost:8081/appname/odata/standard.odata/$metadata`
### Получить WSDL web-сервиса
```
> Покажи WSDL сервиса ОбменСВнешнимиСистемами
```
Claude откроет `http://localhost:8081/appname/ws/ExchangeWithExternalSystems?wsdl`
## Ручная установка Apache
Если автоматическая загрузка невозможна (прокси, firewall), используйте флаг `--manual`:
```
> Опубликуй базу --manual
```
Скрипт выдаст инструкцию:
1. Скачайте Apache Lounge (x64 VS17) с https://www.apachelounge.com/download/
2. Распакуйте содержимое `Apache24/` в `tools/apache24` (или путь из `webPath`)
3. Запустите команду повторно
## Спецификации
- [web-spec.md](web-spec.md) — техническая спецификация (VRD, httpd.conf, wsap24.dll, portable Apache)
- [build-spec.md](build-spec.md) — пакетный режим конфигуратора 1С
+201
View File
@@ -0,0 +1,201 @@
# Веб-публикация 1С — техническая спецификация
Описание артефактов, необходимых для публикации информационной базы 1С через Apache HTTP Server.
## default.vrd
Дескриптор виртуального ресурса. XML-файл, описывающий подключение к информационной базе.
### Формат
```xml
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/appname"
ib="connection-string"
enableStandardOdata="true">
<ws pointEnableCommon="true"/>
<httpServices publishByDefault="true"/>
</point>
```
### Атрибут `base`
URL-путь публикации. Должен начинаться с `/`, совпадает с `Alias` в httpd.conf.
### Атрибут `ib`
Строка подключения к информационной базе.
**Файловая база:**
```
File=&quot;C:\Bases\MyDB&quot;;
```
**Серверная база:**
```
Srvr=&quot;server01&quot;;Ref=&quot;MyDB&quot;;
```
**С авторизацией:**
```
File=&quot;C:\Bases\MyDB&quot;;Usr=&quot;Admin&quot;;Pwd=&quot;123&quot;;
```
> Кавычки внутри значения `ib` экранируются как `&quot;` (XML-сущность).
### Дочерние элементы
#### `enableStandardOdata` (атрибут `<point>`)
Стандартный OData-интерфейс платформы. `enableStandardOdata="true"` открывает REST-доступ ко всем объектам.
URL: `/{AppName}/odata/standard.odata`
#### `<ws>`
Публикация SOAP web-сервисов. `pointEnableCommon="true"` публикует все сервисы из конфигурации.
URL: `/{AppName}/ws/{WebServiceName}?wsdl`
#### `<httpServices>`
Публикация HTTP-сервисов. `publishByDefault="true"` публикует все сервисы из конфигурации.
URL: `/{AppName}/hs/{RootUrl}/...`
### Расположение
`{ApachePath}/publish/{AppName}/default.vrd`
## httpd.conf для 1С
### LoadModule
Apache загружает модуль расширения 1С:
```apache
LoadModule _1cws_module "C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll"
```
- Модуль `wsap24.dll` — 64-разрядный, требует x64-версию Apache
- Путь использует forward slashes
### Listen
```apache
Listen 8081
```
Порт для веб-клиента. По умолчанию `8081` (стандартный `80` может быть занят).
### Alias + Directory
Для каждой публикации добавляется блок:
```apache
Alias "/appname" "C:/path/to/apache/publish/appname"
<Directory "C:/path/to/apache/publish/appname">
AllowOverride All
Require all granted
SetHandler 1c-application
ManagedApplicationDescriptor "C:/path/to/apache/publish/appname/default.vrd"
</Directory>
```
- `Alias` — URL-путь → физический каталог
- `SetHandler 1c-application` — делегирование обработки запросов модулю wsap24
- `ManagedApplicationDescriptor` — путь к default.vrd
### Маркерный подход
Скрипты используют маркерные комментарии для идемпотентного управления блоками:
```apache
# --- 1C: global ---
Listen 8081
LoadModule _1cws_module "C:/Program Files/1cv8/8.3.24.1691/bin/wsap24.dll"
# --- End: global ---
# --- 1C Publication: mydb ---
Alias "/mydb" "C:/tools/apache24/publish/mydb"
<Directory "C:/tools/apache24/publish/mydb">
AllowOverride All
Require all granted
SetHandler 1c-application
ManagedApplicationDescriptor "C:/tools/apache24/publish/mydb/default.vrd"
</Directory>
# --- End: mydb ---
```
При повторном запуске блок между маркерами заменяется целиком.
## wsap24.dll
Модуль расширения Apache для 1С:Предприятие 8.3.
- Расположение: `{V8Path}/wsap24.dll` (в каталоге `bin` платформы)
- Архитектура: x64 (Apache тоже должен быть x64)
- Имя модуля: `_1cws_module`
## Portable Apache
### Дистрибутив
Apache Lounge — Windows-сборка Apache HTTP Server (x64):
- Сайт: `https://www.apachelounge.com/download/`
- Прямая ссылка (2.4.62, VS17): `https://www.apachelounge.com/download/VS17/binaries/httpd-2.4.62-240904-win64-VS17.zip`
- Внутри ZIP: каталог `Apache24/` с полной структурой
### Структура после установки
```
tools/apache24/
├── bin/
│ ├── httpd.exe
│ └── ...
├── conf/
│ ├── httpd.conf
│ └── ...
├── logs/
│ ├── error.log
│ └── access.log
├── modules/
│ └── ...
└── publish/
└── {appname}/
└── default.vrd
```
### Пост-распаковка
1. `Expand-Archive` распаковывает ZIP во временный каталог
2. Содержимое `Apache24/` перемещается в `{ApachePath}`
3. В `httpd.conf` патчится `ServerRoot`:
```apache
Define SRVROOT "C:/path/to/apache24"
ServerRoot "${SRVROOT}"
```
Путь `SRVROOT` — абсолютный, с forward slashes.
### Запуск
```
httpd.exe # foreground (для отладки)
httpd.exe -k start # фоновый запуск (не работает без установки сервиса)
```
> Portable Apache запускается напрямую через `Start-Process httpd.exe` без установки Windows-сервиса.
### Остановка
```
httpd.exe -k stop # graceful shutdown (требует сервис)
Stop-Process -Name httpd # принудительная остановка (portable)
```
### Перезагрузка
```
httpd.exe -k restart # graceful restart (требует сервис)
```
Для portable варианта: остановка + запуск.