Skip to main content

Overview

The Admin Panel provides privileged users with tools to manage the FinAI platform, including user administration, AI monitoring, and system maintenance. Access is restricted through a role-based access control (RBAC) system.

Access Control

RBAC Implementation

FinAI uses a decorator-based RBAC system to protect administrative routes:
# From app/routes/admin.py:12-20
def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # Check if user is logged in
        if 'user_id' not in session:
            return redirect(url_for('auth.login'))
        
        # Verify admin role
        if session.get('user_role') != 'admin':
            flash('Bạn không có quyền truy cập trang này!', 'error')
            return redirect(url_for('views.dashboard'))
        
        return f(*args, **kwargs)
    return decorated_function
Non-admin users attempting to access admin routes are redirected to the dashboard with an error message.

User Roles

The User model defines two roles:
# From app/models.py:8-18
class User(db.Model):
    __tablename__ = 'nguoidung'

    id = db.Column('MaNguoiDung', db.String(8), primary_key=True)
    name = db.Column('HoTen', db.String(100))
    email = db.Column('Email', db.String(100), unique=True, nullable=False)
    password_hash = db.Column('MatKhau', db.String(200), nullable=False)
    role = db.Column('VaiTro', db.String(20), default='user')  # 'user' or 'admin'
    status = db.Column('TrangThai', db.Integer, default=1)
    created_at = db.Column('NgayTao', db.DateTime, default=datetime.now)
    last_login = db.Column('LanDangNhapCuoi', db.DateTime)
Role Values:
  • user - Standard user with access to personal financial features
  • admin - Administrator with system-wide management capabilities
New accounts are created with role='user' by default. Admin privileges must be granted manually via database updates.

Admin Features

User Management

View and manage all registered users. Route: /admin/users
# From app/routes/admin.py:23-27
@admin_bp.route('/admin/users')
@admin_required
def users():
    users = User.query.all()
    return render_template('admin/users.html', users=users)
1

Access User List

Navigate to Admin → Users to view all registered accounts.
2

View User Details

The list displays:
  • User ID (MaNguoiDung)
  • Name (HoTen)
  • Email
  • Role (VaiTro)
  • Status (TrangThai)
  • Registration date (NgayTao)
  • Last login (LanDangNhapCuoi)
3

Manage Accounts

Perform actions such as viewing transaction history, modifying roles, or deactivating accounts.

User Relationships

The User model provides relationships to access all user data:
# From app/models.py:20-26
# Relationships for easy data access
settings = db.relationship('UserSetting', backref='user', uselist=False, lazy=True)
wallets = db.relationship('Wallet', backref='user', lazy=True)
categories = db.relationship('Category', backref='user', lazy=True)
transactions = db.relationship('Transaction', backref='user', lazy=True)
budgets = db.relationship('Budget', backref='user', lazy=True)
Example Usage:
user = User.query.get('U0001')
print(f"Total wallets: {len(user.wallets)}")
print(f"Total transactions: {len(user.transactions)}")
print(f"AI enabled: {user.settings.ai_suggestions}")

Category Management

Configure system-wide and user-specific categories. Route: /admin/categories
# From app/routes/admin.py:29-32
@admin_bp.route('/admin/categories')
@admin_required
def categories():
    return render_template('admin/categories.html')

Category Model

Categories can be hierarchical with parent-child relationships:
# From app/models.py:63-73
class Category(db.Model):
    __tablename__ = 'danhmuc'

    id = db.Column('MaDanhMuc', db.String(8), primary_key=True)
    user_id = db.Column('MaNguoiDung', db.String(8), 
                        db.ForeignKey('nguoidung.MaNguoiDung', 
                        ondelete='CASCADE'))
    name = db.Column('TenDanhMuc', db.String(100), nullable=False)
    type = db.Column('LoaiDanhMuc', db.String(10), nullable=False)  # 'thu' or 'chi'
    parent_id = db.Column('MaDanhMucCha', db.String(8), 
                          db.ForeignKey('danhmuc.MaDanhMuc', 
                          ondelete='SET NULL'))

    # Recursive relationship for subcategories
    children = db.relationship('Category', 
                               backref=db.backref('parent', remote_side=[id]), 
                               lazy=True)
Category Types:
  • thu - Income categories
  • chi - Expense categories

AI Monitoring

AI Performance Dashboard

Route: /admin/ai-monitoring
# From app/routes/admin.py:34-37
@admin_bp.route('/admin/ai-monitoring')
@admin_required
def ai_monitoring():
    return render_template('admin/ai_monitoring.html')
Monitor the performance of AI-powered category suggestions.
Track AI predictions and user feedback:
# From app/models.py:134-143
class AILog(db.Model):
    __tablename__ = 'ai_lichsu'
    
    id = db.Column('MaAI_Log', db.String(8), primary_key=True)
    user_id = db.Column('MaNguoiDung', db.String(8), 
                        db.ForeignKey('nguoidung.MaNguoiDung', 
                        ondelete='CASCADE'))
    transaction_id = db.Column('MaGiaoDich', db.String(8), 
                               db.ForeignKey('giaodich.MaGiaoDich', 
                               ondelete='SET NULL'))
    predicted_cat = db.Column('DanhMucDuDoan', db.String(8), 
                              db.ForeignKey('danhmuc.MaDanhMuc', 
                              ondelete='CASCADE'))
    actual_cat = db.Column('DanhMucChinhXac', db.String(8), 
                           db.ForeignKey('danhmuc.MaDanhMuc', 
                           ondelete='CASCADE'))
    confidence = db.Column('DoTinCay', db.Float)
    feedback = db.Column('PhanHoi', db.String(50))  # 'dung' or 'sai'
    created_at = db.Column('NgayTao', db.DateTime, default=datetime.now)

