← Back to ServiFlow
Looking for the user manual?
ServiFlow User Guide → — step-by-step instructions for admins, experts, and customers.
Getting Started
Get ServiFlow running locally in under five minutes.
Prerequisites
- Node.js 14 or later
- MySQL 8.x running locally (or a remote instance)
Install & Run
# Install dependencies
npm install
# Create databases & seed data
npm run setup-db
# Start the server
npm start
Open http://localhost:3000 in your browser.
Default Credentials
| Role | Username | Password |
| Master Admin | admin | admin123 |
| Tenant Admin | admin | password123 |
| Expert | expert | password123 |
| Customer | customer | password123 |
When logging in as a tenant user, use the tenant code apoyar.
Environment Variables
# .env file
MASTER_DB_HOST=localhost
MASTER_DB_PORT=3306
MASTER_DB_USER=root
MASTER_DB_PASSWORD=
MASTER_DB_NAME=a1_master
PORT=3000
# Email (Gmail SMTP)
SMTP_EMAIL=your-email@gmail.com
SMTP_PASSWORD=your-app-password
Architecture
Multi-Tenant Database
ServiFlow uses a database-per-tenant isolation model:
- Master DB (
a1_master) — tenants, master_users, plans, subscriptions, billing
- Tenant DBs (
a1_tenant_{code}) — users, tickets, cmdb_items, sla_definitions, etc.
┌─────────────┐ ┌────────────────┐ ┌────────────────┐
│ a1_master │ │ a1_tenant_ │ │ a1_tenant_ │
│ │ │ apoyar │ │ bleckmann │
│ master_users│ │ users │ │ users │
│ tenants │ │ tickets │ │ tickets │
│ plans │ │ cmdb_items │ │ cmdb_items │
└─────────────┘ └────────────────┘ └────────────────┘
│ │ │
└──────────────────┼────────────────────┘
│
┌───────────────┐
│ Express API │
│ + SPA Front │
└───────────────┘
Key Files
| File | Purpose |
server.js | Main Express entry point |
config/database.js | Database connection management |
services/tenant-provisioning.js | New tenant creation & schema |
routes/auth.js | Authentication endpoints |
routes/master.js | Master admin API |
routes/admin.js | Tenant admin settings & housekeeping |
services/sla-notifier.js | SLA notification scheduler |
services/email-processor.js | Inbound email → ticket processing |
services/ai-analysis-service.js | AI ticket analysis |
services/housekeeping.js | Data retention & pruning |
Technology Stack
- Backend: Node.js + Express
- Database: MySQL (mysql2)
- Auth: JWT (jsonwebtoken) + bcrypt
- Security: Helmet, CORS, rate limiting
- Email: Nodemailer (Gmail SMTP)
- Frontend: Single-page HTML + vanilla JS
Security
- JWT token authentication on every API call
- bcrypt password hashing (10 rounds)
- Strict tenant isolation — queries always scoped to tenant DB
- Role-based access control (Master Admin, Admin, Expert, Customer)
- Helmet.js security headers
- CORS protection
Feature Overview
Core Capabilities
- Multi-Tenant SaaS — database-per-tenant isolation, self-service signup
- Ticket Management — create, assign, track, resolve with full activity logging
- SLA Tracking — real-time countdowns, breach notifications, pause/resume
- CMDB — configuration item management, asset viewer, custom fields
- Knowledge Base — article creation, categorisation, search
- AI Insights — sentiment analysis, trend detection, root-cause identification
- Email Processing — inbound email creates/updates tickets with threading
- Ticket Processing Rules — automated actions on matching tickets
- Customer Management — CRUD with domain-based email matching
- Analytics Dashboard — charts, SLA compliance, resolution trends
- Housekeeping — configurable data retention and ticket pruning
User Roles
| Role | Access |
| Master Admin | Platform-wide: tenants, plans, billing, system health |
| Admin | Tenant-level: tickets, users, CMDB, settings, rules, analytics |
| Expert | Assigned tickets, CMDB, knowledge base, AI insights |
| Customer | Own tickets, raise requests, company CMDB, analytics |
Email System
- Nodemailer + Gmail SMTP integration
- Notifications for ticket creation, status changes, and resolution
- Inbound email processing with reply threading (header → subject token → URL → domain match)
- HTML email templates
Ticket Management
Ticket Workflow
Tickets progress through the following statuses:
Open → In Progress → Pending → Resolved → Closed
Status Descriptions
| Status | Description |
| Open | New ticket awaiting assignment or triage |
| In Progress | Being actively worked on by an expert |
| Pending | Waiting for customer response or external input |
| Resolved | Fix applied, awaiting customer confirmation |
| Closed | Completed — no further action needed |
SLA Tracking
Each ticket can have an SLA definition applied that tracks:
- Response time — time until first response (
first_responded_at)
- Resolution time — time until ticket is resolved
- Real-time countdown timers in the UI
- Colour-coded risk indicators (OK → Warning → Danger)
- Email notifications at near-breach, breach, and past-breach thresholds
- Pause and resume SLA timers (e.g. waiting for customer)
Activity Logging
Every ticket action is recorded in the ticket_activity table:
| Activity Type | Trigger |
created | Ticket created |
assigned | Expert assigned |
updated | Status or field changed |
comment | Internal note added |
resolved | Ticket resolved with comment |
closed | Ticket closed |
classified | AI classification applied |
email_reply | Customer replied via email |
auto_reply | System auto-response sent |
Demo Scenarios
- Admin: View all tickets, assign to experts, manage SLA definitions
- Expert: Work assigned tickets, update status, use completion modal
- Customer: Raise requests, track status, view CMDB assets
Customer Management
CRUD Operations
| Action | Endpoint | Role |
| List all | GET /api/customers | Admin, Expert |
| Get one | GET /api/customers/:id | Admin, Expert |
| Create | POST /api/customers | Admin |
| Update | PUT /api/customers/:id | Admin |
| Deactivate | DELETE /api/customers/:id | Admin |
| Reactivate | POST /api/customers/:id/reactivate | Admin |
Company Domain Matching
The company_domain field is critical for the email-to-ticket system:
- Customer sends email from
john@acme.com
- System extracts domain:
acme.com
- Looks up domain in customers table
- Creates ticket for that customer (or creates a new customer user if none exists)
Database Schema
| Column | Type | Description |
id | int | Primary key |
user_id | int | FK to users table |
company_name | varchar(100) | Company display name |
company_domain | varchar(255) | Email domain for matching |
contact_phone | varchar(20) | Contact phone |
address | text | Company address |
sla_level | enum | basic / premium / enterprise |
Security
- Domain format validation (regex:
[a-z0-9][a-z0-9-]*\.[a-z]{2,})
- Random 10-character password generated on creation (bcrypt hashed)
- Soft delete preserves data; cannot delete customers with active tickets
- Rate limiting: 30 write operations per 15 minutes
AI Insights
Automatic Analysis
Every incoming ticket is analysed for:
- Sentiment: urgent, negative, neutral, positive
- Category: Infrastructure, Database, Storage, Network, Performance
- Root Cause: system, hardware, software, network, database, resource
- Impact Level: low, medium, high, critical
- Key Phrases & Technical Terms
- Confidence Score (0–100%)
- Estimated Resolution Time
Trend Detection
Automatically detects:
- Volume Spikes — unusual increases in ticket volume
- Recurring Issues — same category appearing repeatedly
- SLA Risks — tickets approaching deadline
- Urgent Backlogs — critical tickets not being addressed
Dashboard Actions
| Action | Description |
| Refresh | Reload latest insights |
| Detect Trends | Manually trigger trend analysis for the last 24 hours |
| Acknowledge | Mark insight as reviewed (tracked with user + timestamp) |
| Dismiss | Remove false positive or resolved insight from view |
API Endpoints
| Method | Endpoint | Description |
| GET | /api/analytics/:tenantId/ai-insights | Dashboard data |
| POST | /api/analytics/:tenantId/detect-trends | Manual trend analysis |
| POST | /api/analytics/:tenantId/insights/:id/acknowledge | Acknowledge insight |
| POST | /api/analytics/:tenantId/insights/:id/dismiss | Dismiss insight |
Database Tables
ai_email_analysis — per-ticket analysis results
ai_insights — detected trends and alerts
ai_category_mappings — pattern learning
ai_system_metrics — performance tracking
Ticket Processing Rules
Create automated rules that match tickets by search criteria and perform actions.
Rule Configuration
| Field | Description |
| Rule Name | Descriptive label |
| Search In | title, body, or both |
| Search Text | Text to match |
| Case Sensitive | Toggle case-sensitive matching |
| Action Type | What to do when a match is found |
| Enabled | Toggle rule on/off without deleting |
Action Types
| Type | Description | Parameters |
delete | Delete matching tickets | (none) |
assign_to_expert | Assign to a specific expert | expert_id, expert_name |
create_for_customer | Forward ticket to another customer | customer_id |
set_priority | Set ticket priority | priority (low/medium/high/critical) |
set_status | Set ticket status | status |
add_tag | Add a tag to the ticket | tag |
Examples
Auto-assign infrastructure alerts
{
"rule_name": "Auto-assign Infrastructure",
"search_in": "title",
"search_text": "Infrastructure Monitoring",
"action_type": "assign_to_expert",
"action_params": { "expert_id": 1, "expert_name": "Infrastructure Team" }
}
Escalate urgent tickets
{
"rule_name": "Escalate Critical",
"search_in": "title",
"search_text": "URGENT",
"case_sensitive": true,
"action_type": "set_priority",
"action_params": { "priority": "critical" }
}
API Endpoints
All prefixed with /api/ticket-rules/:tenantId.
| Method | Path | Description |
| GET | / | List all rules |
| GET | /:ruleId | Get single rule |
| POST | / | Create rule |
| PUT | /:ruleId | Update rule |
| DELETE | /:ruleId | Delete rule |
| POST | /:ruleId/test | Preview matching tickets |
| POST | /:ruleId/execute/:ticketId | Execute on specific ticket |
| POST | /execute-all/:ticketId | Execute all enabled rules on ticket |
| GET | /:ruleId/history | Execution history |
| GET | /statistics | Rule statistics |
API Reference
All endpoints require a Bearer token in the Authorization header unless noted.
Authentication
| Method | Endpoint | Description |
| POST | /api/auth/master/login | Master admin login |
| POST | /api/auth/tenant/login | Tenant user login |
| POST | /api/auth/master/change-password | Change master password |
| POST | /api/auth/tenant/change-password | Change tenant password |
| GET | /api/auth/verify | Verify token validity |
| GET | /api/auth/profile | Get user profile |
| PUT | /api/auth/profile | Update user profile |
| GET | /api/auth/tenants | List available tenants (public) |
Tickets
| Method | Endpoint | Description |
| GET | /api/tickets/:tenantId | Get all tickets |
| GET | /api/tickets/:tenantId/:ticketId | Get specific ticket + activity |
| POST | /api/tickets/:tenantId | Create new ticket |
| PUT | /api/tickets/:tenantId/:ticketId | Update ticket (resolve, assign, etc.) |
Master Admin
| Method | Endpoint | Description |
| GET | /api/master/tenants | Get all tenants |
| GET | /api/master/overview | Platform overview |
| GET | /api/master/subscriptions | Get subscriptions |
| GET | /api/master/billing | Get billing information |
| GET | /api/master/plans | Get subscription plans |
| GET | /api/master/email-settings | Get email settings |
| POST | /api/master/email-settings/test | Test email processing |
| GET | /api/master/audit-logs | Get audit logs |
Customers
| Method | Endpoint | Description |
| GET | /api/customers | List all customers |
| GET | /api/customers/:id | Get single customer |
| POST | /api/customers | Create customer |
| PUT | /api/customers/:id | Update customer |
| DELETE | /api/customers/:id | Deactivate customer |
| POST | /api/customers/:id/reactivate | Reactivate customer |
Analytics & AI
| Method | Endpoint | Description |
| GET | /api/analytics/:tenantId/ai-insights | AI dashboard data |
| POST | /api/analytics/:tenantId/detect-trends | Manual trend detection |
| POST | /api/analytics/:tenantId/insights/:id/acknowledge | Acknowledge insight |
| POST | /api/analytics/:tenantId/insights/:id/dismiss | Dismiss insight |
Admin Settings
| Method | Endpoint | Description |
| GET | /api/admin/:tenantId/housekeeping | Get housekeeping config |
| PUT | /api/admin/:tenantId/housekeeping | Update housekeeping config |
| POST | /api/admin/:tenantId/housekeeping/run | Run housekeeping now |
Health & Status
| Method | Endpoint | Auth | Description |
| GET | /health | No | Server health check |
| GET | /api/db/status | No | Database connection status |
Troubleshooting
Server Hangs on Login
Usually caused by MySQL connection pool exhaustion.
# Kill stale node processes
pkill -f "node.*server"
lsof -ti:3000 | xargs kill -9
# Clean stale MySQL connections
mysql -u root -e "SELECT CONCAT('KILL ', id, ';') \
FROM information_schema.processlist \
WHERE user='root' AND command='Sleep' AND time > 60;" -N | mysql -u root
# Restart
npm start
MySQL Connection Issues
# Check MySQL service
sudo systemctl start mysql
sudo systemctl enable mysql
# Ensure root has privileges
mysql -u root -p
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost';
FLUSH PRIVILEGES;
Port Conflicts
# Use a different port
PORT=3001 npm start
Railway Deployment Not Updating
Changes must be committed to git before railway up. Railway deploys from git, not local files.
git add .
git commit -m "Your message"
railway up --detach
Customer Domain Issues
| Error | Solution |
| "Domain not found in customers" | Add the sender's email domain to a customer record |
| "Username or email already exists" | Choose a different username or update the existing customer |
| "Cannot delete customer with X active tickets" | Close all tickets first, then deactivate |
| Customer can't login | Check: active status, correct password, tenant code = "apoyar" |
Ticket Rules Not Matching
- Verify search text is correct
- Try with case-sensitive disabled
- Check if searching in the correct field (title / body / both)
- Use the Test button to preview matches before enabling
AI Insights Not Loading
- Check browser console for API errors
- Verify authentication token is valid (re-login if expired)
- Ensure the
ai_email_analysis table exists in the tenant database
- Try clicking Refresh or Detect Trends to regenerate data
Adding Columns to Existing Tenant DBs
When adding new columns, update all tenant databases:
# Get Railway MySQL password
railway variables | grep MYSQLPASSWORD
# Run migration on each tenant DB
mysql -h tramway.proxy.rlwy.net -P 19355 -u root -p{PASSWORD} -e "
ALTER TABLE a1_tenant_{code}.tickets ADD COLUMN new_col TYPE;"