Discover how to build a robust support ticket system with Lovable. Follow our step-by-step guide for expert tips, seamless setup, and customization to boost your customer support.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Project Structure Setup
Create a new Lovable project and add the following files and folders to your project:
package.json
server.js
ticketRoutes.js
/public/index.html
/public/style.css
/public/script.js
Make sure each file is created exactly as specified in the file structure above.
Setting Up Dependencies
Since Lovable doesn’t have a terminal, you need to manually add dependency definitions in your project. Open or create the file package.json
in the root directory and insert the following code. This is how Lovable will know about the required packages:
{
"name": "support-ticket-system",
"version": "1.0.0",
"dependencies": {
"express": "^4.17.1",
"body-parser": "^1.19.0"
},
"main": "server.js",
"scripts": {
"start": "node server.js"
}
}
Creating the Server File
In the root directory, create a file called server.js
and add the following code. This file configures the Express server, uses the necessary middleware, serves static files from the public
folder, and integrates ticket routes:
const express = require('express');
const bodyParser = require('body-parser');
const ticketRoutes = require('./ticketRoutes');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static('public'));
app.use('/tickets', ticketRoutes);
app.get('/', (req, res) => {
res.sendFile(\_\_dirname + '/public/index.html');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Defining the Ticket Routes
Create a new file in the root directory called ticketRoutes.js
and insert the following code. This file handles GET and POST requests for tickets by storing them in an in-memory array:
const express = require('express');
const router = express.Router();
let tickets = [];
router.get('/', (req, res) => {
res.json(tickets);
});
router.post('/', (req, res) => {
const { name, email, issue } = req.body;
const newTicket = {
id: tickets.length + 1,
name,
email,
issue,
status: 'Open'
};
tickets.push(newTicket);
res.json({ message: 'Ticket submitted successfully', ticket: newTicket });
});
module.exports = router;
Building the Frontend Interface
Inside the public
folder, create a file named index.html
and paste in the following HTML code. This page provides a user-friendly interface that allows visitors to submit support tickets:
Support Ticket System
Submit a Support Ticket
Adding Custom Styles
In the same public
folder, create a style.css
file to style the support ticket form. Insert the code below:
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f2f2f2;
}
h1 {
text-align: center;
}
form {
max-width: 400px;
margin: 0 auto;
padding: 20px;
background: #fff;
border-radius: 5px;
}
label, input, textarea, button {
display: block;
width: 100%;
margin-top: 10px;
}
button {
margin-top: 20px;
padding: 10px;
background: #007BFF;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
Implementing the Frontend Logic
Next, still in the public
folder, create a file called script.js
and add the following code. This JavaScript file handles form submissions, sending ticket data to the server using a POST request:
document.getElementById('ticketForm').addEventListener('submit', function(e) {
e.preventDefault();
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
const issue = document.getElementById('issue').value;
fetch('/tickets', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: name, email: email, issue: issue })
})
.then(response => response.json())
.then(data => {
const responseDiv = document.getElementById('response');
responseDiv.innerHTML = '' + data.message + '
';
document.getElementById('ticketForm').reset();
})
.catch(error => {
console.error('Error:', error);
});
});
Testing the Support Ticket System
server.js
as the main entry point./tickets
to view the list of all submitted tickets.
const express = require('express');
const bodyParser = require('body-parser');
const { MongoClient, ObjectId } = require('mongodb');
const app = express();
app.use(bodyParser.json());
const mongoUrl = 'mongodb://localhost:27017';
const dbName = 'lovableSupportDB';
let db;
MongoClient.connect(mongoUrl, { useUnifiedTopology: true })
.then(client => {
db = client.db(dbName);
console.log('Connected to MongoDB');
})
.catch(err => console.error(err));
app.post('/api/ticket', async (req, res) => {
try {
const { userId, subject, description, attachments } = req.body;
const processedAttachments = attachments.map(att => {
return {
fileId: att.id,
status: 'processed',
loveScore: Math.random()
};
});
const ticketData = {
userId: ObjectId(userId),
subject,
description,
attachments: processedAttachments,
status: 'open',
createdAt: new Date()
};
const result = await db.collection('tickets').insertOne(ticketData);
res.status(201).json({ ticketId: result.insertedId });
} catch (err) {
res.status(500).json({ error: err.toString() });
}
});
app.get('/api/ticket/:id', async (req, res) => {
try {
const ticket = await db.collection('tickets').findOne({ \_id: ObjectId(req.params.id) });
if (!ticket) {
return res.status(404).json({ error: 'Ticket not found' });
}
res.json(ticket);
} catch (err) {
res.status(500).json({ error: err.toString() });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
const express = require('express');
const fetch = require('node-fetch');
const { MongoClient, ObjectId } = require('mongodb');
const app = express();
app.use(express.json());
const mongoUrl = 'mongodb://localhost:27017';
const dbName = 'lovableTicketsDB';
let db;
(async () => {
try {
const client = await MongoClient.connect(mongoUrl, { useUnifiedTopology: true });
db = client.db(dbName);
console.log('Connected to MongoDB');
app.listen(3001, () => console.log('Server running on port 3001'));
} catch (error) {
console.error('Failed connecting to MongoDB', error);
}
})();
const slackWebhookUrl = 'https://hooks.slack.com/services/XXX/YYY/ZZZ';
app.post('/api/ticket/external', async (req, res) => {
try {
const { userId, subject, description } = req.body;
const newTicket = {
userId: ObjectId(userId),
subject,
description,
status: 'new',
createdAt: new Date()
};
const result = await db.collection('tickets').insertOne(newTicket);
const slackMessage = {
text: `New Support Ticket Created\n*Subject:* ${subject}\n*User ID:* ${userId}`
};
await fetch(slackWebhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(slackMessage)
});
res.status(201).json({ ticketId: result.insertedId });
} catch (error) {
res.status(500).json({ error: error.toString() });
}
});
const express = require('express');
const { MongoClient, ObjectId } = require('mongodb');
const cron = require('node-cron');
const fetch = require('node-fetch');
const app = express();
app.use(express.json());
const mongoUrl = 'mongodb://localhost:27017';
const dbName = 'lovableSupportDB';
let db;
MongoClient.connect(mongoUrl, { useUnifiedTopology: true })
.then(client => {
db = client.db(dbName);
console.log('Connected to MongoDB');
})
.catch(err => console.error('MongoDB connection failed:', err));
app.put('/api/ticket/escalate/:id', async (req, res) => {
try {
const ticketId = new ObjectId(req.params.id);
const updatedTicket = await db.collection('tickets').findOneAndUpdate(
{ \_id: ticketId, status: 'open' },
{ $set: { status: 'escalated', escalatedAt: new Date() } },
{ returnDocument: 'after' }
);
if (!updatedTicket.value) {
return res.status(404).json({ error: 'Ticket not found or already escalated.' });
}
await fetch('https://api.lovable.com/notify/escalation', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ticketId: updatedTicket.value.\_id, subject: updatedTicket.value.subject })
});
res.json(updatedTicket.value);
} catch (error) {
res.status(500).json({ error: error.toString() });
}
});
cron.schedule('0 _ _ _ _', async () => {
try {
const cutoff = new Date(Date.now() - 48 _ 60 _ 60 \* 1000);
const tickets = await db.collection('tickets').find({ status: 'open', createdAt: { $lt: cutoff } }).toArray();
for (const ticket of tickets) {
const result = await db.collection('tickets').findOneAndUpdate(
{ _id: ticket._id, status: 'open' },
{ $set: { status: 'escalated', escalatedAt: new Date() } },
{ returnDocument: 'after' }
);
if (result.value) {
await fetch('https://api.lovable.com/notify/escalation', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ticketId: result.value.\_id, subject: result.value.subject })
});
console.log(`Auto-escalated ticket ${ticket._id}`);
}
}
} catch (error) {
console.error('Auto-escalation error:', error);
}
});
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Understanding the Support Ticket System with AI Code Generators
Prerequisites and Initial Setup
Designing the Ticket Submission Form
<form action="/submit-ticket" method="POST" enctype="multipart/form-data">
<label for="name">Your Name:</label>
<input type="text" id="name" name="name" required>
<label for="email">Email Address:</label>
<input type="email" id="email" name="email" required>
<label for="subject">Subject:</label>
<input type="text" id="subject" name="subject" required>
<label for="description">Issue Description:</label>
<textarea id="description" name="description" rows="4" required></textarea>
<label for="attachment">Attachment (optional):</label>
<input type="file" id="attachment" name="attachment">
<button type="submit">Submit Ticket</button>
</form>
Setting Up the Backend Server
from flask import Flask, request, jsonify
app = Flask(name)
@app.route('/submit-ticket', methods=['POST'])
def submit_ticket():
name = request.form.get('name')
email = request.form.get('email')
subject = request.form.get('subject')
description = request.form.get('description')
# Here you can add code to save the ticket info to a database
# and handle file uploads if necessary.
# For this example, we simply return the data as confirmation.
return jsonify({
'message': 'Ticket submitted successfully!',
'data': {
'name': name,
'email': email,
'subject': subject,
'description': description
}
})
if name == 'main':
app.run(debug=True)
Integrating the AI Code Generator
import requests
def get_ai_code_suggestion(issue_description):
api_url = "https://api.aicodegenerator.com/suggest"
api_key = "YOUR_API_KEY" # Replace with your actual API key
payload = {
"description": issue\_description,
"language": "python" # You can adjust this based on your needs
}
headers = {
"Authorization": f"Bearer {api\_key}",
"Content-Type": "application/json"
}
response = requests.post(api\_url, json=payload, headers=headers)
if response.status\_code == 200:
return response.json().get("suggested\_code")
else:
return "No suggestion available at the moment."
Example usage:
print(get_ai_code_suggestion("How to fix a NullPointer exception?"))
Processing Tickets and Displaying AI Suggestions
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.