Skip to content

ashhim/CRAD

Repository files navigation

CRAD (Captive Redirection Academic Dashboard)

Version: 10.0 - Campus Notifications & Recovery
Last Updated: March 3, 2026
System Status: Production Ready
Platform: Raspberry Pi 3B+ with Captive Portal
Deployment Architecture: Offline-First Hybrid (Local + Cloud Sync)
Total Database Tables: 53 core + 4 optional (notifications/recovery)
API Endpoints: 60+
Frontend Pages: 10+


Executive Summary

CRAD v10 builds on v7 with campus-wide notifications and a governed password-recovery flow, while retaining attendance, chat, batch, and profile capabilities. Both new features are feature-gated: they activate only when additive tables are present. Profiles now include projects and achievements; offline-first access still uses local portal plus optional Cloudflare tunnel + Firebase URL sync.

Key Updates in v10:

  • Campus Notifications: Multi-display (popup/banner/profile-card/feed), audiences, schedules, repeat policies, blocking popups, media uploads/URL, audits, dismissals, rate limits, feature gating.
  • Password Recovery: Self-service request (email+phone+new password) with admin approval, rate limits, TTL, audits; supersedes legacy password_reset_tokens (unused).
  • Profile Projects & Achievements: CRUD with tech stack tags, issuer, links; skills/links parsing retained; photo upload/delete.
  • Teacher Attendance UX: Per-student month calendar; quick status cycling.
  • Env toggles: NOTIFICATION_MAX_UPLOAD_SIZE, NOTIFICATION_FETCH_CACHE_SECONDS, RECOVERY_TOKEN_TTL_SECONDS, RECOVERY_RATE_LIMIT_WINDOW_SECONDS, RECOVERY_RATE_LIMIT_MAX_ATTEMPTS.

Table of Contents

  1. System Architecture
  2. Complete Technology Stack
  3. Directory Structure & File Organization
  4. Captive Portal Configuration
  5. Network & Device Access
  6. Tailscale SSH Configuration
  7. PostgreSQL Database
  8. Website & Frontend Files
  9. Python CGI Backend APIs
  10. Role-Based Authentication
  11. Attendance Module
  12. Student Profile Picture Feature
  13. Chat System & Real-Time Features
  14. Global URL System
  15. Admin Dashboard
  16. Flutter Android Application
  17. System Configuration Files
  18. Deployment & Startup
  19. OLED Monitoring System
  20. Troubleshooting & Maintenance

1. System Architecture

1.1 Complete Technology Stack

Component Technology Version Purpose
Hardware Raspberry Pi 3B+ 1GB RAM Base server
OS Raspberry Pi OS Lite 32-bit Debian Minimal footprint
Python Python 3 3.13+ Backend APIs
Database PostgreSQL 13.6 Main data store (53 tables)
Web Server Lighttpd 1.4.59 HTTP server
Access Point hostapd nl80211 WiFi broadcast
DHCP/DNS dnsmasq 2.86 Network services
Firewall iptables built-in Network filtering
Tunnel Cloudflare Tunnel cloudflared Public access
Database Sync Firebase Realtime DB asia-southeast1 URL sync
Static Redirect GitHub Pages craboxx.github.io/_/ Fixed URL
Monitoring OLED SSD1306 I2C interface System display
Mobile Flutter 3.7+ Android app

1.2 System Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│              Raspberry Pi 3B+ (192.168.4.1)                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────────┐         ┌──────────────┐                │
│  │   hostapd    │         │   dnsmasq    │                │
│  │ (WiFi Access │         │ (DHCP + DNS) │                │
│  │    Point)    │         │  DNS Spoof   │                │
│  └──────┬───────┘         └──────┬───────┘                │
│         │                        │                         │
│         │     ┌──────────────────┘                         │
│         │     │                                            │
│         └─────┼────────┐                                   │
│               │        │                                   │
│         ┌─────▼──┬─────▼──┐                               │
│         │ iptables        │                               │
│         │ (NAT + Redirect)│                               │
│         └────────┬────────┘                               │
│                  │                                        │
│          ┌───────▼──────────┐                            │
│          │    Lighttpd      │                            │
│          │   Web Server     │                            │
│          │    Port 80       │                            │
│          └────────┬─────────┘                            │
│                   │                                      │
│    ┌──────────────┼──────────────┐                      │
│    │              │              │                      │
│    ▼              ▼              ▼                      │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐             │
│ │ Frontend │ │ Backend  │ │  PostgreSQL  │             │
│ │  HTML/   │ │ Python   │ │  Database    │             │
│ │ CSS/JS   │ │  CGI     │ │  (53 tables) │             │
│ └──────────┘ └──────────┘ └──────────────┘             │
│                                                         │
│     ┌───────────────────┐    ┌──────────────────┐      │
│     │   Cloudflared     │    │   Monitor.py     │      │
│     │   (Tunnel)        │    │  (OLED Display)  │      │
│     └───────────────────┘    └──────────────────┘      │
│              │                                          │
└──────────────┼──────────────────────────────────────────┘
               │
               │ (HTTPS)
               │
    ┌──────────▼──────────┐
    │  Cloudflare Tunnel  │
    │  https://random.    │
    │  trycloudflare.com  │
    └──────────┬──────────┘
               │
               │ (Python sync)
               │
    ┌──────────▼──────────┐
    │  Firebase Realtime  │
    │   Database (URL)    │
    └──────────┬──────────┘
               │
               │ (JavaScript)
               │
    ┌──────────▼──────────────────┐
    │  GitHub Pages Fixed Redirect │
    │ https://craboxx.github.io/_/ │
    └──────────────────────────────┘

2. Complete Technology Stack

2.1 Backend Services Running on Pi

# System Services
systemctl status hostapd          # WiFi Access Point
systemctl status dnsmasq          # DHCP + DNS Spoofing
systemctl status lighttpd         # Web Server
systemctl status postgresql       # Database
systemctl status cloudflared       # Cloudflare Tunnel
systemctl status update-tunnel-url # URL Page Updater
systemctl status firebase-update   # Firebase Sync

2.2 Python Backend Architecture

/usr/lib/cgi-bin/
├── config.py                     # Configuration & DB Utilities
├── user.py                       # Auth: Login, Register, Sessions
├── server.py                     # Admin: Dashboard, User Management
├── profile_api.py               # Student Profiles & Portfolios
├── assignment_api.py            # Assignment Submission System
├── attendance_api.py            # Attendance Management
├── batch_api.py                 # Batch Management
├── chat_api.py                  # Group Chat System
├── content_api.py               # Content Sharing
└── .env                         # Environment Variables

2.3 Frontend Architecture

/var/www/html/
├── index.html                   # Login/Registration Portal
├── student.html                 # Student Dashboard
├── teacher.html                 # Teacher Dashboard
├── admin-login.html             # Admin Login
├── safaclgadmin.html            # Admin Dashboard
├── student-profile.html         # Student Portfolio & Skills (WITH PHOTO)
├── student-chat.html            # 1-on-1 Chat Interface
├── group-chat.html              # Group Chat System
├── url.html                     # Auto-Updated Tunnel URL
├── style.css                    # Global Bootstrap Styles
├── css/
│   └── bootstrap.min.css        # Bootstrap Framework
├── js/
│   └── bootstrap.bundle.min.js  # Bootstrap JavaScript
└── uploads/                     # File Storage
    ├── assignments/
    ├── documents/
    ├── images/
    ├── profiles/                # Student Profile Photos
    └── [timestamped files]

3. Directory Structure & File Organization

3.1 Complete Filesystem Layout

/
├── /var/www/html/                              # Web Root (Lighttpd)
│   ├── index.html                              # Login/Registration Portal
│   ├── student.html                            # Student Dashboard
│   ├── teacher.html                            # Teacher Dashboard
│   ├── admin-login.html                        # Admin Login Page
│   ├── safaclgadmin.html                       # Admin Dashboard (Complete)
│   ├── student-profile.html                    # Student Portfolio Management (WITH PHOTO)
│   ├── student-chat.html                       # 1-on-1 Chat Interface
│   ├── group-chat.html                         # Group Chat System
│   ├── style.css                               # Global Styles (27KB)
│   ├── url.html                                # Tunnel URL Display (Auto-Updated)
│   ├── css/
│   │   └── bootstrap.min.css
│   ├── js/
│   │   └── bootstrap.bundle.min.js
│   └── uploads/                                # File Storage (Hierarchical)
│       ├── assignments/
│       ├── documents/
│       ├── images/
│       ├── profiles/                           # Student Profile Photos
│       └── [timestamped files with random hex]
│
├── /usr/lib/cgi-bin/                          # Backend APIs (Python CGI)
│   ├── config.py                              # Database Config (11KB)
│   ├── user.py                                # Auth & User Ops (19KB)
│   ├── server.py                              # Admin Operations (21KB)
│   ├── profile_api.py                         # Student Profile Ops (11KB)
│   ├── assignment_api.py                      # Assignment Management
│   ├── attendance_api.py                      # Attendance Management
│   ├── batch_api.py                           # Batch Management
│   ├── chat_api.py                            # Chat System (16KB)
│   ├── content_api.py                         # Content Sharing
│   ├── .env                                   # Environment Variables
│   └── collegedata.json                       # College Configuration
│
├── /etc/hostapd/                              # Access Point
│   └── hostapd.conf                           # WiFi Configuration
│
├── /etc/dnsmasq.conf                          # DHCP + DNS Configuration
├── /etc/dhcpcd.conf                           # Network Interface Config
│
├── /etc/lighttpd/                             # Web Server
│   └── lighttpd.conf                          # Server Configuration (2KB)
│
├── /etc/rc.local                              # Startup Script (380B)
├── /etc/sysctl.conf                           # Kernel Parameters (21B)
│
├── /etc/systemd/system/                       # System Services
│   ├── cloudflared.service
│   ├── update-tunnel-url.service
│   └── firebase-update.service
│
├── /usr/local/bin/                            # Utilities
│   ├── cloudflared                            # Cloudflare Tunnel Binary
│   ├── update-tunnel-url.sh                   # URL Page Updater (3KB)
│   └── firebase-update.py                     # Firebase Sync Script (2KB)
│
├── /home/crabox/                              # Home Directory
│   ├── monitor.py                             # OLED Display Monitor (31KB)
│   ├── OLED_Stats/
│   └── .env                                   # User Environment Variables
│
└── /var/log/                                  # Logs
    ├── lighttpd/
    │   └── error.log
    ├── postgresql/
    └── syslog

3.2 File Sizes & Statistics

