Initial commit: Visigine (Vite client + Express/SQLite backend)

Container-ready via docker/ compose (frontend nginx + backend Node). Compose adjusted for Coolify on the prod server: frontend uses expose:80 (no host binding — host 8080 is taken by the Coolify proxy; Traefik routes visigine.de), backend ALLOWED_ORIGINS=https://visigine.de. Secrets stay in server/.env (git-ignored); see server/.env.example.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 10:06:48 +02:00
commit e344f1b7e7
88 changed files with 11764 additions and 0 deletions

82
server/checks/json-ld.js Normal file
View File

@@ -0,0 +1,82 @@
// Group C — schema.org / JSON-LD coverage. Validity is checked block-by-block;
// the remaining matches run against the concatenated raw string for resilience.
export function runJsonLdChecks({ jsonLdBlocks, jsonLdJoined }) {
const blocks = jsonLdBlocks || []
const jl = jsonLdJoined || ''
let validity = true
if (blocks.length > 0) {
validity = blocks.some((b) => {
try { JSON.parse(b); return true } catch { return false }
})
}
return [
{
id: 'jsonld.valid',
title: 'JSON-LD: ungültiges JSON',
severity: 'high',
passed: validity,
},
{
id: 'jsonld.organization',
title: 'JSON-LD: kein LocalBusiness/Organization',
severity: 'high',
passed: /"@type"\s*:\s*"?(LocalBusiness|Organization)/i.test(jl),
},
{
id: 'jsonld.faqpage',
title: 'JSON-LD: kein FAQPage-Schema',
severity: 'medium',
passed: jl.includes('FAQPage'),
},
{
id: 'jsonld.sameas',
title: 'JSON-LD: kein sameAs mit externen URLs',
severity: 'medium',
passed: /"sameAs"/.test(jl) && /https?:\/\//.test(jl),
},
{
id: 'jsonld.openinghours',
title: 'JSON-LD: keine Öffnungszeiten',
severity: 'medium',
passed: jl.includes('openingHours'),
},
{
id: 'jsonld.breadcrumb',
title: 'JSON-LD: keine BreadcrumbList',
severity: 'low',
passed: jl.includes('BreadcrumbList'),
},
{
id: 'jsonld.website',
title: 'JSON-LD: kein WebSite-Schema',
severity: 'low',
passed: /"@type"\s*:\s*"?WebSite/.test(jl),
},
{
id: 'jsonld.address',
title: 'JSON-LD: keine PostalAddress',
severity: 'medium',
passed: jl.includes('PostalAddress'),
},
{
id: 'jsonld.telephone',
title: 'JSON-LD: keine Telefonnummer im Schema',
severity: 'low',
passed: /"telephone"/.test(jl),
},
{
id: 'jsonld.service-product',
title: 'JSON-LD: kein Service- oder Product-Schema',
severity: 'low',
passed: /"@type"\s*:\s*"?(Service|Product)/i.test(jl),
},
{
id: 'jsonld.article',
title: 'JSON-LD: kein Article/BlogPosting-Schema',
severity: 'low',
passed: /"@type"\s*:\s*"?(Article|BlogPosting)/i.test(jl),
},
]
}