diff --git a/app.py b/app.py
index 5b0a664a46c315fe9d73b84fe7ade2a5f9848c5c..62cf5ef89d407f31cf860f505f82396a83745673 100644
--- a/app.py
+++ b/app.py
@@ -6,6 +6,7 @@ from modules.login import login_route
 from modules.comment import comment_route
 from modules.register import register_route
 from modules.admin import admin_route
+from modules.page import page_route
 from modules.tools.token import validate_login_token
 
 app = Flask(__name__)
@@ -16,6 +17,7 @@ app.register_blueprint(login_route)
 app.register_blueprint(register_route)
 app.register_blueprint(comment_route)
 app.register_blueprint(admin_route)
+app.register_blueprint(page_route)
 
 cors = CORS(app)
 
@@ -33,32 +35,28 @@ def visualisasi():
 	return render_template("test-visualisasi.html")
 
 # User
-@app.route("/api/user/", methods=['POST', 'GET', 'DELETE', 'PUT'])
-def user():
-	if request.method == 'POST':
-		return "Masukin user baru"	
-	elif request.method == 'GET':
-		return "Ambil data user sesuai id"
-	elif request.method == 'DELETE':
-		return "Hapus user sesuai id"
-	elif request.method == 'PUT':
-		return "Edit user"
+# @app.route("/api/user/", methods=['POST', 'GET', 'DELETE', 'PUT'])
+# def user():
+# 	if request.method == 'POST':
+# 		return "Masukin user baru"	
+# 	elif request.method == 'GET':
+# 		return "Ambil data user sesuai id"
+# 	elif request.method == 'DELETE':
+# 		return "Hapus user sesuai id"
+# 	elif request.method == 'PUT':
+# 		return "Edit user"
 
-# Comment
-@app.route("/api/comment/", methods=['POST', 'GET', 'DELETE', 'PUT'])
-def comment():
-	if request.method == 'POST':
-		return "Masukin comment baru"	
-	elif request.method == 'GET':
-		return "Ambil satu comment sesuai id"
-	elif request.method == 'DELETE':
-		return "Hapus comment sesuai id"
-	elif request.method == 'PUT':
-		return "Edit comment sesuai id"
-
-# @app.route("/api/comments/", methods=['GET'])
-# def 
-	# Ambil komentar-komentar sesuai filter (levelnya)
+# # Comment
+# @app.route("/api/comment/", methods=['POST', 'GET', 'DELETE', 'PUT'])
+# def comment():
+# 	if request.method == 'POST':
+# 		return "Masukin comment baru"	
+# 	elif request.method == 'GET':
+# 		return "Ambil satu comment sesuai id"
+# 	elif request.method == 'DELETE':
+# 		return "Hapus comment sesuai id"
+# 	elif request.method == 'PUT':
+# 		return "Edit comment sesuai id"
 
 @app.after_request
 def after_request(response):
diff --git a/database/database.py b/database/database.py
index c1a57bb2f1baf0961414cc66a561a9972e5179a1..c83b250098c90e1b2c0b46936a06713394313892 100644
--- a/database/database.py
+++ b/database/database.py
@@ -1,6 +1,7 @@
 from flask import Flask
 from flask_mongoengine import MongoEngine
 from bson import json_util
+from datetime import datetime
 import json
 
 mongo = MongoEngine()
@@ -11,7 +12,7 @@ class User(mongo.Document):
     password = mongo.StringField(required=True)
     name = mongo.StringField(required=True)
     role = mongo.IntField(required=True)
-    page_list = mongo.ListField(mongo.ReferenceField("Page"))
+    page_list = mongo.ListField(mongo.ReferenceField("VizData"))
 
     def to_json(self):
         data = self.to_mongo()
@@ -25,20 +26,16 @@ class Reply(mongo.EmbeddedDocument):
 class Comment(mongo.Document):
     commenter_id = mongo.StringField(max_length=20, required=True)
     comment_text = mongo.StringField(required=True)
-    page = mongo.ReferenceField('Page', required=True)
+    page = mongo.ReferenceField('VizData', required=True)
+    date = mongo.DateTimeField(default = datetime.utcnow)
     reply = mongo.EmbeddedDocumentField('Reply')
 