Frontend Files:
- index.html            37 KB
- student.html          61 KB
- teacher.html          87 KB
- admin-login.html      6 KB
- safaclgadmin.html     58 KB
- student-profile.html  38 KB
- student-chat.html     16 KB
- group-chat.html       34 KB
- style.css             28 KB
- url.html              4 KB

Backend Files:
- config.py             21 KB
- user.py               20 KB
- server.py             23 KB
- profile_api.py        16 KB
- assignment_api.py     20 KB
- attendance_api.py     12 KB
- batch_api.py          13 KB
- chat_api.py           16 KB
- content_api.py        15 KB
- .env                  1 KB

Database Files:
- psqldata_datas.txt 240 KB (Database dump)


4. Captive Portal Configuration

4.1 Hostapd Configuration (/etc/hostapd/hostapd.conf)

interface=wlan0
driver=nl80211
ssid=Project-CRAD
hw_mode=g
channel=6
auth_algs=1
wmm_enabled=0
ignore_broadcast_ssid=0

Key Settings:

  • SSID: Project-CRAD (Broadcast enabled)
  • Driver: nl80211 (Linux wireless API)
  • Band: 2.4GHz (802.11g)
  • Channel: 6 (Non-overlapping)
  • WMM: Disabled (Compatibility)

4.2 Dnsmasq Configuration (/etc/dnsmasq.conf)

# DHCP Configuration
interface=wlan0
dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h
domain-needed
bogus-priv
dhcp-option=3,192.168.4.1
dhcp-option=6,192.168.4.1

# Captive Portal Smart Redirect
address=/connectivitycheck.gstatic.com/192.168.4.1
address=/clients3.google.com/192.168.4.1
address=/captive.apple.com/192.168.4.1
address=/msftconnecttest.com/192.168.4.1
address=/msftncsi.com/192.168.4.1
address=/connectivitycheck.platform.hicloud.com/192.168.4.1
address=/connectivitycheck.hicloud.com/192.168.4.1
address=/connectivitycheck.cbg-app.huawei.com/192.168.4.1

DNS Spoofing:

  • Redirects all known captive portal probes to Pi
  • Supports Android, iOS, Windows, Huawei devices
  • DHCP range: 192.168.4.2 - 192.168.4.20 (18 clients)

4.3 Lighttpd Configuration (/etc/lighttpd/lighttpd.conf)

server.modules = (
    "mod_indexfile",
    "mod_access",
    "mod_alias",
    "mod_redirect",
    "mod_dirlisting",
    "mod_staticfile",
    "mod_cgi"
)

server.document-root        = "/var/www/html"
server.port                 = 80
server.username             = "www-data"
server.groupname            = "www-data"
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/run/lighttpd.pid"

# CGI Support
cgi.assign = (
    ".py" => "/usr/bin/python3",
    ".cgi" => "/usr/bin/python3"
)
alias.url += ( "/cgi-bin/" => "/usr/lib/cgi-bin/" )

# Captive Portal Redirects
$HTTP["url"] =~ "^/generate_204$" {
    url.redirect = ("" => "/")
}
$HTTP["url"] =~ "^/hotspot-detect.html$" {
    url.redirect = ("" => "/")
}
$HTTP["url"] =~ "^/ncsi.txt$" {
    url.redirect = ("" => "/")
}
$HTTP["url"] =~ "^/connecttest.txt$" {
    url.redirect = ("" => "/")
}

index-file.names = ("index.php", "index.html")
static-file.exclude-extensions = (".php", ".pl", ".fcgi")

4.4 DHCPCD Configuration (/etc/dhcpcd.conf)

duid
persistent
vendorclassid
option domain_name_servers, domain_name, domain_search
option classless_static_routes
option interface_mtu
option host_name
option rapid_commit
require dhcp_server_identifier
slaac private

interface wlan0
    static ip_address=192.168.4.1/24
    nohook wpa_supplicant

Static IP Setup:

  • wlan0: 192.168.4.1/24
  • No external DHCP needed
  • Direct static configuration

5. PostgreSQL Database

5.1 Database Overview

Database Name: user_system
Host: localhost (127.0.0.1)
Port: 5432
Total Tables: 53 (EXPANDED)
Estimated Size: 5-10 MB (production data)
Engine: PostgreSQL 13.6 (Raspbian)
Encoding: UTF-8
Locale: en_US.UTF-8

5.2 Complete Table Schema (53 Tables)

Core User Management

  1. admin_accounts - Admin users with super-admin flag
  2. admin_messages - Admin-to-users messaging
  3. admin_sessions - Active admin sessions
  4. announcement_reads - Announcement read status
  5. announcements - System announcements
  6. approved_users - Approved students/teachers
  7. assignment_submissions - Student submissions
  8. assignments - Assignment definitions

Attendance Management

  1. attendance - Class attendance tracking
    • id (PK), batch_code, student_id, subject_name
    • teacher_id, attendance_date, status (present/absent/late)
    • marked_at, marked_by, batch_id, remarks
    • Indexes: attendance_date, batch_code, student_id, teacher_id

Batch & Course Management

  1. audit_logs - System audit logs
  2. batch_announcements - Batch-specific announcements
  3. batch_courses - Course assignments to batches
  4. batch_definitions - Batch definitions
  5. batch_models - Batch model configurations
  6. batches - Course batches

Chat & Communication

  1. chat_group_members - Group membership
  2. chat_groups - Chat group definitions
  3. chat_messages - Group chat messages

Class Management

  1. class_schedule - Class timetable
  2. content_read_receipts - Content view tracking
  3. content_submissions - Student content submissions
  4. course_subjects - Subject course mappings
  5. courses - Course definitions

Department & Organization

  1. departments - Department definitions
  2. exam_results - Exam results
  3. exams - Exam definitions
  4. feedback - Student/Teacher feedback
  5. file_attachments - File attachment tracking

File Management

  1. file_uploads - File storage tracking
  2. material_library - Study materials catalog
  3. messages - Direct messages

Notifications

  1. notifications - System notifications

Password Management

  1. password_reset_tokens - Legacy reset tokens (unused in v10; superseded by password_recovery_* tables)
  2. pending_users - Pending approval registrations

Sections & Scheduling

  1. sections - Course sections
  2. semesters - Semester definitions
  3. student_achievements - Student achievements/certifications

Student Features

  1. student_enrollment - Course enrollment tracking
  2. student_profiles - Student portfolio (WITH PHOTO)
  • id (PK), student_id, bio, profile_photo (NEW - file path)
  • skills (JSONB), interests, github_url, linkedin_url
  • portfolio_url, resume_path, created_at, updated_at
  1. student_projects - Student project portfolio
  2. student_roll_counters - Roll number tracking

Study Resources

  1. study_resources - Study materials
  2. subjects - Subject definitions

Submission Management

  1. submission_attachments - Attachment tracking
  2. system_settings - System configuration

Teacher Features

  1. teacher_assignments - Teacher assignment assignments
  2. teacher_batch_assignments - Batch assignments to teachers
  3. teacher_batches - Teacher batch relationships
  4. teacher_content - Teacher-shared content

Timetable

  1. timetable - General timetable management

User Interactions

  1. user_contributions - User contributions tracking
  2. user_interactions - User interaction logs
  3. user_sessions - Active user sessions

Optional additive tables (enable v10 features)

  • campus_notifications, campus_notification_dismissals, campus_notification_audit — Campus-wide notifications, dismissals, admin audits
  • password_recovery_requests, password_recovery_audit — Self-service password recovery with admin approval and audit trail

5.3 Attendance Table Structure

CREATE TABLE attendance (
    id SERIAL PRIMARY KEY,
    batch_code VARCHAR(10) NOT NULL,
    student_id INTEGER NOT NULL,
    subject_name VARCHAR(100),
    teacher_id INTEGER,
    attendance_date DATE NOT NULL,
    status VARCHAR(20) NOT NULL CHECK (status IN ('present', 'absent', 'late')),
    marked_at BIGINT NOT NULL,
    marked_by INTEGER,
    batch_id INTEGER,
    remarks TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    -- Indexes for fast querying
    FOREIGN KEY (student_id) REFERENCES approved_users(id) ON DELETE CASCADE,
    FOREIGN KEY (teacher_id) REFERENCES approved_users(id),
    FOREIGN KEY (batch_id) REFERENCES batch_models(id),
    
    INDEX idx_attendance_date (attendance_date),
    INDEX idx_batch_code (batch_code),
    INDEX idx_student_id (student_id),
    INDEX idx_teacher_id (teacher_id)
);

5.4 Student Profiles Table Enhancement (UPDATED)

-- Profile Photo Column Added
ALTER TABLE student_profiles ADD COLUMN profile_photo VARCHAR(500);

-- Updated student_profiles structure
CREATE TABLE student_profiles (
    id SERIAL PRIMARY KEY,
    student_id INTEGER UNIQUE,
    bio TEXT,
    profile_photo VARCHAR(500),         -- NEW: File path to profile photo
    skills JSONB DEFAULT '[]',
    interests TEXT,
    github_url TEXT,
    linkedin_url TEXT,
    portfolio_url TEXT,
    resume_path TEXT,
    created_at BIGINT,
    updated_at BIGINT,
    
    FOREIGN KEY (student_id) REFERENCES approved_users(id) ON DELETE CASCADE
);

5.5 Database Connection Configuration

# config.py Database Setup
DB_CONFIG = {
    'dbname': os.getenv('DB_NAME', 'user_system'),
    'user': os.getenv('DB_USER', 'postgres'),
    'password': os.getenv('DB_PASSWORD', ''),
    'host': os.getenv('DB_HOST', 'localhost'),
    'port': os.getenv('DB_PORT', '5432'),
    'connect_timeout': 10,
    'application_name': 'safa_college_portal'
}

DB_POOL_CONFIG = {
    'min_connections': 2,
    'max_connections': 10,
    'max_idle': 300  # 5 minutes
}

5.6 Database Initialization

# Connect to PostgreSQL
sudo -u postgres psql

# Create database
CREATE DATABASE user_system;

# Import schema (if available)
psql user_system < schema.sql

# Create indexes
CREATE INDEX idx_users_batch ON approved_users(batch_code);
CREATE INDEX idx_sessions_expires ON user_sessions(expires_at);
CREATE INDEX idx_assignments_batch ON assignments(batch_code);
CREATE INDEX idx_chat_group_user ON chat_group_members(user_id);
CREATE INDEX idx_attendance_date ON attendance(attendance_date);
CREATE INDEX idx_attendance_student ON attendance(student_id);

5.7 Key Queries for Admin

-- Total Users by Role
SELECT role, COUNT(*) as count 
FROM approved_users 
GROUP BY role;

