21 KiB
TechDesk — IT Ticket System
Complete Deployment & Implementation Guide
Table of Contents
- Project Structure
- Prerequisites
- Server Setup
- MySQL Database Setup
- Application Deployment
- Gunicorn Configuration
- Systemd Service
- Nginx Configuration
- SSL Certificate
- First Login & Admin Setup
- AI Chatbot Configuration
- Email Configuration
- Code Change Map
- Features Overview
- Maintenance & Operations
1. Project Structure
it-ticket-system/
├── run.py ← Flask entry point
├── gunicorn.conf.py ← Gunicorn worker config
├── it-ticket-system.service ← Systemd unit file
├── nginx.conf ← Nginx site config
├── setup_db.sql ← MySQL DB + user creation
├── requirements.txt ← Python dependencies
├── .env.example ← Environment variable template
├── config/
│ └── config.py ← Flask config classes (Dev/Prod)
├── app/
│ ├── __init__.py ← App factory, extension init, seed admin
│ ├── models.py ← All SQLAlchemy models
│ ├── routes/
│ │ ├── __init__.py
│ │ ├── auth.py ← Login, register, logout, profile
│ │ ├── tickets.py ← Ticket CRUD, comments, attachments
│ │ ├── admin.py ← IT/admin management views
│ │ ├── api.py ← JSON API + WebSocket events
│ │ └── chatbot.py ← AI assistant endpoint
│ ├── services/
│ │ ├── __init__.py
│ │ ├── notification_service.py ← Email + in-app + WebSocket notifications
│ │ └── log_service.py ← Activity log + ticket history helpers
│ └── templates/
│ ├── base.html ← Sidebar, topbar, chat widget, JS
│ ├── auth/
│ │ ├── login.html
│ │ ├── register.html
│ │ └── profile.html
│ ├── tickets/
│ │ ├── dashboard_employee.html
│ │ ├── dashboard_it.html
│ │ ├── create.html
│ │ ├── list.html
│ │ ├── detail.html
│ │ ├── notifications.html
│ │ ├── knowledge_base.html
│ │ └── kb_article.html
│ └── admin/
│ ├── index.html
│ ├── tickets.html
│ ├── users.html
│ ├── edit_user.html
│ ├── kb_list.html
│ ├── kb_edit.html
│ └── activity_logs.html
└── logs/ ← Created automatically at runtime
2. Prerequisites
On your Ubuntu 22.04 server, ensure the following are installed:
# Update system
sudo apt update && sudo apt upgrade -y
# Python 3.10+, pip, venv
sudo apt install -y python3 python3-pip python3-venv python3-dev
# MySQL Server
sudo apt install -y mysql-server libmysqlclient-dev
# Nginx
sudo apt install -y nginx
# Certbot (Let's Encrypt SSL)
sudo apt install -y certbot python3-certbot-nginx
# Build tools (needed for some pip packages)
sudo apt install -y build-essential libssl-dev libffi-dev
# (Optional) Git for deployment
sudo apt install -y git
3. Server Setup
3.1 Create Application User & Directory
# Create a dedicated system user
sudo useradd --system --no-create-home --shell /bin/false it-tickets
# Create application directory
sudo mkdir -p /var/www/it-ticket-system
sudo chown it-tickets:www-data /var/www/it-ticket-system
sudo chmod 755 /var/www/it-ticket-system
3.2 Deploy Application Files
# Option A: Clone from your Git repository
sudo -u it-tickets git clone https://your-repo-url.git /var/www/it-ticket-system
# Option B: Upload manually via scp
scp -r ./it-ticket-system/* user@your-server:/var/www/it-ticket-system/
3.3 Create Python Virtual Environment
cd /var/www/it-ticket-system
sudo -u it-tickets python3 -m venv venv
sudo -u it-tickets venv/bin/pip install --upgrade pip
sudo -u it-tickets venv/bin/pip install -r requirements.txt
3.4 Create Upload & Log Directories
sudo -u it-tickets mkdir -p /var/www/it-ticket-system/app/static/uploads
sudo -u it-tickets mkdir -p /var/www/it-ticket-system/logs
# Ensure www-data (nginx) can read uploads
sudo chown -R it-tickets:www-data /var/www/it-ticket-system/app/static/uploads
sudo chmod -R 775 /var/www/it-ticket-system/app/static/uploads
4. MySQL Database Setup
4.1 Secure MySQL Installation
sudo mysql_secure_installation
# Follow prompts: set root password, remove anonymous users,
# disallow remote root login, remove test database.
4.2 Create Database and User
# Run the provided SQL setup script
sudo mysql -u root -p < /var/www/it-ticket-system/setup_db.sql
# Or manually:
sudo mysql -u root -p <<'EOF'
CREATE DATABASE IF NOT EXISTS it_tickets CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'it_tickets_user'@'localhost' IDENTIFIED BY 'YOUR_SECURE_PASSWORD';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, REFERENCES
ON it_tickets.* TO 'it_tickets_user'@'localhost';
FLUSH PRIVILEGES;
EOF
4.3 Verify Connection
mysql -u it_tickets_user -p it_tickets
# Should connect without errors. Type \q to exit.
5. Application Deployment
5.1 Configure Environment Variables
# Copy the example env file
sudo -u it-tickets cp /var/www/it-ticket-system/.env.example /var/www/it-ticket-system/.env
# Edit with your actual values
sudo nano /var/www/it-ticket-system/.env
Critical values to change in .env:
# Generate a strong secret key:
# python3 -c "import secrets; print(secrets.token_hex(32))"
SECRET_KEY=your-generated-secret-key
# Database — match what you set in setup_db.sql
DB_PASSWORD=YOUR_SECURE_PASSWORD
# Mail — your SMTP server credentials
MAIL_SERVER=smtp.yourdomain.com
MAIL_USERNAME=ittickets@yourdomain.com
MAIL_PASSWORD=your-email-password
IT_DEPT_EMAIL=it-department@yourdomain.com
# Public URL of your app
APP_BASE_URL=https://tickets.yourdomain.com
# Anthropic API key for AI chatbot
ANTHROPIC_API_KEY=sk-ant-...
# Change default admin password
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASSWORD=YourStrongAdminPassword!
5.2 Initialize the Database
The application automatically creates all tables and seeds the admin user on first startup. You can also trigger it manually:
cd /var/www/it-ticket-system
sudo -u it-tickets venv/bin/python -c "
from app import create_app, db
app = create_app('production')
with app.app_context():
db.create_all()
print('Database tables created successfully.')
"
5.3 Set File Permissions
# Application files: readable by the app user
sudo find /var/www/it-ticket-system -type f -exec chmod 644 {} \;
sudo find /var/www/it-ticket-system -type d -exec chmod 755 {} \;
sudo chmod 600 /var/www/it-ticket-system/.env
sudo chown it-tickets:it-tickets /var/www/it-ticket-system/.env
# Virtual environment executables
sudo chmod +x /var/www/it-ticket-system/venv/bin/gunicorn
sudo chmod +x /var/www/it-ticket-system/venv/bin/python
6. Gunicorn Configuration
The gunicorn.conf.py file at the project root controls the WSGI server.
Key settings explained:
| Setting | Value | Reason |
|---|---|---|
worker_class |
eventlet |
Required for Flask-SocketIO WebSocket support |
workers |
1 |
eventlet mandates a single worker |
worker_connections |
1000 |
Max concurrent connections per worker |
timeout |
120 |
Seconds before killing an unresponsive worker |
bind |
127.0.0.1:5000 |
Internal only — nginx proxies publicly |
Test Gunicorn manually before enabling the service:
cd /var/www/it-ticket-system
sudo -u it-tickets venv/bin/gunicorn --config gunicorn.conf.py run:app
# You should see: [INFO] Listening at: http://127.0.0.1:5000
# Press Ctrl+C to stop.
7. Systemd Service
7.1 Install the Service
# Copy unit file to systemd
sudo cp /var/www/it-ticket-system/it-ticket-system.service /etc/systemd/system/
# Edit to confirm paths and user match your setup
sudo nano /etc/systemd/system/it-ticket-system.service
Update these lines in the service file if needed:
User=it-tickets
Group=www-data
WorkingDirectory=/var/www/it-ticket-system
EnvironmentFile=/var/www/it-ticket-system/.env
ExecStart=/var/www/it-ticket-system/venv/bin/gunicorn \
--config gunicorn.conf.py \
run:app
7.2 Enable and Start the Service
sudo systemctl daemon-reload
sudo systemctl enable it-ticket-system
sudo systemctl start it-ticket-system
# Verify it is running
sudo systemctl status it-ticket-system
7.3 Useful Service Commands
# View live logs
sudo journalctl -u it-ticket-system -f
# Restart after code changes
sudo systemctl restart it-ticket-system
# Stop the service
sudo systemctl stop it-ticket-system
8. Nginx Configuration
8.1 Install Site Configuration
# Copy nginx config
sudo cp /var/www/it-ticket-system/nginx.conf /etc/nginx/sites-available/it-ticket-system
# Edit: replace tickets.yourdomain.com with your actual domain
sudo nano /etc/nginx/sites-available/it-ticket-system
# Enable the site
sudo ln -s /etc/nginx/sites-available/it-ticket-system /etc/nginx/sites-enabled/
# Remove default nginx site (optional)
sudo rm -f /etc/nginx/sites-enabled/default
# Test configuration syntax
sudo nginx -t
# Reload nginx
sudo systemctl reload nginx
8.2 Nginx Tuning (Optional)
Add to /etc/nginx/nginx.conf inside the http {} block:
# Increase for large file uploads
client_max_body_size 20M;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_types text/plain text/css application/json application/javascript text/xml;
# Rate limiting
limit_req_zone $binary_remote_addr zone=app:10m rate=30r/m;
9. SSL Certificate
# Obtain Let's Encrypt certificate
sudo certbot --nginx -d tickets.yourdomain.com
# Certbot will automatically update your nginx config with SSL settings.
# Verify auto-renewal:
sudo certbot renew --dry-run
# The nginx.conf provided already has the SSL block commented out.
# After certbot runs, it will populate the ssl_certificate paths automatically.
10. First Login & Admin Setup
- Open your browser:
https://tickets.yourdomain.com - Log in with the credentials you set in
.env:- Email:
admin@yourdomain.com - Password:
YourStrongAdminPassword!
- Email:
- Change the admin password immediately via Profile → Change Password.
- Navigate to Admin → Users to create IT Staff accounts.
- Set their role to
it_stafforadmin.
Default Roles
| Role | Capabilities |
|---|---|
employee |
Create tickets, add comments, view own tickets, use chatbot, read KB |
it_staff |
All employee permissions + view/update all tickets, assign tickets, internal notes, manage KB |
admin |
All IT staff permissions + manage users, view full activity logs, deactivate accounts |
11. AI Chatbot Configuration
The chatbot uses the Anthropic Claude API (claude-sonnet-4-20250514).
- Obtain an API key from console.anthropic.com
- Add to
.env:ANTHROPIC_API_KEY=sk-ant-api03-... - Restart the service:
sudo systemctl restart it-ticket-system
Chatbot capabilities:
- Conversationally gathers issue details from employees
- Automatically creates tickets with appropriate category and priority
- Notifies IT staff immediately upon ticket creation
- Answers general IT questions without creating tickets
- Detects critical/urgent language and escalates priority accordingly
If ANTHROPIC_API_KEY is not set, the chatbot gracefully informs users to contact IT directly — the rest of the application continues to function normally.
12. Email Configuration
Gmail / Google Workspace
MAIL_SERVER=smtp.gmail.com
MAIL_PORT=587
MAIL_USE_TLS=True
MAIL_USERNAME=ittickets@yourdomain.com
MAIL_PASSWORD=your-app-password # Use App Password, not account password
Microsoft 365 / Outlook
MAIL_SERVER=smtp.office365.com
MAIL_PORT=587
MAIL_USE_TLS=True
MAIL_USERNAME=ittickets@yourdomain.com
MAIL_PASSWORD=your-password
Local Postfix (no external relay)
MAIL_SERVER=localhost
MAIL_PORT=25
MAIL_USE_TLS=False
MAIL_USERNAME=
MAIL_PASSWORD=
Email notifications are sent for:
- New ticket created → IT Department email + all IT staff (in-app)
- Ticket status changed → Ticket creator
- Ticket assigned → Assigned IT staff member
- New comment added → Ticket creator + assignee
If email fails (wrong credentials, network issue), errors are logged silently — the ticket operation still succeeds.
13. Code Change Map
This section documents every file and what was added/changed, as a reference for future modifications.
New Files (All files are new — this is a greenfield application)
| File | Purpose | Key Functions/Routes |
|---|---|---|
run.py |
Entry point | Starts Flask + SocketIO |
config/config.py |
Environment config | Config, DevelopmentConfig, ProductionConfig |
app/__init__.py |
App factory | create_app(), _seed_admin() |
app/models.py |
Database models | User, Ticket, Comment, Attachment, Notification, TicketHistory, ActivityLog, KnowledgeBase |
app/routes/auth.py |
Authentication | GET/POST /auth/login, GET/POST /auth/register, GET /auth/logout, GET/POST /auth/profile |
app/routes/tickets.py |
Ticket management | GET/POST /tickets/new, GET /tickets, GET/POST /tickets/<id>, POST /tickets/<id>/update, POST /comments/<id>/delete, GET /attachments/<id>, GET/POST /notifications, GET /kb, GET /kb/<id> |
app/routes/admin.py |
Admin/IT views | GET /admin/, GET /admin/tickets, GET /admin/users, GET/POST /admin/users/<id>/edit, POST /admin/users/<id>/delete, KB CRUD, GET /admin/logs |
app/routes/api.py |
JSON API + WebSocket | GET /api/notifications/unread-count, POST /api/notifications/<id>/read, POST /api/notifications/mark-all-read, GET /api/stats/tickets, Socket events: connect, disconnect, join_ticket, leave_ticket |
app/routes/chatbot.py |
AI assistant | POST /chatbot/message |
app/services/notification_service.py |
Notification delivery | create_notification(), send_email(), notify_new_ticket(), notify_status_change(), notify_comment_added(), notify_assignment() |
app/services/log_service.py |
Audit logging | log_action(), log_ticket_history() |
gunicorn.conf.py |
WSGI server config | eventlet worker, bind address, log paths |
it-ticket-system.service |
Systemd unit | Auto-start, restart-on-failure |
nginx.conf |
Reverse proxy | SSL termination, WebSocket upgrade, static file serving |
setup_db.sql |
DB initialisation | Creates database, user, grants |
Where Logging (log_action) Is Called
| Event | File | Function | Log Action String |
|---|---|---|---|
| User login | auth.py |
login() |
user_login |
| User registration | auth.py |
register() |
user_register |
| User logout | auth.py |
logout() |
user_logout |
| Profile update | auth.py |
profile() |
user_profile_update |
| Ticket created | tickets.py |
create_ticket() |
ticket_create |
| Ticket updated | tickets.py |
update_ticket() |
ticket_update |
| Comment created | tickets.py |
ticket_detail() |
comment_create |
| Comment deleted | tickets.py |
delete_comment() |
comment_delete |
| Ticket created via chatbot | chatbot.py |
chat() |
ticket_create_chatbot |
| Admin edits user | admin.py |
edit_user() |
admin_user_edit |
| Admin deactivates user | admin.py |
delete_user() |
admin_user_deactivate |
| KB article created | admin.py |
kb_new() |
kb_create |
| KB article edited | admin.py |
kb_edit() |
kb_edit |
| KB article deleted | admin.py |
kb_delete() |
kb_delete |
14. Features Overview
Employee Features
- Dashboard — open/active/resolved ticket counts, recent tickets, top KB articles
- Submit Ticket — form with title, category, priority, location, asset tag, file attachments
- AI Chatbot — floating chat widget (🤖 button, bottom-right); conversationally creates tickets
- Ticket Tracking — full ticket detail with comment thread, change history, attachments
- Notifications — real-time bell (WebSocket) + notification centre page
- Knowledge Base — self-service articles before submitting a ticket
- Profile — update name/department/phone, toggle email/web notifications, change password
IT Staff Features
- IT Dashboard — queue metrics (open/in-progress/pending/resolved), assigned tickets, recent activity
- All Tickets View — filterable by status, priority, assignment (mine/unassigned/all)
- Ticket Update Panel — change status, priority, assignee, due date, resolution notes, internal notes
- Internal Notes — IT-only comments not visible to the employee
- Ticket History — field-level change log on every ticket
- Knowledge Base Management — create, edit, publish/unpublish, delete articles
Admin Features
- User Management — list all users, edit role/department/status, reset passwords, deactivate
- Activity Log — full audit trail of all create/update/delete actions with IP addresses
- IT Overview — aggregate stats across all tickets and users
Technical Features
- Real-time WebSocket — notifications pushed instantly via Flask-SocketIO / eventlet
- Email Notifications — HTML emails for new tickets, status changes, comments, assignments
- File Attachments — on tickets and comments; UUID-stored filenames prevent collisions
- Ticket Numbering — sequential daily format:
TKT-20240315-0001 - Audit Trail — every significant action persisted to
activity_logs+ticket_history - AI Ticket Creation — chatbot flags
ai_generated=Trueon auto-created tickets
15. Maintenance & Operations
Application Logs
# Application logs (Flask)
tail -f /var/www/it-ticket-system/logs/it_tickets.log
# Gunicorn access log
tail -f /var/www/it-ticket-system/logs/gunicorn_access.log
# Gunicorn error log
tail -f /var/www/it-ticket-system/logs/gunicorn_error.log
# Systemd journal
sudo journalctl -u it-ticket-system -f --since "1 hour ago"
# Nginx logs
sudo tail -f /var/log/nginx/it_tickets_access.log
sudo tail -f /var/log/nginx/it_tickets_error.log
Deploying Code Updates
cd /var/www/it-ticket-system
# Pull latest code
sudo -u it-tickets git pull origin main
# Install any new dependencies
sudo -u it-tickets venv/bin/pip install -r requirements.txt
# Apply database migrations (if you add Flask-Migrate)
# sudo -u it-tickets venv/bin/flask db upgrade
# Restart the service
sudo systemctl restart it-ticket-system
sudo systemctl status it-ticket-system
Database Backup
# Full backup
mysqldump -u it_tickets_user -p it_tickets > backup_$(date +%Y%m%d_%H%M%S).sql
# Automated daily backup via cron (add to root's crontab):
# 0 2 * * * mysqldump -u it_tickets_user -pPASSWORD it_tickets | gzip > /backups/it_tickets_$(date +\%Y\%m\%d).sql.gz
Firewall Configuration
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP (redirects to HTTPS)
sudo ufw allow 443/tcp # HTTPS
sudo ufw deny 5000/tcp # Block direct Gunicorn access
sudo ufw enable
sudo ufw status
Troubleshooting Quick Reference
| Symptom | Likely Cause | Fix |
|---|---|---|
| 502 Bad Gateway | Gunicorn not running | sudo systemctl restart it-ticket-system |
| WebSocket not connecting | nginx missing upgrade headers | Verify /socket.io/ location block in nginx.conf |
| Emails not sending | SMTP credentials | Check .env MAIL_* values; test with flask shell |
| Chatbot not responding | Missing API key | Set ANTHROPIC_API_KEY in .env and restart |
| File uploads failing | Wrong permissions on uploads dir | sudo chown -R it-tickets:www-data app/static/uploads |
| DB connection error | Wrong credentials | Verify DB_* values in .env match setup_db.sql |
| Static files 404 | Wrong nginx alias | Check alias path in nginx /static/ block |