diff --git a/lib/control-panel/routers/main.js b/lib/control-panel/routers/main.js
index 6143421..7ef7a87 100644
--- a/lib/control-panel/routers/main.js
+++ b/lib/control-panel/routers/main.js
@@ -22,11 +22,21 @@ async function pageIndex(req, res) {
         limitedList[i].value = value;
     }
 
+    const products = limitedList.map((item) => item.product);
+    const maxValuesArray = await redisUtil.getMaxValuesForIndicator(products, xid);
+    const maxValues = {};
+    const productCount = products.length;
+    for (let i = 0; i < productCount; i += 1) {
+        const product = products[i];
+        maxValues[product] = Number(maxValuesArray[i]) || 0;
+    }
+
     res.render(
         'main.njk',
         {
             pageTitle: 'Produk dan Limit',
             limitedList,
+            maxValues,
         },
     );
 }
@@ -86,6 +96,25 @@ async function pageAddProductQuota(req, res) {
     res.redirect(req.baseUrl);
 }
 
+async function pageEditMaxValueForIndicator(req, res) {
+    const { xid } = res.locals;
+    const { product, maxValue } = req.body;
+
+    try {
+        logger.info(`${MODULE_NAME}: Saving max value`, {
+            xid, product, maxValue,
+        });
+
+        await redisUtil.setMaxValueForIndicator(product, Number(maxValue), xid);
+    } catch (e) {
+        logger.warn(`${MODULE_NAME}: Exception on saving max value for indicator`, {
+            xid, product, maxValue, eCode: e.code, eMessage: e.message,
+        });
+    }
+
+    res.redirect(req.baseUrl);
+}
+
 router.use((req, res, next) => {
     res.locals.baseUrl = req.baseUrl;
     next();
@@ -98,3 +127,5 @@ router.get('/delete/:suplier/:product', pageDelete);
 
 router.post('/edit-product', express.urlencoded({ extended: false }), pageEditProductSubmit);
 router.post('/add-quota', express.urlencoded({ extended: false }), pageAddProductQuota);
+
+router.post('/edit-max-value-for-indicator', express.urlencoded({ extended: false }), pageEditMaxValueForIndicator);
diff --git a/lib/control-panel/views/main.njk b/lib/control-panel/views/main.njk
index e53c019..578b19c 100644
--- a/lib/control-panel/views/main.njk
+++ b/lib/control-panel/views/main.njk
@@ -5,18 +5,34 @@
 <table class="table">
     <thead>
         <tr>
-            <th>Produk</th>
-            <th class="text-right">Sisa Kuota</th>
-            <th>&nbsp;</th>
+            <th style="white-space: nowrap; width: 1%;">Produk</th>
+            <th class="text-right">Sisa</th>
+            <th style="white-space: nowrap; width: 1%;">&nbsp;</th>
         </tr>
     </thead>
     <tbody>
         {% for item in limitedList %}
         <tr>
-            <td><strong>{{ item.product }}</strong></td>
-            <td class="text-right">{{ item.value }}</td>
+            <td style="white-space: nowrap; width: 1%;">
+                <strong>{{ item.product }}</strong>
+            </td>
+
+            <td class="text-right">
+                {% set maxValue = maxValues[item.product] %}
+                {% if maxValue %}    
+                <div class="progress">
+                    <div class="progress-bar" role="progressbar" style="width: {{ 100 * item.value / (maxValue or item.value) }}%;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="{{ maxValue }}"></div>
+                </div>
+                <br>
+                {% endif %}
 
-            <td>
+                <a href="#" title="klik untuk edit nilai maksimal pada grafik indikator" data-toggle="modal" data-target="#editMaxValueModal" data-product="{{ item.product }}" data-maxvalue="{{ item.value }}">
+                {{ item.value }}
+                {% if maxValue %} dari {{ maxValue }} {% endif %}
+                </a>
+            </td>
+
+            <td style="white-space: nowrap; width: 1%;">
                 <button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#editQuotaModal" data-product="{{ item.product }}">
                     Edit
                 </button>
@@ -117,6 +133,34 @@
 </div>
 </form>
 
+<form method="POST" action="{{ baseUrl }}/edit-max-value-for-indicator">
+<div class="modal fade" id="editMaxValueModal" tabindex="-1" role="dialog" aria-labelledby="editMaxValueModalLabel" aria-hidden="true">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="editMaxValueModalLabel">Edit nilai maksimal pada indikator</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <input type="hidden" name="product" id="inputProduct">
+                <div class="form-group">
+                    <label for="raiseValue">Nilai maksimal</label>
+                    <input name="maxValue" type="number" class="form-control" id="maxValue" aria-describedby="maxValueHelp" required>
+                    <small id="maxValueHelp" class="form-text text-muted">Masukkan nilai maksimal (untuk tampilan grafik).</small>
+                </div>
+            </div>
+
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+                <input type="submit" class="btn btn-primary" value="Simpan">
+            </div>
+        </div>
+    </div>
+</div>
+</form>
+
 {% endblock %}
 
 {% block postScriptOnBody %}
@@ -139,6 +183,17 @@ $('#addQuotaModal').on('show.bs.modal', function (event) {
     modal.find('.modal-title').text(`Tambah Kuota ${product}`);
     modal.find('.modal-body #inputProduct').val(product);
 });
+
+$('#editMaxValueModal').on('show.bs.modal', function (event) {
+    var button = $(event.relatedTarget);
+    var product = button.data('product');
+    var maxvalue = button.data('maxvalue');
+
+    var modal = $(this)
+    modal.find('.modal-title').text(`Edit nilai maksimal ${product}`);
+    modal.find('.modal-body #inputProduct').val(product);
+    modal.find('.modal-body #maxValue').val(maxvalue);
+});
 </script>
 
 {% endblock %}
\ No newline at end of file
diff --git a/lib/redis-util.js b/lib/redis-util.js
index 945ab7a..80d709c 100644
--- a/lib/redis-util.js
+++ b/lib/redis-util.js
@@ -240,3 +240,47 @@ const limitedList = (xid) => new Promise((resolve, reject) => {
     });
 });
 exports.limitedList = limitedList;
