fix: add visibility check to getDocument/getTranslations endpoints

Non-public documents (internal, archived, confidential) were accessible
to unauthenticated users via direct slug/ID lookup. List and search
endpoints already filtered for visibility: 'public', but the individual
document endpoints did not. Added optionalAuth middleware and visibility
checks so non-public docs return 404 to public users while remaining
accessible to admin users.

Also adds Guardian Agents translations to village-case-study locale
files (DE, FR, MI) — 8 new keys per locale, flow step renumbered
6→7→8 with new Guardian Agents verification step at position 6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
TheFlow 2026-03-13 17:27:48 +13:00
parent 8b1527c5d8
commit 00d89ce095
5 changed files with 85 additions and 18 deletions

View file

@ -22,7 +22,7 @@
"ai_label": "AI-Modell:",
"ai_value": "Souveränes Lama (QLoRA feinabgestimmt)",
"features_label": "AI-Merkmale:",
"features_value": "4 geregelte Funktionen live",
"features_value": "5 geregelte Funktionen live",
"infra_label": "Infrastruktur:",
"infra_value": "NZ + EU (keine US-Abhängigkeit)"
}
@ -53,7 +53,7 @@
},
"flow": {
"heading": "Wie Governance in der Praxis funktioniert",
"intro": "Wenn ein Mitglied eine KI-Funktion nutzt, durchläuft die Anfrage sechs Governance-Prüfungen, bevor eine Antwort erzeugt wird. Jede Prüfung ist unabhängig und kann die Anfrage blockieren oder ändern.",
"intro": "Wenn ein Mitglied eine KI-Funktion nutzt, durchläuft die Anfrage sieben Governance-Prüfungen, bevor eine Antwort erzeugt wird. Jede Prüfung ist unabhängig und kann die Anfrage blockieren oder ändern.",
"steps": {
"1": {
"title": "Antrag eines Mitglieds erhalten",
@ -76,12 +76,16 @@
"desc": "Das souveräne Llama-Modell erzeugt eine Antwort unter Verwendung des RAG-Kontextes, gefiltert nach den Berechtigungen des Mitglieds. Die gesamte Verarbeitung bleibt in der Infrastruktur."
},
"6": {
"title": "Guardian Agents Verifizierung",
"desc": "Jede Tatsachenbehauptung in der Antwort wird anhand des Quellmaterials mittels Kosinusähnlichkeit von Embeddings überprüft — eine mathematische Messung, kein generatives Prüfen. Jede Behauptung erhält ein Vertrauensabzeichen, das für das Mitglied sichtbar ist."
},
"7": {
"title": "Überprüfung des Umfangs",
"desc": "Entspricht die Antwort dem, was angefordert wurde? Erkennt die Ausweitung des Umfangs und blockiert Antworten, die über die ursprüngliche Anfrage hinausgehen."
},
"7": {
"8": {
"title": "Lieferung mit Namensnennung",
"desc": "Die Antwort wird dem Mitglied mit Quellenangabe zugestellt. Jeder Schritt wird für die Prüfung protokolliert."
"desc": "Antwort an das Mitglied mit Vertrauensabzeichen, Quellenangabe und transparenter Argumentation. Jeder Schritt wird protokolliert."
}
}
},
@ -106,6 +110,13 @@
"title": "AI-Speicher-Transparenz",
"benefit": "Mitglieder können sehen, bearbeiten und löschen, was sich die KI über sie \"merkt\". Das vollständige Audit-Dashboard zeigt jede KI-Interaktion an.",
"governance": "Steuerung: Zustimmung mehrerer Interessengruppen erforderlich. Persistenzentscheidungen werden klassifiziert und sind überprüfbar. Die Mitglieder kontrollieren ihre eigenen Daten."
},
"guardian": {
"title": "Guardian Agents",
"badge": "NEW",
"benefit": "Jede KI-Antwort wird anhand des Quellmaterials mittels Kosinusähnlichkeit von Embeddings überprüft — eine mathematische Messung, kein generatives Modell, das das erste überprüft. Jede Tatsachenbehauptung erhält ein Vertrauensabzeichen (hoch, mittel, niedrig, unbestätigt), das für das Mitglied sichtbar ist.",
"governance": "Steuerung: Die Verifizierung erfolgt in einem grundlegend anderen epistemischen Bereich als die Generierung — und vermeidet so Fehler gemeinsamer Ursache. Korrekturen von Moderatoren fließen in die Verifizierungsschwellen ein. Alles mandantenbezogen.",
"link": "Philosophische Grundlagen →"
}
},
"limitations": {
@ -143,7 +154,8 @@
"• Eine polyzentrische Verwaltung kann in der Produktion ohne übermäßigen Aufwand betrieben werden",
"• Mandantenübergreifende Isolierung mit gemeinschaftsbezogener Governance ist möglich",
"• Governance-Verstöße sind aufdeckbar und überprüfbar",
"• Der Rahmen lernt aus Fehlern (dokumentierte Reaktionen auf Vorfälle)"
"• Der Rahmen lernt aus Fehlern (dokumentierte Reaktionen auf Vorfälle)",
"• Verifizierung ohne Fehler gemeinsamer Ursache ist erreichbar durch mathematische Ähnlichkeit statt generativer Überprüfung"
]
},
"does_not_support": {
@ -162,6 +174,7 @@
"visit_village": "Besuchen Sie das Dorf →",
"village_ai": "Souveränes Sprachmodell →",
"research_paper": "Forschungspapier →",
"guardian_paper": "Philosophie der Guardian Agents →",
"research_details": "Forschung → Details"
}
}

