Files
daveadmin 2e2b0b45fa Full DMS: folders + ACLs, versioning, trash, bulk ops, preview, smart folders
Rebuild the dashboard as a Drive-style document management system on top of
the existing CaveauAI hybrid RAG pipeline.

Backend:
- 5 migrations (versions, trash soft-delete, saved searches, categories, audit)
- DMS helpers (folder ACL walker, disk storage, audit, version snapshot,
  XLSX/PPTX/HTML/CSV/MD extractors)
- New APIs: folders, document-versions, trash, bulk, preview, saved-searches,
  categories, diagnostics
- Extended APIs: documents (folder_id, soft-delete, ACL filter, sort),
  upload (9 file types, version-collision detection with replace/new/keep-both,
  disk persistence), chat-stream (folder scoping + graph related-documents)
- 30-day trash purge cron with Qdrant + disk + graph cleanup

Frontend:
- Drive-style two-pane browser with folder tree, drag-drop, bulk-action bar,
  right-click context menu, multi-select
- New pages: folders (tree + per-folder ACL editor), trash (restore/purge)
- Extended pages: upload (folder picker, version-collision modal, 9 file
  type chips), document (Preview/Versions/Permissions tabs with PDF.js +
  mammoth.js + audio), index (DMS KPIs + activity feed), settings (live
  diagnostics ping MariaDB/Qdrant/LiteLLM/FalkorDB/disk), chat (folder
  scope chips + related-authorities chips)
- New CSS (dms.css) + JS bundle (dms.js) exposing window.DBN_DMS
- Sidebar nav adds Folders + Trash items

All routes return HTTP 200 in local smoke test; all 32 files lint clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 22:24:56 +02:00

97 lines
4.7 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../includes/bootstrap.php';
$dashboardPage = 'settings';
$dashboardTitle = dbnToolsT('dash_title_settings', dbnToolsCurrentLanguage());
$dashboardLead = dbnToolsT('dash_lead_settings', dbnToolsCurrentLanguage());
require_once __DIR__ . '/../includes/layout_dashboard.php';
?>
<section class="dash-card">
<div class="dash-card__head">
<h2><?= htmlspecialchars(dbnToolsT('dash_section_account', $uiLang)) ?></h2>
</div>
<dl style="display:grid; grid-template-columns: max-content 1fr; gap: 0.4rem 1.5rem; font-size:0.92rem;">
<dt style="color:rgba(22,19,15,0.55);"><?= htmlspecialchars(dbnToolsT('dash_label_client_id', $uiLang)) ?></dt>
<dd><code id="setClientId">—</code></dd>
<dt style="color:rgba(22,19,15,0.55);"><?= htmlspecialchars(dbnToolsT('dash_label_corpus_id', $uiLang)) ?></dt>
<dd><code id="setCorpusId">—</code></dd>
<dt style="color:rgba(22,19,15,0.55);"><?= htmlspecialchars(dbnToolsT('dash_label_user_id', $uiLang)) ?></dt>
<dd><code id="setUserId">—</code></dd>
</dl>
</section>
<section class="dash-card">
<div class="dash-card__head">
<h2><?= htmlspecialchars(dbnToolsT('dash_section_rag', $uiLang)) ?></h2>
</div>
<dl style="display:grid; grid-template-columns: max-content 1fr; gap: 0.4rem 1.5rem; font-size:0.92rem;">
<dt style="color:rgba(22,19,15,0.55);">Chunking</dt>
<dd>600 words/passage, 75-word overlap, heading-aware</dd>
<dt style="color:rgba(22,19,15,0.55);">Embedding model</dt>
<dd><code>nomic-embed-text</code> (768-dim) via LiteLLM on Colin</dd>
<dt style="color:rgba(22,19,15,0.55);">Vector DB</dt>
<dd><code>bnl_client_chunks</code> in Qdrant (Colin Docker)</dd>
<dt style="color:rgba(22,19,15,0.55);">Search method</dt>
<dd>Hybrid (vector + keyword), reciprocal rank fusion, private boost 1.5×</dd>
<dt style="color:rgba(22,19,15,0.55);">Graph DB</dt>
<dd><code>dbn_client_graph</code> in FalkorDB (Colin) — citation edges</dd>
</dl>
</section>
<section class="dash-card">
<div class="dash-card__head">
<h2>Live diagnostics</h2>
<div class="dash-card__actions">
<button class="dash-btn" type="button" id="diagRefresh">↻ Refresh</button>
</div>
</div>
<div id="diagPanel" class="dms-diag"><div class="dms-loading"></div></div>
</section>
<section class="dash-card">
<div class="dash-card__head">
<h2><?= htmlspecialchars(dbnToolsT('dash_section_privacy', $uiLang)) ?></h2>
</div>
<p style="margin-top:0; max-width:64ch; line-height:1.6;">
<?= htmlspecialchars(dbnToolsT('dash_privacy_p1', $uiLang)) ?>
</p>
<p style="max-width:64ch; line-height:1.6;">
<?= htmlspecialchars(dbnToolsT('dash_privacy_p2a', $uiLang)) ?>
<a href="/dashboard/documents.php"><?= htmlspecialchars(dbnToolsT('dash_nav_documents', $uiLang)) ?></a>.
<?= htmlspecialchars(dbnToolsT('dash_privacy_p2b', $uiLang)) ?>
</p>
</section>
<script>
(function () {
'use strict';
const d = window.DBN_DASHBOARD || {};
document.getElementById('setClientId').textContent = d.clientId || '—';
document.getElementById('setCorpusId').textContent = d.corpusId || '—';
document.getElementById('setUserId').textContent = d.clientUserId || '—';
const $diag = document.getElementById('diagPanel');
async function loadDiag() {
$diag.innerHTML = '<div class="dms-loading"></div>';
try {
const r = await fetch((d.apiBase || '/api/dashboard') + '/diagnostics.php', { credentials:'same-origin' });
const data = await r.json();
if (!data.ok) throw new Error(data.message || 'Diagnostics unavailable');
const safe = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;' }[c]));
$diag.innerHTML = data.sections.map(s =>
'<div class="dms-diag__row" title="' + safe(s.detail || '') + '">' +
'<div class="dms-diag__label">' + safe(s.label) + '</div>' +
'<div class="dms-diag__value">' + safe(s.value) + '</div>' +
'<div><span class="dms-diag__status dms-diag__status--' + safe(s.status || 'warn') + '">' + safe(s.status) + '</span></div></div>'
).join('');
} catch (e) {
$diag.innerHTML = '<div class="dms-list__empty"><strong>Could not run diagnostics</strong><span>' + e.message + '</span></div>';
}
}
document.getElementById('diagRefresh').addEventListener('click', loadDiag);
loadDiag();
})();
</script>
<?php require_once __DIR__ . '/../includes/layout_dashboard_footer.php'; ?>