diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..cedc68dea4664a15d54e338f245710f4c545f98d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,22 @@
+# Use the official Python image
+FROM python:3.9-slimcd
+
+# Set the working directory
+WORKDIR /code
+
+# Install system dependencies required for mysqlclient
+RUN apt-get update && apt-get install -y \
+    gcc \
+    libmariadb-dev \
+    pkg-config \
+    && rm -rf /var/lib/apt/lists/*
+
+# Copy and install dependencies
+COPY requirements.txt /code/
+RUN pip install --upgrade pip && pip install -r requirements.txt
+
+# Copy the project files
+COPY . /code/
+
+# Command to run the application
+CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
diff --git a/Pipfile b/Pipfile
new file mode 100644
index 0000000000000000000000000000000000000000..aee73115063575b38e6c35eae746ea9f80981029
--- /dev/null
+++ b/Pipfile
@@ -0,0 +1,16 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+django = ">=4.0"
+mysqlclient = "*"
+djangorestframework = "*"
+pymysql = "*"
+cryptography = "*"
+
+[dev-packages]
+
+[requires]
+python_version = "3.13"
diff --git a/Pipfile.lock b/Pipfile.lock
new file mode 100644
index 0000000000000000000000000000000000000000..5ac1f0fc67255d64a907b4fb1e750145f4f83e9a
--- /dev/null
+++ b/Pipfile.lock
@@ -0,0 +1,210 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "2945d5ab87cd0426818793fb4ba82a8e6f0ecac5546e04c1fbb52e092c8cea36"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3.13"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "asgiref": {
+            "hashes": [
+                "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47",
+                "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==3.8.1"
+        },
+        "cffi": {
+            "hashes": [
+                "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8",
+                "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2",
+                "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1",
+                "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15",
+                "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36",
+                "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824",
+                "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8",
+                "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36",
+                "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17",
+                "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf",
+                "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc",
+                "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3",
+                "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed",
+                "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702",
+                "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1",
+                "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8",
+                "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903",
+                "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6",
+                "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d",
+                "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b",
+                "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e",
+                "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be",
+                "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c",
+                "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683",
+                "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9",
+                "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c",
+                "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8",
+                "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1",
+                "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4",
+                "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655",
+                "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67",
+                "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595",
+                "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0",
+                "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65",
+                "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41",
+                "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6",
+                "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401",
+                "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6",
+                "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3",
+                "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16",
+                "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93",
+                "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e",
+                "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4",
+                "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964",
+                "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c",
+                "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576",
+                "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0",
+                "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3",
+                "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662",
+                "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3",
+                "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff",
+                "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5",
+                "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd",
+                "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f",
+                "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5",
+                "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14",
+                "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d",
+                "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9",
+                "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7",
+                "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382",
+                "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a",
+                "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e",
+                "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a",
+                "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4",
+                "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99",
+                "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87",
+                "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==1.17.1"
+        },
+        "cryptography": {
+            "hashes": [
+                "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390",
+                "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41",
+                "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688",
+                "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5",
+                "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1",
+                "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d",
+                "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7",
+                "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843",
+                "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5",
+                "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c",
+                "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a",
+                "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79",
+                "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6",
+                "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181",
+                "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4",
+                "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5",
+                "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562",
+                "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639",
+                "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922",
+                "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3",
+                "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d",
+                "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471",
+                "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd",
+                "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa",
+                "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb",
+                "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699",
+                "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb",
+                "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa",
+                "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0",
+                "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23",
+                "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9",
+                "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615",
+                "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea",
+                "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7",
+                "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'",
+            "version": "==44.0.2"
+        },
+        "django": {
+            "hashes": [
+                "sha256:1323617cb624add820cb9611cdcc788312d250824f92ca6048fda8625514af2b",
+                "sha256:30de4ee43a98e5d3da36a9002f287ff400b43ca51791920bfb35f6917bfe041c"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.10'",
+            "version": "==5.1.7"
+        },
+        "djangorestframework": {
+            "hashes": [
+                "sha256:bea7e9f6b96a8584c5224bfb2e4348dfb3f8b5e34edbecb98da258e892089361",
+                "sha256:f022ff46613584de994c0c6a4aebbace5fd700555fbe9d33b865ebf173eba6c9"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.9'",
+            "version": "==3.16.0"
+        },
+        "mysqlclient": {
+            "hashes": [
+                "sha256:199dab53a224357dd0cb4d78ca0e54018f9cee9bf9ec68d72db50e0a23569076",
+                "sha256:201a6faa301011dd07bca6b651fe5aaa546d7c9a5426835a06c3172e1056a3c5",
+                "sha256:24ae22b59416d5fcce7e99c9d37548350b4565baac82f95e149cac6ce4163845",
+                "sha256:2e3c11f7625029d7276ca506f8960a7fd3c5a0a0122c9e7404e6a8fe961b3d22",
+                "sha256:4b4c0200890837fc64014cc938ef2273252ab544c1b12a6c1d674c23943f3f2e",
+                "sha256:92af368ed9c9144737af569c86d3b6c74a012a6f6b792eb868384787b52bb585",
+                "sha256:977e35244fe6ef44124e9a1c2d1554728a7b76695598e4b92b37dc2130503069",
+                "sha256:a22d99d26baf4af68ebef430e3131bb5a9b722b79a9fcfac6d9bbf8a88800687"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.8'",
+            "version": "==2.2.7"
+        },
+        "pycparser": {
+            "hashes": [
+                "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6",
+                "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2.22"
+        },
+        "pymysql": {
+            "hashes": [
+                "sha256:4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c",
+                "sha256:e127611aaf2b417403c60bf4dc570124aeb4a57f5f37b8e95ae399a42f904cd0"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.7'",
+            "version": "==1.1.1"
+        },
+        "sqlparse": {
+            "hashes": [
+                "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272",
+                "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==0.5.3"
+        },
+        "tzdata": {
+            "hashes": [
+                "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8",
+                "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"
+            ],
+            "markers": "python_version >= '2'",
+            "version": "==2025.2"
+        }
+    },
+    "develop": {}
+}
diff --git a/README.md b/README.md
index a4a019c63d08f68fbacced9f1d9b156f523c1d30..fef23e329fd0ad41f4e961ba1ddfa3c83c641016 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Uni Hub - DSD Project
+# GROUP_PROJECT_UWE
 
 
 
@@ -11,18 +11,18 @@ Already a pro? Just edit this README.md and make it your own. Want to make it ea
 ## Add your files
 
 - [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
-- [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command:
+- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
 
 ```
 cd existing_repo
-git remote add origin https://gitlab.uwe.ac.uk/y2-youssef/uni-hub-dsd-project.git
+git remote add origin https://gitlab.uwe.ac.uk/m2-sefari/group_project_uwe.git
 git branch -M main
 git push -uf origin main
 ```
 
 ## Integrate with your tools
 
-- [ ] [Set up project integrations](https://gitlab.uwe.ac.uk/y2-youssef/uni-hub-dsd-project/-/settings/integrations)
+- [ ] [Set up project integrations](https://gitlab.uwe.ac.uk/m2-sefari/group_project_uwe/-/settings/integrations)
 
 ## Collaborate with your team
 
@@ -30,7 +30,7 @@ git push -uf origin main
 - [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
 - [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
 - [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
-- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
+- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
 
 ## Test and Deploy
 
diff --git a/accounts/__init__.py b/accounts/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/accounts/__pycache__/__init__.cpython-313.pyc b/accounts/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..63ab691557bfd2616aeb18a6be3cf1feab5f7234
Binary files /dev/null and b/accounts/__pycache__/__init__.cpython-313.pyc differ
diff --git a/accounts/__pycache__/__init__.cpython-39.pyc b/accounts/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0bc38790f85d990d9ad61ddc79c2ee330f977ba1
Binary files /dev/null and b/accounts/__pycache__/__init__.cpython-39.pyc differ
diff --git a/accounts/__pycache__/admin.cpython-313.pyc b/accounts/__pycache__/admin.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..81ef455e5599562790f2d46bee1fa32b66089b14
Binary files /dev/null and b/accounts/__pycache__/admin.cpython-313.pyc differ
diff --git a/accounts/__pycache__/admin.cpython-39.pyc b/accounts/__pycache__/admin.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f588d68e1308cf3485b01f620556527c1fc08e69
Binary files /dev/null and b/accounts/__pycache__/admin.cpython-39.pyc differ
diff --git a/accounts/__pycache__/apps.cpython-313.pyc b/accounts/__pycache__/apps.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c738dfa96d77fa16bb801c08988f041f288b900d
Binary files /dev/null and b/accounts/__pycache__/apps.cpython-313.pyc differ
diff --git a/accounts/__pycache__/apps.cpython-39.pyc b/accounts/__pycache__/apps.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d1fed5bf79691aeedf50c4e89bdb54f0097d347e
Binary files /dev/null and b/accounts/__pycache__/apps.cpython-39.pyc differ
diff --git a/accounts/__pycache__/auth_forms.cpython-39.pyc b/accounts/__pycache__/auth_forms.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bab1fa326ecd5cb46eb917ffeaf73d9c11a7edb7
Binary files /dev/null and b/accounts/__pycache__/auth_forms.cpython-39.pyc differ
diff --git a/accounts/__pycache__/forms.cpython-313.pyc b/accounts/__pycache__/forms.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..24d3ee5ecbd76875656389e502afb456b82b9170
Binary files /dev/null and b/accounts/__pycache__/forms.cpython-313.pyc differ
diff --git a/accounts/__pycache__/forms.cpython-39.pyc b/accounts/__pycache__/forms.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8842586f3b933eb434500ad686c325b13c977a36
Binary files /dev/null and b/accounts/__pycache__/forms.cpython-39.pyc differ
diff --git a/accounts/__pycache__/models.cpython-313.pyc b/accounts/__pycache__/models.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ba8f239623aa2c93a88e0d9e92951fd5d256a5e9
Binary files /dev/null and b/accounts/__pycache__/models.cpython-313.pyc differ
diff --git a/accounts/__pycache__/models.cpython-39.pyc b/accounts/__pycache__/models.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..06b64117f518bc5c816e0a6d6b766ae4ae82c94d
Binary files /dev/null and b/accounts/__pycache__/models.cpython-39.pyc differ
diff --git a/accounts/__pycache__/urls.cpython-313.pyc b/accounts/__pycache__/urls.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f4dc712c771852614779519229b64f286d80a267
Binary files /dev/null and b/accounts/__pycache__/urls.cpython-313.pyc differ
diff --git a/accounts/__pycache__/urls.cpython-39.pyc b/accounts/__pycache__/urls.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a26d0697866c0255bed01d4e1c00de3c3e9f0057
Binary files /dev/null and b/accounts/__pycache__/urls.cpython-39.pyc differ
diff --git a/accounts/__pycache__/views.cpython-313.pyc b/accounts/__pycache__/views.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..490bec89c11f8102d00fdb854915497507a1cd68
Binary files /dev/null and b/accounts/__pycache__/views.cpython-313.pyc differ
diff --git a/accounts/__pycache__/views.cpython-39.pyc b/accounts/__pycache__/views.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..da3d75a994d4308aaad2c1e9133b117843171491
Binary files /dev/null and b/accounts/__pycache__/views.cpython-39.pyc differ
diff --git a/accounts/admin.py b/accounts/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/accounts/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/accounts/apps.py b/accounts/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e3c76595bcab116bb99a1722e542e07cdd23c71
--- /dev/null
+++ b/accounts/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AccountsConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'accounts'
diff --git a/accounts/decorators.py b/accounts/decorators.py
new file mode 100644
index 0000000000000000000000000000000000000000..1b3043957d14e724beb2519671e40e3f61d0d7cc
--- /dev/null
+++ b/accounts/decorators.py
@@ -0,0 +1,11 @@
+from django.core.exceptions import PermissionDenied
+
+def role_required(allowed_roles):
+    """ Restrict access to views based on user roles. """
+    def decorator(view_func):
+        def wrapper(request, *args, **kwargs):
+            if not request.user.is_authenticated or request.user.role not in allowed_roles:
+                raise PermissionDenied  # 403 Forbidden
+            return view_func(request, *args, **kwargs)
+        return wrapper
+    return decorator
diff --git a/accounts/forms.py b/accounts/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..637109d3e108babae52a3fcddde5bc8c80fb014b
--- /dev/null
+++ b/accounts/forms.py
@@ -0,0 +1,18 @@
+# accounts/forms.py
+from django import forms
+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth.models import User
+from django.contrib.auth import get_user_model  
+
+User = get_user_model()  
+
+class SignUpForm(UserCreationForm):
+    class Meta:
+        model = User  
+        fields = ["username", "email", "password1", "password2"]
+
+
+
+# forms.py
+
+
diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..34b418a68f21690bec35f9a0af54ed05aa8a767f
--- /dev/null
+++ b/accounts/migrations/0001_initial.py
@@ -0,0 +1,45 @@
+# Generated by Django 4.2.19 on 2025-03-06 22:56
+
+import django.contrib.auth.models
+import django.contrib.auth.validators
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('auth', '0012_alter_user_first_name_max_length'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='User',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('password', models.CharField(max_length=128, verbose_name='password')),
+                ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+                ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+                ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
+                ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
+                ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
+                ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
+                ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+                ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+                ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+                ('role', models.CharField(choices=[('student', 'Student'), ('community_leader', 'Community Leader'), ('admin', 'Admin')], default='student', max_length=20)),
+                ('groups', models.ManyToManyField(blank=True, related_name='custom_user_groups', to='auth.group')),
+                ('user_permissions', models.ManyToManyField(blank=True, related_name='custom_user_permissions', to='auth.permission')),
+            ],
+            options={
+                'verbose_name': 'user',
+                'verbose_name_plural': 'users',
+                'abstract': False,
+            },
+            managers=[
+                ('objects', django.contrib.auth.models.UserManager()),
+            ],
+        ),
+    ]
diff --git a/accounts/migrations/__init__.py b/accounts/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/accounts/migrations/__pycache__/0001_initial.cpython-39.pyc b/accounts/migrations/__pycache__/0001_initial.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..41c6efb56fee2663616aff7ded2853aac90f243d
Binary files /dev/null and b/accounts/migrations/__pycache__/0001_initial.cpython-39.pyc differ
diff --git a/accounts/migrations/__pycache__/__init__.cpython-39.pyc b/accounts/migrations/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ef155c26c26564f4d41fbb44fd05016f668ac3cf
Binary files /dev/null and b/accounts/migrations/__pycache__/__init__.cpython-39.pyc differ
diff --git a/accounts/models.py b/accounts/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..78c42db8500c0c074a16c13ea034354b55656dab
--- /dev/null
+++ b/accounts/models.py
@@ -0,0 +1,31 @@
+from django.contrib.auth.models import AbstractUser
+from django.db import models
+
+class User(AbstractUser):
+    STUDENT = 'student'
+    COMMUNITY_LEADER = 'community_leader'
+    ADMIN = 'admin'
+
+    ROLE_CHOICES = [
+        (STUDENT, 'Student'),
+        (COMMUNITY_LEADER, 'Community Leader'),
+        (ADMIN, 'Admin'),
+    ]
+
+    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default=STUDENT)
+
+    # Fix for SystemCheckError: Add `related_name` to prevent clashes with auth.User
+    groups = models.ManyToManyField(
+        "auth.Group",
+        related_name="custom_user_groups",
+        blank=True
+    )
+    user_permissions = models.ManyToManyField(
+        "auth.Permission",
+        related_name="custom_user_permissions",
+        blank=True
+    )
+
+
+
+# Create your models here.
diff --git a/accounts/templates/accounts/login.html b/accounts/templates/accounts/login.html
new file mode 100644
index 0000000000000000000000000000000000000000..96f3d182847ec172f2a6abfecbad34734ea16f4a
--- /dev/null
+++ b/accounts/templates/accounts/login.html
@@ -0,0 +1,16 @@
+<!-- templates/accounts/signup.html -->
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Login</title>
+</head>
+<body>
+    <h2>Login</h2>
+    <form method="post">
+        {% csrf_token %}
+        {{ form.as_p }}
+        <button type="submit">Login</button>
+    </form>
+    <p>Don't have an account? <a href="{% url 'signup' %}">Register here</a>.</p>
+</body>
+</html>
diff --git a/accounts/templates/accounts/signup.html b/accounts/templates/accounts/signup.html
new file mode 100644
index 0000000000000000000000000000000000000000..d0f7a9c4592e6dc0caad09cf73ea7faf47b873a8
--- /dev/null
+++ b/accounts/templates/accounts/signup.html
@@ -0,0 +1,16 @@
+<!-- templates/accounts/login.html -->
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Sign Up</title>
+</head>
+<body>
+    <h2>Sign Up</h2>
+    <form method="post">
+        {% csrf_token %}
+        {{ form.as_p }}
+        <button type="submit">Sign Up</button>
+    </form>
+    <p>Already have an account?<a href="{% url 'login' %}">Login here</a>.</p>
+</body>
+</html>
diff --git a/accounts/tests.py b/accounts/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/accounts/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/accounts/urls.py b/accounts/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..301858ab4f0d34be91e8e2a081478bd46317acf6
--- /dev/null
+++ b/accounts/urls.py
@@ -0,0 +1,10 @@
+# accounts/urls.py
+from django.urls import path
+from .views import signup_view, login_view
+from django.contrib.auth.views import LogoutView
+
+urlpatterns = [
+    path("signup/", signup_view, name="signup"),
+    path("login/", login_view, name="login"),
+    path("logout/", LogoutView.as_view(next_page="login"), name="logout"),
+]
diff --git a/accounts/views.py b/accounts/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..3680ccd568b644643fb3b3b54ac970f6121db187
--- /dev/null
+++ b/accounts/views.py
@@ -0,0 +1,32 @@
+from django.shortcuts import render
+# accounts/views.py
+from django.shortcuts import render, redirect
+from django.contrib.auth import login, authenticate
+from django.contrib.auth.forms import AuthenticationForm
+
+from .forms import SignUpForm
+
+def signup_view(request):
+    if request.method == "POST":
+        form = SignUpForm(request.POST)
+        if form.is_valid():
+            user = form.save()
+            login(request, user)  # Automatically log in the user after signup
+            return redirect("home")  # Redirect to homepage after signup
+    else:
+        form = SignUpForm()
+    return render(request, "accounts/signup.html", {"form": form})
+
+def login_view(request):
+    if request.method == "POST":
+        form = AuthenticationForm(request, data=request.POST)
+        if form.is_valid():
+            user = form.get_user()
+            login(request, user)
+            return redirect("home")  # Redirect to homepage after login
+    else:
+        form = AuthenticationForm()
+    return render(request, "accounts/login.html", {"form": form})
+
+
+# Create your views here.
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..294c75f41fc03bb5aea78f6f0124b55780d62571
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,27 @@
+
+services:
+  web:
+    build: .
+    command: python manage.py runserver 0.0.0.0:8000
+    volumes:
+      - .:/code
+    ports:
+      - "8000:8000"
+    depends_on:
+      - db
+
+  db:
+    image: mysql:8.0
+    restart: always
+    environment:
+      MYSQL_DATABASE: unihub_db
+      MYSQL_USER: unihub_user
+      MYSQL_PASSWORD: Thescotts111
+      MYSQL_ROOT_PASSWORD: Constantine.25
+    ports:
+      - "3307:3306"
+    volumes:
+      - db_data:/var/lib/mysql
+
+volumes:
+  db_data:
diff --git a/events/__init__.py b/events/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/events/__pycache__/__init__.cpython-313.pyc b/events/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..81fd327f1a1854dd82d2e08cec1ea1d8efa9c99b
Binary files /dev/null and b/events/__pycache__/__init__.cpython-313.pyc differ
diff --git a/events/__pycache__/__init__.cpython-39.pyc b/events/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..07c93c299966525bb0dc622df306925289af718a
Binary files /dev/null and b/events/__pycache__/__init__.cpython-39.pyc differ
diff --git a/events/__pycache__/admin.cpython-313.pyc b/events/__pycache__/admin.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..85bc0c386dbe0456b22170ca5b7fa2e5481a1ed3
Binary files /dev/null and b/events/__pycache__/admin.cpython-313.pyc differ
diff --git a/events/__pycache__/admin.cpython-39.pyc b/events/__pycache__/admin.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7c49eeed3100ad2cdafa4c41ca39dbccdb6af90a
Binary files /dev/null and b/events/__pycache__/admin.cpython-39.pyc differ
diff --git a/events/__pycache__/apps.cpython-313.pyc b/events/__pycache__/apps.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2f869b4099b269e211c70696a8cff4d216864919
Binary files /dev/null and b/events/__pycache__/apps.cpython-313.pyc differ
diff --git a/events/__pycache__/apps.cpython-39.pyc b/events/__pycache__/apps.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..37181a8abb832d49b5a6c91ac678d152b2f0b3f3
Binary files /dev/null and b/events/__pycache__/apps.cpython-39.pyc differ
diff --git a/events/__pycache__/forms.cpython-313.pyc b/events/__pycache__/forms.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..edcd646bdc553765cd6c930a26c2cc72dc1d859b
Binary files /dev/null and b/events/__pycache__/forms.cpython-313.pyc differ
diff --git a/events/__pycache__/forms.cpython-39.pyc b/events/__pycache__/forms.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9aabdf07b080c83280a5d08b175275127a7f4139
Binary files /dev/null and b/events/__pycache__/forms.cpython-39.pyc differ
diff --git a/events/__pycache__/models.cpython-313.pyc b/events/__pycache__/models.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1bf1f0ac9993b8700854969bde01d7e201101eed
Binary files /dev/null and b/events/__pycache__/models.cpython-313.pyc differ
diff --git a/events/__pycache__/models.cpython-39.pyc b/events/__pycache__/models.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dd7106e098e800bd3a6e197810a8db1f7ca78aba
Binary files /dev/null and b/events/__pycache__/models.cpython-39.pyc differ
diff --git a/events/__pycache__/urls.cpython-313.pyc b/events/__pycache__/urls.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6e92f1c16f9a755e6408ae0499c87a268fe41634
Binary files /dev/null and b/events/__pycache__/urls.cpython-313.pyc differ
diff --git a/events/__pycache__/urls.cpython-39.pyc b/events/__pycache__/urls.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ee5c8912770e457abb17b6d4f2f1e379b14f02e8
Binary files /dev/null and b/events/__pycache__/urls.cpython-39.pyc differ
diff --git a/events/__pycache__/views.cpython-313.pyc b/events/__pycache__/views.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0637b9595f1cf1bfd3006bdac8d8f2c183d68728
Binary files /dev/null and b/events/__pycache__/views.cpython-313.pyc differ
diff --git a/events/__pycache__/views.cpython-39.pyc b/events/__pycache__/views.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a3d48a69ccce03e41d2399db0a1989976706d79e
Binary files /dev/null and b/events/__pycache__/views.cpython-39.pyc differ
diff --git a/events/admin.py b/events/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/events/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/events/apps.py b/events/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..20f48f26beb374dce75650546404b1c5a26bb006
--- /dev/null
+++ b/events/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class EventsConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'events'
diff --git a/events/forms.py b/events/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8efb620627471913da11d7cf581d8881638c2f4
--- /dev/null
+++ b/events/forms.py
@@ -0,0 +1,7 @@
+from django import forms
+from .models import Event
+
+class EventForm(forms.ModelForm):
+    class Meta:
+        model = Event
+        fields = ["title", "description", "date", "time", "location"]
diff --git a/events/migrations/0001_initial.py b/events/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..d3ece7df837c0f5cbbbdd2468666e34756c286b1
--- /dev/null
+++ b/events/migrations/0001_initial.py
@@ -0,0 +1,30 @@
+# Generated by Django 4.2.20 on 2025-03-11 22:38
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Event',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('title', models.CharField(max_length=255)),
+                ('description', models.TextField()),
+                ('date', models.DateField()),
+                ('time', models.TimeField()),
+                ('location', models.CharField(max_length=255)),
+                ('created_at', models.DateTimeField(auto_now_add=True)),
+                ('organizer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organized_events', to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]
diff --git a/events/migrations/__init__.py b/events/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/events/migrations/__pycache__/0001_initial.cpython-39.pyc b/events/migrations/__pycache__/0001_initial.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9ff70ed178a0d1e18a7bf8a70edba9b2845be094
Binary files /dev/null and b/events/migrations/__pycache__/0001_initial.cpython-39.pyc differ
diff --git a/events/migrations/__pycache__/__init__.cpython-39.pyc b/events/migrations/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..37c89e2a65040891a4a594bcbedc537cf624664d
Binary files /dev/null and b/events/migrations/__pycache__/__init__.cpython-39.pyc differ
diff --git a/events/models.py b/events/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..5913ad1f9e8eaabc96cd60df3b7f326b75718d9b
--- /dev/null
+++ b/events/models.py
@@ -0,0 +1,18 @@
+from django.db import models
+from django.conf import settings
+
+class Event(models.Model):
+    title = models.CharField(max_length=255)
+    description = models.TextField()
+    date = models.DateField()
+    time = models.TimeField()
+    location = models.CharField(max_length=255)
+    organizer = models.ForeignKey(
+        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="organized_events"
+    )
+    created_at = models.DateTimeField(auto_now_add=True)
+
+    def __str__(self):
+        return self.title
+
+# Create your models here.
diff --git a/events/templates/events/event_detail.html b/events/templates/events/event_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..d11f455f476c6d7aefba22f46959f059464e81fc
--- /dev/null
+++ b/events/templates/events/event_detail.html
@@ -0,0 +1,7 @@
+{% extends "base.html" %}
+{% block content %}
+<h2>{{ event.title }}</h2>
+<p><strong>Date:</strong> {{ event.date }} at {{ event.time }}</p>
+<p><strong>Location:</strong> {{ event.location }}</p>
+<p>{{ event.description }}</p>
+{% endblock %}
diff --git a/events/templates/events/event_form.html b/events/templates/events/event_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..cc7b8c92c4e1357b8f75c76d3cdb6cbe10bab867
--- /dev/null
+++ b/events/templates/events/event_form.html
@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+{% block content %}
+<h2>Create an Event</h2>
+<form method="POST">
+    {% csrf_token %}
+    {{ form.as_p }}
+    <button type="submit">Save Event</button>
+</form>
+{% endblock %}
diff --git a/events/templates/events/event_list.html b/events/templates/events/event_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..509e014b0bf365c47a69b6a8db83236508dd3699
--- /dev/null
+++ b/events/templates/events/event_list.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+
+{% block content %}
+    <h2>Upcoming Events</h2>
+    <ul>
+        {% for event in events %}
+            <li><a href="{% url 'event_detail' event.id %}">{{ event.title }}</a> - {{ event.date }}</li>
+        {% empty %}
+            <li>No events available.</li>
+        {% endfor %}
+    </ul>
+    
+    {% if user.is_authenticated and user.role == "community_leader" %}
+        <a href="{% url 'create_event' %}">Create Event</a>
+    {% endif %}
+{% endblock %}
diff --git a/events/templates/home.html b/events/templates/home.html
new file mode 100644
index 0000000000000000000000000000000000000000..8e6f219d95494fd1c3769c8ffcd05768d33c633a
--- /dev/null
+++ b/events/templates/home.html
@@ -0,0 +1,2 @@
+<h1>Welcome to Uni Hub</h1>
+<p>Go to <a href="/events/">Events</a></p>
diff --git a/events/tests.py b/events/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/events/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/events/urls.py b/events/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..7377619cf33ab7785872f2610819dd1cd19dedad
--- /dev/null
+++ b/events/urls.py
@@ -0,0 +1,11 @@
+from django.urls import path
+from .views import event_list, event_detail, create_event
+
+
+urlpatterns = [
+    path("", event_list, name="event_list"),  # Show all events
+    path("<int:event_id>/", event_detail, name="event_detail"),  # View event details
+    path("create/", create_event, name="create_event"),  # Create an event
+]
+
+
diff --git a/events/views.py b/events/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..eacb72c94b6ceec0a62f61f9a56710e0270b33e6
--- /dev/null
+++ b/events/views.py
@@ -0,0 +1,32 @@
+from django.shortcuts import render, get_object_or_404, redirect
+from django.contrib.auth.decorators import login_required
+from .models import Event
+from .forms import EventForm
+
+# ✅ View All Events (Homepage)
+def event_list(request):
+    events = Event.objects.all().order_by('date')
+    return render(request, "events/event_list.html", {"events": events})
+
+# ✅ View a Single Event
+def event_detail(request, event_id):
+    event = get_object_or_404(Event, id=event_id)
+    return render(request, "events/event_detail.html", {"event": event})
+
+# ✅ Create an Event (Only for Community Leaders)
+@login_required
+def create_event(request):
+    if request.user.role != "community_leader":  # Restrict access
+        return redirect("event_list")  # Redirect unauthorized users
+    
+    if request.method == "POST":
+        form = EventForm(request.POST)
+        if form.is_valid():
+            event = form.save(commit=False)
+            event.organizer = request.user  # Set the event creator
+            event.save()
+            return redirect("event_list")
+    else:
+        form = EventForm()
+    
+    return render(request, "events/event_form.html", {"form": form})
diff --git a/manage.py b/manage.py
new file mode 100644
index 0000000000000000000000000000000000000000..497afbc36b6be7facc3b6a6420b630390b413385
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import os
+import sys
+
+def main():
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'unihub_project.settings')
+
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError:
+        try:
+            import django
+        except ImportError:
+            raise ImportError(
+                "Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable?"
+            )
+        raise
+
+    execute_from_command_line(sys.argv)
+
+if __name__ == '__main__':
+    main()
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fabc354a21ad8c3f7aab29d4488cc238e67e6d58
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+Django>=4.0
+mysqlclient
+djangorestframework
+pymysql
+cryptography
diff --git a/unihub_project/__init__.py b/unihub_project/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/unihub_project/__pycache__/__init__.cpython-313.pyc b/unihub_project/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..77b1621ecfe7f0844cf92f21e92efc123645fae2
Binary files /dev/null and b/unihub_project/__pycache__/__init__.cpython-313.pyc differ
diff --git a/unihub_project/__pycache__/__init__.cpython-39.pyc b/unihub_project/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0c893463e52528bb5219b3f6587d4cf85c5371ff
Binary files /dev/null and b/unihub_project/__pycache__/__init__.cpython-39.pyc differ
diff --git a/unihub_project/__pycache__/settings.cpython-313.pyc b/unihub_project/__pycache__/settings.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cb8c527d375feb8531c6c77abea1dd56c24c28fa
Binary files /dev/null and b/unihub_project/__pycache__/settings.cpython-313.pyc differ
diff --git a/unihub_project/__pycache__/settings.cpython-39.pyc b/unihub_project/__pycache__/settings.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..92d747bfaf1605954944f125db7e4cd20b58e124
Binary files /dev/null and b/unihub_project/__pycache__/settings.cpython-39.pyc differ
diff --git a/unihub_project/__pycache__/urls.cpython-313.pyc b/unihub_project/__pycache__/urls.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c725bca990714f571f369a13026b258e0f8067c8
Binary files /dev/null and b/unihub_project/__pycache__/urls.cpython-313.pyc differ
diff --git a/unihub_project/__pycache__/urls.cpython-39.pyc b/unihub_project/__pycache__/urls.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..476840f2406d3b785ac9d1d402638f6149707e40
Binary files /dev/null and b/unihub_project/__pycache__/urls.cpython-39.pyc differ
diff --git a/unihub_project/__pycache__/views.cpython-313.pyc b/unihub_project/__pycache__/views.cpython-313.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1e59009d6588ca854fc5532d6fc070549160e1d1
Binary files /dev/null and b/unihub_project/__pycache__/views.cpython-313.pyc differ
diff --git a/unihub_project/__pycache__/views.cpython-39.pyc b/unihub_project/__pycache__/views.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..91529644c8eda20741bd3dd07afca03ab6032b4c
Binary files /dev/null and b/unihub_project/__pycache__/views.cpython-39.pyc differ
diff --git a/unihub_project/__pycache__/wsgi.cpython-39.pyc b/unihub_project/__pycache__/wsgi.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..56c909a3d223001ddc5f74ef328b5ad153c132e7
Binary files /dev/null and b/unihub_project/__pycache__/wsgi.cpython-39.pyc differ
diff --git a/unihub_project/asgi.py b/unihub_project/asgi.py
new file mode 100644
index 0000000000000000000000000000000000000000..02da32152d7e269360664e23e7502f96983aa229
--- /dev/null
+++ b/unihub_project/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for unihub_project project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'unihub_project.settings')
+
+application = get_asgi_application()
diff --git a/unihub_project/settings.py b/unihub_project/settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..745d403881a0fbfc196ffda3cee25f6035400160
--- /dev/null
+++ b/unihub_project/settings.py
@@ -0,0 +1,137 @@
+"""
+Django settings for unihub_project project.
+
+Generated by 'django-admin startproject' using Django 5.1.6.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/5.1/ref/settings/
+"""
+
+from pathlib import Path
+import pymysql
+pymysql.install_as_MySQLdb()
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-9os%w6o3zjgxf-7^=51h4vtl)j)7e4yp--puf!v8_zmh7!#@nc'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'accounts',
+    'events',
+]
+
+AUTH_USER_MODEL = 'accounts.User'
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'unihub_project.urls'
+
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'unihub_project.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
+
+# unihub_project/settings.py
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.mysql',
+        'NAME': 'unihub_db',
+        'USER': 'unihub_user',
+        'PASSWORD': 'Thescotts111',
+        'HOST': 'db',  # Refer to the service name in docker-compose.yml
+        'PORT': '3306',
+    }
+}
+
+
+
+# Password validation
+# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/5.1/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/5.1/howto/static-files/
+
+STATIC_URL = 'static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
diff --git a/unihub_project/urls.py b/unihub_project/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..0feeb72922d0a6cf108adb0f9c5b356caa59a71f
--- /dev/null
+++ b/unihub_project/urls.py
@@ -0,0 +1,26 @@
+"""
+URL configuration for unihub_project project.
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/5.1/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path, include
+from .views import home_view  # Import the homepage view
+
+urlpatterns = [
+    path("admin/", admin.site.urls),  
+    path("accounts/", include("accounts.urls")),  # Include accounts URLs
+    path("events/", include("events.urls")),  #  Include events URLs
+    path("", home_view, name="home"),  # Homepage
+]
diff --git a/unihub_project/views.py b/unihub_project/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab86773e39581e9ed649212d223d75ae4ab3d1e2
--- /dev/null
+++ b/unihub_project/views.py
@@ -0,0 +1,4 @@
+from django.shortcuts import render
+
+def home_view(request):
+    return render(request, "home.html")  # This will look for templates/home.html
diff --git a/unihub_project/wsgi.py b/unihub_project/wsgi.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8a08ab5372c0839f9dfc22c87c6474b106651b6
--- /dev/null
+++ b/unihub_project/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for unihub_project project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'unihub_project.settings')
+
+application = get_wsgi_application()