Chatbot Monitoring

Route: /admin/chatbot-logs
# From app/routes/admin.py:39-42
@admin_bp.route('/admin/chatbot-logs')
@admin_required
def chatbot_logs():
    return render_template('admin/chatbot_logs.html')
View conversation history and analyze chatbot interactions. ChatbotLog Model:
# From app/models.py:152-158
class ChatbotLog(db.Model):
    __tablename__ = 'chatbot_lichsu'
    
    id = db.Column('MaHoiThoai', db.String(8), primary_key=True)
    user_id = db.Column('MaNguoiDung', db.String(8), 
                        db.ForeignKey('nguoidung.MaNguoiDung', 
                        ondelete='CASCADE'))
    question = db.Column('NoiDungHoi', db.Text)
    answer = db.Column('NoiDungTraLoi', db.Text)
    created_at = db.Column('NgayTao', db.DateTime, default=datetime.now)

System Maintenance

Log Cleanup

Automatically remove old chatbot logs to maintain database performance. API Endpoint: DELETE /api/admin/cleanup-logs
# From app/routes/admin.py:44-55
@admin_bp.route('/api/admin/cleanup-logs', methods=['DELETE'])
@admin_required
def cleanup_logs():
    try:
        # Delete logs older than 30 days
        expiration_date = datetime.now() - timedelta(days=30)
        deleted_count = ChatbotLog.query.filter(
            ChatbotLog.created_at < expiration_date
        ).delete()
        
        db.session.commit()
        return jsonify({
            'status': 'success', 
            'message': f'Đã xóa {deleted_count} tin nhắn cũ hơn 30 ngày.'
        })
    except Exception as e:
        db.session.rollback()
        return jsonify({'status': 'error', 'message': str(e)}), 500
1

Navigate to Chatbot Logs

Access Admin → Chatbot Logs.
2

Review Old Logs

Check the date range of existing logs.
3

Execute Cleanup

Click Cleanup Old Logs to remove entries older than 30 days.
4

Verify Results

The system returns the count of deleted records.
Log cleanup is irreversible. Ensure you have backups if historical data is needed for analysis.

Security Features

Two-Factor Authentication

Administrators can manage 2FA settings for users:
# From app/models.py:145-150
class TwoFactorAuth(db.Model):
    __tablename__ = 'xacthuc2fa'
    
    user_id = db.Column('MaNguoiDung', db.String(8), 
                        db.ForeignKey('nguoidung.MaNguoiDung', 
                        ondelete='CASCADE'), primary_key=True)
    secret_key = db.Column('SecretKey', db.String(100), nullable=False)
    is_active = db.Column('DaKichHoat', db.Integer, default=0)
    backup_code = db.Column('MaDuPhong', db.String(200))
Fields:
  • secret_key - TOTP secret for authenticator apps
  • is_active - 1 if 2FA is enabled, 0 if disabled
  • backup_code - Emergency access codes

Password Reset Management

# From app/models.py:160-164
class PasswordResetToken(db.Model):
    __tablename__ = 'password_reset_tokens'
    
    email = db.Column('Email', db.String(100), 
                      db.ForeignKey('nguoidung.Email', 
                      ondelete='CASCADE'), primary_key=True)
    token = db.Column('Token', db.String(100), nullable=False)
    expires_at = db.Column('ThoiGianHetHan', db.DateTime, nullable=False)
Administrators can:
  • View active reset tokens
  • Revoke compromised tokens
  • Monitor reset request patterns

Admin Blueprint Structure

# From app/routes/admin.py:1-9
from flask import Blueprint, render_template, session, redirect, url_for, flash, jsonify
from functools import wraps
from datetime import datetime, timedelta

from app import db
from app.models import User, ChatbotLog

# Blueprint declaration
admin_bp = Blueprint('admin', __name__)
Available Routes:
RouteMethodPurpose
/admin/usersGETList all users
/admin/categoriesGETManage categories
/admin/ai-monitoringGETView AI performance
/admin/chatbot-logsGETView chatbot history
/api/admin/cleanup-logsDELETERemove old logs
All routes are protected by the @admin_required decorator and require an active admin session.

Best Practices

Regular Monitoring

  • Review AI accuracy metrics weekly
  • Monitor user growth and activity patterns
  • Check for unusual login patterns or security issues

Data Maintenance

  • Run log cleanup monthly to optimize database size
  • Archive important logs before deletion
  • Monitor database growth and plan capacity accordingly

Security Audits

  • Regularly review admin access logs
  • Verify that only authorized users have admin roles
  • Monitor password reset requests for suspicious activity

Troubleshooting

Access Denied

If you receive “Bạn không có quyền truy cập trang này!”:
  • Verify your account has role='admin' in the database
  • Check that your session is active
  • Log out and log back in to refresh session variables

Database Errors

If cleanup or other operations fail:
# The system automatically rolls back on errors
db.session.rollback()
Check application logs for specific error messages and stack traces.

Build docs developers (and LLMs) love