+
+const setMaxValueForIndicator = (product, val, xid) => new Promise((resolve) => {
+    if (!(product || '').trim()) {
+        logger.warn(`${MODULE_NAME}: Skip saving max value for empty product`, {
+            xid, product, val,
+        });
+        resolve();
+        return;
+    }
+
+    const keyword = `${composeKeyword(product)}_MAX_VALUE`;
+    logger.info(`${MODULE_NAME}: Saving max value`, {
+        xid, product, val, keyword,
+    });
+
+    redisClient.set(keyword, Number(val), 'EX', DEFAULT_TTL, (err) => {
+        if (err) {
+            logger.warn(`9E4965F4 ${MODULE_NAME}: Error on set max value on redis`, {
+                xid, product, val, eCode: err.code, eMessage: err.message,
+            });
+            resolve();
+            return;
+        }
+
+        resolve(val);
+    });
+});
+exports.setMaxValueForIndicator = setMaxValueForIndicator;
+
+const getMaxValuesForIndicator = (products, xid) => new Promise((resolve, reject) => {
+    const keywords = products.map((item) => `${composeKeyword(item)}_MAX_VALUE`);
+    redisClient.mget(...keywords, (err, reply) => {
+        if (err) {
+            logger.warn(`63BE7706 ${MODULE_NAME}: Error on getting max values on redis`, {
+                xid, eCode: err.code, eMessage: err.message,
+            });
+            reject(err);
+            return;
+        }
+
+        resolve(reply);
+    });
+});
+exports.getMaxValuesForIndicator = getMaxValuesForIndicator;