Documentation Index Fetch the complete documentation index at: https://mintlify.com/Braian551/viax/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Audit Logs provide a comprehensive, searchable record of all administrative actions and system events, ensuring transparency, accountability, and compliance.
All admin actions are automatically logged with timestamps, user IDs, IP addresses, and detailed descriptions.
Audit Logs Screen
Access the audit log viewer from the admin panel:
admin/presentation/screens/audit_logs_screen.dart
class AuditLogsScreen extends StatefulWidget {
final int adminId;
const AuditLogsScreen ({
super .key,
required this .adminId,
});
}
Log Entry Structure
class AuditLog {
final int id;
final int ? adminId;
final int ? usuarioAfectadoId;
final String accion;
final String ? descripcion;
final String ? ipAddress;
final String ? userAgent;
final DateTime fechaCreacion;
final Map < String , dynamic > ? metadata;
}
Database Schema
CREATE TABLE audit_logs (
id INT AUTO_INCREMENT PRIMARY KEY ,
admin_id INT ,
usuario_afectado_id INT ,
accion VARCHAR ( 100 ) NOT NULL ,
descripcion TEXT ,
ip_address VARCHAR ( 45 ),
user_agent VARCHAR ( 255 ),
metadata JSON ,
fecha_creacion TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (admin_id) REFERENCES usuarios(id),
FOREIGN KEY (usuario_afectado_id) REFERENCES usuarios(id),
INDEX idx_admin_id (admin_id),
INDEX idx_accion (accion),
INDEX idx_fecha_creacion (fecha_creacion)
);
Logged Actions
Authentication
User Management
Driver Management
Trip Management
Configuration
Actions:
admin_login - Admin logged in
admin_logout - Admin logged out
failed_login - Failed login attempt
session_expired - Session timeout
Icon: Login/LogoutColor: Green (#11998e)Actions:
create_user - New user created
update_user - User profile updated
activate_user - User account activated
deactivate_user - User account deactivated
delete_user - User deleted
Icon: PeopleColor: Blue (#667eea)Actions:
approve_driver - Driver approved
reject_driver - Driver rejected (with reason)
verify_documents - Driver documents verified
suspend_driver - Driver suspended
Icon: ID CardColor: Yellow (#FFFF00)Actions:
cancel_trip - Trip cancelled by admin
reassign_driver - Driver reassigned
adjust_price - Trip price adjusted
resolve_dispute - Dispute resolved
Icon: RouteColor: Orange (#ffa726)Actions:
update_pricing - Pricing configuration changed
update_service_area - Service area modified
update_company - Company information updated
Icon: SettingsColor: Purple (#764ba2)
Audit Log Screen Implementation
Search Functionality
admin/presentation/screens/audit_logs_screen.dart
Widget _buildSearchBar () {
return Container (
decoration : BoxDecoration (
color : const Color ( 0xFF1A1A1A ). withValues (alpha : 0.8 ),
borderRadius : BorderRadius . circular ( 20 ),
border : Border . all (color : Colors .white. withValues (alpha : 0.1 )),
),
child : TextField (
controller : _searchController,
style : TextStyle (color : Colors .white),
decoration : InputDecoration (
hintText : 'Buscar logs...' ,
prefixIcon : Icon ( Icons .search_rounded),
suffixIcon : _searchController.text.isNotEmpty
? IconButton (
icon : Icon ( Icons .clear),
onPressed : () {
_searchController. clear ();
_loadLogs ();
},
)
: null ,
border : InputBorder .none,
),
onSubmitted : (_) => _loadLogs (),
),
);
}
Filter Chips
admin/presentation/screens/audit_logs_screen.dart
Widget _buildFilterChips () {
return SingleChildScrollView (
scrollDirection : Axis .horizontal,
child : Row (
children : [
_buildFilterChip ( 'Todos' , null , Icons .all_inclusive_rounded),
_buildFilterChip ( 'Login' , 'login' , Icons .login_rounded),
_buildFilterChip ( 'Crear' , 'crear' , Icons .add_circle_outline_rounded),
_buildFilterChip ( 'Actualizar' , 'actualizar' , Icons .edit_rounded),
_buildFilterChip ( 'Eliminar' , 'eliminar' , Icons .delete_outline_rounded),
],
),
);
}
Widget _buildFilterChip ( String label, String ? value, IconData icon) {
final isSelected = _selectedFilter == value;
return GestureDetector (
onTap : () {
setState (() => _selectedFilter = value);
_loadLogs ();
},
child : Container (
padding : const EdgeInsets . symmetric (horizontal : 16 , vertical : 10 ),
decoration : BoxDecoration (
color : isSelected
? const Color ( 0xFF667eea ). withValues (alpha : 0.3 )
: const Color ( 0xFF1A1A1A ). withValues (alpha : 0.8 ),
borderRadius : BorderRadius . circular ( 16 ),
border : Border . all (
color : isSelected
? const Color ( 0xFF667eea )
: Colors .white. withValues (alpha : 0.1 ),
),
),
child : Row (
children : [
Icon (icon, size : 18 ),
const SizedBox (width : 6 ),
Text (label),
],
),
),
);
}
Log Card Display
admin/presentation/screens/audit_logs_screen.dart
Widget _buildLogCard ( Map < String , dynamic > log) {
final accion = log[ 'accion' ] ?? '' ;
final descripcion = log[ 'descripcion' ] ?? '' ;
final usuario = ' ${ log [ 'nombre' ] ?? '' } ${ log [ 'apellido' ] ?? '' } ' . trim ();
final email = log[ 'email' ] ?? '' ;
final fecha = _formatDate (log[ 'fecha_creacion' ]);
final actionColor = _getActionColor (accion);
final actionIcon = _getActionIcon (accion);
return ClipRRect (
borderRadius : BorderRadius . circular ( 20 ),
child : BackdropFilter (
filter : ImageFilter . blur (sigmaX : 10 , sigmaY : 10 ),
child : Container (
decoration : BoxDecoration (
color : const Color ( 0xFF1A1A1A ). withValues (alpha : 0.8 ),
borderRadius : BorderRadius . circular ( 20 ),
border : Border . all (color : Colors .white. withValues (alpha : 0.1 )),
),
child : Material (
color : Colors .transparent,
child : InkWell (
borderRadius : BorderRadius . circular ( 20 ),
onTap : () => _showLogDetails (log),
child : Padding (
padding : const EdgeInsets . all ( 16 ),
child : Column (
children : [
Row (
children : [
Container (
padding : const EdgeInsets . all ( 10 ),
decoration : BoxDecoration (
color : actionColor. withValues (alpha : 0.2 ),
borderRadius : BorderRadius . circular ( 12 ),
),
child : Icon (actionIcon, color : actionColor, size : 20 ),
),
const SizedBox (width : 12 ),
Expanded (
child : Column (
crossAxisAlignment : CrossAxisAlignment .start,
children : [
Text (
accion. toUpperCase (),
style : TextStyle (
color : actionColor,
fontSize : 12 ,
fontWeight : FontWeight .bold,
),
),
Text (
descripcion,
style : TextStyle (fontSize : 14 ),
maxLines : 2 ,
overflow : TextOverflow .ellipsis,
),
],
),
),
],
),
if (usuario.isNotEmpty || email.isNotEmpty)
_buildUserInfo (usuario, email),
],
),
),
),
),
),
),
);
}
Action Color Coding
admin/presentation/screens/audit_logs_screen.dart
Color _getActionColor ( String accion) {
final lower = accion. toLowerCase ();
if (lower. contains ( 'login' ) || lower. contains ( 'acceso' )) {
return const Color ( 0xFF11998e ); // Green
}
if (lower. contains ( 'crear' ) || lower. contains ( 'registro' )) {
return const Color ( 0xFF667eea ); // Blue
}
if (lower. contains ( 'actualizar' ) || lower. contains ( 'editar' )) {
return AppColors .primary; // Yellow
}
if (lower. contains ( 'eliminar' ) || lower. contains ( 'desactivar' )) {
return const Color ( 0xFFf5576c ); // Red
}
return const Color ( 0xFF667eea ); // Default blue
}
IconData _getActionIcon ( String accion) {
final lower = accion. toLowerCase ();
if (lower. contains ( 'login' ) || lower. contains ( 'acceso' )) {
return Icons .login_rounded;
}
if (lower. contains ( 'crear' ) || lower. contains ( 'registro' )) {
return Icons .add_circle_rounded;
}
if (lower. contains ( 'actualizar' ) || lower. contains ( 'editar' )) {
return Icons .edit_rounded;
}
if (lower. contains ( 'eliminar' ) || lower. contains ( 'desactivar' )) {
return Icons .delete_rounded;
}
return Icons .info_rounded;
}
Log Details Modal
admin/presentation/screens/audit_logs_screen.dart
void _showLogDetails ( Map < String , dynamic > log) {
showModalBottomSheet (
context : context,
backgroundColor : Colors .transparent,
isScrollControlled : true ,
builder : (context) => ClipRRect (
borderRadius : const BorderRadius . vertical (top : Radius . circular ( 24 )),
child : BackdropFilter (
filter : ImageFilter . blur (sigmaX : 10 , sigmaY : 10 ),
child : Container (
padding : const EdgeInsets . all ( 24 ),
decoration : BoxDecoration (
color : const Color ( 0xFF1A1A1A ). withValues (alpha : 0.95 ),
borderRadius : const BorderRadius . vertical (top : Radius . circular ( 24 )),
),
child : Column (
mainAxisSize : MainAxisSize .min,
children : [
_buildDetailRow ( 'Acción' , log[ 'accion' ]),
_buildDetailRow ( 'Descripción' , log[ 'descripcion' ]),
_buildDetailRow ( 'Usuario' , ' ${ log [ 'nombre' ]} ${ log [ 'apellido' ]} ' ),
_buildDetailRow ( 'Email' , log[ 'email' ]),
_buildDetailRow ( 'IP' , log[ 'ip_address' ]),
_buildDetailRow ( 'User Agent' , log[ 'user_agent' ]),
_buildDetailRow ( 'Fecha' , _formatFullDate (log[ 'fecha_creacion' ])),
],
),
),
),
),
);
}
Widget _buildDetailRow ( String label, String ? value) {
if (value == null || value.isEmpty) return const SizedBox . shrink ();
return Padding (
padding : const EdgeInsets . only (bottom : 16 ),
child : Column (
crossAxisAlignment : CrossAxisAlignment .start,
children : [
Text (label, style : TextStyle (fontSize : 12 , color : Colors .white60)),
const SizedBox (height : 6 ),
Container (
width : double .infinity,
padding : const EdgeInsets . all ( 12 ),
decoration : BoxDecoration (
color : Colors .white. withValues (alpha : 0.05 ),
borderRadius : BorderRadius . circular ( 10 ),
),
child : Text (value, style : TextStyle (fontSize : 14 )),
),
],
),
);
}
admin/presentation/screens/audit_logs_screen.dart
String _formatDate ( String ? dateStr) {
if (dateStr == null ) return '' ;
try {
final date = DateTime . parse (dateStr);
final now = DateTime . now ();
final diff = now. difference (date);
if (diff.inMinutes < 1 ) return 'Ahora' ;
if (diff.inMinutes < 60 ) return 'Hace ${ diff . inMinutes } m' ;
if (diff.inHours < 24 ) return 'Hace ${ diff . inHours } h' ;
if (diff.inDays < 7 ) return 'Hace ${ diff . inDays } d' ;
return DateFormat ( 'dd/MM/yy' ). format (date);
} catch (e) {
return dateStr;
}
}
String _formatFullDate ( String ? dateStr) {
if (dateStr == null ) return '' ;
try {
final date = DateTime . parse (dateStr);
return DateFormat ( 'dd/MM/yyyy HH:mm:ss' ). format (date);
} catch (e) {
return dateStr;
}
}
Creating Audit Log Entries
PHP Backend Implementation
backend/utils/audit_logger.php
function logAuditAction (
$pdo ,
$adminId ,
$accion ,
$descripcion ,
$usuarioAfectadoId = null ,
$metadata = null
) {
$ipAddress = $_SERVER [ 'REMOTE_ADDR' ] ?? null ;
$userAgent = $_SERVER [ 'HTTP_USER_AGENT' ] ?? null ;
$stmt = $pdo -> prepare ( "
INSERT INTO audit_logs (
admin_id,
usuario_afectado_id,
accion,
descripcion,
ip_address,
user_agent,
metadata
) VALUES (?, ?, ?, ?, ?, ?, ?)
" );
$stmt -> execute ([
$adminId ,
$usuarioAfectadoId ,
$accion ,
$descripcion ,
$ipAddress ,
$userAgent ,
json_encode ( $metadata )
]);
}
Usage Example
// When approving a driver
logAuditAction (
$pdo ,
$adminId ,
'approve_driver' ,
"Conductor aprobado: { $conductor ['nombre']} (ID: { $conductorId })" ,
$conductorId ,
[ 'previous_status' => 'pendiente' , 'new_status' => 'aprobado' ]
);
// When rejecting a driver
logAuditAction (
$pdo ,
$adminId ,
'reject_driver' ,
"Conductor rechazado: { $conductor ['nombre']} - Motivo: { $motivo }" ,
$conductorId ,
[ 'motivo' => $motivo , 'previous_status' => 'pendiente' ]
);
Retrieving Audit Logs
Backend API Endpoint
backend/admin/get_audit_logs.php
// GET /admin/get_audit_logs.php?admin_id=1&page=1&per_page=50&filter=login
$stmt = $pdo -> prepare ( "
SELECT
al.*,
u.nombre,
u.apellido,
u.email
FROM audit_logs al
LEFT JOIN usuarios u ON al.usuario_afectado_id = u.id
WHERE al.admin_id = ?
AND (? IS NULL OR al.accion LIKE ?)
ORDER BY al.fecha_creacion DESC
LIMIT ? OFFSET ?
" );
$filter = $_GET [ 'filter' ] ?? null ;
$filterParam = $filter ? "%{ $filter }%" : null ;
$limit = intval ( $_GET [ 'per_page' ] ?? 50 );
$offset = ( intval ( $_GET [ 'page' ] ?? 1 ) - 1 ) * $limit ;
$stmt -> execute ([ $adminId , $filterParam , $filterParam , $limit , $offset ]);
Export Audit Logs
Export functionality is planned for future releases. Will support CSV and PDF formats for compliance reporting.
Retention Policy
Define how long to keep audit logs:
-- Delete logs older than 1 year
DELETE FROM audit_logs
WHERE fecha_creacion < DATE_SUB( NOW (), INTERVAL 1 YEAR );
-- Archive old logs to separate table
INSERT INTO audit_logs_archive
SELECT * FROM audit_logs
WHERE fecha_creacion < DATE_SUB( NOW (), INTERVAL 6 MONTH );
DELETE FROM audit_logs
WHERE fecha_creacion < DATE_SUB( NOW (), INTERVAL 6 MONTH );
Best Practices
Ensure every administrative action is logged for complete audit trail.
Log not just what action was taken, but why and by whom, with before/after states.
Audit logs should be write-only for admins - no deletion or modification allowed.
Periodically review audit logs to identify suspicious patterns or security issues.
Maintain logs for required retention period for regulatory compliance.
Dashboard View recent activity summary
User Management User change tracking
Driver Management Driver approval history