View file

@ -22,7 +22,7 @@
"ai_label": "Modèle AI :",
"ai_value": "Lama souverain (QLoRA affiné)",
"features_label": "Caractéristiques de l'IA :",
"features_value": "4 fonctions gouvernées en direct",
"features_value": "5 fonctions gouvernées en direct",
"infra_label": "L'infrastructure :",
"infra_value": "NZ + UE (pas de dépendance à l'égard des États-Unis)"
}
@ -53,7 +53,7 @@
},
"flow": {
"heading": "Comment fonctionne la gouvernance dans la pratique",
"intro": "Lorsqu'un membre utilise une fonction d'IA, la demande passe par six contrôles de gouvernance avant qu'une réponse ne soit générée. Chaque contrôle est indépendant et peut bloquer ou modifier la demande.",
"intro": "Lorsqu'un membre utilise une fonction d'IA, la demande passe par sept contrôles de gouvernance avant qu'une réponse ne soit générée. Chaque contrôle est indépendant et peut bloquer ou modifier la demande.",
"steps": {
"1": {
"title": "Demande d'adhésion reçue",
@ -76,12 +76,16 @@
"desc": "Le modèle du lama souverain génère une réponse en utilisant le contexte RAG filtré par les autorisations du membre. Tout le traitement reste sur l'infrastructure."
},
"6": {
"title": "Vérification par les Guardian Agents",
"desc": "Chaque affirmation factuelle dans la réponse est vérifiée par rapport au matériel source à l'aide de la similarité cosinus des embeddings — une mesure mathématique, pas une vérification générative. Chaque affirmation reçoit un badge de confiance visible par le membre."
},
"7": {
"title": "Vérification du champ d'application",
"desc": "La réponse est-elle adaptée à ce qui a été demandé ? Détecte l'élargissement du champ d'application et bloque les réponses qui dépassent la demande initiale."
},
"7": {
"8": {
"title": "Livraison avec attribution",
"desc": "La réponse est envoyée au membre avec l'indication de la source. Chaque étape est enregistrée à des fins d'audit."
"desc": "Réponse fournie au membre avec des badges de confiance, l'attribution de la source et un raisonnement transparent. Chaque étape est enregistrée."
}
}
},
@ -106,6 +110,13 @@
"title": "Transparence de la mémoire de l'IA",
"benefit": "Les membres peuvent voir, modifier et supprimer ce que l'IA \"retient\" d'eux. Un tableau de bord d'audit complet montre chaque interaction de l'IA.",
"governance": "Gouvernance : Le consentement de plusieurs parties prenantes est requis. Les décisions relatives à la persistance sont classifiées et vérifiables. Les membres contrôlent leurs propres données."
},
"guardian": {
"title": "Guardian Agents",
"badge": "NEW",
"benefit": "Chaque réponse de l'IA est vérifiée par rapport au matériel source à l'aide de la similarité cosinus des embeddings — une comparaison mathématique, pas un modèle génératif qui se vérifie lui-même. Chaque affirmation factuelle reçoit un badge de confiance (élevé, moyen, faible, non vérifié) visible par le membre.",
"governance": "Gouvernance : La vérification opère dans un domaine épistémique fondamentalement différent de celui de la génération — évitant ainsi les défaillances de mode commun. Les corrections des modérateurs alimentent les seuils de vérification. Le tout est limité au locataire.",
"link": "Fondements philosophiques →"
}
},
"limitations": {
@ -143,7 +154,8 @@
"• La gouvernance polycentrique peut fonctionner en production sans frais généraux prohibitifs",
"• Il est possible d'isoler plusieurs locataires avec une gouvernance par communauté",
"• Les violations de la gouvernance sont détectables et peuvent faire l'objet d'un audit",
"• Le cadre tire les leçons des échecs (réponses documentées aux incidents)"
"• Le cadre tire les leçons des échecs (réponses documentées aux incidents)",
"• La vérification sans défaillance de mode commun est réalisable grâce à la similarité mathématique plutôt qu'à la vérification générative"
]
},
"does_not_support": {
@ -162,6 +174,7 @@
"visit_village": "Visiter le village →",
"village_ai": "Modèle de langue souveraine →",
"research_paper": "Document de recherche →",
"guardian_paper": "Philosophie des Guardian Agents →",
"research_details": "Détails de la recherche →"
}
}