-- Students per Batch
SELECT batch_code, COUNT(*) as student_count 
FROM approved_users 
WHERE role = 'student' 
GROUP BY batch_code;

-- Pending Approvals
SELECT * FROM pending_users 
ORDER BY submitted_at DESC;

-- Active Sessions
SELECT u.username, u.role, s.created_at, s.expires_at 
FROM user_sessions s 
JOIN approved_users u ON s.user_id = u.id 
WHERE s.expires_at > NOW();

-- Recent Assignments
SELECT title, teacher_id, batch_code, due_date 
FROM assignments 
ORDER BY created_at DESC 
LIMIT 10;

-- Chat Activity (Last 24h)
SELECT g.group_name, COUNT(m.id) as message_count 
FROM chat_messages m 
JOIN chat_groups g ON m.group_id = g.id 
WHERE m.created_at > NOW() - INTERVAL '1 day' 
GROUP BY g.group_name;

-- Attendance Statistics
SELECT 
    batch_code, 
    attendance_date, 
    COUNT(*) as total_marked,
    SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present,
    SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent,
    SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late
FROM attendance
WHERE attendance_date >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY batch_code, attendance_date
ORDER BY attendance_date DESC;

6. Website & Frontend Files

6.1 Frontend Architecture Overview

Frontend Technology Stack:
- HTML5 (Semantic structure)
- CSS3 + Bootstrap 5 (Responsive design)
- JavaScript ES6+ (Client-side logic)
- Fetch API (AJAX requests)
- Session Storage (Client-side state)
- Firebase JS SDK (Real-time URL fetching)

6.2 Frontend Pages

6.2.1 index.html - Login/Registration Portal

Features:

  • Unified login/register interface
  • Role selection (Student/Teacher)
  • Student ID validation (SFAXBCA001 format)
  • Real-time form validation
  • Password strength indicator
  • Email verification (optional)
  • Phone number validation (Indian format)
  • Auto-redirect based on role

Key Elements:

  • Form validation with regex
  • Captcha integration ready
  • Responsive design (Mobile-first)
  • Dark mode toggle
  • Accessibility features (ARIA labels)

6.2.2 student.html - Student Dashboard (60 KB)

Dashboard Sections:

  1. Header - Student info, logout, theme toggle
  2. Sidebar Navigation - Dashboard, Assignments, Attendance, Chat, Profile, Content
  3. Statistics Cards - Active assignments, attendance, chat messages, files uploaded
  4. Quick Actions - View assignments, Check attendance, Join chat, Upload file
  5. Recent Activity - Latest announcements, assignments, messages

Key Features:

  • Assignment submission interface
  • Attendance View - View personal attendance records
  • Chat integration (group + individual)
  • File upload management
  • Performance analytics (marks, attendance)
  • Study resources access
  • Notification center

6.2.3 teacher.html - Teacher Dashboard (88 KB)

Dashboard Sections:

  1. Header - Teacher info, assigned batches, logout
  2. Sidebar - Dashboard, Content, Batches, Attendance, Students, Chat
  3. Statistics - Assigned students, content shared, pending submissions
  4. Quick Actions - Share content, Create assignment, Mark attendance, View submissions

Key Features:

  • Assignment creation & management
  • Attendance Marking Interface - Mark attendance for batch
  • Content sharing interface
  • Batch management
  • Student performance tracking
  • Group chat creation
  • Submission review interface
  • Grading system
  • Class schedule management

6.2.4 safaclgadmin.html - Admin Dashboard (59 KB)

Admin Panels:

  1. Dashboard Overview - Total users, pending approvals, batches, activity
  2. User Management - Approve/reject users, manage roles, deactivate accounts
  3. Batch Management - Create/edit batches, manage assignments, toggle status
  4. Pending Requests - Review student/teacher registration requests
  5. Users List - Search, filter, bulk actions
  6. Statistics - Usage analytics, system health

Key Features:

  • User approval workflow
  • Batch configuration
  • Role management
  • Activity logging
  • System health monitoring
  • Bulk operations
  • Export functionality (CSV)
  • Advanced search & filters

6.2.5 student-profile.html - Student Portfolio (38 KB)

Profile Sections:

  1. Profile Information - Name, ID, batch, contact info
  2. Profile Photo Section - Upload, display, and delete profile picture
  3. Bio & Skills - Personal bio, technical skills, interests
  4. Projects - Portfolio projects with GitHub/demo links
  5. Achievements - Certifications, awards, competitions
  6. Links - GitHub, LinkedIn, portfolio website

Key Features:

  • Editable profile information
  • Profile Photo Upload - JPG/PNG, max 5MB, 300x300px recommended
  • Photo Display - Circular avatar with fallback
  • Photo Management - View, change, remove options
  • Skill management
  • Project portfolio management
  • Achievement tracking
  • Social links integration
  • Public profile view option

6.2.6 student-chat.html - Chat Interface (16 KB)

Chat Features:

  1. Group Chat - Batch-wide messaging
  2. 1-on-1 Chat - Direct messaging with peers/teachers
  3. Message History - Scrollable message thread
  4. Online Status - Show user online/offline status
  5. Typing Indicators - See when others are typing
  6. File Sharing - Send files in chat
  7. Notifications - New message alerts
  8. Message Search - Search through message history

6.3 Frontend Styling (style.css - 27 KB)

/* Color Scheme */
--crad-primary: #1e40af (Blue)
--crad-secondary: #059669 (Green)
--crad-accent: #f59e0b (Amber)

/* Components */
- Navigation bars with gradients
- Card components with shadows
- Form inputs with focus states
- Buttons with hover effects
- Modals & dialogs
- Data tables with sorting
- Responsive grid layout
- Theme switching (light/dark)

6.4 Bootstrap Integration

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/bootstrap.min.css">

<!-- Bootstrap JS Bundle -->
<script src="bootstrap.bundle.min.js"></script>

<!-- Bootstrap 5 Components Used -->
- Grid system (Responsive containers)
- Navbar (Navigation)
- Cards (Content blocks)
- Forms (Input groups, validation)
- Modals (Dialogs)
- Alerts (Notifications)
- Tables (Data display)
- Buttons (Interactive elements)
- Badges (Status indicators)
- Dropdowns (Menu options)

6.5 JavaScript Architecture

// Session Management
sessionStorage.setItem('session_id', token)
sessionStorage.setItem('user_role', role)

// Fetch API Patterns
fetch('/cgi-bin/user.py', {
    method: 'POST',
    body: new FormData(form)
})
.then(r => r.json())
.then(data => { /* handle response */ })

// Firebase URL Fetching
firebase.database()
    .ref('/public/tunnel_url/url')
    .on('value', snap => { /* update UI */ })

// Event Delegation
document.addEventListener('click', e => {
    if(e.target.matches('.btn-delete')) { /* handle */ }
})

// Real-time Updates
setInterval(() => { /* fetch updates */ }, 5000)

7. Python CGI Backend APIs

7.1 Backend Architecture

Python 3.13 CGI Backend
├── request handling (parse_qs, POST/GET)
├── database connections (psycopg2)
├── session verification
├── CORS headers
├── JSON responses
└── error handling

7.2 Core Modules

7.2.1 config.py (11 KB) - Configuration Management

Functions:

def get_db_connection()
    # Returns psycopg2 database connection

def get_cors_headers()
    # Returns CORS headers dict

def get_current_timestamp()
    # Returns Unix epoch timestamp

def parse_batch_code(student_id)
    # Parses SFAXBCA001 format → dict

def get_cors_headers()
    # CORS headers for cross-origin requests

Configuration:

# Database Configuration
DB_CONFIG = {
    'dbname': 'user_system',
    'user': 'postgres',
    'password': '***',
    'host': 'localhost',
    'port': '5432'
}

# Session Configuration
SESSION_CONFIG = {
    'user_session_ttl': 3600,      # 1 hour
    'admin_session_ttl': 7200,     # 2 hours
    'remember_me_ttl': 2592000     # 30 days
}

# Security Configuration
SECURITY_CONFIG = {
    'password_min_length': 8,
    'bcrypt_rounds': 12,
    'rate_limit_enabled': True,
    'max_login_attempts': 5,
    'lockout_duration': 900
}

# Batch ID Configuration
BATCH_ID_CONFIG = {
    'student_id_pattern': r'^[A-Z]{3}[A-Z][A-Z]{2,6}\d{3}$',
    'teacher_id_pattern': r'^[A-Z0-9]{6,15}$',
    'batch_letters': ['A', 'B', 'C', ..., 'Z'],
    'course_codes': {
        'BCA': 'Bachelor of Computer Applications',
        'BBA': 'Bachelor of Business Administration',
        ...
    }
}

7.2.2 user.py (19 KB) - User Authentication & Operations

Authentication Endpoints:

POST /cgi-bin/user.py?action=register
{
    "username": "student_name",
    "email": "student@example.com",
    "password": "SecurePass123!",
    "full_name": "Full Name",
    "student_id": "SFAXBCA001",
    "phone": "+919876543210"
}
Response: { "success": true, "session_id": "...", "user": {...} }

POST /cgi-bin/user.py?action=login
{
    "username": "student_name",
    "password": "SecurePass123!"
}
Response: { "success": true, "session_id": "...", "user": {...} }

POST /cgi-bin/user.py?action=logout
{ "session_id": "..." }
Response: { "success": true }

GET /cgi-bin/user.py?action=verify_session&session_id=...
Response: { "success": true, "user": {...}, "expires_at": ... }

Key Functions:

def send_json_response(data, status_code=200)
def send_error(message, status_code=400, error_code=None)
def get_request_data()  # Parse POST/GET
def hash_password(password)  # bcrypt hashing
def verify_password(password, hashed)  # bcrypt verification
def validate_password(password)  # Strength validation
def validate_email(email)  # Email format validation
def validate_phone(phone)  # Indian phone validation
def generate_session_id()  # Create secure session ID
def create_user_session(conn, user_id, role, batch_code)
def validate_student_id(student_id)  # Parse SFAXBCA001
def validate_teacher_id(teacher_id)  # Random alphanumeric

Security Features:

  • bcrypt password hashing (12 rounds)
  • Session token generation (secrets.token_urlsafe)
  • Password validation (min 8 chars, uppercase, lowercase, digit)
  • Email format validation
  • Phone number validation (Indian +91)
  • SQL injection prevention (parameterized queries)
  • CORS headers

7.2.3 server.py (21 KB) - Admin API

Admin Endpoints:

POST /cgi-bin/server.py?action=admin_login
{
    "username": "admin@college.com",
    "password": "AdminPass123!"
}
Response: { "success": true, "session_id": "...", "redirect_url": "/safaclgadmin.html" }

