1.8.2 - Anpassungen am Bulk-System
release-tag / release-image (push) Successful in 1m40s

This commit is contained in:
2026-07-23 08:49:28 +02:00
parent 4439684e41
commit ec58fc30f8
19 changed files with 88 additions and 20 deletions
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## 1.8.2 - 2026-07-23
- Fixed the Bulk results view so it previews the same accessible badge-plus-visible-text disclosure used by the recommended `embedHtml` export.
- Renamed the raw badge link to `SVG (nur Grafik)` to make clear that the standalone SVG is only the visual asset and not the recommended first-exposure integration.
- Kept Bulk HTML exports unchanged on `embedHtml`; this release fixes the misleading preview/link presentation rather than introducing a second rendering path.
## 1.8.1 - 2026-07-23
- Added an accessible first-exposure embed with visible link text next to the SVG badge instead of relying on SVG/`alt` information alone.
+1 -1
View File
@@ -28,7 +28,7 @@ build-bulk:
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/ai-disclosure-bulk ./cmd/bulk
docker-build:
docker build -t ai-disclosure-standard:1.8.1-local .
docker build -t ai-disclosure-standard:1.8.2-local .
docker-build-bulk:
docker build -f Dockerfile.bulk -t ai-disclosure-bulk:1.0.0-local .
+1 -1
View File
@@ -1,4 +1,4 @@
# AI Disclosure Standard 1.8.1
# AI Disclosure Standard 1.8.2
Ein zustandsloser Go-Dienst für sichtbare und maschinenlesbare Erklärungen zur KI-Nutzung in Artikeln, Webseiten und einzelnen Inhaltsbestandteilen.
File diff suppressed because one or more lines are too long
+28 -2
View File
@@ -311,6 +311,30 @@
return {html, markdown, json, jsonl, csv};
}
function buildDisclosurePreview(data) {
const wrap = document.createElement('p');
wrap.className = 'bulk-disclosure-preview';
const link = document.createElement('a');
link.className = 'bulk-disclosure-preview__link';
link.href = data.declarationUrl;
link.target = '_blank';
link.rel = 'noopener';
const badge = document.createElement('img');
badge.className = 'bulk-disclosure-preview__badge';
badge.src = data.badgeUrl;
badge.alt = '';
badge.setAttribute('aria-hidden', 'true');
const text = document.createElement('span');
text.className = 'bulk-disclosure-preview__text';
text.textContent = data.accessibleText || 'KI-Nutzung Details zur Kennzeichnung';
link.append(badge, text);
wrap.appendChild(link);
return wrap;
}
function renderResults(results) {
currentResults = results;
exportsCache = buildExports(results);
@@ -326,14 +350,16 @@
const code = document.createElement('code');
code.textContent = item.subject;
subjectCell.appendChild(code);
const previewCell = document.createElement('td');
const statusCell = document.createElement('td');
statusCell.className = item.ok ? 'ok' : 'failed';
statusCell.textContent = item.ok ? '✓ erzeugt' : `Fehler: ${item.error || 'unbekannt'}`;
const linksCell = document.createElement('td');
if (item.ok && item.data) {
previewCell.appendChild(buildDisclosurePreview(item.data));
const links = document.createElement('div');
links.className = 'result-links';
[['Declaration', item.data.declarationUrl], ['JSON-LD', item.data.manifestUrl], ['Badge', item.data.badgeUrl]].forEach(([label, href]) => {
[['Declaration', item.data.declarationUrl], ['JSON-LD', item.data.manifestUrl], ['SVG (nur Grafik)', item.data.badgeUrl]].forEach(([label, href]) => {
const a = document.createElement('a');
a.textContent = label;
a.href = href;
@@ -343,7 +369,7 @@
});
linksCell.appendChild(links);
}
tr.append(subjectCell, statusCell, linksCell);
tr.append(subjectCell, previewCell, statusCell, linksCell);
tbody.appendChild(tr);
});
$('output-html').value = exportsCache.html;
+2 -2
View File
@@ -211,11 +211,11 @@
<button type="button" class="button secondary" data-download="csv">CSV herunterladen</button>
</div>
<p class="embed-note">Der HTML-Export ist die empfohlene Ein-Schritt-Integration: sichtbarer, tastaturerreichbarer Hinweis mit Text neben dem Badge plus eingebettetes JSON-LD. Das SVG ist dabei dekorativ; die zugängliche Bezeichnung stammt aus dem sichtbaren Linktext.</p>
<p class="embed-note">Der HTML-Export ist die empfohlene Ein-Schritt-Integration: sichtbarer, tastaturerreichbarer Hinweis mit Text neben dem Badge plus eingebettetes JSON-LD. Die Vorschau unten zeigt genau diese sichtbare Kennzeichnung. Der Link „SVG (nur Grafik)“ dient nur zum separaten Abruf der Bilddatei und ist nicht die empfohlene alleinstehende Integration.</p>
<div class="result-table-wrap">
<table class="result-table">
<thead><tr><th>Inhalt</th><th>Status</th><th>Links</th></tr></thead>
<thead><tr><th>Inhalt</th><th>Kennzeichnung</th><th>Status</th><th>Links</th></tr></thead>
<tbody id="result-rows"></tbody>
</table>
</div>
+1 -1
View File
@@ -25,7 +25,7 @@ spec:
type: RuntimeDefault
containers:
- name: app
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.1
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.2
imagePullPolicy: IfNotPresent
ports:
- name: http
+1 -1
View File
@@ -1,7 +1,7 @@
version: "3.9"
services:
app:
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.1
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.2
environment:
BASE_URL: https://ai.example.org
PUBLIC_NAME: AI Usage Disclosure
+1 -1
View File
@@ -1,6 +1,6 @@
# Mehrsprachige Hintergrundseite
Version 1.8.1 stellt unter `/background` eine eigenständige Informationsseite zur KI-Kennzeichnung und zu Artikel 50 des EU AI Act bereit.
Version 1.8.2 stellt unter `/background` eine eigenständige Informationsseite zur KI-Kennzeichnung und zu Artikel 50 des EU AI Act bereit.
## Routen
+1 -1
View File
@@ -16,7 +16,7 @@ Initialization is performed in `internal/app/server.go`. The product ID and embe
```go
licenses := licenseclient.New(ctx, licenseclient.Config{
Product: "ai-disclosure-standard",
ClientVersion: "1.8.1",
ClientVersion: "1.8.2",
Token: cfg.LicenseToken,
TrustStore: trustStore,
BaseURL: cfg.BaseURL,
+1 -1
View File
@@ -119,7 +119,7 @@ Anfrage:
"baseUrl": "https://ai.example.org",
"host": "ai.example.org",
"instanceId": "production-eu-1",
"clientVersion": "1.8.1"
"clientVersion": "1.8.2"
}
```
+1 -1
View File
@@ -9,7 +9,7 @@ import (
const (
ProductID = "ai-disclosure-standard"
ProductVersion = "1.8.1"
ProductVersion = "1.8.2"
FeatureCustomText = "custom_text"
FeatureCustomBadge = "custom_badge"
FeatureWhiteLabel = "white_label"
+1 -1
View File
@@ -18,7 +18,7 @@ import (
bulkweb "github.com/b1tsblog/ai-disclosure-standard/bulkweb"
)
const Version = "1.0.1"
const Version = "1.0.2"
type Server struct {
cfg Config
+34
View File
@@ -123,3 +123,37 @@ func TestRenderBatchHonoursConfiguredLimit(t *testing.T) {
t.Fatalf("status %d: %s", w.Code, w.Body.String())
}
}
func TestBulkUIUsesAccessibleDisclosurePreview(t *testing.T) {
h, err := New(Config{
ListenAddress: ":0", CoreInternalURL: "http://127.0.0.1:9",
DisclosureBaseURL: "https://public.example", GeneratorURL: "https://public.example",
PublicName: "Bulk", MaxURLs: 10, Workers: 1, RequestTimeout: time.Second,
}, testLogger())
if err != nil {
t.Fatal(err)
}
indexReq := httptest.NewRequest(http.MethodGet, "/", nil)
indexRes := httptest.NewRecorder()
h.ServeHTTP(indexRes, indexReq)
if indexRes.Code != http.StatusOK {
t.Fatalf("index status %d: %s", indexRes.Code, indexRes.Body.String())
}
if !strings.Contains(indexRes.Body.String(), "<th>Kennzeichnung</th>") {
t.Fatalf("bulk result table does not expose the disclosure preview column")
}
jsReq := httptest.NewRequest(http.MethodGet, "/static/bulk.js", nil)
jsRes := httptest.NewRecorder()
h.ServeHTTP(jsRes, jsReq)
if jsRes.Code != http.StatusOK {
t.Fatalf("bulk.js status %d: %s", jsRes.Code, jsRes.Body.String())
}
body := jsRes.Body.String()
for _, required := range []string{"buildDisclosurePreview", "accessibleText", "SVG (nur Grafik)"} {
if !strings.Contains(body, required) {
t.Fatalf("bulk.js missing accessible preview marker %q", required)
}
}
}
+2 -2
View File
@@ -183,13 +183,13 @@ func Build(lang, productName, baseURL, salesURL, contactURL string, prices Price
# Adjust BASE_URL and PUBLIC_NAME in .env
docker compose up -d --build
curl -fsS http://localhost:8080/readyz`},
{ID: "docker", Title: copy.InstallTitles[1], Summary: copy.InstallSummaries[1], Code: `docker build -t ai-disclosure-standard:1.8.1 .
{ID: "docker", Title: copy.InstallTitles[1], Summary: copy.InstallSummaries[1], Code: `docker build -t ai-disclosure-standard:1.8.2 .
docker run -d --name ai-disclosure \
-p 8080:8080 \
-e BASE_URL=https://ai.example.org \
-e PUBLIC_NAME="AI Usage Disclosure" \
--read-only --tmpfs /tmp \
ai-disclosure-standard:1.8.1`},
ai-disclosure-standard:1.8.2`},
{ID: "kubernetes", Title: copy.InstallTitles[2], Summary: copy.InstallSummaries[2], Code: `# Image, Domain und TLS-Secret in deploy/kubernetes.yaml ersetzen
kubectl create secret generic ai-disclosure-license \
--from-literal=token='...'
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: AI Usage Disclosure API
version: 1.8.1
version: 1.8.2
description: Stateless multilingual badge, declaration and validation API with optional licensed presentation capabilities.
servers:
- url: https://ai.example.org
+1 -1
View File
@@ -158,7 +158,7 @@
</section>
</main>
<footer><span>{{.Background.Footer}} · App 1.8.1 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
<footer><span>{{.Background.Footer}} · App 1.8.2 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
<script src="/static/marketing.js" defer></script>
</body>
</html>
+1 -1
View File
@@ -290,7 +290,7 @@
<article><p class="eyebrow">HA</p><h2>{{index .Text "api_stateless_title"}}</h2><p>{{index .Text "api_stateless_desc"}}</p></article>
</section>
</main>
<footer><span>AI Usage Disclosure · App 1.8.1 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
<footer><span>AI Usage Disclosure · App 1.8.2 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
<script nonce="{{.CSPNonce}}">window.APP_CONFIG={{.AppConfig}};</script>
<script src="/static/app.js" defer></script>
</body>
+1 -1
View File
@@ -119,7 +119,7 @@
</section>
</main>
<footer><span>{{.Marketing.Footer}} · App 1.8.1 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
<footer><span>{{.Marketing.Footer}} · App 1.8.2 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
<script src="/static/marketing.js" defer></script>
</body>
</html>