Add registry curation system with role-based moderation

Implement comprehensive moderation system for the CmdForge registry:

- Role-based access control (user, moderator, admin)
- Tool moderation workflow: pending → approved/rejected/removed
- Tool visibility: public, private, unlisted
- Publisher management: ban/unban with token revocation
- Report resolution with configurable actions
- Audit logging for all moderation actions

Database changes:
- Add role, banned columns to publishers table
- Add visibility, moderation_status columns to tools table
- Create audit_log table for accountability

API additions:
- Admin endpoints for tool moderation (approve/reject/remove)
- Publisher management endpoints (ban/unban/role)
- Report resolution endpoint
- Audit log query endpoint

Web UI:
- Admin dashboard with stats overview
- Pending tools queue with approve/reject
- Publisher management with ban/role controls
- Report queue with resolve actions
- Role badge in dashboard sidebar

Existing tools grandfathered as approved, all publishers default to user role.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
rob
2026-01-13 22:58:37 -04:00
co-authored by Claude Opus 4.5
parent b1d1a3692d
commit 946a5933b4
9 changed files with 1681 additions and 13 deletions
+24 -2
View File
@@ -6,8 +6,19 @@
<div class="bg-white border-b border-gray-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{% block dashboard_header %}
<h1 class="text-2xl font-bold text-gray-900">Dashboard</h1>
<p class="mt-1 text-gray-600">Welcome back, {{ user.display_name }}</p>
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-gray-900">Dashboard</h1>
<p class="mt-1 text-gray-600">
Welcome back, {{ user.display_name }}
{% if user.role in ('moderator', 'admin') %}
<span class="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {% if user.role == 'admin' %}bg-red-100 text-red-800{% else %}bg-purple-100 text-purple-800{% endif %}">
{{ user.role|capitalize }}
</span>
{% endif %}
</p>
</div>
</div>
{% endblock %}
</div>
</div>
@@ -46,6 +57,17 @@
</svg>
Settings
</a>
{% if user.role in ('moderator', 'admin') %}
<div class="border-t border-gray-200 mt-2 pt-2">
<a href="{{ url_for('web.admin_dashboard') }}"
class="flex items-center px-4 py-3 text-sm font-medium {{ 'bg-red-50 text-red-700 border-l-4 border-red-600' if active_page and active_page.startswith('admin') else 'text-red-600 hover:bg-red-50' }}">
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
</svg>
Admin Panel
</a>
</div>
{% endif %}
</nav>
<!-- Quick Stats (mobile hidden) -->