GET /cgi-bin/server.py?action=dashboard&session_id=...
Response: {
    "success": true,
    "stats": {
        "total_students": 150,
        "total_teachers": 25,
        "pending_users": 5,
        "total_batches": 4
    },
    "pending_users": [...],
    "batches": [...]
}

POST /cgi-bin/server.py?action=approve_user
{
    "session_id": "...",
    "user_id": 123,
    "status": "approved"
}

POST /cgi-bin/server.py?action=manage_batch
{
    "session_id": "...",
    "batch_id": 1,
    "action": "toggle_status"
}

Admin Functions:

def verify_session(conn, session_id)  # Verify admin session
def admin_login(data)
def dashboard(data)  # Dashboard statistics
def get_pending_users(data)
def approve_user(data)
def reject_user(data)
def manage_batch(data)  # Create/update/delete
def manage_users(data)  # User management
def view_activity_logs(data)
def send_mass_message(data)
def configure_system(data)

7.2.4 profile_api.py (16 KB) - Student Profiles & Photos

Profile Endpoints:

POST /cgi-bin/profile_api.py?action=get_profile
{ "session_id": "...", "student_id": 123 }
Response: {
    "success": true,
    "user": {...},
    "profile": {...},
    "profile_photo_url": "uploads/profiles/photo_12345.jpg",
    "projects": [...],
    "achievements": [...]
}

POST /cgi-bin/profile_api.py?action=update_profile
{
    "session_id": "...",
    "bio": "...",
    "skills": "Python, JavaScript, HTML",
    "github_url": "https://github.com/...",
    "linkedin_url": "https://linkedin.com/..."
}

POST /cgi-bin/profile_api.py?action=upload_photo
{
    "session_id": "...",
    "photo": <file_object>  # Multipart form data
}
Response: { "success": true, "photo_url": "uploads/profiles/photo_12345.jpg" }

POST /cgi-bin/profile_api.py?action=delete_photo
{ "session_id": "..." }
Response: { "success": true, "message": "Photo deleted" }

POST /cgi-bin/profile_api.py?action=add_project
{
    "session_id": "...",
    "project_title": "CRAD Portal",
    "description": "Academic dashboard",
    "technologies_used": "Python, PostgreSQL, JavaScript",
    "project_url": "https://...",
    "github_repo": "https://github.com/..."
}

POST /cgi-bin/profile_api.py?action=add_achievement
{
    "session_id": "...",
    "achievement_title": "Google Cloud Certification",
    "achievement_type": "certification",
    "issuer": "Google",
    "description": "Cloud Engineer Associate"
}

Photo Upload Features:

  • File format validation: JPG, PNG only
  • File size limit: 5MB
  • Image dimensions: Recommended 300x300px
  • Storage path: /var/www/html/uploads/profiles/
  • Filename format: photo_<student_id>_<timestamp>.<ext>
  • Auto-resize to 300x300px (if PIL available)
  • Circular display with CSS border-radius
  • Fallback to initials avatar

7.2.5 assignment_api.py - Assignment Management

Assignment Endpoints:

POST /cgi-bin/assignment_api.py?action=create_assignment
{
    "session_id": "...",
    "batch_code": "SFAA",
    "subject_name": "Data Structures",
    "title": "Assignment 1 - Arrays",
    "description": "...",
    "max_marks": 100,
    "due_date": 1698768000,
    "allow_late_submission": true,
    "late_penalty_percent": 10
}

POST /cgi-bin/assignment_api.py?action=get_assignments
{
    "session_id": "...",
    "batch_code": "SFAA"
}

POST /cgi-bin/assignment_api.py?action=submit_assignment
{
    "session_id": "...",
    "assignment_id": 1,
    "submission_content": "...",
    "files": [...]
}

POST /cgi-bin/assignment_api.py?action=grade_assignment
{
    "session_id": "...",
    "submission_id": 1,
    "marks": 85,
    "feedback": "Good work!"
}

7.2.6 attendance_api.py (11 KB) - Attendance Management

Attendance Endpoints:

POST /cgi-bin/attendance_api.py?action=get_teacher_batches
{
    "session_id": "..."
}
Response: {
    "success": true,
    "batches": [
        {
            "id": 1,
            "batch_code": "SFAA",
            "batch_name": "BCA 2023 - A",
            "course_name": "BCA",
            "student_count": 50
        }
    ]
}

POST /cgi-bin/attendance_api.py?action=get_batch_students
{
    "session_id": "...",
    "batch_code": "SFAA",
    "date": "2026-01-01"
}
Response: {
    "success": true,
    "students": [
        {
            "student_id": 123,
            "full_name": "John Doe",
            "registration_number": "SFAXBCA001",
            "email": "john@example.com",
            "status": "present" or "absent" or "late" or null
        }
    ],
    "date": "2026-01-01",
    "batch_code": "SFAA"
}

POST /cgi-bin/attendance_api.py?action=mark_attendance
{
    "session_id": "...",
    "student_id": 123,
    "batch_code": "SFAA",
    "date": "2026-01-01",
    "status": "present"  // or "absent", "late"
}
Response: {
    "success": true,
    "message": "Attendance marked as present",
    "status": "present"
}

POST /cgi-bin/attendance_api.py?action=get_student_attendance
{
    "session_id": "...",
    "month": 1,  // optional
    "year": 2026  // optional
}
Response: {
    "success": true,
    "records": [
        {
            "attendance_date": "2026-01-01",
            "status": "present"
        }
    ],
    "statistics": {
        "total": 20,
        "present": 18,
        "absent": 1,
        "late": 1,
        "percentage": 90.0
    }
}

Attendance Functions:

def get_teacher_batches(post, user)
    # Get batches assigned to teacher

def get_batch_students(post, user)
    # Get all students in batch with attendance status

def mark_attendance(post, user)
    # Mark or update attendance for a student
    
def get_student_attendance(post, user)
    # Get attendance records for a student with statistics

def verify_session(sessiontoken)
    # Verify user session and return user details

Attendance Features:

  • Teacher-only marking (role-based access)
  • Batch-wise filtering
  • Date-based organization
  • Status tracking (present, absent, late)
  • Student statistics (count, percentage)
  • Monthly/yearly filtering
  • Update existing records
  • Marked-by tracking (teacher_id)
  • Timestamp tracking (marked_at)

7.2.7 chat_api.py (15 KB) - Chat System

Chat Endpoints:

POST /cgi-bin/chat_api.py?action=create_group
{
    "session_id": "...",
    "group_name": "BCA-A Class",
    "batch_code": "SFAA",
    "description": "Class discussion group"
}

POST /cgi-bin/chat_api.py?action=get_user_groups
{ "session_id": "..." }
Response: {
    "success": true,
    "groups": [
        {
            "id": 1,
            "group_name": "BCA-A Class",
            "unread_count": 3,
            "last_message_time": 1698768000
        }
    ]
}

POST /cgi-bin/chat_api.py?action=get_messages
{
    "session_id": "...",
    "group_id": 1,
    "limit": 50,
    "offset": 0
}

POST /cgi-bin/chat_api.py?action=send_message
{
    "session_id": "...",
    "group_id": 1,
    "message_text": "Hello everyone!",
    "reply_to": null
}

Chat Features:

  • Group chat with batch-based auto-membership
  • Private 1-on-1 messaging
  • Message threading (reply_to_message)
  • Read receipts (last_read_at)
  • Unread message counting
  • Message history with pagination
  • Online/offline status
  • Typing indicators
  • File attachments in chat

7.2.8 batch_api.py - Batch Management

Batch Endpoints:

GET /cgi-bin/batch_api.py?action=get_batches
Response: { "success": true, "batches": [...] }

GET /cgi-bin/batch_api.py?action=get_active_batches
Response: { "success": true, "batches": [...] }

POST /cgi-bin/batch_api.py?action=create_batch
{
    "session_id": "...",
    "batchName": "BCA 2023-2026",
    "startYear": 2023,
    "endYear": 2026,
    "isActive": true
}

PUT /cgi-bin/batch_api.py?action=update_batch
{
    "session_id": "...",
    "batchId": 1,
    "batchName": "BCA 2023-2026",
    "isActive": false
}

DELETE /cgi-bin/batch_api.py?action=delete_batch
{
    "session_id": "...",
    "batchId": 1
}

7.3 Common API Response Format

{
    "success": true/false,
    "message": "Operation successful",
    "data": { /* endpoint-specific data */ },
    "error": "Error message (if failed)",
    "error_code": "ERROR_CODE",
    "timestamp": 1698768000
}

7.4 Error Handling

# Standard Error Codes
'AUTH_FAILED'      # Authentication failed
'UNAUTHORIZED'     # Authorization failed
'NOT_FOUND'        # Resource not found
'VALIDATION_ERROR' # Input validation failed
'DATABASE_ERROR'   # Database error
'CONFLICT'         # Resource already exists
'INTERNAL_ERROR'   # Server error

8. Role-Based Authentication

8.1 User Roles

1. STUDENT
   - Register with student ID (SFAXBCA001)
   - Access: Dashboard, Assignments, Attendance, Chat, Profile, Resources
   - Permissions: View assignments, submit, view grades, check attendance, chat
   - Batch-based access control

2. TEACHER
   - Register with teacher ID (alphanumeric)
   - Access: Dashboard, Create assignments, Manage content, Mark Attendance, Grade
   - Permissions: Create assignments, share content, grade submissions, manage chat
   - Batch assignment required
   - Attendance marking for assigned batches

3. ADMIN
   - Separate login (admin portal)
   - Access: All dashboards, user management, batch management
   - Permissions: Approve users, manage batches, view analytics, send mass messages
   - Super-admin flag for system configuration

8.2 Authentication Flow

1. User visits http://192.168.4.1/
   ↓
2. Captive portal redirects to login page
   ↓
3. User enters credentials (Student ID / Email, Password)
   ↓
4. POST /cgi-bin/user.py?action=login
   ↓
5. Server validates credentials (bcrypt check)
   ↓
6. Server creates session (session_id = secrets.token_urlsafe(32))
   ↓
7. Server stores session in database (user_sessions table)
   ↓
8. Client stores session_id in sessionStorage
   ↓
9. User redirected to role-specific dashboard
   ↓
10. All subsequent requests include session_id in POST data
    ↓
11. Server verifies session before processing request
    ↓
12. Session expires after TTL (default 1 hour)

8.3 Session Management

# Session Creation
session_id = secrets.token_urlsafe(32)  # Cryptographically secure
created_at = get_current_timestamp()
expires_at = created_at + 3600  # 1 hour