View file

@ -22,7 +22,7 @@
"ai_label": "Mōdēra AI:",
"ai_value": "Sovereign Llama (i whakangāwarihia mō QLoRA)",
"features_label": "Ngā āhuatanga AI:",
"features_value": "4 āhuatanga whakahaere ora",
"features_value": "5 āhuatanga whakahaere ora",
"infra_label": "Tūāpapa:",
"infra_value": "Aotearoa + Uniana o Europi (kāore he whakawhirinaki ki te US)"
}
@ -53,7 +53,7 @@
},
"flow": {
"heading": "Te āhua o te whakahaere i roto i te mahi",
"intro": "Ka whakamahi tētahi mema i tētahi āhuatanga AI, ka puta te tono i ngā tirohanga whakahaere e ono i mua i te whakaputa i tētahi whakautu. He motuhake ia tirohanga, ā, ka taea e ia te aukati, te whakarerekē rānei i te tono.",
"intro": "Ka whakamahi tētahi mema i tētahi āhuatanga AI, ka puta te tono i ngā tirohanga whakahaere e whitu i mua i te whakaputa i tētahi whakautu. He motuhake ia tirohanga, ā, ka taea e ia te aukati, te whakarerekē rānei i te tono.",
"steps": {
"1": {
"title": "Kua whiwhi i te tono a te mema",
@ -76,12 +76,16 @@
"desc": "Ka whakaputa urupare te tauira Llama rangatira mā te whakamahi i te horopaki RAG kua tātarihia e ngā whakaaetanga a te mema. Ka noho katoa ngā tukanga ki runga i te hanganga."
},
"6": {
"title": "Te whakamana a ngā Guardian Agents",
"desc": "Ka tirohia ia kōrero tūturu i roto i te whakautu ki ngā rauemi taketake mā te whakamahi i te ōritetanga cosine o ngā embedding — he inenga pāngarau, ehara i te tirotiro whakaputa. Ka whiwhi ia kōrero i tētahi tohu whakawhirinaki ka kitea e te mema."
},
"7": {
"title": "Whakamana i te whānuitanga",
"desc": "He tika te whakautu ki tā i pātaihia? Ka kitea te whakawhānuitanga o te kaupapa, ā, ka aukati i ngā whakautu e neke atu ana i te tono taketake."
},
"7": {
"8": {
"title": "Tuku me te tohu kaituhi",
"desc": "Ka tukuna te whakautu ki te mema me te tohu i te puna. Ka tuhia ia hikoinga mō te arotake."
"desc": "Whakautu i tukuna ki te mema me ngā tohu whakawhirinaki, te tohu pūtake, me te whakamārama mārama. Ka tuhia ia hikoinga."
}
}
},
@ -106,6 +110,13 @@
"title": "Mārama o te Mahara AI",
"benefit": "Ka taea e ngā mema te kite, te whakatika, me te muku i ngā mea e 'maumahara ana' te AI mō rātou. Ka whakaatu te papamātātai arotake katoa i ia whakawhitinga katoa ki te AI.",
"governance": "Whakahaere: Me whakaae ngā kaiwhai pānga maha. Ka whakarōpūhia ngā whakataunga mō te manawanui, ā, ka taea te arotake. Ka whakahaere ngā mema i ā rātou ake raraunga."
},
"guardian": {
"title": "Guardian Agents",
"badge": "NEW",
"benefit": "Ka whakamana ia whakautu AI ki ngā rauemi taketake mā te whakamahi i te ōritetanga cosine o ngā embedding — he whakataurite pāngarau, ehara i te tauira whakaputa e tirotiro ana i a ia anō. Ka whiwhi ia kōrero tūturu i tētahi tohu whakawhirinaki (teitei, waenga, iti, kāore i te whakamana) ka kitea e te mema.",
"governance": "Whakahaere: He rāngai mātauranga tino rerekē tō te whakamana i te rāngai whakaputa — ā, mā reira e karo ai ngā tauira hapa aronga-kotahi. Ka whāngai ngā whakatikanga a ngā kaiwhakahaere ki ngā paenga whakamana. Katoa he ā-teneti.",
"link": "Ngā tūāpapa arorangi →"
}
},
"limitations": {
@ -143,7 +154,8 @@
"• Ka taea e te whakahaere ā-pokapū maha te whakahaere i roto i te whakaputanga me te kore he utu taumata teitei",
"• Ka taea te wehewehe maha-teneti me te whakahaere ā-hapori",
"• Ka taea te kitea, ka taea hoki te arotake i ngā hē whakahaere",
"• Ka ako te anga i ngā hapa (ngā urupare aitua kua tuhia)"
"• Ka ako te anga i ngā hapa (ngā urupare aitua kua tuhia)",
"• Ka taea te whakamana me te kore hapa aronga-kotahi mā te whakamahi i te ōritetanga pāngarau, kaua ko te tirotiro whakaputa"
]
},
"does_not_support": {
@ -162,6 +174,7 @@
"visit_village": "Haere ki te kāinga →",
"village_ai": "Mōdela Reo Rangatira →",
"research_paper": "Pepa Rangahau →",
"guardian_paper": "Te Aronga Hinengaro o ngā Guardian Agents →",
"research_details": "Ngā taipitopito rangahau →"
}
}

