Compare commits

..

2 commits

Author SHA1 Message Date
X9 Dev
9027718f7f feat: auto-deploy web on git pull + deploy SHA in spec footer
heal.sh now:
1. git fetch + reset --hard origin/main when remote is ahead
2. writes web/data/deploy.json (sha + timestamp) after each pull
3. nginx reload if web/ files changed
4. falls back to writing deploy.json on first run if missing

spec/index.html shows deployed commit SHA + timestamp in footer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 15:52:41 +02:00
X9 Dev
be412e99bc docs(spec): update spec page to reflect current reality
- Sidebar: all 13 steps listed in order (00-12), arch updated
- Step 03: add Edge new tab page policy rows (quick links, background, content)
- Step 04: taskbar pin row updated — explicit Explorer+Edge pins, PinListPlacement=Replace
- Step 05: add Wallpaper="" fix row (black desktop for new users)
- Steps 09/10/11: correct IDs (step-09/10/11), moved out of "Planovane" section
- Step 12: new Windows Update card with PSWindowsUpdate details
- Arch: xetup.exe rewritten — Walk GUI (Win32), no OpenGL, VMware-safe, step strip, auto-reboot
- Version bump: 0.3-draft -> 0.4
- JS STEP_SCRIPT: updated IDs to match new step anchor names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 15:51:14 +02:00
2 changed files with 147 additions and 68 deletions

37
heal.sh Executable file
View file

@ -0,0 +1,37 @@
#!/bin/bash
# Self-heal: pull latest git changes, deploy web content, keep containers up.
# Runs every 5 minutes via systemd timer.
set -euo pipefail
cd /opt/xetup
LOG="[heal $(date '+%H:%M:%S')]"
# Pull latest changes (ff-only: never merge, just update)
BEFORE=$(git rev-parse HEAD 2>/dev/null || echo "none")
git fetch --quiet origin main 2>/dev/null || true
REMOTE=$(git rev-parse origin/main 2>/dev/null || echo "")
if [ -n "$REMOTE" ] && [ "$BEFORE" != "$REMOTE" ]; then
git reset --hard origin/main --quiet 2>/dev/null || true
AFTER=$(git rev-parse HEAD)
echo "$LOG deployed $BEFORE$AFTER"
# Write deployed commit info for the web (spec page footer)
echo "{\"sha\":\"$(git rev-parse --short HEAD)\",\"ts\":\"$(date -u '+%Y-%m-%dT%H:%M:%SZ')\"}" \
> web/data/deploy.json
# If web content changed, reload nginx config
if git diff --name-only "$BEFORE" "$AFTER" 2>/dev/null | grep -q '^web/'; then
echo "$LOG web/ changed - reloading nginx"
/usr/bin/docker compose exec -T web nginx -s reload 2>/dev/null || true
fi
else
# Always keep deploy.json fresh on first run if missing
if [ ! -f web/data/deploy.json ]; then
echo "{\"sha\":\"$(git rev-parse --short HEAD)\",\"ts\":\"$(date -u '+%Y-%m-%dT%H:%M:%SZ')\"}" \
> web/data/deploy.json
fi
fi
# Ensure all containers are running
/usr/bin/docker compose up -d --remove-orphans 2>&1 | grep -v "up-to-date\|unchanged" || true

View file