-class Data(mongo.Document):
+class VizData(mongo.Document):
     name = mongo.StringField(required = True)
-    value = mongo.IntField(required = True)
-    categories = mongo.ListField(mongo.StringField(), default=[])
-    detail = mongo.StringField()
-
-class Page(mongo.Document):
-    level = mongo.IntField(required=True)
-    data = mongo.ListField(mongo.ReferenceField("Data", required=True))
-    comments = mongo.ListField(mongo.ReferenceField("Comment"), default=[])
-
+    level = mongo.IntField(required= True)
+    value = mongo.LongField(required = True)
+    year = mongo.IntField(required=True)
+    subdata = mongo.ListField(mongo.ReferenceField("VizData"))
 
 
 if __name__ == "__main__":
diff --git a/modules/admin.py b/modules/admin.py
index 851384101784f275a2e6ee7becb2ae8ecc615e66..4af0cf49a5e4d1fa37eabda0cec56702008ce6d5 100644
--- a/modules/admin.py
+++ b/modules/admin.py
@@ -15,7 +15,7 @@ def add_page():
     data = request.get_json()
 
     admin = db.User.objects.with_id(data.get("admin_id"))
-    admin.page_list.append(db.Page.objects.with_id(data.get("page_id")))
+    admin.page_list.append(db.VizData.objects.with_id(data.get("page_id")))
     admin.save()
     return jsonify({
         "status":200,
@@ -29,7 +29,7 @@ def remove_page():
     data = request.get_json()
 
     admin = db.User.objects.with_id(data.get("admin_id"))
-    admin.update(pull__page_list = db.Page.objects.with_id(data.get("page_id")))
+    admin.update(pull__page_list = db.VizData.objects.with_id(data.get("page_id")))
     
     return jsonify({
         "status":200,
diff --git a/modules/comment.py b/modules/comment.py
index c4a7cf6a01d4a8becc87eb6c33b7d950fe050dff..d03e9cb03cb32e186322568bc85a0363c20fa625 100644
--- a/modules/comment.py
+++ b/modules/comment.py
@@ -1,3 +1,69 @@
-from flask import Blueprint
+import json
+import jwt
+from datetime import datetime
+from flask import Blueprint, jsonify, request, current_app
+from database import database as db
+from modules.tools.token import Token, validate_login_token
+from modules.tools.roles import Roles
 
-comment_route = Blueprint('comment', __name__, template_folder="templates")
\ No newline at end of file
+comment_route = Blueprint('comment', __name__, template_folder="templates")
+
+@comment_route.route("/api/comment/get", methods = ["POST"])
+def get_comment():
+    page_id = request.get_json().get("page_id")
+    page = db.VizData.objects.with_id(page_id)
+    comments = db.Comment.objects(page=page).order_by('-date')
+    return jsonify({
+        "status":200,
+        "data":comments
+    })
+
+@comment_route.route("/api/comment/get-unreplied", methods=["POST"])
+def get_unreplied_comment():
+    page_id = request.get_json().get("page_id")
+    page = db.VizData.objects.with_id(page_id)
+    comments = db.Comment.objects(page=page, reply__exists=False).order_by('-date')
+    return jsonify({
+        "status":200,
+        "data":comments
+    })
+
+
+@comment_route.route("/api/comment/add", methods=["POST"])
+@validate_login_token(pass_user=True)
+def add_comment(user):
+    req = request.get_json()
+    page_id = req.get("page_id")
+    text = req.get("text")
+    try:
+        page = db.VizData.objects.with_id(page_id)
+        new_comment = db.Comment(commenter_id = user.id, comment_text=text, page = page)
+        new_comment.save()
+        return jsonify({
+            "status":200,
+            "message":"comment added successfully"
+        })
+    except Exception as e:
+        return jsonify({
+            "status":500,
+            "message":str(e)
+        })
+
+@comment_route.route("/api/comment/add-reply", methods=["POST"])
+@validate_login_token(min_access_level=Roles.ADMIN, pass_user=True)
+def add_reply(user):
+    req = request.get_json()
+    comment_id = req.get("comment_id")
+    reply_text = req.get("text")
+
+    comment = db.Comment.objects.with_id(comment_id)
+    if comment.page not in user.page_list:
+        return jsonify({
+            "status":401,
+            "message":"Unauthorized reply"
+        })
+    comment.update(reply=db.Reply(replier_id = user.id, reply_text=reply_text))
+    return jsonify({
+        "status":200,
+        "message":"Reply added successfully"
+    })
\ No newline at end of file
diff --git a/modules/login.py b/modules/login.py
index 05b14c24e54f26389b6203a274de7e161a73a513..221a76778fa8dccf344ec6aa8d0368251eb83107 100644
--- a/modules/login.py
+++ b/modules/login.py
@@ -61,8 +61,22 @@ def check_user_existence():
 @login_route.route("/api/get-user", methods=["POST"])
 @validate_login_token(pass_user=True)
 def get_user_from_token(user):
+    del user.password
     return jsonify({
         "status": 200,
+        "data": user #sends back all information about user except password
+    })
+    
+@login_route.route("/api/get-user-public", methods=["POST"])
+def get_user_from_id():
+    req = request.get_json()
+    user_id = req.get("user_id")
+    user = db.User.objecs.with_id(user_id)
+    del user.password
+    del user.username
+    del user.page_list
+    del user.role
+    return jsonify({
+        "status":200,
         "data": user
     })
-    
\ No newline at end of file
diff --git a/modules/page.py b/modules/page.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ca7092fbf73b7eb18737edc7c4d4704bd907f079 100644
--- a/modules/page.py
+++ b/modules/page.py
@@ -0,0 +1,62 @@
+import json
+import jwt
+import datetime
+from flask import Blueprint, jsonify, request, current_app
+from database import database as db
+from modules.tools.token import Token, validate_login_token
+from modules.tools.roles import Roles
+
+page_route = Blueprint('page', __name__, template_folder="templates")
+
+@page_route.route("/api/page/get-top", methods=["POST"])
+def get_top_page():
+    year = request.get_json().get("year")
+    try:
+        vdata = db.VizData.objects.get(level = 0, year = year)
+        return jsonify({
+            "status":200,
+            "data": vdata,
+            "subdata": [child for child in vdata.subdata]
+        })
+    except Exception as e:
+        return jsonify({
+            "status": 500,
+            "message": str(e)
+        })
+
+@page_route.route("/api/page/get", methods=["POST"])
+def get_page():
+    data_id = request.get_json().get("page_id")
+    try:
+        vdata = db.VizData.objects.with_id(data_id)
+        if vdata is not None:
+            return jsonify({
+                "status":200,
+                "data":vdata,
+                "subdata":[child for child in vdata.subdata]
+            })
+        else:
+            return jsonify({
+                "status":404,
+                "message":"page not found"
+            })
+    except Exception as e:
+        return jsonify({
+            "status": 500,
+            "message": str(e)
+        })
+
+
+@page_route.route("/api/hidden/add-data", methods=["POST"])
+def add_page():
+    data = request.get_json()
+    name = data.get("name")
+    value = data.get("value")
+    level = data.get("level")
+    year = data.get("year")
+
+    db.VizData(name=name, value=value, level=level, year=year).save()
+    return jsonify({
+        "status":200,
+        "message":"data added, but this endpoint is only for testing"
+    })
diff --git a/modules/register.py b/modules/register.py
index 7f4bdfe6191b5cfe50593019b7cf6636c109a3e7..aa30c164daa15dc962d73e93db850497d21f3631 100644
--- a/modules/register.py
+++ b/modules/register.py
@@ -1,6 +1,7 @@
 from flask import Blueprint, jsonify, request, current_app
 from database import database as db
-from modules.tools.token import Token
+from modules.tools.token import Token, validate_login_token
+from modules.tools.roles import Roles
 
 register_route = Blueprint('register', __name__, template_folder="templates")
 
@@ -33,20 +34,20 @@ def add_new_user():
 
 
 @register_route.route('/api/unregister', methods=["POST"])
-def delete_user():
+@validate_login_token(pass_user=True)
+def delete_user(user):
     try:
-        token = request.headers.get("Authorization")
-        password = request.get_json().get("password")
-        if token is not None:
-            code, user_id = Token.decode_token(token) 
-            if code > 0:
-                raise Exception(user_id)
+        user_id = request.get_json().get("user_id")
+        if user_id is not None:
+            del_user = db.User.objects.with_id(user_id)
+            if del_user != user and user.role < Roles.ADMIN:
+                return jsonify({
+                    "status":401,
+                    "message":"unauthorized delete"
+                })
         else:
-            user_id = request.get_json().get("user_id")
-            if user_id is None:
-                raise Exception("Invalid credentials")
-        check = db.User.objects.with_id(user_id)
-        check.delete()
+            del_user = user
+        del_user.delete()
         return jsonify({
             "status": 200,
             "message": "User deleted successfully"
diff --git a/readme.md b/readme.md
index 17759fbc793e871dd1bc7760c08aa2c42fde3b26..f9e8344e0623898ab83b11aebe0ed0a4e65400e1 100644
--- a/readme.md
+++ b/readme.md
@@ -10,4 +10,100 @@ Server ini akan menyediakan api yang menangani akun-akun pengguna dan pemrosesan
 pip install flask
 pip install flask_mongoengine
 pip install PyJWT
-```
\ No newline at end of file
+```
+
+## API Endpoints
+
+Berikut adalah API endpoints dari backend server VIS-MASY:
+
+### Login dan Register
+
+* #### /api/login
+    Method: POST  
+    Data request: username, password  
+    Response: status, token  
+    Melakukan login dan mengirim balik token login
+
+* #### /api/check-user
+    Method: POST  
+    Data request: username  
+    Response: status, message, exist  
+    Mengecek apakah suatu username sudah terdaftar
+
+* #### /api/get-user
+    Method: POST  
+    Data request: Authorization header  
+    Response: status, data 
+    Mengirim data user lengkap berdasarkan authorization token
+
+* #### /api/get-user-public
+    Method: POST  
+    Data request: user_id  
+    Response: status, data  
+    Mengirim data user yang bersifat publik
+
+* #### /api/register
+    Method: POST  
+    Data request: user_id, username, name, password, role  
+    Response: status, message  
+    Menambah user ke database pengguna
+
+* #### /api/unregister
+    Method: POST  
+    Data request: Authorization header \[, user_id] 
+    Response: status, message  
+    Menghapus pengguna dengan user_id jika authorization header untuk admin, atau menghapus pengguna dalam authorization header jika user_id tidak diberikan.
+
+### Page
+
+* #### /api/page/get-top
+    Method: POST  
+    Data request: year  
+    Response: status, data, subdata  
+    Mengirim data untuk halaman data paling atas dan subdata yang akan menjadi visualisasi
+
+* #### /api/page/get
+    Method: POST  
+    Data request: page_id
+    Response: status, data, subdata
+    Mengirim data yang akan menjadi halaman dan subdata yang akan menjadi visualisasi
+
+### Comment and Reply
+
+* #### /api/comment/get
+    Method: POST  
+    Data req: page_id  
+    Response: status, data  
+    Mengirim list comment dan reply-nya (jika ada) pada sebuah page dengan terurut waktu (yang terbaru paling awal)
+
+* #### /api/comment/get-unreplied
+    Method: POST  
+    Data req: page_id  
+    Response: status, data  
+    Mengirim list comment yang belum direply pada page dengan terurut waktu (yang terbaru paling awal)
+
+* #### /api/comment/add
+    Method: POST  
+    Data req: Authorization header, page_id, text  
+    Response: status, message  
+    Menambahkan sebuah comment dari user yang sesuai authorization pada sebuah page
+
+* #### /api/comment/add-reply
+    Method: POST  
+    Data req: Authorization header, comment_id, text  
+    Response: status, message  
+    Menambahkan sebuah reply pada sebuah comment jika comment tersebut dalam wewenang user pada authorization
+
+### Administration
+
+* #### /api/admin/add-page
+    Method: POST  
+    Data req: Authorization header, admin_id, page_id  
+    Response: status, message  
+    Menambah page yang diadministrasi seorang admin jika authorization level SUPERADMIN
+
+* #### /api/admin/remove-page
+    Method: POST  
+    Data req: Authorization header, admin_id, page_id  
+    Response: status, message  
+    Mengurangi page yang diadministrasi seorang admin jika authorization level SUPERADMIN
\ No newline at end of file