# =================================================================== # QUY TẮC DỰ ÁN CHẤM CÔNG HIKVISION (RULES) - v2 (CHẶT CHẼ) # =================================================================== # Tất cả code PHẢI tuân thủ các quy tắc sau. # Vi phạm bất kỳ quy tắc nào sẽ được ghi vào audit log. # Chạy `python audit.py` (code) + `python audit_data.py` (dữ liệu). # =================================================================== # --------------------------------------------------------------- # R1: CHỐNG LOCK THIẾT BỊ (CRITICAL — KHÔNG ĐƯỢC NỚI LỎNG) # --------------------------------------------------------------- # R1.1: Tối đa 18 POST request mỗi session (nonce expires ở 20) # R1.2: Phải đợi 9 giây sau khi close session trước khi tạo mới # R1.3: KHÔNG BAO GIỜ tạo session mới khi thiết bị đang LOCKED # R1.4: Kiểm tra lock status trước mỗi lần sync (1 GET, không POST) # R1.5: Nếu nhận 401, DỪNG NGAY - không retry tự động # R1.6: Ghi log mỗi lần tạo session mới với lý do # R1.7: Tối đa 1 sync chạy đồng thời (global lock - sync_lock) # R1.8: Tối thiểu 30s giữa 2 lần sync liên tiếp (rate limit toàn cục) # R1.9: Circuit breaker — sau 3 lần fail liên tiếp, KHÓA sync 30 phút # R1.10: Sync 1 ngày tối đa 200 records (paging chia nhỏ nếu cần) # R1.11: NEVER chạy sync trong giờ đông quét (07:00-09:00, 17:00-19:00) # trừ khi user xác nhận override (chống nghẽn thiết bị real-time) # --------------------------------------------------------------- # R2: BẢO MẬT DỮ LIỆU # --------------------------------------------------------------- # R2.1: Password phải được lưu trong config.json, KHÔNG hardcode # R2.2: Config.json KHÔNG được commit vào git # R2.3: API server mặc định localhost. Khi bind 0.0.0.0 (cho LAN/Tailscale): # bắt buộc đứng sau Tailscale ACL hoặc firewall - KHÔNG public Internet # R2.4: Không log password trong bất kỳ file log nào # R2.5: DEFAULT_CONFIG trong code KHÔNG được chứa password thật # (chỉ placeholder rỗng — buộc user phải set qua config.json) # R2.6: Backup config.json trước khi save_config() ghi đè # --------------------------------------------------------------- # R3: TOÀN VẸN DỮ LIỆU # --------------------------------------------------------------- # R3.1: Mỗi bản ghi chấm công phải có UNIQUE key (raw_time + employee_no) # R3.2: KHÔNG xóa dữ liệu cũ khi sync dữ liệu mới (INSERT OR IGNORE) # R3.3: Mỗi lần sync phải ghi sync_log với kết quả # R3.4: Database phải có index trên date và employee_no # R3.5: SQLite phải bật WAL mode (cho phép đọc song song khi đang ghi) # → tránh xung đột giữa Flet GUI / API server / Power Query # R3.6: Khi import từ CSV phải LƯU raw_status thật (không gán 'undefined') # R3.7: employee_name PHẢI được fill từ bảng employees khi xuất/hiển thị # (JOIN bắt buộc — không để rỗng nếu employees có dữ liệu) # R3.8: Backup DB tự động trước mỗi lần sync (giữ 7 bản gần nhất) # R3.9: Bản ghi với employee_no rỗng phải được flag (suspicious_log) # R3.10: Foreign key check — orphan employee_no phải báo cáo qua audit_data.py # --------------------------------------------------------------- # R4: LOGGING & AUDIT # --------------------------------------------------------------- # R4.1: Tất cả thao tác sync phải ghi log vào file # R4.2: Log phải bao gồm: timestamp, action, result, duration # R4.3: Log phải rotate hàng ngày (1 file/ngày), giữ 30 ngày # R4.4: Audit log ghi lại vi phạm rule (nếu có) # R4.5: Không log dữ liệu nhạy cảm (password, token) # R4.6: audit.py (code) + audit_data.py (dữ liệu) phải chạy được mọi lúc # R4.7: Mỗi sync ghi rõ: sessions_used, total_posts (để verify R1.1) # --------------------------------------------------------------- # R5: HIỆU SUẤT # --------------------------------------------------------------- # R5.1: Sync 1 ngày phải hoàn thành trong < 3 giây # R5.2: Query database phải hoàn thành trong < 1 giây # R5.3: API response phải < 2 giây # R5.4: Ghi timing vào performance log # R5.5: Nếu sync 1 ngày > 5s liên tiếp 3 lần → audit log + thông báo # --------------------------------------------------------------- # R6: EXCEL POWER QUERY (3 KÊNH HỢP LỆ) # --------------------------------------------------------------- # R6.1: Excel KHÔNG BAO GIỜ kết nối trực tiếp thiết bị # R6.2: Excel chỉ đọc từ một trong các nguồn sau: # (a) API server localhost (Flask) — http://127.0.0.1:5000 # (b) File export Excel/CSV (data/export/*.xlsx hoặc *.csv) # (c) SQLite ODBC driver đọc trực tiếp data/attendance.db (READ-ONLY) # R6.3: Refresh Excel KHÔNG gây bất kỳ request nào đến thiết bị # R6.4: API phải trả JSON format chuẩn # R6.5: Khi PQ đọc trực tiếp SQLite → bắt buộc mode=ro (read-only) # để tránh khóa file khi đang sync ghi # R6.6: Export file phải đặt trong data/export/ và được gitignore # --------------------------------------------------------------- # R7: VẬN HÀNH AN TOÀN (NEW) # --------------------------------------------------------------- # R7.1: Trước khi sync 1 khoảng > 7 ngày, phải xác nhận với user # (lượng request nhiều → rủi ro lock cao hơn) # R7.2: Không sync đồng thời từ nhiều process (file-lock data/.sync.lock) # R7.3: Khi DB bị lock SQLite (process khác đang ghi), retry tối đa 3 lần # với backoff 200ms / 500ms / 1000ms — không vô hạn # R7.4: Mọi route GET trong attendance_api.py KHÔNG được khởi tạo HikvisionDevice # R7.5: Mọi job tự động (cron, scheduler) phải gọi qua API /api/sync, # không bypass rate-limit nội bộ # --------------------------------------------------------------- # R8: KHẢ NĂNG PHỤC HỒI (NEW) # --------------------------------------------------------------- # R8.1: Backup DB hàng ngày → data/backups/attendance_YYYYMMDD.db, giữ 14 bản # R8.2: Restore script phải có (audit_data.py --restore ) # R8.3: Mọi schema migration phải có ALTER thay vì DROP # R8.4: Khi mất kết nối thiết bị, tiếp tục phục vụ từ cache, KHÔNG raise lỗi # trong các endpoint GET # --------------------------------------------------------------- # CONSTANTS # --------------------------------------------------------------- MAX_POSTS_PER_SESSION = 18 SESSION_COOLDOWN_SECONDS = 9 MAX_CONSECUTIVE_ERRORS = 3 LOCK_CHECK_BEFORE_SYNC = True MIN_SECONDS_BETWEEN_SYNCS = 30 # R1.8 CIRCUIT_BREAKER_FAILS = 3 # R1.9 CIRCUIT_BREAKER_LOCK_MINUTES = 30 # R1.9 MAX_RECORDS_PER_DAY = 200 # R1.10 PEAK_HOURS = [(7, 9), (17, 19)] # R1.11 LARGE_RANGE_DAYS_THRESHOLD = 7 # R7.1 # DEPLOYMENT: bind 0.0.0.0 cho Tailscale (R2.3 - bao mat: bat buoc co Tailscale ACL # hoac Windows Firewall rule cho phep port 5000 chi tu interface Tailscale). API_HOST = "0.0.0.0" API_PORT = 5000 LOG_ROTATE_DAILY = True LOG_BACKUP_COUNT = 30 # R4.3 PERFORMANCE_WARN_SYNC_DAY_MS = 3000 PERFORMANCE_WARN_QUERY_MS = 1000 PERFORMANCE_WARN_API_MS = 2000 PERFORMANCE_CRITICAL_SYNC_DAY_MS = 5000 # R5.5 # DB backup DB_BACKUP_KEEP_DAYS = 14 # R8.1 SYNC_BACKUP_KEEP = 7 # R3.8 SQLITE_LOCK_RETRY = 3 # R7.3 SQLITE_LOCK_BACKOFF_MS = [200, 500, 1000]