diff --git a/backend/api_test.go b/backend/api_test.go
index e21c0e7..4bf31d4 100644
--- a/backend/api_test.go
+++ b/backend/api_test.go
@@ -549,12 +549,12 @@ func TestCompleteTask(t *testing.T) {
 	// Create two allowance goals
 	e.POST("/user/1/allowance").WithJSON(CreateAllowanceRequest{
 		Name:   "Test Allowance 1",
-		Target: 1000,
+		Target: 100,
 		Weight: 50,
 	}).Expect().Status(201)
 	e.POST("/user/1/allowance").WithJSON(CreateAllowanceRequest{
 		Name:   "Test Allowance 1",
-		Target: 1000,
+		Target: 10,
 		Weight: 25,
 	}).Expect().Status(201)
 
@@ -568,11 +568,11 @@ func TestCompleteTask(t *testing.T) {
 	allowances := e.GET("/user/1/allowance").Expect().Status(200).JSON().Array()
 	allowances.Length().IsEqual(3)
 	allowances.Value(0).Object().Value("id").Number().IsEqual(0)
-	allowances.Value(0).Object().Value("progress").Number().IsEqual(26)
+	allowances.Value(0).Object().Value("progress").Number().IsEqual(31)
 	allowances.Value(1).Object().Value("id").Number().IsEqual(1)
-	allowances.Value(1).Object().Value("progress").Number().IsEqual(50)
+	allowances.Value(1).Object().Value("progress").Number().IsEqual(60)
 	allowances.Value(2).Object().Value("id").Number().IsEqual(2)
-	allowances.Value(2).Object().Value("progress").Number().IsEqual(25)
+	allowances.Value(2).Object().Value("progress").Number().IsEqual(10)
 
 	// And also for user 2
 	allowances = e.GET("/user/2/allowance").Expect().Status(200).JSON().Array()
diff --git a/backend/db.go b/backend/db.go
index fe02ac2..0aa5570 100644
--- a/backend/db.go
+++ b/backend/db.go
@@ -416,16 +416,20 @@ func (db *Db) CompleteTask(taskId int) error {
 
 		if sumOfWeights > 0 {
 			// Distribute the reward to the allowances
-			for allowanceRow := range tx.Query("select id, weight from allowances where user_id = ? and weight > 0").Bind(userId).Range(&err) {
-				var allowanceId int
+			for allowanceRow := range tx.Query("select id, weight, target, balance from allowances where user_id = ? and weight > 0 order by (target - balance) asc").Bind(userId).Range(&err) {
+				var allowanceId, allowanceTarget, allowanceBalance int
 				var allowanceWeight float64
-				err = allowanceRow.Scan(&allowanceId, &allowanceWeight)
+				err = allowanceRow.Scan(&allowanceId, &allowanceWeight, &allowanceTarget, &allowanceBalance)
 				if err != nil {
 					return err
 				}
 
 				// Calculate the amount to add to the allowance
 				amount := int((allowanceWeight / sumOfWeights) * float64(remainingReward))
+				if allowanceBalance+amount > allowanceTarget {
+					// If the amount reaches past the target, set it to the target
+					amount = allowanceTarget - allowanceBalance
+				}
 				sumOfWeights -= allowanceWeight
 				err = tx.Query("update allowances set balance = balance + ? where id = ? and user_id = ?").
 					Bind(amount, allowanceId, userId).Exec()
diff --git a/backend/web.go b/backend/web.go
index 97b906a..12abbd0 100644
--- a/backend/web.go
+++ b/backend/web.go
@@ -13,6 +13,7 @@ type ViewModel struct {
 	Allowances  []Allowance
 	Tasks       []Task
 	History     []History
+	Error       string
 }
 
 func loadWebEndpoints(router *gin.Engine) {
@@ -20,6 +21,9 @@ func loadWebEndpoints(router *gin.Engine) {
 	router.GET("/", renderIndex)
 	router.GET("/login", renderLogin)
 	router.POST("/createTask", renderCreateTask)
+	router.GET("/completeTask", renderCompleteTask)
+	router.POST("/createAllowance", renderCreateAllowance)
+	router.GET("/completeAllowance", renderCompleteAllowance)
 }
 
 func renderLogin(c *gin.Context) {
@@ -30,49 +34,16 @@ func renderLogin(c *gin.Context) {
 }
 
 func renderIndex(c *gin.Context) {
-	currentUserStr, err := c.Cookie("user")
-	if errors.Is(err, http.ErrNoCookie) {
-		renderNoUser(c)
+	currentUser := getCurrentUser(c)
+	if currentUser == nil {
 		return
 	}
-
-	if err != nil {
-		unsetUserCookie(c)
-		return
-	}
-	currentUser, err := strconv.Atoi(currentUserStr)
-	if err != nil {
-		unsetUserCookie(c)
-		return
-	}
-	userExists, err := db.UserExists(currentUser)
-	if !userExists || err != nil {
-		unsetUserCookie(c)
-		return
-	}
-	renderWithUser(c, currentUser)
+	renderWithUser(c, *currentUser)
 }
 
 func renderCreateTask(c *gin.Context) {
-	currentUserStr, err := c.Cookie("user")
-	if errors.Is(err, http.ErrNoCookie) {
-		c.HTML(http.StatusBadRequest, "error.gohtml", gin.H{
-			"error": "User not logged in",
-		})
-		return
-	}
-	if err != nil {
-		unsetUserCookie(c)
-		return
-	}
-	currentUser, err := strconv.Atoi(currentUserStr)
-	if err != nil {
-		unsetUserCookie(c)
-		return
-	}
-	userExists, err := db.UserExists(currentUser)
-	if !userExists || err != nil {
-		unsetUserCookie(c)
+	currentUser := getCurrentUser(c)
+	if currentUser == nil {
 		return
 	}
 
@@ -80,15 +51,11 @@ func renderCreateTask(c *gin.Context) {
 	rewardStr := c.PostForm("reward")
 	reward, err := strconv.Atoi(rewardStr)
 	if err != nil {
-		c.HTML(http.StatusBadRequest, "error.gohtml", gin.H{
-			"error": "Invalid reward value",
-		})
+		renderError(c, http.StatusBadRequest, err)
 		return
 	}
 	if name == "" || reward <= 0 {
-		c.HTML(http.StatusBadRequest, "error.gohtml", gin.H{
-			"error": "Name and reward must be provided",
-		})
+		renderError(c, http.StatusBadRequest, err)
 		return
 	}
 
@@ -97,15 +64,112 @@ func renderCreateTask(c *gin.Context) {
 		Reward: reward,
 	})
 	if err != nil {
-		c.HTML(http.StatusInternalServerError, "error.gohtml", gin.H{
-			"error": err.Error(),
-		})
+		renderError(c, http.StatusInternalServerError, err)
 		return
 	}
 
 	c.Redirect(http.StatusFound, "/")
 }
 
+func renderCompleteTask(c *gin.Context) {
+	taskIDStr := c.Query("task")
+	taskID, err := strconv.Atoi(taskIDStr)
+	if err != nil {
+		renderError(c, http.StatusBadRequest, err)
+		return
+	}
+
+	err = db.CompleteTask(taskID)
+	if err != nil {
+		renderError(c, http.StatusInternalServerError, err)
+		return
+	}
+
+	c.Redirect(http.StatusFound, "/")
+}
+
+func renderCreateAllowance(c *gin.Context) {
+	currentUser := getCurrentUser(c)
+	if currentUser == nil {
+		return
+	}
+
+	name := c.PostForm("name")
+	targetStr := c.PostForm("target")
+	target, err := strconv.Atoi(targetStr)
+	if err != nil {
+		renderError(c, http.StatusBadRequest, err)
+		return
+	}
+	weightStr := c.PostForm("weight")
+	weight, err := strconv.ParseFloat(weightStr, 64)
+	if err != nil {
+		renderError(c, http.StatusBadRequest, err)
+		return
+	}
+	if name == "" || target <= 0 || weight <= 0 {
+		renderError(c, http.StatusBadRequest, err)
+		return
+	}
+
+	_, err = db.CreateAllowance(*currentUser, &CreateAllowanceRequest{
+		Name:   name,
+		Target: target,
+		Weight: weight,
+	})
+	if err != nil {
+		renderError(c, http.StatusInternalServerError, err)
+		return
+	}
+
+	c.Redirect(http.StatusFound, "/")
+}
+
+func renderCompleteAllowance(c *gin.Context) {
+	currentUser := getCurrentUser(c)
+	if currentUser == nil {
+		return
+	}
+
+	allowanceIDStr := c.Query("allowance")
+	allowanceID, err := strconv.Atoi(allowanceIDStr)
+	if err != nil {
+		renderError(c, http.StatusBadRequest, err)
+		return
+	}
+
+	err = db.CompleteAllowance(*currentUser, allowanceID)
+	if err != nil {
+		renderError(c, http.StatusInternalServerError, err)
+		return
+	}
+
+	c.Redirect(http.StatusFound, "/")
+}
+
+func getCurrentUser(c *gin.Context) *int {
+	currentUserStr, err := c.Cookie("user")
+	if errors.Is(err, http.ErrNoCookie) {
+		renderNoUser(c)
+		return nil
+	}
+	if err != nil {
+		unsetUserCookie(c)
+		return nil
+	}
+	currentUser, err := strconv.Atoi(currentUserStr)
+	if err != nil {
+		unsetUserCookie(c)
+		return nil
+	}
+	userExists, err := db.UserExists(currentUser)
+	if !userExists || err != nil {
+		unsetUserCookie(c)
+		return nil
+	}
+	return &currentUser
+}
+
 func unsetUserCookie(c *gin.Context) {
 	c.SetCookie("user", "", -1, "/", "localhost", false, true)
 	c.Redirect(http.StatusFound, "/")
@@ -114,9 +178,7 @@ func unsetUserCookie(c *gin.Context) {
 func renderNoUser(c *gin.Context) {
 	users, err := db.GetUsers()
 	if err != nil {
-		c.HTML(http.StatusInternalServerError, "error.gohtml", gin.H{
-			"error": err.Error(),
-		})
+		renderError(c, http.StatusInternalServerError, err)
 		return
 	}
 
@@ -128,33 +190,25 @@ func renderNoUser(c *gin.Context) {
 func renderWithUser(c *gin.Context, currentUser int) {
 	users, err := db.GetUsers()
 	if err != nil {
-		c.HTML(http.StatusInternalServerError, "error.gohtml", gin.H{
-			"error": err.Error(),
-		})
+		renderError(c, http.StatusInternalServerError, err)
 		return
 	}
 
 	allowances, err := db.GetUserAllowances(currentUser)
 	if err != nil {
-		c.HTML(http.StatusInternalServerError, "error.gohtml", gin.H{
-			"error": err.Error(),
-		})
+		renderError(c, http.StatusInternalServerError, err)
 		return
 	}
 
 	tasks, err := db.GetTasks()
 	if err != nil {
-		c.HTML(http.StatusInternalServerError, "error.gohtml", gin.H{
-			"error": err.Error(),
-		})
+		renderError(c, http.StatusInternalServerError, err)
 		return
 	}
 
 	history, err := db.GetHistory(currentUser)
 	if err != nil {
-		c.HTML(http.StatusInternalServerError, "error.gohtml", gin.H{
-			"error": err.Error(),
-		})
+		renderError(c, http.StatusInternalServerError, err)
 		return
 	}
 
@@ -166,3 +220,9 @@ func renderWithUser(c *gin.Context, currentUser int) {
 		History:     history,
 	})
 }
+
+func renderError(c *gin.Context, statusCode int, err error) {
+	c.HTML(statusCode, "web.gohtml", ViewModel{
+		Error: err.Error(),
+	})
+}
diff --git a/backend/web.gohtml b/backend/web.gohtml
index 11272a5..1ed49ee 100644
--- a/backend/web.gohtml
+++ b/backend/web.gohtml
@@ -2,97 +2,131 @@
 <html lang="en">
 <head>
 	<title>Allowance Planner 2000</title>
+	<style>
+		tr:hover {
+			background-color: #f0f0f0;
+		}
+	</style>
 </head>
 <body>
 <h1>Allowance Planner 2000</h1>
-<h2>Users</h2>
-{{range .Users}}
-	{{if eq $.CurrentUser .ID}}
-		<strong>{{.Name}}</strong>
-	{{else}}
-		<a href="/login?user={{.ID}}">{{.Name}}</a>
-	{{end}}
-{{end}}
 
-{{if ne .CurrentUser 0}}
-	<h2>Allowances</h2>
-	<table border="1">
-		<thead>
-		<tr>
-			<th>Name</th>
-			<th>Progress</th>
-			<th>Target</th>
-			<th>Weight</th>
-		</tr>
-		</thead>
-		<tbody>
-		{{range .Allowances}}
-			{{if eq .ID 0}}
-				<tr>
-					<td>Total</td>
-					<td>{{.Progress}}</td>
-					<td></td>
-					<td>{{.Weight}}</td>
-				</tr>
-			{{else}}
-				<tr>
-					<td>{{.Name}}</td>
-					<td>{{.Progress}}</td>
-					<td>{{.Target}}</td>
-					<td>{{.Weight}}</td>
-				</tr>
-			{{end}}
+{{if ne .Error ""}}
+	<h2>Error</h2>
+	<p>{{.Error}}</p>
+{{else}}
+	<h2>Users</h2>
+	{{range .Users}}
+		{{if eq $.CurrentUser .ID}}
+			<strong>{{.Name}}</strong>
+		{{else}}
+			<a href="/login?user={{.ID}}">{{.Name}}</a>
 		{{end}}
-		</tbody>
-	</table>
+	{{end}}
 
-	<h2>Tasks</h2>
-	<form method="post" action="/createTask">
+	{{if ne .CurrentUser 0}}
+		<h2>Allowances</h2>
+		<form action="/createAllowance" method="post">
+			<table border="1">
+				<thead>
+				<tr>
+					<th>Name</th>
+					<th>Progress</th>
+					<th>Target</th>
+					<th>Weight</th>
+					<th>Actions</th>
+				</tr>
+				</thead>
+				<tbody>
+					<tr>
+						<td><label><input type="text" name="name" placeholder="Name"></label></td>
+						<td></td>
+						<td><label><input type="number" name="target" placeholder="Target"></label></td>
+						<td><label><input type="number" name="weight" placeholder="Weight"></label></td>
+						<td><button>Create</button></td>
+					</tr>
+				{{range .Allowances}}
+					{{if eq .ID 0}}
+						<tr>
+							<td>Total</td>
+							<td>{{.Progress}}</td>
+							<td></td>
+							<td>{{.Weight}}</td>
+						</tr>
+					{{else}}
+						<tr>
+							<td>{{.Name}}</td>
+							<td><progress max="{{.Target}}" value="{{.Progress}}"></progress> ({{.Progress}})</td>
+							<td>{{.Target}}</td>
+							<td>{{.Weight}}</td>
+                            {{if ge .Progress .Target}}
+								<td>
+									<a href="/completeAllowance?allowance={{.ID}}">Mark as completed</a>
+								</td>
+                            {{end}}
+						</tr>
+					{{end}}
+				{{end}}
+				</tbody>
+			</table>
+		</form>
+
+		<h2>Tasks</h2>
+		<form method="post" action="/createTask">
+			<table border="1">
+				<thead>
+				<tr>
+					<th>Name</th>
+					<th>Assigned</th>
+					<th>Reward</th>
+					<th>Actions</th>
+				</tr>
+				</thead>
+				<tbody>
+				{{range .Tasks}}
+					<tr>
+						<td>{{.Name}}</td>
+						<td>
+							{{if eq .Assigned nil}}
+								None
+							{{else}}
+								{{.Assigned}}
+							{{end}}
+						</td>
+						<td>{{.Reward}}</td>
+						<td>
+							<a href="/completeTask?task={{.ID}}">Mark as completed</a>
+						</td>
+					</tr>
+				{{end}}
+						<tr>
+							<td><label><input type="text" name="name" placeholder="Name"></label></td>
+							<td></td>
+							<td><label><input type="number" name="reward" placeholder="Reward"></label></td>
+							<td><button>Create</button></td>
+						</tr>
+				</tbody>
+			</table>
+		</form>
+
+		<h2>History</h2>
 		<table border="1">
 			<thead>
 			<tr>
-				<th>Name</th>
-				<th>Assigned</th>
-				<th>Reward</th>
+				<th>Timestamp</th>
+				<th>Allowance</th>
 			</tr>
 			</thead>
 			<tbody>
-			{{range .Tasks}}
+			{{range .History}}
 				<tr>
-					<td>{{.Name}}</td>
-					<td>{{.Assigned}}</td>
-					<td>{{.Reward}}</td>
+					<td>{{.Timestamp}}</td>
+					<td>{{.Allowance}}</td>
 				</tr>
 			{{end}}
-					<tr>
-						<td><label><input type="text" placeholder="Name"></label></td>
-						<td></td>
-						<td>
-							<label><input type="number" placeholder="Reward"></label>
-							<button>Create</button>
-						</td>
-					</tr>
 			</tbody>
 		</table>
-	</form>
-
-	<h2>History</h2>
-	<table border="1">
-		<thead>
-		<tr>
-			<th>Timestamp</th>
-			<th>Allowance</th>
-		</tr>
-		</thead>
-		<tbody>
-		{{range .History}}
-			<tr>
-				<td>{{.Timestamp}}</td>
-				<td>{{.Allowance}}</td>
-			</tr>
-		{{end}}
-		</tbody>
-	</table>
+	{{end}}
 {{end}}
 </body>
 </html>