# Session Storage (SQL)
INSERT INTO user_sessions 
(session_id, user_id, role, batch_code, created_at, expires_at)
VALUES (...) 

# Session Verification
SELECT * FROM user_sessions 
WHERE session_id = ? AND expires_at > NOW()

# Session Cleanup
DELETE FROM user_sessions 
WHERE expires_at < NOW()

# Session Extension (optional)
UPDATE user_sessions 
SET expires_at = ? 
WHERE session_id = ?

8.4 Password Security

# Password Hashing (bcrypt 12 rounds)
import bcrypt

password_hash = bcrypt.hashpw(
    password.encode('utf-8'),
    bcrypt.gensalt(rounds=12)
).decode('utf-8')

# Password Verification
verified = bcrypt.checkpw(
    password.encode('utf-8'),
    stored_hash.encode('utf-8')
)

# Password Requirements
- Minimum 8 characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 digit
- Special characters (optional)

8.5 CORS & CSRF Protection

# CORS Headers
def get_cors_headers():
    return {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
        'Access-Control-Allow-Credentials': 'true'
    }

# CSRF Token (if enabled)
csrf_token = secrets.token_urlsafe(32)
store in session
validate on state-changing requests

9. Attendance Module

9.1 Attendance System Overview

Purpose:

  • Track daily class attendance for students
  • Provide teachers with attendance marking interface
  • Enable students to view personal attendance records
  • Generate attendance statistics and reports

Access Control:

  • Teachers: Can mark attendance for assigned batches
  • Students: Can view only their own attendance
  • Admins: Can view all attendance records

9.2 Attendance Marking Flow

Teacher Login
    ↓
Select Batch → Get assigned batches list
    ↓
Select Date → Choose attendance date
    ↓
Load Students → GET /cgi-bin/attendance_api.py?action=get_batch_students
    ↓
Display Student List → Show all students with current status
    ↓
Mark Attendance → For each student:
    - Select status (Present/Absent/Late)
    - Click mark button
    - POST to attendance_api.py
    ↓
Confirm → Success message with timestamp
    ↓
Update Display → Refresh student list with marked status

9.3 Student Attendance View

Student Dashboard
    ↓
Click "Attendance" Tab/Menu
    ↓
GET /cgi-bin/attendance_api.py?action=get_student_attendance
    ↓
Display Calendar View → Show attendance status per day
    ↓
Show Statistics → Total, Present, Absent, Late, Percentage
    ↓
Optional Filters:
    - Month/Year selection
    - Subject-wise (if tracked)
    - Date range

9.4 Attendance API Implementation

Database Structure:

Table: attendance
- id (SERIAL PRIMARY KEY)
- batch_code (VARCHAR - for batch grouping)
- student_id (INTEGER FK - student reference)
- subject_name (VARCHAR - optional subject)
- teacher_id (INTEGER FK - who marked)
- attendance_date (DATE - marking date)
- status (VARCHAR - present/absent/late)
- marked_at (BIGINT - timestamp)
- marked_by (INTEGER - teacher who marked)
- batch_id (INTEGER FK - batch reference)
- remarks (TEXT - optional notes)
- Indexes: (attendance_date, batch_code, student_id, teacher_id)

Key Endpoints:

  1. get_teacher_batches - List batches assigned to teacher
  2. get_batch_students - List students with current attendance status
  3. mark_attendance - Mark/update attendance for one student
  4. get_student_attendance - Get personal attendance records

9.5 Attendance Statistics Calculation

def calculate_attendance_stats(records):
    """Calculate attendance percentage and distribution"""
    
    total = len(records)
    if total == 0:
        return {
            'total': 0,
            'present': 0,
            'absent': 0,
            'late': 0,
            'percentage': 0
        }
    
    present = sum(1 for r in records if r['status'] == 'present')
    absent = sum(1 for r in records if r['status'] == 'absent')
    late = sum(1 for r in records if r['status'] == 'late')
    
    # Calculate percentage: (present + late/2) / total * 100
    # Some institutions count late as half-present
    percentage = ((present + (late * 0.5)) / total) * 100
    
    return {
        'total': total,
        'present': present,
        'absent': absent,
        'late': late,
        'percentage': round(percentage, 2)
    }

9.6 Frontend Implementation

Teacher Interface:

<!-- Batch Selection -->
<select id="batchSelect">
    <option>Select Batch</option>
    <!-- populated by API -->
</select>

<!-- Date Selection -->
<input type="date" id="attendanceDate" />

<!-- Students List -->
<table id="studentsTable">
    <thead>
        <tr>
            <th>Name</th>
            <th>ID</th>
            <th>Status</th>
            <th>Action</th>
        </tr>
    </thead>
    <tbody>
        <!-- populated by API -->
    </tbody>
</table>

<!-- Status Radio Buttons (per student) -->
<div class="status-group">
    <label><input type="radio" name="status_123" value="present"> Present</label>
    <label><input type="radio" name="status_123" value="absent"> Absent</label>
    <label><input type="radio" name="status_123" value="late"> Late</label>
</div>

Student Interface:

<!-- Attendance Calendar -->
<div class="attendance-calendar">
    <!-- Month/Year selector -->
    <select id="monthSelect"></select>
    <select id="yearSelect"></select>
    
    <!-- Calendar Grid -->
    <div class="calendar-grid">
        <!-- Days populated with status indicators -->
    </div>
</div>

<!-- Statistics Box -->
<div class="attendance-stats">
    <div class="stat">Total: <span id="totalDays">0</span></div>
    <div class="stat">Present: <span id="presentDays">0</span></div>
    <div class="stat">Absent: <span id="absentDays">0</span></div>
    <div class="stat">Late: <span id="lateDays">0</span></div>
    <div class="stat">Percentage: <span id="percentage">0%</span></div>
</div>

9.7 Attendance Status Color Coding

.status-present {
    background-color: #10b981;  /* Green */
    color: white;
}

.status-absent {
    background-color: #ef4444;  /* Red */
    color: white;
}

.status-late {
    background-color: #f59e0b;  /* Amber */
    color: white;
}

.status-none {
    background-color: #e5e7eb;  /* Gray */
    color: #6b7280;
}

10. Student Profile Picture Feature

10.1 Profile Picture System Overview

Features:

  • Upload student profile photo
  • Display circular avatar in dashboard
  • Store in local file system
  • Database reference for retrieval
  • Support for JPG/PNG formats
  • File size and dimension validation

Benefits:

  • Personalization of student profile
  • Easy identification in dashboards
  • Professional portfolio presentation
  • Enhanced UI/UX with visual elements

10.2 Photo Upload Flow

Student → Click "Change Photo" Button
    ↓
File Input Dialog → Select JPG/PNG file (max 5MB)
    ↓
Validation (Frontend)
    - File type check: .jpg, .png, .jpeg
    - File size: < 5MB
    - Image preview
    ↓
Upload
    - POST to /cgi-bin/profile_api.py?action=upload_photo
    - Multipart form data (file upload)
    - Include session_id for authentication
    ↓
Backend Processing
    - Verify user authentication
    - Delete old photo (if exists)
    - Save new photo to /var/www/html/uploads/profiles/
    - Generate filename: photo_<student_id>_<timestamp>.<ext>
    - Update student_profiles.profile_photo with file path
    - Return photo URL
    ↓
Frontend Update
    - Display new photo in UI
    - Update avatar in all locations
    - Show success message

10.3 Database Schema

Column Addition (student_profiles table):

-- NEW Column
profile_photo VARCHAR(500);
-- Stores: /uploads/profiles/photo_123_1672531200.jpg

-- Example path: /var/www/html/uploads/profiles/photo_123_1672531200.jpg
-- Example URL:  /uploads/profiles/photo_123_1672531200.jpg

10.4 Photo Upload API Implementation

Backend Function (profile_api.py):

def upload_photo(post, user):
    """Handle profile photo upload"""
    
    # Verify authentication
    if not user or user['role'] != 'student':
        send_error("Unauthorized", "UNAUTHORIZED")
    
    # Get uploaded file
    photo_file = post.get('photo')
    if not photo_file:
        send_error("No file uploaded", "VALIDATION_ERROR")
    
    # Validate file type
    allowed_types = ['image/jpeg', 'image/png']
    if photo_file.content_type not in allowed_types:
        send_error("Only JPG/PNG allowed", "VALIDATION_ERROR")
    
    # Validate file size (5MB max)
    max_size = 5 * 1024 * 1024
    photo_file.file.seek(0, 2)  # Seek to end
    file_size = photo_file.file.tell()
    if file_size > max_size:
        send_error("File too large (max 5MB)", "VALIDATION_ERROR")
    
    # Generate safe filename
    timestamp = get_current_timestamp()
    ext = 'jpg' if photo_file.content_type == 'image/jpeg' else 'png'
    filename = f"photo_{user['id']}_{timestamp}.{ext}"
    filepath = f"/var/www/html/uploads/profiles/{filename}"
    
    # Delete old photo (if exists)
    conn = get_db_connection()
    cur = conn.cursor()
    cur.execute(
        "SELECT profile_photo FROM student_profiles WHERE student_id = %s",
        (user['id'],)
    )
    old_photo = cur.fetchone()
    if old_photo and old_photo[0]:
        try:
            os.remove(f"/var/www/html{old_photo[0]}")
        except:
            pass
    
    # Save new photo
    photo_file.file.seek(0)
    with open(filepath, 'wb') as f:
        f.write(photo_file.file.read())
    
    # Update database
    photo_url = f"/uploads/profiles/{filename}"
    cur.execute(
        "UPDATE student_profiles SET profile_photo = %s WHERE student_id = %s",
        (photo_url, user['id'])
    )
    
    conn.commit()
    cur.close()
    conn.close()
    
    send_json({
        'success': True,
        'photo_url': photo_url,
        'message': 'Photo uploaded successfully'
    })

10.5 Photo Display Implementation

Frontend - Student Profile Page:

<!-- Profile Photo Section -->
<div class="profile-photo-section">
    <div class="photo-container">
        <!-- Display photo or fallback avatar -->
        <img 
            id="profilePhoto" 
            src="/uploads/profiles/photo_123_timestamp.jpg" 
            alt="Profile Photo"
            class="profile-photo"
            onerror="this.src='data:image/svg+xml,%3Csvg...%3E'" <!-- SVG fallback -->
        />
    </div>
    
    <!-- Action Buttons -->
    <div class="photo-actions">
        <label class="btn btn-primary btn-sm">
            📷 Change Photo
            <input type="file" id="photoInput" accept="image/jpeg,image/png" hidden />
        </label>
        <button class="btn btn-danger btn-sm" id="removePhotoBtn">
            🗑️ Remove
        </button>
    </div>
    
    <!-- Photo Info -->
    <small class="text-muted">JPG or PNG, max 5MB</small>
