Version: 0.1.0 Status: Draft Author: DBBASIC Team Date: 2025-01-17
Links: - PyPI: https://pypi.org/project/dbbasic-admin/ (pending) - GitHub: https://github.com/askrobots/dbbasic-admin (pending) - Specification: https://dbbasic.com/admin-spec
Admin interfaces should auto-generate from installed modules, not require manual configuration.
Core Principles:
1. Auto-discovery - Installing a dbbasic module automatically adds its admin panels
2. Convention over configuration - Modules just need admin.py and templates/admin/
3. Filesystem routing - Admin routes follow file paths (like CGI/PHP)
4. No database required - Module registry and config stored in flat files
5. Composable - Each module owns its admin UI, dbbasic-admin just discovers and renders
Traditional approach:
# Manual route registration - breaks modularity
admin.register_route('/admin/posts', posts_handler)
admin.register_route('/admin/products', products_handler)
admin.register_route('/admin/comments', comments_handler)
Problems: - Installing a new module requires updating admin config - Admin interface tightly coupled to specific modules - No way to add admin panels without modifying core code
Flask/Django approach:
# Each module registers routes programmatically
from admin import register_blueprint
register_blueprint(posts_blueprint)
Problems: - Requires running registration code on startup - Route conflicts must be managed - Order of registration matters
DBBASIC approach:
1. Modules export admin.py with ADMIN_CONFIG
2. Modules include templates/admin/ with HTML files
3. dbbasic-web's filesystem router handles routing automatically
4. Admin sidebar auto-populates from discovered modules
Benefits: - Zero configuration - just install the module - No registration code needed - File structure = URL structure - Works with dbbasic-web's existing routing
An admin interface is: 1. Navigation sidebar - Links to all admin sections 2. CRUD operations - Create, read, update, delete for data tables 3. Search & filters - Find and filter records 4. Dashboard - Overview of system status
dbbasic-admin provides: - Core admin pages (Dashboard, Code, Database, Settings, Jobs, Logs) - Auto-discovery of module admin pages - Auto-generated CRUD for TSV tables - Dynamic sidebar rendering
import importlib
import pkgutil
def discover_admin_modules():
"""Scan installed packages for admin configs"""
modules = []
for pkg in pkgutil.iter_modules():
if pkg.name.startswith('dbbasic_'):
try:
admin_mod = importlib.import_module(f'{pkg.name}.admin')
if hasattr(admin_mod, 'ADMIN_CONFIG'):
modules.append({
'name': pkg.name,
'config': admin_mod.ADMIN_CONFIG
})
except (ImportError, AttributeError):
pass # Module has no admin interface
return modules
Each module exports an admin.py file:
# dbbasic_blog/admin.py
ADMIN_CONFIG = [
{
"icon": "📝",
"label": "Posts",
"href": "/admin/posts",
"order": 20,
"table": "posts", # Optional: auto-generates CRUD
},
{
"icon": "💬",
"label": "Comments",
"href": "/admin/comments",
"order": 21,
"table": "comments",
}
]
Core admin module:
dbbasic_admin/
├── __init__.py
├── admin.py # Discovery and registry
├── api/
│ └── nav.py # Returns nav items as JSON
└── templates/
└── admin/
├── index.html # Dashboard
├── code.html # Code editor
├── database.html # Database browser
├── jobs.html # Background jobs
├── logs.html # System logs
└── settings.html # Settings
Module with admin pages:
dbbasic_blog/
├── __init__.py
├── admin.py # Exports ADMIN_CONFIG
└── templates/
└── admin/
├── posts/
│ ├── list.html # /admin/posts/list
│ ├── new.html # /admin/posts/new
│ └── [id].html # /admin/posts/123 (pattern routing)
└── comments/
└── list.html # /admin/comments/list
discover_modules()Purpose: Find all installed dbbasic modules with admin interfaces
Signature:
def discover_modules() -> List[Dict[str, Any]]
Returns:
[
{
'name': 'dbbasic_blog',
'config': [
{'icon': '📝', 'label': 'Posts', 'href': '/admin/posts', 'order': 20}
]
},
{
'name': 'dbbasic_commerce',
'config': [
{'icon': '🛒', 'label': 'Products', 'href': '/admin/products', 'order': 30}
]
}
]
Caching: Results cached for 60 seconds to avoid repeated filesystem scans
build_nav(modules)Purpose: Generate sidebar navigation from discovered modules
Signature:
def build_nav(modules: List[Dict]) -> List[Dict[str, Any]]
Returns:
[
# Core items (always present)
{'icon': '📊', 'label': 'Dashboard', 'href': '/admin/', 'order': 0},
{'icon': '💻', 'label': 'Code', 'href': '/admin/code', 'order': 10},
{'icon': '🗄️', 'label': 'Database', 'href': '/admin/database', 'order': 11},
# Module items (from ADMIN_CONFIG)
{'icon': '📝', 'label': 'Posts', 'href': '/admin/posts', 'order': 20},
{'icon': '🛒', 'label': 'Products', 'href': '/admin/products', 'order': 30},
# System items (always at bottom)
{'icon': '⏰', 'label': 'Jobs', 'href': '/admin/jobs', 'order': 90},
{'icon': '📋', 'label': 'Logs', 'href': '/admin/logs', 'order': 91},
{'icon': '⚙️', 'label': 'Settings', 'href': '/admin/settings', 'order': 99},
]
generate_crud(table_name)Purpose: Auto-generate CRUD interface for a TSV table
Signature:
def generate_crud(table_name: str, config: Dict = None) -> str
Parameters:
- table_name: Name of TSV table in _data/
- config: Optional configuration for fields, labels, validation
Returns: HTML for list, create, edit, delete pages
Example:
# Automatically generates:
# - /admin/posts/list.html (list view with search/filter)
# - /admin/posts/new.html (create form)
# - /admin/posts/[id].html (edit form)
# dbbasic_admin/admin.py
import importlib
import pkgutil
from typing import List, Dict, Any
from functools import lru_cache
# Core admin navigation (always present)
CORE_NAV = [
{'icon': '📊', 'label': 'Dashboard', 'href': '/admin/', 'order': 0},
{'icon': '💻', 'label': 'Code', 'href': '/admin/code', 'order': 10},
{'icon': '🗄️', 'label': 'Database', 'href': '/admin/database', 'order': 11},
{'icon': '⏰', 'label': 'Jobs', 'href': '/admin/jobs', 'order': 90},
{'icon': '📋', 'label': 'Logs', 'href': '/admin/logs', 'order': 91},
{'icon': '⚙️', 'label': 'Settings', 'href': '/admin/settings', 'order': 99},
]
@lru_cache(maxsize=1)
def discover_modules() -> List[Dict[str, Any]]:
"""Auto-discover admin modules from installed packages"""
modules = []
for pkg in pkgutil.iter_modules():
if pkg.name.startswith('dbbasic_') and pkg.name != 'dbbasic_admin':
try:
admin_mod = importlib.import_module(f'{pkg.name}.admin')
if hasattr(admin_mod, 'ADMIN_CONFIG'):
modules.append({
'name': pkg.name,
'config': admin_mod.ADMIN_CONFIG
})
except (ImportError, AttributeError):
continue
return modules
def build_nav() -> List[Dict[str, Any]]:
"""Build complete navigation from core + discovered modules"""
nav_items = CORE_NAV.copy()
# Add module nav items
for module in discover_modules():
nav_items.extend(module['config'])
# Sort by order
nav_items.sort(key=lambda x: x.get('order', 50))
return nav_items
def clear_cache():
"""Clear discovery cache (call after installing new module)"""
discover_modules.cache_clear()
# dbbasic_admin/api/nav.py
import json
from dbbasic_admin.admin import build_nav
from dbbasic_web.responses import json as json_response
def GET(request):
"""Return navigation items as JSON"""
nav = build_nav()
return json_response(json.dumps(nav))
1. Install the module:
pip install dbbasic-blog
2. Module includes admin.py:
# dbbasic_blog/admin.py
ADMIN_CONFIG = [
{'icon': '📝', 'label': 'Posts', 'href': '/admin/posts', 'order': 20}
]
3. Admin sidebar automatically shows "Posts":
Dashboard
Code
Database
Posts ← Automatically added!
Jobs
Logs
Settings
4. No configuration needed! Just install and it appears.
# dbbasic_myapp/admin.py
ADMIN_CONFIG = [
{
'icon': '📦',
'label': 'Inventory',
'href': '/admin/inventory',
'order': 25,
'table': 'inventory', # Auto-generates CRUD
'fields': {
'name': {'label': 'Product Name', 'required': True},
'sku': {'label': 'SKU', 'required': True},
'quantity': {'label': 'Quantity', 'type': 'number'},
'price': {'label': 'Price', 'type': 'number', 'min': 0},
}
}
]
This automatically creates: - List view with search and filtering - Create form with validation - Edit form - Delete confirmation
For complex admin pages, provide a custom handler:
# dbbasic_commerce/admin.py
ADMIN_CONFIG = [
{
'icon': '📊',
'label': 'Sales Dashboard',
'href': '/admin/sales',
'order': 35,
'custom': True # No auto-CRUD
}
]
# dbbasic_commerce/templates/admin/sales.html
# Custom template with charts, graphs, etc.
| Operation | Time |
|---|---|
| Module discovery (cold) | ~50ms |
| Module discovery (cached) | ~0.1ms |
| Nav building | ~1ms |
| Total page load impact | <5ms |
Caching strategy:
- Discovery results cached with @lru_cache
- Cache invalidated on module install/uninstall
- 60-second TTL for development mode
[dependencies]
python = "^3.9"
dbbasic-web = "^0.1.7"
dbbasic-tsv = "^0.1.0"
jinja2 = "^3.1.0"
pip install dbbasic-admin
1. Include admin routes:
# asgi.py
from dbbasic_admin import include_admin_routes
app = create_app()
include_admin_routes(app) # Adds /admin/* routes
2. That's it! Admin is available at /admin/
pip install dbbasic-blog
# Admin automatically shows "Posts" tab
ADMIN_CONFIG = [
{
# Required fields
'label': 'Posts', # Display name
'href': '/admin/posts', # URL path
# Optional fields
'icon': '📝', # Emoji or icon class
'order': 20, # Sort order (0-99)
'badge': '3', # Notification badge
'divider': False, # Show divider before this item
# Auto-CRUD options
'table': 'posts', # TSV table name
'fields': { # Field configuration
'title': {
'label': 'Title',
'required': True,
'maxlength': 200
},
'content': {
'label': 'Content',
'type': 'textarea',
'rows': 10
}
},
# Advanced options
'custom': True, # Disable auto-CRUD
'permissions': ['admin'], # Required permissions
}
]
Alternatives considered:
Manual registration
python
admin.register('Posts', '/admin/posts') # ❌ Requires config
Config files ```yaml admin:
Auto-discovery
python
# Module just exports ADMIN_CONFIG ✅ Zero config!
Decision: Auto-discovery wins because it requires zero configuration and follows the Unix philosophy of composability.
Aligns with dbbasic-web's philosophy: - File structure mirrors URL structure - No route tables to maintain - Easy to understand and debug - Works with existing dbbasic-web routing
Order numbers (0-99):
{'label': 'Dashboard', 'order': 0}
{'label': 'Posts', 'order': 20}
{'label': 'Settings', 'order': 99}
vs Groups:
{'label': 'Dashboard', 'group': 'core'}
{'label': 'Posts', 'group': 'content'}
Decision: Order numbers are simpler and give precise control over positioning.
dbbasic_* packages (namespace protection)Admin pages should check authentication:
# In each admin template/handler
from dbbasic_sessions import get_session
def GET(request):
session = get_session(request)
if not session or not session.get('is_admin'):
return redirect('/login')
# ... render admin page
Forms should include CSRF tokens:
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<!-- ... form fields ... -->
</form>
def test_discover_modules():
"""Test module discovery"""
modules = discover_modules()
assert isinstance(modules, list)
def test_build_nav():
"""Test nav building"""
nav = build_nav()
assert len(nav) >= 6 # At least core items
assert nav[0]['label'] == 'Dashboard'
def test_nav_ordering():
"""Test nav items are sorted by order"""
nav = build_nav()
orders = [item.get('order', 50) for item in nav]
assert orders == sorted(orders)
def test_admin_nav_endpoint():
"""Test /admin/api/nav returns JSON"""
response = client.get('/admin/api/nav')
assert response.status_code == 200
nav = json.loads(response.body)
assert isinstance(nav, list)
| Feature | dbbasic-admin | Django Admin | Flask-Admin | Rails Admin |
|---|---|---|---|---|
| Auto-discovery | ✅ Zero config | ❌ Manual registration | ❌ Manual setup | ❌ Manual setup |
| Filesystem routing | ✅ Yes | ❌ URL patterns | ❌ Route decorators | ❌ Route files |
| Auto-CRUD | ✅ From TSV | ✅ From models | ✅ From models | ✅ From models |
| Database required | ❌ No | ✅ Yes | ✅ Yes | ✅ Yes |
| Lines of code | ~500 | ~50,000 | ~10,000 | ~20,000 |
| Module plugins | ✅ Auto-detected | ❌ Manual | ❌ Manual | ❌ Manual |
Use Django Admin when: - You need a mature, battle-tested admin - You're already using Django ORM - You need complex permissions and workflows
Use dbbasic-admin when: - You want zero-configuration module discovery - You're using TSV files instead of SQL - You want a lightweight admin (<500 lines) - You want filesystem-based routing
Before:
# app.py
admin.add_route('/admin/posts', posts_handler)
admin.add_route('/admin/comments', comments_handler)
After:
# dbbasic_blog/admin.py
ADMIN_CONFIG = [
{'label': 'Posts', 'href': '/admin/posts', 'order': 20},
{'label': 'Comments', 'href': '/admin/comments', 'order': 21},
]
No registration code needed!
dbbasic-admin provides a zero-configuration admin interface that auto-discovers installed modules and generates CRUD interfaces for TSV tables.
Key innovations: 1. Auto-discovery - Just install a module, admin tab appears 2. Filesystem routing - Files define routes (like CGI/PHP) 3. Composable - Each module owns its admin UI 4. Lightweight - ~500 lines total
Next steps:
1. Install: pip install dbbasic-admin
2. Access: http://localhost:8000/admin/
3. Install modules: pip install dbbasic-blog (auto-adds "Posts" tab)
Built for simplicity, composability, and the Unix philosophy.