diff --git a/packages/audit_log/components/ui.json b/packages/audit_log/components/ui.json new file mode 100644 index 000000000..2fd6d5bc5 --- /dev/null +++ b/packages/audit_log/components/ui.json @@ -0,0 +1,447 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json", + "schemaVersion": "2.0.0", + "package": "audit_log", + "description": "UI components for audit log viewer and stats dashboard", + "components": [ + { + "id": "audit_stats_cards", + "name": "AuditStatsCard", + "description": "Grid of stat cards showing audit log summary", + "props": [ + { + "name": "stats", + "type": "object", + "required": true, + "description": "Statistics object with total, successful, failed, and rateLimit counts" + } + ], + "handlers": { + "prepare": "stats.prepareStatsDisplay" + }, + "render": { + "type": "element", + "template": { + "type": "Grid", + "props": { + "cols": 4, + "gap": 4, + "className": "md:grid-cols-4" + }, + "children": [ + { + "type": "Card", + "children": [ + { + "type": "CardHeader", + "props": { + "className": "flex flex-row items-center justify-between pb-2 space-y-0" + }, + "children": [ + { + "type": "CardTitle", + "props": { + "className": "text-sm font-medium", + "text": "Total Operations" + } + }, + { + "type": "Icon", + "props": { + "name": "ChartLine", + "className": "w-4 h-4 text-muted-foreground" + } + } + ] + }, + { + "type": "CardContent", + "children": [ + { + "type": "Typography", + "props": { + "variant": "h4", + "className": "text-2xl font-bold", + "text": "{{stats.total}}" + } + } + ] + } + ] + }, + { + "type": "Card", + "children": [ + { + "type": "CardHeader", + "props": { + "className": "flex flex-row items-center justify-between pb-2 space-y-0" + }, + "children": [ + { + "type": "CardTitle", + "props": { + "className": "text-sm font-medium", + "text": "Successful" + } + }, + { + "type": "Icon", + "props": { + "name": "ShieldCheck", + "className": "w-4 h-4 text-green-600" + } + } + ] + }, + { + "type": "CardContent", + "children": [ + { + "type": "Typography", + "props": { + "variant": "h4", + "className": "text-2xl font-bold text-green-600", + "text": "{{stats.successful}}" + } + } + ] + } + ] + }, + { + "type": "Card", + "children": [ + { + "type": "CardHeader", + "props": { + "className": "flex flex-row items-center justify-between pb-2 space-y-0" + }, + "children": [ + { + "type": "CardTitle", + "props": { + "className": "text-sm font-medium", + "text": "Failed" + } + }, + { + "type": "Icon", + "props": { + "name": "Warning", + "className": "w-4 h-4 text-red-600" + } + } + ] + }, + { + "type": "CardContent", + "children": [ + { + "type": "Typography", + "props": { + "variant": "h4", + "className": "text-2xl font-bold text-red-600", + "text": "{{stats.failed}}" + } + } + ] + } + ] + }, + { + "type": "Card", + "children": [ + { + "type": "CardHeader", + "props": { + "className": "flex flex-row items-center justify-between pb-2 space-y-0" + }, + "children": [ + { + "type": "CardTitle", + "props": { + "className": "text-sm font-medium", + "text": "Rate Limited" + } + }, + { + "type": "Icon", + "props": { + "name": "Clock", + "className": "w-4 h-4 text-yellow-600" + } + } + ] + }, + { + "type": "CardContent", + "children": [ + { + "type": "Typography", + "props": { + "variant": "h4", + "className": "text-2xl font-bold text-yellow-600", + "text": "{{stats.rateLimit}}" + } + } + ] + } + ] + } + ] + } + } + }, + { + "id": "audit_log_viewer", + "name": "AuditLogViewer", + "description": "Complete audit log viewer with stats and scrollable log list", + "props": [ + { + "name": "logs", + "type": "array", + "required": false, + "default": [] + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": false + } + ], + "state": [ + { + "name": "stats", + "type": "object", + "default": {} + }, + { + "name": "formattedLogs", + "type": "array", + "default": [] + } + ], + "handlers": { + "loadLogs": "init.loadLogs", + "calculateStats": "stats.calculateStats", + "formatLogs": "formatting.formatAllLogs", + "applyFilters": "filters.applyFilters" + }, + "render": { + "type": "element", + "template": { + "type": "Box", + "props": { + "className": "space-y-6" + }, + "children": [ + { + "type": "ComponentRef", + "props": { + "ref": "audit_stats_cards", + "stats": "{{stats}}" + } + }, + { + "type": "Card", + "children": [ + { + "type": "CardHeader", + "children": [ + { + "type": "CardTitle", + "props": { + "text": "Security Audit Log" + } + }, + { + "type": "CardDescription", + "props": { + "text": "Last 100 database operations with access control enforcement" + } + }, + { + "type": "Button", + "props": { + "size": "sm", + "className": "mt-2", + "disabled": "{{loading}}" + }, + "events": { + "onClick": "loadLogs" + }, + "children": [ + { + "type": "Text", + "props": { + "text": "{{loading ? 'Loading...' : 'Refresh'}}" + } + } + ] + } + ] + }, + { + "type": "CardContent", + "children": [ + { + "type": "ScrollArea", + "props": { + "className": "h-[600px] pr-4" + }, + "children": [ + { + "type": "List", + "props": { + "dataSource": "formattedLogs", + "className": "space-y-3", + "emptyText": "No audit logs found" + }, + "itemTemplate": { + "type": "Box", + "props": { + "className": "flex items-start gap-3 p-3 rounded-lg border {{item.rowClass}}" + }, + "children": [ + { + "type": "Box", + "props": { + "className": "flex items-center justify-center w-8 h-8 rounded-full bg-muted" + }, + "children": [ + { + "type": "Icon", + "props": { + "name": "{{item.resourceIcon}}", + "className": "w-4 h-4" + } + } + ] + }, + { + "type": "Box", + "props": { + "className": "flex-1 space-y-1" + }, + "children": [ + { + "type": "Box", + "props": { + "className": "flex items-center gap-2" + }, + "children": [ + { + "type": "Badge", + "props": { + "className": "{{item.operationColor}}", + "text": "{{item.operation}}" + } + }, + { + "type": "Typography", + "props": { + "variant": "body2", + "fontWeight": "medium", + "text": "{{item.resource}}" + } + }, + { + "type": "Typography", + "props": { + "variant": "caption", + "color": "textSecondary", + "text": "{{item.resourceId}}" + } + }, + { + "type": "ConditionalRender", + "props": { + "condition": "{{!item.success}}" + }, + "children": [ + { + "type": "Badge", + "props": { + "variant": "destructive", + "className": "ml-auto", + "text": "Failed" + } + } + ] + } + ] + }, + { + "type": "Typography", + "props": { + "variant": "caption", + "color": "textSecondary" + }, + "children": [ + { + "type": "Text", + "props": { + "fontWeight": "medium", + "text": "{{item.username}}" + } + }, + { + "type": "Text", + "props": { + "text": " • {{item.timestamp}}" + } + }, + { + "type": "ConditionalRender", + "props": { + "condition": "{{item.ipAddress}}" + }, + "children": [ + { + "type": "Text", + "props": { + "text": " • {{item.ipAddress}}" + } + } + ] + } + ] + }, + { + "type": "ConditionalRender", + "props": { + "condition": "{{item.errorMessage}}" + }, + "children": [ + { + "type": "Typography", + "props": { + "variant": "caption", + "color": "error", + "text": "{{item.errorMessage}}" + } + } + ] + } + ] + } + ] + } + } + ] + } + ] + } + ] + } + ] + } + } + } + ], + "exports": { + "components": ["AuditStatsCard", "AuditLogViewer"] + } +} diff --git a/packages/audit_log/entities/schema.json b/packages/audit_log/entities/schema.json new file mode 100644 index 000000000..1fccd22d7 --- /dev/null +++ b/packages/audit_log/entities/schema.json @@ -0,0 +1,133 @@ +{ + "$schema": "https://metabuilder.dev/schemas/entities.schema.json", + "schemaVersion": "2.0.0", + "entities": [ + { + "name": "AuditLog", + "version": "1.0", + "description": "Audit log entry for tracking user and system actions", + "primaryKey": "id", + "timestamps": false, + "softDelete": false, + "fields": { + "id": { + "type": "string", + "generated": true, + "description": "Unique identifier (CUID)" + }, + "tenantId": { + "type": "string", + "required": true, + "index": true, + "description": "Tenant identifier for multi-tenancy" + }, + "userId": { + "type": "string", + "nullable": true, + "index": true, + "description": "User who performed the action" + }, + "username": { + "type": "string", + "nullable": true, + "description": "Username for display purposes" + }, + "action": { + "type": "enum", + "required": true, + "index": true, + "enum": ["create", "update", "delete", "login", "logout", "access", "execute", "export", "import"], + "description": "Type of action performed" + }, + "entity": { + "type": "string", + "required": true, + "maxLength": 100, + "description": "Entity/resource type affected" + }, + "entityId": { + "type": "string", + "nullable": true, + "description": "Specific entity instance identifier" + }, + "oldValue": { + "type": "text", + "nullable": true, + "description": "JSON: previous state before change" + }, + "newValue": { + "type": "text", + "nullable": true, + "description": "JSON: new state after change" + }, + "ipAddress": { + "type": "string", + "nullable": true, + "maxLength": 45, + "description": "IP address of the client (IPv4 or IPv6)" + }, + "userAgent": { + "type": "string", + "nullable": true, + "description": "Browser/client user agent string" + }, + "details": { + "type": "text", + "nullable": true, + "description": "JSON: additional context and metadata" + }, + "timestamp": { + "type": "bigint", + "required": true, + "index": true, + "description": "Unix timestamp in milliseconds" + } + }, + "indexes": [ + { + "fields": ["tenantId"], + "name": "idx_audit_tenant" + }, + { + "fields": ["userId"], + "name": "idx_audit_user" + }, + { + "fields": ["entity", "entityId"], + "name": "idx_audit_entity" + }, + { + "fields": ["action"], + "name": "idx_audit_action" + }, + { + "fields": ["timestamp"], + "name": "idx_audit_timestamp" + } + ], + "relations": [ + { + "name": "tenant", + "type": "belongsTo", + "entity": "Tenant", + "field": "tenantId", + "onDelete": "Cascade" + }, + { + "name": "user", + "type": "belongsTo", + "entity": "User", + "field": "userId", + "onDelete": "SetNull", + "optional": true + } + ], + "acl": { + "create": ["admin", "system"], + "read": ["admin", "god"], + "update": ["supergod"], + "delete": ["supergod"] + } + } + ] +} diff --git a/packages/audit_log/package.json b/packages/audit_log/package.json new file mode 100644 index 000000000..3353f3c45 --- /dev/null +++ b/packages/audit_log/package.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json", + "packageId": "audit_log", + "name": "Audit Log", + "version": "1.0.0", + "description": "Security audit log viewer and stats dashboard", + "author": "MetaBuilder", + "license": "MIT", + "category": "admin", + "minLevel": 3, + "primary": true, + "dependencies": {}, + "devDependencies": { + "lua_test": "*", + "package_validator": "*" + }, + "exports": { + "components": [ + "AuditLogViewer", + "AuditStatsCard", + "LogTable", + "LogFilters" + ], + "scripts": [ + "init", + "stats", + "filters", + "formatting" + ] + }, + "tests": { + "scripts": [ + "tests/metadata.test.lua", + "tests/components.test.lua", + "tests/stats.test.lua", + "tests/filters.test.lua" + ] + } +} diff --git a/packages/audit_log/scripts/functions.json b/packages/audit_log/scripts/functions.json new file mode 100644 index 000000000..589bedd3b --- /dev/null +++ b/packages/audit_log/scripts/functions.json @@ -0,0 +1,138 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script.schema.json", + "schemaVersion": "2.2.0", + "package": "audit_log", + "description": "Business logic functions for audit log package", + "functions": [ + { + "id": "init", + "name": "init", + "exported": true, + "description": "Package initialization and main entry point", + "category": "lifecycle", + "luaScript": "init.lua" + }, + { + "id": "stats_calculate", + "name": "calculateStats", + "exported": true, + "description": "Calculate audit log statistics", + "category": "analytics", + "luaScript": "stats.lua" + }, + { + "id": "stats_prepare_display", + "name": "prepareStatsDisplay", + "exported": true, + "description": "Prepare statistics for display", + "category": "analytics", + "luaScript": "stats.lua" + }, + { + "id": "filters_apply", + "name": "applyFilters", + "exported": true, + "description": "Apply filters to audit log entries", + "category": "data", + "luaScript": "filters.lua" + }, + { + "id": "filters_by_username", + "name": "filterByUsername", + "exported": true, + "description": "Filter logs by username", + "category": "data", + "luaScript": "filters/filter_by_username.lua" + }, + { + "id": "filters_by_operation", + "name": "filterByOperation", + "exported": true, + "description": "Filter logs by operation type", + "category": "data", + "luaScript": "filters/filter_by_operation.lua" + }, + { + "id": "filters_by_resource", + "name": "filterByResource", + "exported": true, + "description": "Filter logs by resource", + "category": "data", + "luaScript": "filters/filter_by_resource.lua" + }, + { + "id": "filters_by_date_range", + "name": "filterByDateRange", + "exported": true, + "description": "Filter logs by date range", + "category": "data", + "luaScript": "filters/filter_by_date_range.lua" + }, + { + "id": "formatting_format_all", + "name": "formatAllLogs", + "exported": true, + "description": "Format all log entries for display", + "category": "ui", + "luaScript": "formatting.lua" + }, + { + "id": "formatting_format_entry", + "name": "formatLogEntry", + "exported": true, + "description": "Format a single log entry", + "category": "ui", + "luaScript": "formatting/format_log_entry.lua" + }, + { + "id": "formatting_format_timestamp", + "name": "formatTimestamp", + "exported": true, + "description": "Format timestamp for display", + "category": "ui", + "luaScript": "formatting/format_timestamp.lua" + }, + { + "id": "formatting_get_operation_color", + "name": "getOperationColor", + "exported": true, + "description": "Get color for operation type", + "category": "ui", + "luaScript": "formatting/get_operation_color.lua" + }, + { + "id": "formatting_get_resource_icon", + "name": "getResourceIcon", + "exported": true, + "description": "Get icon for resource type", + "category": "ui", + "luaScript": "formatting/get_resource_icon.lua" + }, + { + "id": "formatting_get_status_badge", + "name": "getStatusBadge", + "exported": true, + "description": "Get status badge styling", + "category": "ui", + "luaScript": "formatting/get_status_badge.lua" + } + ], + "exports": { + "functions": [ + "init", + "calculateStats", + "prepareStatsDisplay", + "applyFilters", + "filterByUsername", + "filterByOperation", + "filterByResource", + "filterByDateRange", + "formatAllLogs", + "formatLogEntry", + "formatTimestamp", + "getOperationColor", + "getResourceIcon", + "getStatusBadge" + ] + } +} diff --git a/packages/audit_log/storybook/config.json b/packages/audit_log/storybook/config.json new file mode 100644 index 000000000..0340d0c8c --- /dev/null +++ b/packages/audit_log/storybook/config.json @@ -0,0 +1,114 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json", + "featured": true, + "title": "Audit Log Package", + "description": "Security audit log viewer and stats dashboard components", + "stories": [ + { + "name": "AuditLogViewer", + "render": "init", + "description": "Complete audit log viewer with stats and scrollable log list", + "args": { + "limit": 100 + }, + "argTypes": { + "limit": { + "type": "number", + "defaultValue": 100, + "description": "Maximum number of log entries to display" + } + } + }, + { + "name": "AuditStatsCard", + "render": "stats", + "description": "Statistics cards showing audit log summary", + "args": { + "stats": { + "total": 1250, + "successful": 1100, + "failed": 120, + "rateLimit": 30 + } + } + } + ], + "renders": { + "init": { + "description": "Main audit log viewer with full functionality", + "featured": true + }, + "stats": { + "description": "Audit statistics dashboard cards" + }, + "filters": { + "description": "Log filtering interface" + }, + "formatting": { + "description": "Log entry formatting utilities" + } + }, + "defaultContext": { + "user": { + "id": "demo-admin", + "username": "admin_user", + "level": 4, + "email": "admin@example.com" + }, + "tenant": { + "id": "demo-tenant", + "name": "Demo Organization" + }, + "nerdMode": false, + "theme": "light" + }, + "contextVariants": [ + { + "name": "Admin User", + "description": "Full admin access to audit logs", + "context": { + "user": { + "username": "admin", + "level": 4 + } + } + }, + { + "name": "Moderator", + "description": "Limited audit log access", + "context": { + "user": { + "username": "moderator", + "level": 3 + } + } + }, + { + "name": "God Mode", + "description": "Super admin with full access", + "context": { + "user": { + "username": "god_user", + "level": 5 + } + } + } + ], + "scripts": { + "renderFunctions": ["init", "stats", "filters", "formatting"], + "ignoredScripts": ["db/operations", "tests"] + }, + "parameters": { + "layout": "fullscreen", + "backgrounds": { + "default": "light", + "values": [ + { "name": "light", "value": "#ffffff" }, + { "name": "dark", "value": "#1a1a1a" } + ] + }, + "docs": { + "description": "Security audit log viewer for tracking database operations and user actions" + } + } +} diff --git a/packages/audit_log/styles/tokens.json b/packages/audit_log/styles/tokens.json new file mode 100644 index 000000000..c9b86705c --- /dev/null +++ b/packages/audit_log/styles/tokens.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-styles.schema.json", + "schemaVersion": "2.0.0", + "colors": { + "auditSuccess": "#28a745", + "auditFailed": "#dc3545", + "auditRateLimit": "#ffc107", + "auditInfo": "#17a2b8", + "auditBackground": "#f8f9fa", + "auditBorder": "#dee2e6" + }, + "spacing": { + "auditCard": "16px", + "auditRow": "12px" + }, + "typography": { + "fontFamily": { + "audit": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif" + } + }, + "customStyles": { + "audit_log_base": { + "description": "Base styles for Audit Log package", + "css": ".audit_log { /* Add package-specific styles here */ }" + } + } +}