View file

@ -103,6 +103,15 @@ async function getDocument(req, res) {
});
}
// SECURITY: Non-public documents only accessible to admin users
const isAdmin = req.user && req.user.role === 'admin';
if (document.visibility !== 'public' && !isAdmin) {
return res.status(404).json({
error: 'Not Found',
message: 'Document not found'
});
}
// If language parameter provided and not English, return translated version
if (lang && lang !== 'en') {
const supportedLangs = ['de', 'fr'];
@ -146,6 +155,14 @@ async function getDocument(req, res) {
const translatedDoc = await Document.findBySlug(translatedSlug);
if (translatedDoc) {
// SECURITY: Visibility check on fallback document too
if (translatedDoc.visibility !== 'public' && !isAdmin) {
return res.status(404).json({
error: 'Not Found',
message: 'Document not found'
});
}
return res.json({
success: true,
document: {
@ -652,6 +669,15 @@ async function getTranslations(req, res) {
});
}
// SECURITY: Non-public documents only accessible to admin users
const isAdmin = req.user && req.user.role === 'admin';
if (document.visibility !== 'public' && !isAdmin) {
return res.status(404).json({
error: 'Not Found',
message: 'Document not found'
});
}
// Build list of available translations
const translations = {
en: {

View file

@ -7,7 +7,7 @@ const express = require('express');
const router = express.Router();
const documentsController = require('../controllers/documents.controller');
const { authenticateToken, requireRole } = require('../middleware/auth.middleware');
const { authenticateToken, requireRole, optionalAuth } = require('../middleware/auth.middleware');
const { validateRequired, validateObjectId, validateSlug } = require('../middleware/validation.middleware');
const { asyncHandler } = require('../middleware/error.middleware');
@ -47,13 +47,15 @@ router.get('/', (req, res, next) => {
next();
}, asyncHandler(documentsController.listDocuments));
// GET /api/documents/:identifier/translations (public)
// GET /api/documents/:identifier/translations (public, visibility-filtered)
router.get('/:identifier/translations',
optionalAuth,
asyncHandler(documentsController.getTranslations)
);
// GET /api/documents/:identifier (ID or slug)
// GET /api/documents/:identifier (ID or slug, visibility-filtered)
router.get('/:identifier',
optionalAuth,
asyncHandler(documentsController.getDocument)
);