</div>

<style>
.profile-photo-section {
    text-align: center;
    margin: 20px 0;
}

.photo-container {
    margin: 20px 0;
}

.profile-photo {
    width: 150px;
    height: 150px;
    border-radius: 50%;  /* Circular */
    border: 4px solid #1e40af;
    object-fit: cover;  /* Cover without distortion */
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.photo-actions {
    margin-top: 15px;
}

.photo-actions button, .photo-actions label {
    margin: 0 5px;
}
</style>

<script>
// Handle file selection
document.getElementById('photoInput').addEventListener('change', function(e) {
    const file = e.target.files[0];
    if (!file) return;
    
    // Validate file
    if (!['image/jpeg', 'image/png'].includes(file.type)) {
        alert('Only JPG/PNG allowed');
        return;
    }
    if (file.size > 5 * 1024 * 1024) {
        alert('File too large (max 5MB)');
        return;
    }
    
    // Show preview
    const preview = new FileReader();
    preview.onload = (e) => {
        document.getElementById('profilePhoto').src = e.target.result;
    };
    preview.readAsDataURL(file);
    
    // Upload photo
    const formData = new FormData();
    formData.append('action', 'upload_photo');
    formData.append('session_id', sessionStorage.session_id);
    formData.append('photo', file);
    
    fetch('/cgi-bin/profile_api.py', {
        method: 'POST',
        body: formData
    })
    .then(r => r.json())
    .then(data => {
        if (data.success) {
            console.log('Photo uploaded:', data.photo_url);
            // Update src with actual uploaded URL
            document.getElementById('profilePhoto').src = data.photo_url;
            alert('Photo updated successfully!');
        } else {
            alert('Error: ' + data.error);
            location.reload();  // Reload to show old photo
        }
    })
    .catch(err => {
        alert('Upload failed: ' + err);
        location.reload();
    });
});

// Handle photo removal
document.getElementById('removePhotoBtn').addEventListener('click', () => {
    if (!confirm('Remove profile photo?')) return;
    
    fetch('/cgi-bin/profile_api.py', {
        method: 'POST',
        body: new FormData({
            action: 'delete_photo',
            session_id: sessionStorage.session_id
        })
    })
    .then(r => r.json())
    .then(data => {
        if (data.success) {
            location.reload();
        } else {
            alert('Error: ' + data.error);
        }
    });
});
</script>

10.6 Photo Storage Configuration

Directory Structure:

/var/www/html/uploads/
├── profiles/                         # Profile photos
│   ├── photo_123_1672531200.jpg
│   ├── photo_124_1672531500.png
│   ├── photo_125_1672531800.jpg
│   └── ...
├── assignments/
├── documents/
└── images/

Permissions:

# Set directory permissions
sudo chown www-data:www-data /var/www/html/uploads/profiles
sudo chmod 755 /var/www/html/uploads/profiles

# Set file permissions after upload
sudo chmod 644 /var/www/html/uploads/profiles/*

10.7 Avatar Fallback (No Photo)

Method 1: User Initials Avatar

<div class="avatar-fallback" id="fallbackAvatar">
    <span class="initials">JD</span>  <!-- John Doe -->
</div>

<style>
.avatar-fallback {
    width: 150px;
    height: 150px;
    border-radius: 50%;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 48px;
    color: white;
    font-weight: bold;
    margin: 0 auto;
}
</style>

Method 2: Default Avatar Image

<img 
    id="profilePhoto" 
    src="/default-avatar.png" 
    alt="Profile Photo"
    class="profile-photo"
/>

11. Chat System & Real-Time Features

11.1 Chat Architecture

Database Tables:
├── chat_groups
│   ├── id (PK)
│   ├── group_name
│   ├── group_type (batch/class/custom)
│   ├── batch_code
│   ├── created_by
│   └── is_active
│
├── chat_group_members
│   ├── id (PK)
│   ├── group_id (FK)
│   ├── user_id (FK)
│   ├── role (admin/member)
│   └── last_read_at
│
└── chat_messages
    ├── id (PK)
    ├── group_id (FK)
    ├── sender_id (FK)
    ├── message_text
    ├── message_type (text/announcement/system)
    ├── reply_to_message (thread support)
    ├── is_deleted
    └── created_at

11.2 Real-Time Features

// Polling-based updates (every 5 seconds)
setInterval(() => {
    fetch('/cgi-bin/chat_api.py', {
        method: 'POST',
        body: new FormData({
            action: 'get_messages',
            session_id: sessionStorage.session_id,
            group_id: currentGroupId,
            offset: lastMessageCount
        })
    })
    .then(r => r.json())
    .then(data => {
        if(data.success) {
            appendMessages(data.messages);
            updateUnreadCount();
        }
    });
}, 5000);

// Send Message
document.getElementById('sendBtn').addEventListener('click', () => {
    const message = document.getElementById('messageInput').value;
    fetch('/cgi-bin/chat_api.py', {
        method: 'POST',
        body: new FormData({
            action: 'send_message',
            session_id: sessionStorage.session_id,
            group_id: currentGroupId,
            message_text: message
        })
    })
    .then(r => r.json())
    .then(data => {
        if(data.success) {
            document.getElementById('messageInput').value = '';
            fetchMessages();
        }
    });
});

// Update Last Read
function markAsRead() {
    fetch('/cgi-bin/chat_api.py', {
        method: 'POST',
        body: new FormData({
            action: 'mark_as_read',
            session_id: sessionStorage.session_id,
            group_id: currentGroupId
        })
    });
}

11.3 Chat Features

  1. Group Chat

    • Batch-based automatic membership
    • Teachers can create groups
    • Students auto-added by batch_code
    • Message history with pagination
  2. 1-on-1 Messaging

    • Direct peer-to-peer chat
    • Teacher-student communication
    • Message history per user pair
  3. Message Types

    • Text messages
    • Announcements (from teachers/admins)
    • System messages (user joined, left, etc.)
    • Threaded replies (reply_to_message)
  4. Notifications

    • Unread message count
    • Last message preview
    • Browser notifications (if enabled)
  5. Read Receipts

    • Track when user last read messages
    • Show read/unread status
    • Update on viewing

12. Global URL System

12.1 3-Layer URL Access

Layer 1: Local Network (192.168.4.1)
├── Direct access on local WiFi
├── Works offline
├── Updated at /url.html
└── Access: http://192.168.4.1/

Layer 2: Cloudflare Tunnel (Random URL)
├── Generated by cloudflared binary
├── Changes on every reboot
├── Example: https://random-string.trycloudflare.com
├── Access: Direct tunnel to Pi
└── Validity: Until cloudflared restarts

Layer 3: Fixed GitHub Redirect (Global)
├── Permanent fixed URL
├── Never changes
├── Reads Firebase for current tunnel URL
├── Instant redirect to Layer 2
├── Access: https://craboxx.github.io/_/
└── Always share this URL

12.2 Cloudflare Tunnel Setup

Service File: /etc/systemd/system/cloudflared.service

[Unit]
Description=Cloudflare Tunnel
After=network.target

[Service]
Type=simple
User=crabox
ExecStart=/usr/local/bin/cloudflared tunnel --url http://192.168.4.1:80
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Commands:

# Get tunnel binary
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm -O /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared

# Start tunnel
sudo systemctl start cloudflared
sudo systemctl enable cloudflared

# View tunnel URL from logs
sudo journalctl -u cloudflared -n 50 | grep "https://.*trycloudflare.com"

# Get current tunnel URL
curl https://crad-8e69b-default-rtdb.asia-southeast1.firebasedatabase.app/public/tunnel_url/url.json

12.3 Firebase Realtime Database Setup

Firebase Config:

Project: crad-8e69b
Database URL: https://crad-8e69b-default-rtdb.asia-southeast1.firebasedatabase.app
Region: asia-southeast1

Database Rules (Security):
{
  "rules": {
    "public": {
      ".read": true,
      ".write": false
    },
    "secure_update": {
      "$secret": {
        ".write": true,
        ".read": false
      }
    }
  }
}

Data Paths:
├── /public/tunnel_url/url → Read-only (frontend)
└── /secure_update/crad_secure_2025_pi/url → Write-only (backend)

12.4 Firebase Sync Script (/usr/local/bin/firebase-update.py)

#!/usr/bin/env python3

import subprocess
import requests
import time
import re

FIREBASE_URL = "https://crad-8e69b-default-rtdb.asia-southeast1.firebasedatabase.app"
SECRET_KEY = "crad_secure_2025_pi"

def get_tunnel_url():
    """Get current Cloudflare tunnel URL from systemd logs"""
    try:
        cmd = "sudo journalctl -u cloudflared -n 100 --no-pager"
        result = subprocess.run(cmd.split(), capture_output=True, text=True)
        match = re.search(r'https://[a-z0-9-]+\.trycloudflare\.com', result.stdout)
        if match:
            return match.group(0)
        return None
    except Exception as e:
        print(f"Error getting tunnel URL: {e}")
        return None

def update_firebase(url):
    """Update Firebase with current tunnel URL"""
    try:
        timestamp = int(time.time())
        data = {"url": url, "timestamp": timestamp}
        
        # 1) Secure path (Pi writes)
        secure_path = f"{FIREBASE_URL}/secure_update/{SECRET_KEY}.json"
        r1 = requests.put(secure_path, json=data)
        
        # 2) Public path (Frontend reads)
        public_path = f"{FIREBASE_URL}/public/tunnel_url/url.json"
        r2 = requests.put(public_path, json=url)  # Direct string, no object
        
        print(f"? Secure: {r1.status_code} | Public: {r2.status_code}")
        print(f"🌐 URL: {url}")
        return r1.status_code == 200 and r2.status_code == 200
    except Exception as e:
        print(f"❌ Error: {e}")
        return False

def main():
    print("🔄 Waiting for tunnel...")
    time.sleep(35)  # Wait for cloudflared to start
    
    tunnel_url = get_tunnel_url()
    if tunnel_url:
        print(f"🌐 Found: {tunnel_url}")
        update_firebase(tunnel_url)
    else:
        print("❌ No tunnel URL found")

if __name__ == "__main__":
    main()

Service File: /etc/systemd/system/firebase-update.service

[Unit]
Description=Update Firebase with Tunnel URL
After=cloudflared.service
Requires=cloudflared.service

[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /usr/local/bin/firebase-update.py
User=crabox

[Install]
WantedBy=multi-user.target

12.5 GitHub Pages Redirect

Repository: craboxx/_ on GitHub
File: index.html (root of repository)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CRAD - Loading...</title>
</head>
<body>
    <h1>Connecting to CRAD Portal...</h1>
    <p id="status">Fetching tunnel URL...</p>
    
    <script>
        // Fetch tunnel URL from Firebase
        async function getTunnelUrl() {
            try {
                const response = await fetch(
                    'https://crad-8e69b-default-rtdb.asia-southeast1.firebasedatabase.app/public/tunnel_url/url.json'
                );
                const url = await response.json();
                
                if(url) {
                    document.getElementById('status').textContent = 'Redirecting...';
                    window.location.href = url;
                } else {
                    document.getElementById('status').textContent = 'Portal URL not available. Try again later.';
                }
            } catch(err) {
                document.getElementById('status').textContent = 'Error: ' + err.message;
            }
        }
        
        // Fetch on page load
        getTunnelUrl();
        
        // Retry every 5 seconds
        setInterval(getTunnelUrl, 5000);
    </script>
</body>
</html>

13. Admin Dashboard

13.1 Admin Features (safaclgadmin.html - 59 KB)

Admin Dashboard Interface
├── Dashboard Overview
│   ├── Total Students (Active)
│   ├── Total Teachers (Active)
│   ├── Pending Approvals
│   ├── Campus Notifications (status, counts)
│   ├── Password Recovery Queue
│   └── Active Batches
│
├── User Management
│   ├── View all users (search, filter)
│   ├── Approve/Reject pending registrations
│   ├── Deactivate/Reactivate accounts
│   ├── Reset passwords
│   └── Edit user roles
│
├── Batch Management
│   ├── Create new batches
│   ├── Edit batch details
│   ├── Toggle batch active status
│   ├── View batch statistics
│   └── Manage batch assignments
│
├── Monitoring & Analytics
│   ├── User activity logs
│   ├── System health metrics
│   ├── Database statistics
│   ├── Usage analytics
│   └── Report generation
│
├── System Configuration
│   ├── College settings
│   ├── Email configuration
│   ├── Notification settings
│   ├── Security policies
│   └── Backup & restore
│
└── Communication
    ├── Send mass messages
    ├── Create announcements
    ├── Broadcast to batch/all
    └── Message history

13.2 Admin Statistics

// Fetch Dashboard Stats
fetch('/cgi-bin/server.py', {
    method: 'POST',
    body: new FormData({
        action: 'dashboard',
        session_id: adminSession
    })
})
.then(r => r.json())
.then(data => {
    document.getElementById('totalStudents').textContent = data.stats.total_students;
    document.getElementById('totalTeachers').textContent = data.stats.total_teachers;
    document.getElementById('pendingUsers').textContent = data.stats.pending_users;
    document.getElementById('totalBatches').textContent = data.stats.total_batches;
    
    // Populate tables
    populatePendingUsersTable(data.pending_users);
    populateBatchesTable(data.batches);
});

13.3 Admin Operations

# Approve User
POST /cgi-bin/server.py
{
    "action": "approve_user",
    "session_id": "...",
    "user_id": 123,
    "status": "approved",
    "message": "Welcome to SAFA College!"
}

# Send Mass Message
POST /cgi-bin/server.py
{
    "action": "send_mass_message",
    "session_id": "...",
    "recipient_type": "batch",  # all/teachers/students/batch/individual
    "batch_id": 1,
    "subject": "Important Notice",
    "message": "...",
    "priority": "high"  # normal/high/urgent
}

# Manage Batch
POST /cgi-bin/server.py
{
    "action": "manage_batch",
    "session_id": "...",
    "batch_id": 1,
    "operation": "toggle_status"  # create/update/delete/toggle_status
}

# View Activity Logs
POST /cgi-bin/server.py
{
    "action": "view_activity_logs",
    "session_id": "...",
    "start_date": 1698000000,
    "end_date": 1698086400,
    "event_type": "all"  # login/registration/file_upload/etc
}

14. Flutter Android Application

14.1 Flutter App Architecture

Technology Stack:

  • Flutter 3.7+
  • Dart
  • WebView (webview_flutter)
  • File Selector Plugin
  • FileProvider

Features:

  • Full-screen WebView of CRAD portal
  • Native file picker integration
  • File upload from device storage
  • Multiple file format support
  • Splash screen with logo
  • Progress indicators
  • Custom app icon

14.2 Main App File (main.dart)

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:file_selector/file_selector.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const WebApp());
}

class WebApp extends StatelessWidget {
  const WebApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: WebViewPage(),
    );
  }
}

class WebViewPage extends StatefulWidget {
  const WebViewPage({super.key});

  @override
  State<WebViewPage> createState() => _WebViewPageState();
}

class _WebViewPageState extends State<WebViewPage> {
  late final WebViewController _controller;
  bool isLoading = true;

  @override
  void initState() {
    super.initState();

    final PlatformWebViewControllerCreationParams params =
        const PlatformWebViewControllerCreationParams();

    final WebViewController controller =
        WebViewController.fromPlatformCreationParams(params)
          ..setJavaScriptMode(JavaScriptMode.unrestricted)
          ..setBackgroundColor(Colors.white)
          ..setNavigationDelegate(
            NavigationDelegate(
              onPageFinished: (_) {
                setState(() {
                  isLoading = false;
                });
              },
            ),
          )
          ..loadRequest(Uri.parse('https://craboxx.github.io/_/'));

    // Android-specific: handle <input type="file">
    if (controller.platform is AndroidWebViewController) {
      final androidController = controller.platform as AndroidWebViewController;

      androidController.setOnShowFileSelector((_) async {
        // Open native file picker
        final XFile? file = await openFile(
          acceptedTypeGroups: const [
            XTypeGroup(
              label: 'Files',
              extensions: ['pdf', 'doc', 'docx', 'zip', 'jpg', 'jpeg', 'png'],
            ),
          ],
        );

        if (file == null) {
          return <String>[];
        }

        // Return URI string (not plain path)
        final uri = Uri.file(file.path).toString();
        return <String>[uri];
      });
    }

    _controller = controller;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          WebViewWidget(controller: _controller),
          if (isLoading) 
            const Center(child: CircularProgressIndicator()),
        ],
      ),
    );
  }
}

14.3 Flutter Configuration (pubspec.yaml)

name: crad
description: "CRAD Mobile App - WebView wrapper"
publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: ^3.7.2

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8
  webview_flutter: ^4.8.0
  webview_flutter_android: ^3.14.0
  file_selector: ^1.0.3

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^5.0.0
  flutter_launcher_icons: ^0.13.1

flutter:
  uses-material-design: true
  assets:
    - assets/logo.png

flutter_icons:
  android: true
  ios: true
  image_path: "assets/logo.png"

14.4 Android Configuration

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Required Permissions -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application
        android:label="CRAD"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher"
        android:hardwareAccelerated="true">

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:taskAffinity=""
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:windowSoftInputMode="adjustResize">

            <meta-data
                android:name="io.flutter.embedding.android.NormalTheme"
                android:resource="@style/NormalTheme" />

            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <!-- Flutter plugin auto-registration -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />

    </application>

    <!-- Query intent for text processing -->
    <queries>
        <intent>
            <action android:name="android.intent.action.PROCESS_TEXT"/>
            <data android:mimeType="text/plain"/>
        </intent>
    </queries>

</manifest>

filepaths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>

14.5 Build & Release

# Build APK
flutter clean
flutter pub get
flutter build apk --release

# Build AAB (Google Play)
flutter build appbundle --release

# Build with custom icon
dart run flutter_launcher_icons

# Install on device
flutter install

# Run in development
flutter run

15. System Configuration Files

15.1 /etc/rc.local - Startup Script

#!/bin/bash

# Unblock Wi-Fi
rfkill unblock all

# Wait for hardware to be ready
sleep 5

# Bring up wlan0
ip link set wlan0 up

# Assign static IP
ip addr add 192.168.4.1/24 dev wlan0

# Wait for interface initialization
sleep 5

# Restart captive services
systemctl restart dnsmasq
systemctl restart hostapd
systemctl restart lighttpd

exit 0

Permissions:

sudo chmod +x /etc/rc.local

15.2 /etc/sysctl.conf - Kernel Parameters

# Enable IP forwarding for NAT
net.ipv4.ip_forward=1

Apply changes:

sudo sysctl -p

15.3 /etc/update-alternatives - Default Python

# Make Python 3 the default
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 1

16. Deployment & Startup

16.1 Complete Installation Checklist

# 1. System Update
sudo apt-get update && sudo apt-get upgrade -y

# 2. Install Dependencies
sudo apt-get install -y \
    python3-pip \
    postgresql \
    postgresql-contrib \
    lighttpd \
    hostapd \
    dnsmasq \
    curl \
    wget \
    git \
    python3-psycopg2 \
    python3-requests

# 3. Create System User
sudo useradd -m -s /bin/bash crabox

# 4. Setup Database
sudo -u postgres createdb user_system
sudo -u postgres psql -d user_system < schema.sql

# 5. Create Upload Directory
sudo mkdir -p /var/www/html/uploads/profiles
sudo chown www-data:www-data /var/www/html/uploads
sudo chmod 755 /var/www/html/uploads

# 6. Setup CGI Directory
sudo chown -R crabox:www-data /usr/lib/cgi-bin
sudo chmod 755 /usr/lib/cgi-bin
sudo chmod 755 /usr/lib/cgi-bin/*.py

# 7. Setup Cloudflare Tunnel
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm
sudo mv cloudflared /usr/local/bin/
sudo chmod +x /usr/local/bin/cloudflared

# 8. Copy Configuration Files
sudo cp hostapd.conf /etc/hostapd/
sudo cp dnsmasq.conf /etc/
sudo cp dhcpcd.conf /etc/
sudo cp lighttpd.conf /etc/lighttpd/
sudo cp rc.local /etc/
sudo cp sysctl.conf /etc/

# 9. Create Systemd Services
sudo cp cloudflared.service /etc/systemd/system/
sudo cp update-tunnel-url.service /etc/systemd/system/
sudo cp firebase-update.service /etc/systemd/system/

# 10. Enable Services
sudo systemctl daemon-reload
sudo systemctl enable hostapd dnsmasq lighttpd postgresql cloudflared
sudo systemctl enable update-tunnel-url firebase-update

# 11. Start Services
sudo systemctl restart hostapd dnsmasq lighttpd postgresql
sudo systemctl start cloudflared update-tunnel-url firebase-update

# 12. Verify Setup
sudo systemctl status hostapd
sudo systemctl status dnsmasq
sudo systemctl status lighttpd
sudo systemctl status cloudflared

16.2 Post-Installation Setup

# 1. Configure PostgreSQL
sudo -u postgres psql
# CREATE USER craduser WITH PASSWORD 'secure_password';
# GRANT ALL PRIVILEGES ON DATABASE user_system TO craduser;
# \q

# 2. Update .env file
sudo nano /usr/lib/cgi-bin/.env
# Set database credentials

# 3. Test Connectivity
curl http://192.168.4.1/
# Should return index.html

# 4. Test CGI
curl -X POST http://192.168.4.1/cgi-bin/user.py?action=status
# Should return JSON response

# 5. View Tunnel URL
sudo journalctl -u cloudflared -n 20 | grep "trycloudflare"

# 6. Test Firebase Sync
sudo systemctl status firebase-update

16.3 Service Management Commands

# View all services
sudo systemctl list-units --type=service

# Check service status
sudo systemctl status cloudflared

# View service logs
sudo journalctl -u cloudflared -n 50
sudo journalctl -u cloudflared -f  # Follow logs

# Restart service
sudo systemctl restart cloudflared

# Stop service
sudo systemctl stop cloudflared

# Start service
sudo systemctl start cloudflared

# Enable/disable on boot
sudo systemctl enable cloudflared
sudo systemctl disable cloudflared

17. OLED Monitoring System

17.1 OLED Display Setup

Hardware:

  • Display: SSD1306 128x64 OLED
  • Interface: I2C (0x3C)
  • Connection: GPIO pins (SDA, SCL)
  • Libraries: Adafruit CircuitPython

Installation:

sudo apt-get install -y python3-pip
pip3 install adafruit-circuitpython-ssd1306 pillow

# Test I2C
sudo i2cdetect -y 1  # Check for 0x3C address

17.2 Monitor Script (monitor.py - 31 KB)

Features:

  • Real-time system metrics (CPU, RAM, Disk)
  • Network statistics (WiFi speed, connected devices)
  • Temperature monitoring
  • Process tracking
  • Load average display
  • Uptime display
  • Rotating screens (6s per screen)
  • Non-blocking data collection
  • GLITCHY title animation

Screens:

  1. Title Screen - CRABOX (animated)
  2. CPU/Temp/RAM/Disk - System resources
  3. Load/Processes/GPU/IP - Performance metrics
  4. Ethernet/Network Speed/Clients - Network info
  5. Hardware/System Info - Uptime, voltage, clock
  6. Network Diagnostics - Ping, DNS, gateway
  7. Storage/Memory - Swap, disk I/O, mounts
  8. Processes - Top processes, users, services

Key Functions:

def read_cpu_usage()
def read_memory_usage()
def read_disk_usage()
def read_temperature()
def read_load_average()
def count_processes()
def get_network_speeds()
def count_connected_devices()
def read_uptime()
def draw_row(draw, y, icon, label, value)
def draw_title_glitch(image, draw)

Running Monitor:

cd /home/crabox
python3 monitor.py

As Service (optional):

[Unit]
Description=CRAD OLED Monitor
After=network.target

[Service]
Type=simple
User=crabox
ExecStart=/usr/bin/python3 /home/crabox/monitor.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

18. Troubleshooting & Maintenance

18.1 Common Issues & Solutions

Issue: WiFi Access Point Not Broadcasting

# Check hostapd status
sudo systemctl status hostapd

# Check interface
ip link show wlan0

# Restart hostapd
sudo systemctl restart hostapd

# View logs
sudo journalctl -u hostapd -n 20

Issue: DNS Not Spoofing / Captive Portal Not Triggering

# Check dnsmasq
sudo systemctl status dnsmasq

# Verify DNS configuration
cat /etc/dnsmasq.conf

# Check DHCP assignment
sudo tail -f /var/log/dnsmasq.log

# Restart dnsmasq
sudo systemctl restart dnsmasq

Issue: Lighttpd Not Serving Pages

# Check lighttpd status
sudo systemctl status lighttpd

# Check configuration
lighttpd -t -f /etc/lighttpd/lighttpd.conf

# View error log
tail -f /var/log/lighttpd/error.log

# Restart lighttpd
sudo systemctl restart lighttpd

Issue: CGI Scripts Not Executing

# Check CGI permissions
ls -la /usr/lib/cgi-bin/

# Ensure executable
sudo chmod +x /usr/lib/cgi-bin/*.py

# Test directly
/usr/bin/python3 /usr/lib/cgi-bin/user.py

# Check lighttpd CGI configuration
grep "cgi.assign" /etc/lighttpd/lighttpd.conf

Issue: Database Connection Failed

# Check PostgreSQL status
sudo systemctl status postgresql

# Test connection
psql -U postgres -d user_system -c "SELECT 1;"

# Check .env file
cat /usr/lib/cgi-bin/.env

# Restart PostgreSQL
sudo systemctl restart postgresql

Issue: Attendance Records Not Saving

# Check attendance table
psql -U postgres -d user_system -c "SELECT COUNT(*) FROM attendance;"

# Check for errors
sudo journalctl -u lighttpd -n 50

# Verify API endpoint
curl -X POST http://192.168.4.1/cgi-bin/attendance_api.py

# Check database permissions
psql -U postgres -d user_system -c "\d attendance"

Issue: Profile Photos Not Uploading

# Check directory permissions
ls -la /var/www/html/uploads/profiles/

# Ensure writable
sudo chmod 755 /var/www/html/uploads/profiles

# Check file ownership
sudo chown www-data:www-data /var/www/html/uploads

# Test photo endpoint
curl -X POST http://192.168.4.1/cgi-bin/profile_api.py

# View upload logs
sudo tail -f /var/log/lighttpd/error.log

18.2 Performance Optimization

# Monitor disk usage
du -sh /var/www/html/uploads
du -sh /var/lib/postgresql

# Clean old sessions (PostgreSQL)
DELETE FROM user_sessions WHERE expires_at < NOW();
DELETE FROM admin_sessions WHERE expires_at < NOW();

# Clean old attendance records (if needed)
DELETE FROM attendance WHERE attendance_date < CURRENT_DATE - INTERVAL '1 year';

# Optimize database
VACUUM user_system;
REINDEX DATABASE user_system;

# Check system resources
free -h  # Memory
df -h    # Disk
top      # Processes

18.3 Regular Maintenance Schedule

Daily:
- Check system temperature
- Monitor disk space
- Verify services running
- Check attendance records saved

Weekly:
- Backup database
- Clean up old files
- Review logs
- Test file uploads

Monthly:
- Optimize database
- Update packages
- Review security settings
- Verify photo uploads working

Quarterly:
- Full system backup
- Update documentation
- Review user access logs
- Test attendance module

18.4 Backup & Restore

# Backup PostgreSQL database
pg_dump -U postgres user_system > backup_$(date +%Y%m%d).sql

# Backup web files
tar -czf web_backup_$(date +%Y%m%d).tar.gz /var/www/html

# Backup system configuration
tar -czf config_backup_$(date +%Y%m%d).tar.gz /etc/{hostapd,dnsmasq.conf,rc.local}

# Restore database
psql -U postgres user_system < backup_20260101.sql

# Restore web files
tar -xzf web_backup_20260101.tar.gz -C /

# Restore system config
tar -xzf config_backup_20260101.tar.gz -C /

# Automated backup (cron)
# Add to crontab:
# 0 2 * * * /home/crabox/backup.sh

18.5 Security Best Practices

# Update system regularly
sudo apt-get update && sudo apt-get upgrade -y

# Secure PostgreSQL
sudo nano /etc/postgresql/13/main/postgresql.conf
# Ensure: listen_addresses = 'localhost'

# Secure SSH (if enabled)
sudo nano /etc/ssh/sshd_config
# Set: PermitRootLogin no
# Set: PasswordAuthentication no (use key-based auth)

# Setup Firewall (iptables)
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT (SSH only if needed)
sudo iptables -A INPUT -j DROP  # Default deny

# File permissions
sudo chown www-data:www-data /var/www/html -R
sudo chmod 755 /var/www/html
sudo chmod 600 /usr/lib/cgi-bin/.env

# SSL/TLS (if using domain)
sudo apt-get install certbot python3-certbot-nginx
sudo certbot certonly --standalone -d yourdomain.com

Summary

CRAD v10 is production-ready and currently includes:

  • Captive portal auto-redirect for first-time device access (dnsmasq probe-domain mapping + lighttpd probe-path redirects)
  • Role-based authentication with pending-registration approval flow (student/teacher/admin)
  • Admin batch lifecycle (create/update/toggle/delete) with teacher-to-batch subject assignments
  • Password recovery request + admin approval workflow with audit trail (feature-gated by optional recovery tables)
  • Campus notifications with audience targeting, schedules, repeat policies, dismiss tracking, and admin audits (feature-gated by optional notification tables)
  • Teacher attendance marking for assigned batches with present/absent/late, plus marked_at and marked_by
  • Student attendance calendar and attendance statistics in dashboard view
  • Student profiles and portfolios: bio, skills, links, projects, achievements, and profile photo upload/delete
  • Batch portfolio browsing on dashboards (students can browse same-batch profiles; teachers can open student profile details)
  • Batch group messaging with history, unread counts, reply threads, and polling-based refresh
  • Teacher content sharing with multipart file upload support and due dates; students can view/download shared files
  • Assignment API endpoints for create/list/submit/grade workflows (text submission + grading feedback in backend API)
  • Optional remote access stack: cloudflared tunnel + Firebase URL sync + GitHub redirect page + local tunnel URL updater page
  • Android WebView wrapper distribution (CRAD.apk and ADMIN.apk) with file-picker support configuration
  • Operational tooling: systemd service files, startup scripts, and OLED monitoring script
  • Local PostgreSQL-first data storage; cloud sync layer publishes tunnel URL only

Not currently implemented in this codebase: one-to-one chat, typing indicators, attendance/submission export APIs, and hard per-user storage quotas.

Total System Size: ~600 KB (Lightweight for Raspberry Pi) Database Tables: 53 core + 4 optional (notifications/recovery) API Endpoints: 60+ (includes notifications/recovery) Uptime: 99.9% (automated service management) Support: Full-stack documentation with troubleshooting


Last Updated: March 3, 2026
Version: 10.0 - Campus Notifications & Recovery
Status: All systems operational

About

Offline-first Raspberry Pi-powered academic management system with captive portal authentication, role-based dashboards, attendance, assignments, chat, notifications, and hybrid cloud synchronization.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages