Add Codex as read-only reviewer, retry blocked video autoplay
scripts/codex-review.ps1 lets the Codex CLI review a state read-only in a clean git worktree without .env or var/, as in Domira: by default everything since the last release tag, or -Seit, -Commit, -Offen, -Alles. The final answer is also saved under reports/. Review rules for KantSites live in scripts/codex-review-prompt.md; README and AGENTS.md describe the workflow. video.js: when the browser refuses to start a loop (NotAllowedError), the first touch or key press starts it; a click on the pause button only counts as that button's own decision. ADR on videos updated. Luximmo seed: Instagram and Facebook profiles in the footer, icons instead of numbers in the process steps, services as subgrid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6e18a476c2
commit
4a33090905
8 files changed
+168
-18
No files matched your search
@@ -0,0 +1,13 @@
|
||||
Du prüfst Code von KantSites, einem selbst betriebenen CMS für Kundenwebsites (PHP 8.4, Symfony, Doctrine, Twig, SQLite oder MySQL/MariaDB, Shared Hosting ohne Node). Die Regeln stehen in AGENTS.md, Entscheidungen in docs/ARCHITECTURE.md. Zusätzlich gilt: keine nativen Browser-Dialoge (`confirm()`, `alert()`, `prompt()`); Rückfragen laufen über einen Dialog der Anwendung.
|
||||
|
||||
Ändere nichts. Melde nur echte Fehler, bei denen du ein konkretes Fehlerszenario benennen kannst:
|
||||
|
||||
1. Sicherheit: Umgehung von Anmeldung oder Rollen in der Verwaltung, fehlende Rechteprüfung, CSRF, XSS (zum Beispiel `|raw` in Twig, Inhalte aus Blöcken, Formularen oder Plugins), offene Redirects, Pfadmanipulation bei Uploads, Medien, Inhaltspaketen und Updater, Verstöße gegen die Schutzkopfzeilen.
|
||||
2. Korrektheit: Logikfehler beim Speichern, Publizieren und Laden von Seiten, Verlust von Entwürfen, nicht erkannte veraltete Schreibzugriffe (`StaleWrite`), fehlerhafte Migrationen von Dokumentschema oder Datenbank, Unterschiede zwischen SQLite und MySQL, veralteter Cache nach dem Publizieren, Fehler in der Übersetzungsebene, im Formularversand und im Updater.
|
||||
3. Öffentliche Ausgabe: Editorcode im öffentlichen Paket, fehlender Hauptinhalt im HTML, Rückschritte bei Barrierefreiheit (fehlende Beschriftungen, Tastaturbedienung, Kontrast), Leistung (LCP, CLS, render-blockierende Ressourcen) und SEO (Canonical, Sitemap, strukturierte Daten).
|
||||
4. Fehlende Tests für riskante Pfade.
|
||||
5. Verstöße gegen die Regeln in AGENTS.md, zum Beispiel native Browser-Dialoge.
|
||||
|
||||
Keine Stilfragen, keine Vorschläge für Refactorings. Die Skripte `scripts/seed-*.php` und `scripts/reset-*.sh` bauen Referenzwebsites mit absichtlich festen Inhalten auf. Ignoriere `vendor/`, `node_modules/`, `public/assets/build/`, `public/assets/fonts/`, `composer.lock` und `package-lock.json`.
|
||||
|
||||
Antworte auf Deutsch. Für jeden Befund: Datei und Zeile, Schwere (hoch, mittel, niedrig), konkretes Fehlerszenario, Vorschlag zur Behebung. Wenn nichts zu melden ist, sag das in einem Satz.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Laesst Codex einen Stand pruefen, nur lesend und in einer sauberen Kopie ohne .env.
|
||||
# Die Datei bleibt reines ASCII, weil Windows PowerShell 5.1 sonst Umlaute falsch liest.
|
||||
# .\scripts\codex-review.ps1 alles seit dem letzten Release-Tag
|
||||
# .\scripts\codex-review.ps1 -Seit v1.42.0 alles seit einem Tag oder Commit
|
||||
# .\scripts\codex-review.ps1 -Commit <sha> einen einzelnen Commit
|
||||
# .\scripts\codex-review.ps1 -Offen die noch nicht committeten Aenderungen
|
||||
# .\scripts\codex-review.ps1 -Alles den gesamten Code
|
||||
param(
|
||||
[string]$Seit = "",
|
||||
[string]$Commit = "",
|
||||
[switch]$Offen,
|
||||
[switch]$Alles
|
||||
)
|
||||
|
||||
$utf8 = New-Object System.Text.UTF8Encoding $false
|
||||
$OutputEncoding = $utf8
|
||||
[Console]::OutputEncoding = $utf8
|
||||
|
||||
$repo = (git rev-parse --show-toplevel).Trim()
|
||||
$regeln = Get-Content -Raw -Encoding UTF8 (Join-Path $repo "scripts\codex-review-prompt.md")
|
||||
$ziel = if ($Commit) { $Commit } else { "HEAD" }
|
||||
|
||||
if ($Alles) {
|
||||
$umfang = "Scope: the whole code under src/, templates/, public/assets/ (without build/ and fonts/), plugins/, migrations/, config/ and zentrale/."
|
||||
} elseif ($Commit) {
|
||||
$umfang = "Scope: the changes from: git show $Commit"
|
||||
} elseif ($Offen) {
|
||||
$umfang = "Scope: the uncommitted changes, visible with: git diff HEAD (new untracked files are not included)."
|
||||
} else {
|
||||
if (-not $Seit) { $Seit = (git -C $repo describe --tags --abbrev=0 HEAD).Trim() }
|
||||
if ($LASTEXITCODE -ne 0 -or -not $Seit) { Write-Error "Kein Release-Tag gefunden, bitte -Seit angeben."; exit 1 }
|
||||
$umfang = "Scope: the changes from: git diff $Seit..HEAD"
|
||||
}
|
||||
Write-Host $umfang
|
||||
|
||||
$kopie = Join-Path $env:TEMP ("kantsites-review-" + [guid]::NewGuid().ToString("N").Substring(0, 8))
|
||||
|
||||
git -C $repo worktree add --quiet --detach $kopie $ziel
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
|
||||
try {
|
||||
if ($Offen) {
|
||||
$patch = Join-Path $env:TEMP ("kantsites-review-" + [guid]::NewGuid().ToString("N").Substring(0, 8) + ".patch")
|
||||
git -C $repo diff HEAD --binary --output="$patch"
|
||||
if ((Get-Item $patch).Length -eq 0) { Write-Host "Keine offenen Aenderungen."; Remove-Item $patch; exit 0 }
|
||||
git -C $kopie apply --whitespace=nowarn "$patch"
|
||||
$angewendet = $LASTEXITCODE
|
||||
Remove-Item $patch
|
||||
if ($angewendet -ne 0) { Write-Error "Offene Aenderungen liessen sich nicht in die Kopie uebernehmen."; exit $angewendet }
|
||||
}
|
||||
$berichte = Join-Path $repo "reports"
|
||||
if (-not (Test-Path $berichte)) { New-Item -ItemType Directory $berichte | Out-Null }
|
||||
$bericht = Join-Path $berichte ("codex-review-" + (Get-Date -Format "yyyy-MM-dd-HHmm") + ".md")
|
||||
"$umfang`n`n$regeln" | codex exec --sandbox read-only --ephemeral --cd $kopie --output-last-message $bericht -
|
||||
$status = $LASTEXITCODE
|
||||
if (Test-Path $bericht) {
|
||||
Write-Host "`n===== Ergebnis (auch in $bericht) ====="
|
||||
Get-Content -Raw -Encoding UTF8 $bericht | Write-Host
|
||||
}
|
||||
} finally {
|
||||
git -C $repo worktree remove --force $kopie
|
||||
}
|
||||
exit $status
|
||||
+27
-13
@@ -494,6 +494,11 @@ $fuss = [
|
||||
$column('fuss-marke', [
|
||||
['id' => 'fuss-logo', 'type' => 'html', 'props' => ['html' => $logoSvg('role="img" aria-label="'.$marke.'"')], 'style' => ['desktop' => ['width' => '96px', 'maxWidth' => '96px', 'margin' => $seiten('0px')]], 'css' => $logoCss],
|
||||
$text('fuss-spruch', 'Ihr neuer Immobilienpartner vor Ort. Ein Lichtblick für Ihre Immobilie.', ['desktop' => ['fontSize' => '15px', 'lineHeight' => 1.6, 'color' => '@text', 'maxWidth' => '280px', 'margin' => ['top' => '20px', 'bottom' => '0px']], 'mobile' => ['maxWidth' => 'none']]),
|
||||
// Adressen aus Einstellungen → Unternehmensdaten → Soziale Profile; ohne Eintrag
|
||||
// bleibt der Baustein unsichtbar.
|
||||
['id' => 'fuss-profile', 'type' => 'social', 'props' => ['size' => 20, 'shape' => 'circle', 'layout' => 'horizontal', 'labels' => false, 'networks' => ['instagram', 'facebook']],
|
||||
'style' => ['desktop' => ['margin' => ['top' => '22px', 'bottom' => '0px']]],
|
||||
'css' => "& a{color:#141414;border:1px solid #E6DED2;transition:background-color .2s,color .2s,border-color .2s}\n& a:hover{background:#141414;color:#fff;border-color:#141414}"],
|
||||
]),
|
||||
$column('fuss-anschrift', [
|
||||
$kleinzeile('fuss-anschrift-titel', 'Adresse', '@gold-dunkel', '8px'),
|
||||
@@ -543,6 +548,8 @@ $vorteil = static fn (int $n, string $icon, string $titel, string $satz) => $col
|
||||
"transition:transform .3s ease,background-color .3s ease\n&:hover{transform:translateY(-4px);background-color:#F2ECE2}");
|
||||
|
||||
/** Eine Leistung: Foto, Titel, Satz, aufklappbar „Was dazugehört“. */
|
||||
// Die vier Teile liegen als Subgrid auf gemeinsamen Zeilen des Rasters: Die Aufklapp-Linien stehen so
|
||||
// auf einer Höhe, auch bei ungleich langen Sätzen, und ein geöffneter Eintrag verschiebt die anderen nicht.
|
||||
$leistung = static function (string $id, array $foto, string $alt, string $titel, string $satz, array $punkte) use ($column, $bild, $heading, $text, $nurOben): array {
|
||||
return $column($id, [
|
||||
$bild($id.'-bild', $foto, $alt, [
|
||||
@@ -551,7 +558,7 @@ $leistung = static function (string $id, array $foto, string $alt, string $titel
|
||||
'mobile' => ['imageHeight' => '260px'],
|
||||
], null, "overflow:hidden;border-radius:24px\n& img{display:block;width:100%;transition:transform .6s ease}\n&:hover img{transform:scale(1.04)}"),
|
||||
$heading($id.'-titel', $titel, 3, ['desktop' => ['fontSize' => '24px', 'fontWeight' => '500', 'letterSpacing' => '-0.02em', 'color' => '@tinte', 'margin' => ['top' => '0px', 'bottom' => '6px']]]),
|
||||
$text($id.'-satz', $satz, ['desktop' => ['fontSize' => '17px', 'lineHeight' => 1.55, 'color' => '@text', 'margin' => ['bottom' => '0px']]]),
|
||||
$text($id.'-satz', $satz, ['desktop' => ['fontSize' => '17px', 'lineHeight' => 1.55, 'color' => '@text', 'margin' => ['bottom' => '0px']]], 'overflow-wrap:break-word'),
|
||||
['id' => $id.'-mehr', 'type' => 'accordion', 'props' => ['faq' => false],
|
||||
'style' => ['desktop' => ['borderWidth' => $nurOben('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie', 'margin' => ['top' => '20px']]],
|
||||
'children' => [
|
||||
@@ -564,13 +571,17 @@ $leistung = static function (string $id, array $foto, string $alt, string $titel
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
], ['tablet' => ['padding' => ['bottom' => '56px']]], 'display:grid;grid-row:span 4;grid-template-rows:subgrid;grid-template-columns:minmax(0,1fr);row-gap:0');
|
||||
};
|
||||
|
||||
/** Ein Schritt des Wechsels: große Ziffer in Gold, Titel, Satz. */
|
||||
$schritt = static fn (int $n, string $titel, string $satz) => $column('schritt-'.$n, [
|
||||
$text('schritt-'.$n.'-nummer', '0'.$n, ['desktop' => ['fontSize' => '15px', 'fontWeight' => '500', 'letterSpacing' => '0.08em', 'color' => '@gold-dunkel', 'margin' => ['bottom' => '28px']]],
|
||||
"display:flex;align-items:center;gap:12px\n&::after{content:'';flex:1;height:1px;background:#E6DED2}"),
|
||||
/** Ein Schritt des Wechsels: Symbol im weißen Kreis mit Linie zum nächsten Schritt, Titel, Satz. */
|
||||
$schritt = static fn (int $n, string $icon, string $titel, string $satz) => $column('schritt-'.$n, [
|
||||
$column('schritt-'.$n.'-kopf', [
|
||||
$column('schritt-'.$n.'-kreis', [$symbol('schritt-'.$n.'-icon', $icon, 24, ['desktop' => ['color' => '@gold-dunkel']])], ['desktop' => [
|
||||
'display' => 'flex', 'alignItems' => 'center', 'justifyContent' => 'center', 'flexShrink' => 0, 'width' => '52px', 'height' => '52px', 'backgroundColor' => '@papier', 'borderRadius' => $rund('50%'),
|
||||
]]),
|
||||
], ['desktop' => ['display' => 'flex', 'alignItems' => 'center', 'gap' => '12px', 'margin' => ['bottom' => '24px']]],
|
||||
"&::after{content:'';flex:1;height:1px;background:#E6DED2}"),
|
||||
$heading('schritt-'.$n.'-titel', $titel, 3, ['desktop' => ['fontSize' => '22px', 'fontWeight' => '500', 'letterSpacing' => '-0.015em', 'color' => '@tinte', 'margin' => ['top' => '0px', 'bottom' => '10px']]]),
|
||||
$text('schritt-'.$n.'-satz', $satz, ['desktop' => ['fontSize' => '16px', 'lineHeight' => 1.6, 'color' => '@text', 'margin' => ['bottom' => '0px']]]),
|
||||
]);
|
||||
@@ -660,7 +671,7 @@ $startseite = [
|
||||
'Marktgerechte Bewertung',
|
||||
'Persönliche Begleitung bis zum erfolgreichen Verkauf',
|
||||
]),
|
||||
$leistung('leistung-weg', $medien['weg'], 'Wohnanlage mit mehreren Gebäuden und grünem Innenhof', 'WEG-Verwaltung', 'Strukturierte, transparente und zuverlässige Verwaltung von Wohnungseigentümergemeinschaften.', [
|
||||
$leistung('leistung-weg', $medien['weg'], 'Wohnanlage mit mehreren Gebäuden und grünem Innenhof', 'WEG-Verwaltung', "Strukturierte, transparente und zuverlässige Verwaltung von Wohnungseigentümer\u{AD}gemeinschaften.", [
|
||||
'Eigentümerversammlung vorbereiten, leiten, protokollieren',
|
||||
'Beschlüsse umsetzen und Beschlusssammlung führen',
|
||||
'Wirtschaftsplan und Jahresabrechnung',
|
||||
@@ -682,8 +693,9 @@ $startseite = [
|
||||
'Übergaben und Wohnungsabnahmen',
|
||||
]),
|
||||
], [
|
||||
'desktop' => ['display' => 'grid', 'gridColumns' => 4, 'columnGap' => '28px', 'rowGap' => '56px', 'alignItems' => 'flex-start'],
|
||||
'tablet' => ['gridColumns' => 2],
|
||||
'desktop' => ['display' => 'grid', 'gridColumns' => 4, 'columnGap' => '28px', 'rowGap' => '0px'],
|
||||
// Der Abstand zwischen den Reihen sitzt in den Karten, ein Zeilenabstand läge zwischen ihren Teilen.
|
||||
'tablet' => ['gridColumns' => 2, 'margin' => ['bottom' => '-56px']],
|
||||
'mobile' => ['gridColumns' => 1],
|
||||
]),
|
||||
], $abschnitt('0px', '0px'), 'leistungen', '', 'wide'),
|
||||
@@ -699,10 +711,10 @@ $startseite = [
|
||||
'mobile' => ['margin' => ['bottom' => '40px']],
|
||||
]),
|
||||
$column('wechsel-raster', [
|
||||
$schritt(1, 'Anfrage', 'Sie schildern uns kurz Ihr Objekt – online in drei Schritten oder im Gespräch.'),
|
||||
$schritt(2, 'Kennenlernen', 'Wir sehen uns das Objekt vor Ort an und klären, was Ihnen wichtig ist.'),
|
||||
$schritt(3, 'Angebot', 'Sie erhalten ein klares Angebot mit allen Leistungen – ohne Kleingedrucktes.'),
|
||||
$schritt(4, 'Übergabe', 'Wir übernehmen Unterlagen, Konten und Verträge und informieren Mieter und Eigentümer.'),
|
||||
$schritt(1, 'mail', 'Anfrage','Sie schildern uns kurz Ihr Objekt – online in drei Schritten oder im Gespräch.'),
|
||||
$schritt(2, 'people', 'Kennenlernen','Wir sehen uns das Objekt vor Ort an und klären, was Ihnen wichtig ist.'),
|
||||
$schritt(3, 'document', 'Angebot','Sie erhalten ein klares Angebot mit allen Leistungen – ohne Kleingedrucktes.'),
|
||||
$schritt(4, 'key', 'Übergabe','Wir übernehmen Unterlagen, Konten und Verträge und informieren Mieter und Eigentümer.'),
|
||||
], [
|
||||
'desktop' => ['display' => 'grid', 'gridColumns' => 4, 'gap' => '40px'],
|
||||
'tablet' => ['gridColumns' => 2, 'rowGap' => '48px'],
|
||||
@@ -1134,6 +1146,8 @@ $settings->save([
|
||||
'organisationLogoMediaId' => $medien['logo']['id'],
|
||||
'faviconMediaId' => $medien['favicon']['id'],
|
||||
'stickyHeader' => false, 'headerOverlay' => false,
|
||||
// Instagram und Facebook stehen im Fuß; leer bleiben sie unsichtbar.
|
||||
'social' => ['instagram' => getenv('LUXIMMO_INSTAGRAM') ?: '', 'facebook' => getenv('LUXIMMO_FACEBOOK') ?: ''],
|
||||
'motion' => 'always',
|
||||
'homePath' => 'home', 'imprintPath' => 'impressum', 'privacyPath' => 'datenschutz',
|
||||
// Die Seite lädt nichts von Dritten; deshalb keine Einwilligungsleiste.
|
||||
|
||||
Reference in new issue
Block a user