@ -504,15 +504,13 @@
<a href="#step-06">06 &ndash; Scheduled Tasks</a>
<a href="#step-07">07 &ndash; BackInfo</a>
<a href="#step-08">08 &ndash; Aktivace Windows</a>
<hr class="sidebar-divider">
<h4>Planovane kroky</h4>
<a href="#step-pc">09 &ndash; PC identita + C:\X9</a>
<a href="#step-net">10 &ndash; Network discovery</a>
<a href="#step-dell">11 &ndash; Dell Command | Update</a>
<a href="#step-taskbar">Taskbar profily</a>
<a href="#step-09">09 &ndash; PC identita</a>
<a href="#step-10">10 &ndash; Network discovery</a>
<a href="#step-11">11 &ndash; Dell Command | Update</a>
<a href="#step-12">12 &ndash; Windows Update</a>
<hr class="sidebar-divider">
<h4>Architektura</h4>
<a href="#arch-xetup">xetup.exe (Go TUI)</a>
<a href="#arch-xetup">xetup.exe (Go GUI)</a>
<a href="#arch-spec">spec.yaml</a>
<hr class="sidebar-divider">
<a href="#new-requests">+ Novy pozadavek</a>
@ -523,7 +521,7 @@
<h1>Specifikace &amp; anotace</h1>
<div class="meta">
<span>Verze: 0.3-draft</span>
<span>Verze: 0.4</span>
<span>Datum: 2026-04-16</span>
<span><a href="https://git.xetup.x9.cz/x9/xetup">x9/xetup</a></span>
<span>Status: aktivni vyvoj</span>
@ -641,6 +639,9 @@
<tr class="flag-done"><td>OneDrive uninstall (intentional)</td><td>OneDriveSetup.exe /uninstall &ndash; odstrani pre-installed verzi. M365 si nainstaluje vlastni.</td></tr>
<tr class="flag-done"><td>Powercfg nastaveni (spotreba energie)</td><td>standby-ac 0, monitor-ac 60, standby-dc 30, monitor-dc 15</td></tr>
<tr class="flag-done"><td>Proxy auto-detect zakaz (AutoDetect = 0)</td><td>HKLM\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings</td></tr>
<tr class="flag-done"><td>Edge nova karta &ndash; zakaz rychlych odkazu</td><td>NewTabPageQuickLinksEnabled = 0</td></tr>
<tr class="flag-done"><td>Edge nova karta &ndash; zakaz pozadi</td><td>NewTabPageBackgroundEnabled = 0</td></tr>
<tr class="flag-done"><td>Edge nova karta &ndash; zakaz obsahu / feedu</td><td>NewTabPageAllowedBackgroundTypes = 3 (pouze plna barva)</td></tr>
</table>
</div>
<div class="step-footer">
@ -661,7 +662,7 @@
<tr class="flag-done"><td>Taskbar: zarovnat vlevo (TaskbarAl = 0)</td><td>Win11 default je center</td></tr>
<tr class="flag-done"><td>Taskbar: skryt Search, Copilot, Task View, Widgets, Chat</td><td>OK</td></tr>
<tr class="flag-done"><td>Taskbar: zobrazit vsechny ikonky v tray (Scheduled task)</td><td>ShowAllTrayIcons</td></tr>
<tr class="flag-done"><td>Taskbar: vyprazdnit pinlist (TaskbarLayoutModification.xml)</td><td>OK</td></tr>
<tr class="flag-done"><td>Taskbar: explicitni pinlist (TaskbarLayoutModification.xml)</td><td>default/user: Pruzkumnik + Edge; admin: Pruzkumnik + Edge + PowerShell. <code>PinListPlacement="Replace"</code> &ndash; prazdny seznam by dovoloval Windows pridat Store a dalsi vychozi.</td></tr>
<tr class="flag-done"><td>Explorer: zobrazovat pripony souboru (HideFileExt = 0)</td><td>OK</td></tr>
<tr class="flag-done"><td>Explorer: otevrit na This PC (LaunchTo = 1)</td><td>OK</td></tr>
<tr class="flag-done"><td>Start menu: vyprazdnit piny (Win11)</td><td>ConfigureStartPins = {"pinnedList":[]}</td></tr>
@ -701,6 +702,7 @@
<tr class="flag-done"><td>Accent barva na Start a taskbaru: ano</td><td>OK</td></tr>
<tr class="flag-done"><td>Pruhlednost: vypnuta</td><td>OK</td></tr>
<tr class="flag-done"><td>Tapeta: jednobarevna #223B47 (bez obrazku)</td><td>BackInfo prepise tapetu svym BMP</td></tr>
<tr class="flag-done"><td>Wallpaper="" v default hive (oprava cerne tapety)</td><td>Bez tohoto klice novy uzivatel zdedi neplatnou cestu k tapete a dostane cernou plochu. Prazdny retezec = solid barva z <code>Control Panel\Colors\Background</code></td></tr>
</table>
<div class="note">
BackInfo.exe (STEP 07) prepise tapetu BMP se systemovymi informacemi.
@ -785,37 +787,8 @@
</div>
</div>
<!-- STEP 11 -->
<div class="step" id="step-dell">
<div class="step-header">
<span class="step-num">11</span>
<span class="step-title">Dell Command | Update</span>
<span class="badge badge-ok">OK</span>
</div>
<div class="step-body">
<table class="items">
<tr class="flag-done"><td>Detekce Dell hardware (<code>Win32_ComputerSystem</code>)</td><td>Non-Dell stroj krok preskoci bez chyby &ndash; stejny skript pro vsechny HW</td></tr>
<tr class="flag-done"><td>Instalace Dell Command | Update via winget</td><td><code>Dell.CommandUpdate.Universal</code> &ndash; silent, Win10 + Win11</td></tr>
<tr class="flag-done"><td>Spusteni vsech aktualizaci: drivery, firmware, BIOS</td><td><code>dcu-cli.exe /applyUpdates -silent -reboot=disable</code></td></tr>
<tr class="flag-done"><td>BIOS/firmware se staging &ndash; dokonci se pri restartu</td><td>Restart po konci deploymenty (krok 10 rename) vse dokonci</td></tr>
</table>
<div class="note">
Non-Dell stroje: krok se preskoci automaticky, zadna chyba. Dell Latitude, OptiPlex,
Precision, Vostro, XPS &ndash; vsechny podporovane DCU Universal.<br><br>
<strong>Casova narocnost:</strong> 5&ndash;20 minut podle poctu dostupnych aktualizaci a rychlosti siteho pripojeni.
</div>
</div>
<div class="step-footer">
<span class="step-status">Script: <code>11-dell-update.ps1</code></span>
<div class="comment-widget" data-issue="16"></div>
</div>
</div>
<!-- ============================================================ -->
<p class="section-label">Nove kroky (planovane)</p>
<!-- STEP 09 -->
<div class="step" id="step-pc">
<div class="step" id="step-09">
<div class="step-header">
<span class="step-num">09</span>
<span class="step-title">PC identita &ndash; Rename + C:\X9</span>
@ -823,13 +796,13 @@
</div>
<div class="step-body">
<table class="items">
<tr class="flag-done"><td>Rename-Computer dle parametru z TUI nebo config.json</td><td><code>deployment.pcName</code> v config.json; preskoci pokud neni nastaveno</td></tr>
<tr class="flag-done"><td>Rename-Computer dle parametru z GUI nebo config.json</td><td><code>deployment.pcName</code> v config.json; preskoci pokud neni nastaveno</td></tr>
<tr class="flag-done"><td>Nastavit popis pocitace (Computer Description)</td><td>LanmanServer\Parameters\SrvComment; default "X9 deployment"</td></tr>
<tr class="flag-done"><td>Vytvorit <code>C:\X9\</code> adresarovou strukturu</td><td>C:\X9\Logs, Scripts, Assets</td></tr>
<tr class="flag-done"><td>Vlastni ikonka pro <code>C:\X9\</code> slozku</td><td>Desktop.ini + X9-ikona.ico z assets\Logo\</td></tr>
</table>
<div class="note">
Rename-Computer vyzaduje restart. Tento krok bezi jako posledni pred finalnim shrnutim.
Rename-Computer vyzaduje restart. Tento krok bezi jako posledni pred finalnim shrnutim &ndash; po nem nasleduje automaticky odpocet a restart v GUI.
</div>
</div>
<div class="step-footer">
@ -839,7 +812,7 @@
</div>
<!-- STEP 10 -->
<div class="step" id="step-net">
<div class="step" id="step-10">
<div class="step-header">
<span class="step-num">10</span>
<span class="step-title">Network discovery + firewall</span>
@ -858,7 +831,59 @@
</div>
</div>
<!-- TASKBAR -->
<!-- STEP 11 -->
<div class="step" id="step-11">
<div class="step-header">
<span class="step-num">11</span>
<span class="step-title">Dell Command | Update</span>
<span class="badge badge-ok">OK</span>
</div>
<div class="step-body">
<table class="items">
<tr class="flag-done"><td>Detekce Dell hardware (<code>Win32_ComputerSystem</code>)</td><td>Non-Dell stroj krok preskoci bez chyby &ndash; stejny skript pro vsechny HW</td></tr>
<tr class="flag-done"><td>Instalace Dell Command | Update via winget</td><td><code>Dell.CommandUpdate.Universal</code> &ndash; silent, Win10 + Win11</td></tr>
<tr class="flag-done"><td>Spusteni vsech aktualizaci: drivery, firmware, BIOS</td><td><code>dcu-cli.exe /applyUpdates -silent -reboot=disable</code></td></tr>
<tr class="flag-done"><td>BIOS/firmware se staging &ndash; dokonci se pri restartu</td><td>Restart na konci deploymetu vse dokonci</td></tr>
</table>
<div class="note">
Non-Dell stroje: krok se preskoci automaticky, zadna chyba. Dell Latitude, OptiPlex,
Precision, Vostro, XPS &ndash; vsechny podporovane DCU Universal.<br><br>
<strong>Casova narocnost:</strong> 5&ndash;20 minut podle poctu dostupnych aktualizaci a rychlosti sitoveho pripojeni.
</div>
</div>
<div class="step-footer">
<span class="step-status">Script: <code>11-dell-update.ps1</code></span>
<div class="comment-widget" data-issue="16"></div>
</div>
</div>
<!-- STEP 12 -->
<div class="step" id="step-12">
<div class="step-header">
<span class="step-num">12</span>
<span class="step-title">Windows Update</span>
<span class="badge badge-ok">OK</span>
</div>
<div class="step-body">
<table class="items">
<tr class="flag-done"><td>Instalace NuGet providera + PSWindowsUpdate modulu ze PSGallery</td><td>Install-PackageProvider + Install-Module PSWindowsUpdate -Force</td></tr>
<tr class="flag-done"><td>Prvni pruchod aktualizaci (bez rebootu)</td><td>Install-WindowsUpdate -AcceptAll -IgnoreReboot</td></tr>
<tr class="flag-done"><td>X9-WindowsUpdate scheduled task &ndash; pokracovani po restartu</td><td>Bezi pri kazdem logonu jako SYSTEM; po pruchodu bez novych update se task sam smaze</td></tr>
<tr class="flag-done"><td>Automaticky restart po skonceni deploymetu (GUI odpocet)</td><td>xetup.exe zobrazi 60s odpocet + tlacitka "Restartovat ted" / "Zrusit restart"</td></tr>
</table>
<div class="note">
Windows Update typicky vyzaduje vice restartovacich kolu. Prvni pruchod probehne behem deploymetu,
dalsi kola zaridti scheduled task, ktery se po dokonceni sam odregistruje.<br><br>
<strong>Pozor:</strong> Prvni restart spusti jak Windows Update task, tak Dell firmware staging (krok 11).
</div>
</div>
<div class="step-footer">
<span class="step-status">Script: <code>12-windows-update.ps1</code></span>
<div class="comment-widget" data-issue="17"></div>
</div>
</div>
<!-- TASKBAR PROFILY - detail implementace kroku 04 -->
<div class="step" id="step-taskbar">
<div class="step-header">
<span class="step-num">04+</span>
@ -868,14 +893,13 @@
</div>
<div class="step-body">
<table class="items">
<tr class="flag-done"><td><code>-ProfileType</code> parametr: admin vs user varianta</td><td>Deploy-Windows.ps1 -ProfileType [default|admin|user]; predano do 04</td></tr>
<tr class="flag-done"><td>XML layout pro "admin": Explorer, PS, Edge</td><td>TaskbarLayoutModification.xml; File Explorer.lnk + PowerShell.lnk + Edge.lnk</td></tr>
<tr class="flag-done"><td>XML layout pro "user": Explorer, Edge</td><td>Konzervativni sada &ndash; Outlook/Teams pridany az po instalaci M365</td></tr>
<tr class="flag-done"><td><code>-ProfileType</code> parametr: default / admin / user</td><td>Parametr GUI nebo config.json; predano do skriptu 04</td></tr>
<tr class="flag-done"><td>XML layout pro "default" a "user": Pruzkumnik + Edge</td><td><code>PinListPlacement="Replace"</code> &ndash; explicitni seznam zamezuje pridani Store a dalsich vychozich appek</td></tr>
<tr class="flag-done"><td>XML layout pro "admin": Pruzkumnik + Edge + PowerShell</td><td>TaskbarLayoutModification.xml; PowerShell.lnk z System32</td></tr>
<tr class="flag-open"><td>Win11 24H2 kompatibilita layoutu</td><td>24H2 vyzaduje ProvisionedLayoutModification.xml &ndash; nutno otestovat na realne instalaci</td></tr>
</table>
<div class="note">
Aplikace pinnutych appek: <code>Deploy-Windows.ps1 -ProfileType admin</code> nebo <code>-ProfileType user</code>.<br>
Layout se zablokuje, UnlockStartLayout task (krok 06) ho odemkne 5 min po startu.
Layout se pri aplikaci zamkne. UnlockStartLayout task (krok 06) ho odemkne 5 min po startu, aby uzivatel mohl dale upravovat.
</div>
</div>
<div class="step-footer">
@ -885,35 +909,37 @@
</div>
<!-- ============================================================ -->
<p class="section-label">Architektura (budoucnost)</p>
<p class="section-label">Architektura</p>
<!-- ARCH XETUP -->
<div class="step" id="arch-xetup">
<div class="step-header">
<span class="step-num">Arc</span>
<span class="step-title">xetup.exe &ndash; Go TUI launcher</span>
<span class="badge badge-future">Future</span>
<span class="step-title">xetup.exe &ndash; Go GUI (Walk / Win32)</span>
<span class="badge badge-ok">OK</span>
</div>
<div class="step-body">
<table class="items">
<tr class="flag-done"><td>Single binary (go:embed scripty + assets)</td><td><code>embed.go</code> + <code>cmd/xetup/main.go</code>; builduje se jako 5 MB .exe</td></tr>
<tr class="flag-done"><td>TUI form (huh/bubbletea): PC name, popis, product key</td><td><code>internal/tui/tui.go</code> &ndash; huh form, 2 stranky</td></tr>
<tr class="flag-done"><td>Checklist kroku (on/off per-script) + ulozit do config.json</td><td>MultiSelect v TUI; <code>internal/config/config.go</code></td></tr>
<tr class="flag-done"><td>Live log output behem spousteni PS scriptu</td><td><code>internal/runner/runner.go</code>; channel + bubbletea cmd</td></tr>
<tr class="flag-done"><td>Finalni summary OK/ERROR</td><td>viewDone() v tui.go</td></tr>
<tr class="flag-todo"><td>Self-update: stahnout novou verzi z xetup.x9.cz</td><td>Overit hash pred spustenim</td></tr>
<tr class="flag-future"><td>config.json: per-klient preset (prefix jmena PC, SW, klic)</td><td>Lezi vedle .exe na USB klienta</td></tr>
<tr class="flag-future"><td>OpenVPN soubor + doménovy join + domén. uzivatel pro profil</td><td>Rozsireni TUI formulare v budoucnu</td></tr>
<tr class="flag-done"><td>Single binary (go:embed scripty + assets)</td><td><code>embed.go</code> + <code>cmd/xetup/main.go</code>; ~5 MB .exe, zadne externi zavislosti</td></tr>
<tr class="flag-done"><td>Walk GUI &ndash; Win32 nativni ovladky, bez OpenGL</td><td>Funguje na VMware ESXi / SVGA II (Fyne/OpenGL nefungovalo). <code>internal/gui/gui.go</code></td></tr>
<tr class="flag-done"><td>Formular: PC jmeno, popis, product key, profil</td><td>Faze 1 &ndash; config form pred spustenim</td></tr>
<tr class="flag-done"><td>Checklist kroku (on/off per-feature) + nacist / ulozit config.json</td><td>Tlacitka "Nacist config..." a "Ulozit config..." pro per-klient presety</td></tr>
<tr class="flag-done"><td>Live log + prubehovy strip kroku (0&ndash;12)</td><td>Barevne indikatory: · cekajici, &#x25ba; bezici (modra), &#x2713; OK (zelena), &#x2717; chyba (cervena)</td></tr>
<tr class="flag-done"><td>Summary s odpoctem a automatickym restartem</td><td>Faze 3 &ndash; 60s odpocet, tlacitka "Restartovat ted" / "Zrusit restart"</td></tr>
<tr class="flag-done"><td>UAC requireAdministrator (app.manifest + rsrc)</td><td>Windows vyzada elevaci pri spusteni; ComCtl32 v6 + DPI awareness</td></tr>
<tr class="flag-done"><td>PowerShell okno skryte na pozadi</td><td>SysProcAttr.HideWindow = true; PS chyby filtrovane (At line:, CategoryInfo atd.)</td></tr>
<tr class="flag-todo"><td>Self-update: stahnout novou verzi z xetup.x9.cz/dl</td><td>Overit hash pred spustenim</td></tr>
<tr class="flag-future"><td>config.json: per-klient preset na USB</td><td>Jmeno PC prefix, SW seznam, klic &ndash; lezi vedle .exe</td></tr>
</table>
<div class="note">
<strong>Struktura:</strong> <code>cmd/xetup/</code>, <code>internal/config/</code>,
<code>internal/spec/</code>, <code>internal/tui/</code>, <code>internal/runner/</code><br><br>
<strong>Go zavislosti:</strong>
bubbletea (TUI framework), huh (forms), lipgloss (styling)
<strong>Struktura:</strong> <code>cmd/xetup/</code>, <code>internal/config/</code>, <code>internal/gui/</code>, <code>internal/runner/</code><br><br>
<strong>Go zavislosti:</strong> github.com/lxn/walk (Win32 GUI), golang.org/x/sys<br><br>
<strong>Build:</strong> <code>GOOS=windows GOARCH=amd64 go build -ldflags="-H windowsgui" ./cmd/xetup/</code><br>
CI (Forgejo Actions) sestavi a publikuje automaticky pri kazdem push na main.
</div>
</div>
<div class="step-footer">
<span class="step-status">Status: v implementaci &ndash; <code>cmd/xetup/</code>, <code>internal/{config,runner,tui}/</code></span>
<span class="step-status">Status: v provozu &ndash; <a href="https://xetup.x9.cz/dl" style="color:var(--blue)">xetup.x9.cz/dl</a></span>
<div class="comment-widget" data-issue="11"></div>
</div>
</div>
@ -989,6 +1015,8 @@
<a href="https://git.xetup.x9.cz/x9/xetup">Forgejo</a>
&nbsp;&middot;&nbsp;
<a href="/">xetup.x9.cz</a>
&nbsp;&middot;&nbsp;
web: <span id="deploy-sha" style="font-family:monospace">...</span>
</footer>
<script>
@ -1129,10 +1157,11 @@
'step-05': '05-personalization',
'step-06': '06-scheduled-tasks',
'step-07': '07-backinfo',
'step-pc': '09-pc-identity',
'step-net': '10-network',
'step-08': '08-activation',
'step-dell': '11-dell-update',
'step-09': '09-pc-identity',
'step-10': '10-network',
'step-11': '11-dell-update',
'step-12': '12-windows-update',
};
function getItemDesc(stepId, slug) {
@ -1349,6 +1378,19 @@
})();
enhanceRows();
// Show deployed commit in footer
fetch('/data/deploy.json')
.then(r => r.json())
.then(d => {
const el = document.getElementById('deploy-sha');
if (el && d.sha) {
const ts = d.ts ? ' (' + new Date(d.ts).toLocaleString('cs-CZ', {day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'}) + ')' : '';
el.textContent = d.sha + ts;
el.title = d.ts || '';
}
})
.catch(() => {});
})();
</script>
</body>