diff --git a/.gitignore b/.gitignore
index a6090ec..fc51efe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,6 @@ go.work
 .air.toml
 /tmp
 tls/
+test.db.old
+.gitignore
+.nvim/session
diff --git a/cmd/web/handlers.go b/cmd/web/handlers.go
index 20225b3..d929ba8 100644
--- a/cmd/web/handlers.go
+++ b/cmd/web/handlers.go
@@ -2,10 +2,14 @@ package main
 
 import (
 	"net/http"
+
 	"git.32bit.cafe/32bitcafe/guestbook/ui/views"
 )
 
 func (app *application) home(w http.ResponseWriter, r *http.Request) {
-    data := app.newCommonData(r)
-    views.Home("Home", data).Render(r.Context(), w)
+	if app.isAuthenticated(r) {
+		http.Redirect(w, r, "/websites", http.StatusSeeOther)
+		return
+	}
+	views.Home("Home", app.newCommonData(r)).Render(r.Context(), w)
 }
diff --git a/cmd/web/handlers_guestbook.go b/cmd/web/handlers_guestbook.go
index be24010..fb25a96 100644
--- a/cmd/web/handlers_guestbook.go
+++ b/cmd/web/handlers_guestbook.go
@@ -11,35 +11,6 @@ import (
 	"git.32bit.cafe/32bitcafe/guestbook/ui/views"
 )
 
-func (app *application) getGuestbookCreate(w http.ResponseWriter, r *http.Request) {
-	data := app.newCommonData(r)
-	views.GuestbookCreate("New Guestbook", data).Render(r.Context(), w)
-}
-
-func (app *application) postGuestbookCreate(w http.ResponseWriter, r *http.Request) {
-	userId := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId")
-	err := r.ParseForm()
-	if err != nil {
-		app.serverError(w, r, err)
-		return
-	}
-	siteUrl := r.Form.Get("siteurl")
-	shortId := app.createShortId()
-	_, err = app.guestbooks.Insert(shortId, siteUrl, userId)
-	if err != nil {
-		app.serverError(w, r, err)
-		return
-	}
-	app.sessionManager.Put(r.Context(), "flash", "Guestbook successfully created!")
-	if r.Header.Get("HX-Request") == "true" {
-		w.Header().Add("HX-Trigger", "newGuestbook")
-		data := app.newTemplateData(r)
-		app.renderHTMX(w, r, http.StatusOK, "guestbookcreatebutton.part.html", data)
-		return
-	}
-	http.Redirect(w, r, fmt.Sprintf("/guestbooks/%s", shortIdToSlug(shortId)), http.StatusSeeOther)
-}
-
 func (app *application) getGuestbookList(w http.ResponseWriter, r *http.Request) {
 	userId := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId")
 	guestbooks, err := app.guestbooks.GetAll(userId)
@@ -53,7 +24,7 @@ func (app *application) getGuestbookList(w http.ResponseWriter, r *http.Request)
 
 func (app *application) getGuestbook(w http.ResponseWriter, r *http.Request) {
 	slug := r.PathValue("id")
-	guestbook, err := app.guestbooks.Get(slugToShortId(slug))
+	website, err := app.websites.Get(slugToShortId(slug))
 	if err != nil {
 		if errors.Is(err, models.ErrNoRecord) {
 			http.NotFound(w, r)
@@ -62,42 +33,18 @@ func (app *application) getGuestbook(w http.ResponseWriter, r *http.Request) {
 		}
 		return
 	}
-	comments, err := app.guestbookComments.GetAll(guestbook.ID)
+	comments, err := app.guestbookComments.GetAll(website.Guestbook.ID)
 	if err != nil {
 		app.serverError(w, r, err)
 		return
 	}
 	data := app.newCommonData(r)
-	views.GuestbookView("Guestbook", data, guestbook, comments, forms.CommentCreateForm{}).Render(r.Context(), w)
-}
-
-func (app *application) getGuestbookDashboard(w http.ResponseWriter, r *http.Request) {
-	slug := r.PathValue("id")
-	guestbook, err := app.guestbooks.Get(slugToShortId(slug))
-	if err != nil {
-		if errors.Is(err, models.ErrNoRecord) {
-			http.NotFound(w, r)
-		} else {
-			app.serverError(w, r, err)
-		}
-		return
-	}
-	user := app.getCurrentUser(r)
-	if user.ID != guestbook.UserId {
-		app.clientError(w, http.StatusUnauthorized)
-	}
-	comments, err := app.guestbookComments.GetAll(guestbook.ID)
-	if err != nil {
-		app.serverError(w, r, err)
-		return
-	}
-	data := app.newCommonData(r)
-	views.GuestbookDashboardView("Guestbook", data, guestbook, comments).Render(r.Context(), w)
+	views.GuestbookView("Guestbook", data, website, website.Guestbook, comments, forms.CommentCreateForm{}).Render(r.Context(), w)
 }
 
 func (app *application) getGuestbookComments(w http.ResponseWriter, r *http.Request) {
 	slug := r.PathValue("id")
-	guestbook, err := app.guestbooks.Get(slugToShortId(slug))
+	website, err := app.websites.Get(slugToShortId(slug))
 	if err != nil {
 		if errors.Is(err, models.ErrNoRecord) {
 			http.NotFound(w, r)
@@ -106,19 +53,19 @@ func (app *application) getGuestbookComments(w http.ResponseWriter, r *http.Requ
 		}
 		return
 	}
-	comments, err := app.guestbookComments.GetAll(guestbook.ID)
+	comments, err := app.guestbookComments.GetAll(website.Guestbook.ID)
 	if err != nil {
 		app.serverError(w, r, err)
 		return
 	}
 	data := app.newCommonData(r)
-	views.GuestbookDashboardCommentsView("Comments", data, guestbook, comments).Render(r.Context(), w)
+	views.GuestbookDashboardCommentsView("Comments", data, website, website.Guestbook, comments).Render(r.Context(), w)
 }
 
 func (app *application) getGuestbookCommentCreate(w http.ResponseWriter, r *http.Request) {
 	// TODO: This will be the embeddable form
 	slug := r.PathValue("id")
-	guestbook, err := app.guestbooks.Get(slugToShortId(slug))
+	website, err := app.websites.Get(slugToShortId(slug))
 	if err != nil {
 		if errors.Is(err, models.ErrNoRecord) {
 			http.NotFound(w, r)
@@ -127,15 +74,15 @@ func (app *application) getGuestbookCommentCreate(w http.ResponseWriter, r *http
 		}
 		return
 	}
-	data := app.newTemplateData(r)
-	data.Guestbook = guestbook
-	data.Form = forms.CommentCreateForm{}
-	app.render(w, r, http.StatusOK, "commentcreate.view.tmpl.html", data)
+
+	data := app.newCommonData(r)
+	form := forms.CommentCreateForm{}
+	views.CreateGuestbookComment("New Comment", data, website, website.Guestbook, form).Render(r.Context(), w)
 }
 
 func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *http.Request) {
-	guestbookSlug := r.PathValue("id")
-	guestbook, err := app.guestbooks.Get(slugToShortId(guestbookSlug))
+	slug := r.PathValue("id")
+	website, err := app.websites.Get(slugToShortId(slug))
 	if err != nil {
 		if errors.Is(err, models.ErrNoRecord) {
 			http.NotFound(w, r)
@@ -161,21 +108,24 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt
 	form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
 
 	if !form.Valid() {
-		data := app.newTemplateData(r)
-		data.Guestbook = guestbook
-		data.Form = form
-		app.render(w, r, http.StatusUnprocessableEntity, "commentcreate.view.tmpl.html", data)
+		comments, err := app.guestbookComments.GetAll(website.Guestbook.ID)
+		if err != nil {
+			app.serverError(w, r, err)
+			return
+		}
+		data := app.newCommonData(r)
+		views.GuestbookView("Guestbook", data, website, website.Guestbook, comments, forms.CommentCreateForm{}).Render(r.Context(), w)
 		return
 	}
 
 	shortId := app.createShortId()
-	_, err = app.guestbookComments.Insert(shortId, guestbook.ID, 0, form.AuthorName, form.AuthorEmail, form.AuthorSite, form.Content, "", true)
+	_, err = app.guestbookComments.Insert(shortId, website.Guestbook.ID, 0, form.AuthorName, form.AuthorEmail, form.AuthorSite, form.Content, "", true)
 	if err != nil {
 		app.serverError(w, r, err)
 		return
 	}
 	// app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!")
-	http.Redirect(w, r, fmt.Sprintf("/guestbooks/%s", guestbookSlug), http.StatusSeeOther)
+	http.Redirect(w, r, fmt.Sprintf("/websites/%s/guestbook", slug), http.StatusSeeOther)
 }
 
 func (app *application) updateGuestbookComment(w http.ResponseWriter, r *http.Request) {
@@ -188,8 +138,8 @@ func (app *application) deleteGuestbookComment(w http.ResponseWriter, r *http.Re
 }
 
 func (app *application) getCommentQueue(w http.ResponseWriter, r *http.Request) {
-	guestbookSlug := r.PathValue("id")
-	guestbook, err := app.guestbooks.Get(slugToShortId(guestbookSlug))
+	slug := r.PathValue("id")
+	website, err := app.websites.Get(slugToShortId(slug))
 	if err != nil {
 		if errors.Is(err, models.ErrNoRecord) {
 			http.NotFound(w, r)
@@ -199,7 +149,7 @@ func (app *application) getCommentQueue(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	comments, err := app.guestbookComments.GetQueue(guestbook.ID)
+	comments, err := app.guestbookComments.GetQueue(website.Guestbook.ID)
 	if err != nil {
 		if errors.Is(err, models.ErrNoRecord) {
 			http.NotFound(w, r)
@@ -210,7 +160,7 @@ func (app *application) getCommentQueue(w http.ResponseWriter, r *http.Request)
 	}
 
 	data := app.newCommonData(r)
-	views.GuestbookDashboardCommentsView("Message Queue", data, guestbook, comments).Render(r.Context(), w)
+	views.GuestbookDashboardCommentsView("Message Queue", data, website, website.Guestbook, comments).Render(r.Context(), w)
 }
 
 func (app *application) putHideGuestbookComment(w http.ResponseWriter, r *http.Request) {
diff --git a/cmd/web/handlers_user.go b/cmd/web/handlers_user.go
index f0884d8..b2b0163 100644
--- a/cmd/web/handlers_user.go
+++ b/cmd/web/handlers_user.go
@@ -4,128 +4,127 @@ import (
 	"errors"
 	"net/http"
 
-        "git.32bit.cafe/32bitcafe/guestbook/internal/forms"
+	"git.32bit.cafe/32bitcafe/guestbook/internal/forms"
 	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
 	"git.32bit.cafe/32bitcafe/guestbook/internal/validator"
 	"git.32bit.cafe/32bitcafe/guestbook/ui/views"
 )
 
 func (app *application) getUserRegister(w http.ResponseWriter, r *http.Request) {
-    form := forms.UserRegistrationForm{}
-    data := app.newCommonData(r)
-    views.UserRegistration("User Registration", data, form).Render(r.Context(), w)
+	form := forms.UserRegistrationForm{}
+	data := app.newCommonData(r)
+	views.UserRegistration("User Registration", data, form).Render(r.Context(), w)
 }
 
-
 func (app *application) getUserLogin(w http.ResponseWriter, r *http.Request) {
-    views.UserLogin("Login", app.newCommonData(r), forms.UserLoginForm{}).Render(r.Context(), w)
+	views.UserLogin("Login", app.newCommonData(r), forms.UserLoginForm{}).Render(r.Context(), w)
 }
 
 func (app *application) postUserRegister(w http.ResponseWriter, r *http.Request) {
-    var form forms.UserRegistrationForm
-    err := app.decodePostForm(r, &form)
-    if err != nil {
-        app.clientError(w, http.StatusBadRequest)
-        return
-    }
-    form.CheckField(validator.NotBlank(form.Name), "name", "This field cannot be blank")
-    form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank")
-    form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address")
-    form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
-    form.CheckField(validator.MinChars(form.Password, 8), "password", "This field must be at least 8 characters long")
-    if !form.Valid() {
-        data := app.newCommonData(r)
-        w.WriteHeader(http.StatusUnprocessableEntity)
-        views.UserRegistration("User Registration", data, form).Render(r.Context(), w)
-        return
-    }
-    shortId := app.createShortId()
-    err = app.users.Insert(shortId, form.Name, form.Email, form.Password)
-    if err != nil {
-        if errors.Is(err, models.ErrDuplicateEmail) {
-            form.AddFieldError("email", "Email address is already in use")
-            data := app.newCommonData(r)
-            w.WriteHeader(http.StatusUnprocessableEntity)
-            views.UserRegistration("User Registration", data, form).Render(r.Context(), w)
-        } else {
-            app.serverError(w, r, err)
-        }
-        return
-    }
-    app.sessionManager.Put(r.Context(), "flash", "Registration successful. Please log in.")
-    http.Redirect(w, r, "/users/login", http.StatusSeeOther)
+	var form forms.UserRegistrationForm
+	err := app.decodePostForm(r, &form)
+	if err != nil {
+		app.clientError(w, http.StatusBadRequest)
+		return
+	}
+	form.CheckField(validator.NotBlank(form.Name), "name", "This field cannot be blank")
+	form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank")
+	form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address")
+	form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
+	form.CheckField(validator.MinChars(form.Password, 8), "password", "This field must be at least 8 characters long")
+	if !form.Valid() {
+		data := app.newCommonData(r)
+		w.WriteHeader(http.StatusUnprocessableEntity)
+		views.UserRegistration("User Registration", data, form).Render(r.Context(), w)
+		return
+	}
+	shortId := app.createShortId()
+	err = app.users.Insert(shortId, form.Name, form.Email, form.Password)
+	if err != nil {
+		if errors.Is(err, models.ErrDuplicateEmail) {
+			form.AddFieldError("email", "Email address is already in use")
+			data := app.newCommonData(r)
+			w.WriteHeader(http.StatusUnprocessableEntity)
+			views.UserRegistration("User Registration", data, form).Render(r.Context(), w)
+		} else {
+			app.serverError(w, r, err)
+		}
+		return
+	}
+	app.sessionManager.Put(r.Context(), "flash", "Registration successful. Please log in.")
+	http.Redirect(w, r, "/users/login", http.StatusSeeOther)
 }
 
 func (app *application) postUserLogin(w http.ResponseWriter, r *http.Request) {
-    var form forms.UserLoginForm
-    err := app.decodePostForm(r, &form)
-    if err != nil {
-        app.clientError(w, http.StatusBadRequest)
-    }
-    form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank")
-    form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address")
-    form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
-    if !form.Valid() {
-        data := app.newCommonData(r)
-        w.WriteHeader(http.StatusUnprocessableEntity)
-        views.UserLogin("Login", data, form).Render(r.Context(), w)
-        return
-    }
-    id, err := app.users.Authenticate(form.Email, form.Password)
-    if err != nil {
-        if errors.Is(err, models.ErrInvalidCredentials) {
-            form.AddNonFieldError("Email or password is incorrect")
-            data := app.newCommonData(r)
-            views.UserLogin("Login", data, form).Render(r.Context(), w)
-        } else {
-            app.serverError(w, r, err)
-        }
-        return
-    }
-    err = app.sessionManager.RenewToken(r.Context())
-    if err != nil {
-        app.serverError(w, r, err)
-        return
-    }
-    app.sessionManager.Put(r.Context(), "authenticatedUserId", id)
-    http.Redirect(w, r, "/", http.StatusSeeOther)
+	var form forms.UserLoginForm
+	err := app.decodePostForm(r, &form)
+	if err != nil {
+		app.clientError(w, http.StatusBadRequest)
+	}
+	form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank")
+	form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address")
+	form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
+	if !form.Valid() {
+		data := app.newCommonData(r)
+		w.WriteHeader(http.StatusUnprocessableEntity)
+		views.UserLogin("Login", data, form).Render(r.Context(), w)
+		return
+	}
+	id, err := app.users.Authenticate(form.Email, form.Password)
+	if err != nil {
+		if errors.Is(err, models.ErrInvalidCredentials) {
+			form.AddNonFieldError("Email or password is incorrect")
+			data := app.newCommonData(r)
+			views.UserLogin("Login", data, form).Render(r.Context(), w)
+		} else {
+			app.serverError(w, r, err)
+		}
+		return
+	}
+	err = app.sessionManager.RenewToken(r.Context())
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	app.sessionManager.Put(r.Context(), "authenticatedUserId", id)
+	http.Redirect(w, r, "/", http.StatusSeeOther)
 }
 
 func (app *application) postUserLogout(w http.ResponseWriter, r *http.Request) {
-    err := app.sessionManager.RenewToken(r.Context())
-    if err != nil {
-        app.serverError(w, r, err)
-        return
-    }
-    app.sessionManager.Remove(r.Context(), "authenticatedUserId")
-    app.sessionManager.Put(r.Context(), "flash", "You've been logged out successfully!")
-    http.Redirect(w, r, "/", http.StatusSeeOther)
+	err := app.sessionManager.RenewToken(r.Context())
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	app.sessionManager.Remove(r.Context(), "authenticatedUserId")
+	app.sessionManager.Put(r.Context(), "flash", "You've been logged out successfully!")
+	http.Redirect(w, r, "/", http.StatusSeeOther)
 }
 
-func (app *application) getUsersList(w http.ResponseWriter, r *http.Request) {
-    // skip templ conversion for this view, which will not be available in the final app
-    // something similar will be available in the admin panel
-    users, err := app.users.GetAll()
-    if err != nil {
-        app.serverError(w, r, err)
-        return
-    }
-    data := app.newTemplateData(r)
-    data.Users = users
-    app.render(w, r, http.StatusOK, "userlist.view.tmpl.html", data)
-}
+// func (app *application) getUsersList(w http.ResponseWriter, r *http.Request) {
+//     // skip templ conversion for this view, which will not be available in the final app
+//     // something similar will be available in the admin panel
+//     users, err := app.users.GetAll()
+//     if err != nil {
+//         app.serverError(w, r, err)
+//         return
+//     }
+//     data := app.newTemplateData(r)
+//     data.Users = users
+//     app.render(w, r, http.StatusOK, "userlist.view.tmpl.html", data)
+// }
 
 func (app *application) getUser(w http.ResponseWriter, r *http.Request) {
-    slug := r.PathValue("id") 
-    user, err := app.users.Get(slugToShortId(slug))
-    if err != nil {
-        if errors.Is(err, models.ErrNoRecord) {
-            http.NotFound(w, r)
-        } else {
-            app.serverError(w, r, err)
-        }
-        return
-    }
-    data := app.newCommonData(r)
-    views.UserProfile(user.Username, data, user).Render(r.Context(), w)
+	slug := r.PathValue("id")
+	user, err := app.users.Get(slugToShortId(slug))
+	if err != nil {
+		if errors.Is(err, models.ErrNoRecord) {
+			http.NotFound(w, r)
+		} else {
+			app.serverError(w, r, err)
+		}
+		return
+	}
+	data := app.newCommonData(r)
+	views.UserProfile(user.Username, data, user).Render(r.Context(), w)
 }
diff --git a/cmd/web/handlers_website.go b/cmd/web/handlers_website.go
new file mode 100644
index 0000000..93df46f
--- /dev/null
+++ b/cmd/web/handlers_website.go
@@ -0,0 +1,92 @@
+package main
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+
+	"git.32bit.cafe/32bitcafe/guestbook/internal/forms"
+	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
+	"git.32bit.cafe/32bitcafe/guestbook/internal/validator"
+	"git.32bit.cafe/32bitcafe/guestbook/ui/views"
+)
+
+func (app *application) getWebsiteCreate(w http.ResponseWriter, r *http.Request) {
+	form := forms.WebsiteCreateForm{}
+	data := app.newCommonData(r)
+	views.WebsiteCreate("Add Website", data, form).Render(r.Context(), w)
+}
+
+func (app *application) postWebsiteCreate(w http.ResponseWriter, r *http.Request) {
+	userId := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId")
+	var form forms.WebsiteCreateForm
+	err := app.decodePostForm(r, &form)
+	if err != nil {
+		app.clientError(w, http.StatusBadRequest)
+		return
+	}
+
+	form.CheckField(validator.NotBlank(form.AuthorName), "authorName", "This field cannot be blank")
+	form.CheckField(validator.MaxChars(form.AuthorName, 256), "authorName", "This field cannot exceed 256 characters")
+	form.CheckField(validator.NotBlank(form.Name), "sitename", "This field cannot be blank")
+	form.CheckField(validator.MaxChars(form.Name, 256), "sitename", "This field cannot exceed 256 characters")
+	form.CheckField(validator.NotBlank(form.SiteUrl), "siteurl", "This field cannot be blank")
+	form.CheckField(validator.MaxChars(form.SiteUrl, 512), "siteurl", "This field cannot exceed 512 characters")
+
+	if !form.Valid() {
+		data := app.newCommonData(r)
+		w.WriteHeader(http.StatusUnprocessableEntity)
+		views.WebsiteCreate("Add a Website", data, form).Render(r.Context(), w)
+	}
+	websiteShortID := app.createShortId()
+	websiteId, err := app.websites.Insert(websiteShortID, userId, form.Name, form.SiteUrl, form.AuthorName)
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	// TODO: how to handle website creation success but guestbook creation failure?
+	guestbookShortID := app.createShortId()
+	_, err = app.guestbooks.Insert(guestbookShortID, userId, websiteId)
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	app.sessionManager.Put(r.Context(), "flash", "Website successfully registered!")
+	if r.Header.Get("HX-Request") == "true" {
+		w.Header().Add("HX-Trigger", "newWebsite")
+		views.WebsiteCreateButton().Render(r.Context(), w)
+		return
+	}
+	http.Redirect(w, r, fmt.Sprintf("/websites/%s", shortIdToSlug(websiteShortID)), http.StatusSeeOther)
+}
+
+func (app *application) getWebsiteDashboard(w http.ResponseWriter, r *http.Request) {
+	slug := r.PathValue("id")
+	user := app.getCurrentUser(r)
+	website, err := app.websites.Get(slugToShortId(slug))
+	if err != nil {
+		if errors.Is(err, models.ErrNoRecord) {
+			http.NotFound(w, r)
+		} else {
+			app.serverError(w, r, err)
+		}
+		return
+	}
+	if user.ID != website.UserId {
+		app.clientError(w, http.StatusUnauthorized)
+	}
+	data := app.newCommonData(r)
+	views.WebsiteDashboard("Guestbook", data, website).Render(r.Context(), w)
+}
+
+func (app *application) getWebsiteList(w http.ResponseWriter, r *http.Request) {
+
+	userId := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId")
+	websites, err := app.websites.GetAll(userId)
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	data := app.newCommonData(r)
+	views.WebsiteList("My Websites", data, websites).Render(r.Context(), w)
+}
diff --git a/cmd/web/helpers.go b/cmd/web/helpers.go
index e19001c..164f603 100644
--- a/cmd/web/helpers.go
+++ b/cmd/web/helpers.go
@@ -9,133 +9,101 @@ import (
 	"time"
 
 	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
+	"git.32bit.cafe/32bitcafe/guestbook/ui/views"
 	"github.com/gorilla/schema"
+	"github.com/justinas/nosurf"
 )
 
 func (app *application) serverError(w http.ResponseWriter, r *http.Request, err error) {
-    var (
-        method = r.Method
-        uri = r.URL.RequestURI()
-    )
+	var (
+		method = r.Method
+		uri    = r.URL.RequestURI()
+	)
 
-    app.logger.Error(err.Error(), "method", method, "uri", uri)
-    http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+	app.logger.Error(err.Error(), "method", method, "uri", uri)
+	http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
 }
 
 func (app *application) clientError(w http.ResponseWriter, status int) {
-    http.Error(w, http.StatusText(status), status)
+	http.Error(w, http.StatusText(status), status)
 }
 
-func (app *application) renderHTMX(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) {
-    ts, ok := app.templateCacheHTMX[page]
-    if !ok {
-        err := fmt.Errorf("the template %s does not exist", page)
-        app.serverError(w, r, err)
-        return
-    }
-
-    w.WriteHeader(status)
-    err := ts.Execute(w, data)
-    if err != nil {
-        app.serverError(w, r, err)
-    }
+func (app *application) nextSequence() uint16 {
+	val := app.sequence
+	if app.sequence == math.MaxUint16 {
+		app.sequence = 0
+	} else {
+		app.sequence += 1
+	}
+	return val
 }
 
-func (app *application) renderFullPage(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) {
-    ts, ok := app.templateCache[page]
-    if !ok {
-        err := fmt.Errorf("the template %s does not exist", page)
-        app.serverError(w, r, err)
-        return
-    }
-
-    w.WriteHeader(status)
-    err := ts.ExecuteTemplate(w, "base", data)
-    if err != nil {
-        app.serverError(w, r, err)
-    }
-}
-
-func (app *application) render(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) {
-    ts, ok := app.templateCache[page]
-    if !ok {
-        err := fmt.Errorf("the template %s does not exist", page)
-        app.serverError(w, r, err)
-        return
-    }
-
-    w.WriteHeader(status)
-    err := ts.ExecuteTemplate(w, "base", data)
-    if err != nil {
-        app.serverError(w, r, err)
-    }
-}
-
-func (app *application) nextSequence () uint16 {
-    val := app.sequence
-    if app.sequence == math.MaxUint16 {
-        app.sequence = 0
-    } else {
-        app.sequence += 1
-    }
-    return val
-}
-
-func (app *application) createShortId () uint64 {
-    now := time.Now().UTC()
-    epoch, err := time.Parse(time.RFC822Z, "01 Jan 20 00:00 -0000")
-    if err != nil {
-        fmt.Println(err)
-        return 0
-    }
-    d := now.Sub(epoch)
-    ms := d.Milliseconds()
-    seq := app.nextSequence()
-    return (uint64(ms) & 0x0FFFFFFFFFFFFFFF) | (uint64(seq) << 48)
+func (app *application) createShortId() uint64 {
+	now := time.Now().UTC()
+	epoch, err := time.Parse(time.RFC822Z, "01 Jan 20 00:00 -0000")
+	if err != nil {
+		fmt.Println(err)
+		return 0
+	}
+	d := now.Sub(epoch)
+	ms := d.Milliseconds()
+	seq := app.nextSequence()
+	return (uint64(ms) & 0x0FFFFFFFFFFFFFFF) | (uint64(seq) << 48)
 }
 
 func shortIdToSlug(id uint64) string {
-    slug := strconv.FormatUint(id, 36)
-    return slug
+	slug := strconv.FormatUint(id, 36)
+	return slug
 }
 
 func slugToShortId(slug string) uint64 {
-    id, _ := strconv.ParseUint(slug, 36, 64)
-    return id
+	id, _ := strconv.ParseUint(slug, 36, 64)
+	return id
 }
 
 func (app *application) decodePostForm(r *http.Request, dst any) error {
-    err := r.ParseForm()
-    if err != nil {
-        return err
-    }
+	err := r.ParseForm()
+	if err != nil {
+		return err
+	}
 
-    err = app.formDecoder.Decode(dst, r.PostForm)
-    if err != nil {
-        var multiErrors *schema.MultiError
-        if !errors.As(err, &multiErrors) {
-            panic(err)
-        }
-        return err
-    }
-    return nil
+	err = app.formDecoder.Decode(dst, r.PostForm)
+	if err != nil {
+		var multiErrors *schema.MultiError
+		if !errors.As(err, &multiErrors) {
+			panic(err)
+		}
+		return err
+	}
+	return nil
 }
 
 func (app *application) isAuthenticated(r *http.Request) bool {
-    isAuthenticated, ok := r.Context().Value(isAuthenticatedContextKey).(bool)
-    if !ok {
-        return false
-    }
-    return isAuthenticated
+	isAuthenticated, ok := r.Context().Value(isAuthenticatedContextKey).(bool)
+	if !ok {
+		return false
+	}
+	return isAuthenticated
 }
 
 func (app *application) getCurrentUser(r *http.Request) *models.User {
-    if !app.isAuthenticated(r) {
-        return nil
-    }
-    user, ok := r.Context().Value(userNameContextKey).(models.User)
-    if !ok {
-        return nil
-    }
-    return &user
+	if !app.isAuthenticated(r) {
+		return nil
+	}
+	user, ok := r.Context().Value(userNameContextKey).(models.User)
+	if !ok {
+		return nil
+	}
+	return &user
+}
+
+func (app *application) newCommonData(r *http.Request) views.CommonData {
+	return views.CommonData{
+		CurrentYear:     time.Now().Year(),
+		Flash:           app.sessionManager.PopString(r.Context(), "flash"),
+		IsAuthenticated: app.isAuthenticated(r),
+		CSRFToken:       nosurf.Token(r),
+		CurrentUser:     app.getCurrentUser(r),
+		IsHtmx:          r.Header.Get("Hx-Request") == "true",
+	}
 }
diff --git a/cmd/web/main.go b/cmd/web/main.go
index 4e715de..7a6d51b 100644
--- a/cmd/web/main.go
+++ b/cmd/web/main.go
@@ -7,7 +7,6 @@ import (
 	"log/slog"
 	"net/http"
 	"os"
-	"text/template"
 	"time"
 
 	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
@@ -18,90 +17,76 @@ import (
 )
 
 type application struct {
-    sequence uint16
-    logger *slog.Logger
-    templateCache map[string]*template.Template
-    templateCacheHTMX map[string]*template.Template
-    guestbooks *models.GuestbookModel
-    users *models.UserModel
-    guestbookComments *models.GuestbookCommentModel
-    sessionManager *scs.SessionManager
-    formDecoder *schema.Decoder
+	sequence          uint16
+	logger            *slog.Logger
+	websites          *models.WebsiteModel
+	guestbooks        *models.GuestbookModel
+	users             *models.UserModel
+	guestbookComments *models.GuestbookCommentModel
+	sessionManager    *scs.SessionManager
+	formDecoder       *schema.Decoder
 }
 
 func main() {
-    addr := flag.String("addr", ":3000", "HTTP network address")
-    dsn := flag.String("dsn", "guestbook.db", "data source name")
-    flag.Parse()
+	addr := flag.String("addr", ":3000", "HTTP network address")
+	dsn := flag.String("dsn", "guestbook.db", "data source name")
+	flag.Parse()
 
-    logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
+	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
 
-    db, err := openDB(*dsn)
-    if err != nil {
-        logger.Error(err.Error())
-        os.Exit(1)
-    }
-    defer db.Close()
+	db, err := openDB(*dsn)
+	if err != nil {
+		logger.Error(err.Error())
+		os.Exit(1)
+	}
+	defer db.Close()
 
-    templateCache, err := newTemplateCache()
-    if err != nil {
-        logger.Error(err.Error())
-        os.Exit(1)
-    }
+	sessionManager := scs.New()
+	sessionManager.Store = sqlite3store.New(db)
+	sessionManager.Lifetime = 12 * time.Hour
 
-    templateCacheHTMX, err := newHTMXTemplateCache()
-    if err != nil {
-        logger.Error(err.Error())
-        os.Exit(1)
-    }
+	formDecoder := schema.NewDecoder()
+	formDecoder.IgnoreUnknownKeys(true)
 
-    sessionManager := scs.New()
-    sessionManager.Store = sqlite3store.New(db)
-    sessionManager.Lifetime = 12 * time.Hour
+	app := &application{
+		sequence:          0,
+		logger:            logger,
+		sessionManager:    sessionManager,
+		websites:          &models.WebsiteModel{DB: db},
+		guestbooks:        &models.GuestbookModel{DB: db},
+		users:             &models.UserModel{DB: db},
+		guestbookComments: &models.GuestbookCommentModel{DB: db},
+		formDecoder:       formDecoder,
+	}
 
-    formDecoder := schema.NewDecoder()
-    formDecoder.IgnoreUnknownKeys(true)
+	tlsConfig := &tls.Config{
+		CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
+	}
 
-    app := &application{
-        sequence: 0,
-        templateCache: templateCache,
-        templateCacheHTMX: templateCacheHTMX,
-        logger: logger,
-        sessionManager: sessionManager,
-        guestbooks: &models.GuestbookModel{DB: db},
-        users: &models.UserModel{DB: db},
-        guestbookComments: &models.GuestbookCommentModel{DB: db},
-        formDecoder: formDecoder,
-    }
+	srv := &http.Server{
+		Addr:         *addr,
+		Handler:      app.routes(),
+		ErrorLog:     slog.NewLogLogger(logger.Handler(), slog.LevelError),
+		TLSConfig:    tlsConfig,
+		IdleTimeout:  time.Minute,
+		ReadTimeout:  5 * time.Second,
+		WriteTimeout: 10 * time.Second,
+	}
 
-    tlsConfig := &tls.Config{
-        CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
-    }
+	logger.Info("Starting server", slog.Any("addr", *addr))
 
-    srv := &http.Server {
-        Addr: *addr,
-        Handler: app.routes(),
-        ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
-        TLSConfig: tlsConfig,
-        IdleTimeout: time.Minute,
-        ReadTimeout: 5 * time.Second,
-        WriteTimeout: 10 * time.Second,
-    }
-
-    logger.Info("Starting server", slog.Any("addr", *addr))
-
-    err = srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem")
-    logger.Error(err.Error())
-    os.Exit(1)
+	err = srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem")
+	logger.Error(err.Error())
+	os.Exit(1)
 }
 
 func openDB(dsn string) (*sql.DB, error) {
-    db, err := sql.Open("sqlite3", dsn)
-    if err != nil {
-        return nil, err
-    }
-    if err = db.Ping(); err != nil {
-        return nil, err
-    }
-    return db, nil
+	db, err := sql.Open("sqlite3", dsn)
+	if err != nil {
+		return nil, err
+	}
+	if err = db.Ping(); err != nil {
+		return nil, err
+	}
+	return db, nil
 }
diff --git a/cmd/web/routes.go b/cmd/web/routes.go
index 81c8b17..fd45458 100644
--- a/cmd/web/routes.go
+++ b/cmd/web/routes.go
@@ -7,35 +7,33 @@ import (
 )
 
 func (app *application) routes() http.Handler {
-    mux := http.NewServeMux()
-    fileServer := http.FileServer(http.Dir("./ui/static"))
-    mux.Handle("GET /static/", http.StripPrefix("/static", fileServer))
-    
-    dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate)
-    standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)
+	mux := http.NewServeMux()
+	fileServer := http.FileServer(http.Dir("./ui/static"))
+	mux.Handle("GET /static/", http.StripPrefix("/static", fileServer))
 
-    mux.Handle("/{$}", dynamic.ThenFunc(app.home))
-    mux.Handle("POST /guestbooks/{id}/comments/create", standard.ThenFunc(app.postGuestbookCommentCreate))
-    mux.Handle("GET /guestbooks/{id}", dynamic.ThenFunc(app.getGuestbook))
-    mux.Handle("GET /users/register", dynamic.ThenFunc(app.getUserRegister))
-    mux.Handle("POST /users/register", dynamic.ThenFunc(app.postUserRegister))
-    mux.Handle("GET /users/login", dynamic.ThenFunc(app.getUserLogin))
-    mux.Handle("POST /users/login", dynamic.ThenFunc(app.postUserLogin))
+	dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate)
+	standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)
 
-    protected := dynamic.Append(app.requireAuthentication)
+	mux.Handle("/{$}", dynamic.ThenFunc(app.home))
+	mux.Handle("POST /websites/{id}/guestbook/comments/create", standard.ThenFunc(app.postGuestbookCommentCreate))
+	mux.Handle("GET /websites/{id}/guestbook", dynamic.ThenFunc(app.getGuestbook))
+	mux.Handle("GET /users/register", dynamic.ThenFunc(app.getUserRegister))
+	mux.Handle("POST /users/register", dynamic.ThenFunc(app.postUserRegister))
+	mux.Handle("GET /users/login", dynamic.ThenFunc(app.getUserLogin))
+	mux.Handle("POST /users/login", dynamic.ThenFunc(app.postUserLogin))
 
-    mux.Handle("GET /users", protected.ThenFunc(app.getUsersList))
-    mux.Handle("GET /users/{id}", protected.ThenFunc(app.getUser))
-    mux.Handle("POST /users/logout", protected.ThenFunc(app.postUserLogout))
-    mux.Handle("GET /guestbooks", protected.ThenFunc(app.getGuestbookList))
-    mux.Handle("GET /guestbooks/create", protected.ThenFunc(app.getGuestbookCreate))
-    mux.Handle("POST /guestbooks/create", protected.ThenFunc(app.postGuestbookCreate))
-    mux.Handle("GET /guestbooks/{id}/dashboard", protected.ThenFunc(app.getGuestbookDashboard))
-    mux.Handle("GET /guestbooks/{id}/dashboard/comments", protected.ThenFunc(app.getGuestbookComments))
-    mux.Handle("GET /guestbooks/{id}/comments/create", protected.ThenFunc(app.getGuestbookCommentCreate))
-    mux.Handle("GET /guestbooks/{id}/dashboard/comments/queue", protected.ThenFunc(app.getCommentQueue))
+	protected := dynamic.Append(app.requireAuthentication)
 
+	// mux.Handle("GET /users", protected.ThenFunc(app.getUsersList))
+	mux.Handle("GET /users/{id}", protected.ThenFunc(app.getUser))
+	mux.Handle("POST /users/logout", protected.ThenFunc(app.postUserLogout))
+	mux.Handle("GET /websites", protected.ThenFunc(app.getWebsiteList))
+	mux.Handle("GET /websites/create", protected.ThenFunc(app.getWebsiteCreate))
+	mux.Handle("POST /websites/create", protected.ThenFunc(app.postWebsiteCreate))
+	mux.Handle("GET /websites/{id}/dashboard", protected.ThenFunc(app.getWebsiteDashboard))
+	mux.Handle("GET /websites/{id}/dashboard/guestbook/comments", protected.ThenFunc(app.getGuestbookComments))
+	mux.Handle("GET /websites/{id}/dashboard/guestbook/comments/queue", protected.ThenFunc(app.getCommentQueue))
+	mux.Handle("GET /websites/{id}/guestbook/comments/create", protected.ThenFunc(app.getGuestbookCommentCreate))
 
-    return standard.Then(mux)
+	return standard.Then(mux)
 }
-
diff --git a/cmd/web/templates.go b/cmd/web/templates.go
deleted file mode 100644
index 7d2908b..0000000
--- a/cmd/web/templates.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"path/filepath"
-	"text/template"
-	"time"
-
-	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
-	"git.32bit.cafe/32bitcafe/guestbook/ui/views"
-	"github.com/justinas/nosurf"
-)
-
-type templateData struct {
-    CurrentYear int
-    User models.User
-    Users []models.User
-    Guestbook models.Guestbook
-    Guestbooks []models.Guestbook
-    Comment models.GuestbookComment
-    Comments []models.GuestbookComment
-    Flash string
-    Form any
-    IsAuthenticated bool
-    CSRFToken string
-    CurrentUser *models.User
-}
-
-func humanDate(t time.Time) string {
-    return t.Format("02 Jan 2006 at 15:04")
-}
-
-var functions = template.FuncMap {
-    "humanDate": humanDate,
-    "shortIdToSlug": shortIdToSlug,
-    "slugToShortId": slugToShortId,
-}
-
-func newHTMXTemplateCache() (map[string]*template.Template, error) {
-    cache := map[string]*template.Template{}
-    pages, err := filepath.Glob("./ui/html/htmx/*.part.html")
-    if err != nil {
-        return nil, err
-    }
-    for _, page := range pages {
-        name := filepath.Base(page)
-        ts, err := template.New(name).Funcs(functions).ParseFiles(page)
-        if err != nil {
-            return nil, err
-        }
-        cache[name] = ts
-    }
-    return cache, nil
-}
-
-func newTemplateCache() (map[string]*template.Template, error) {
-    cache := map[string]*template.Template{}
-    pages, err := filepath.Glob("./ui/html/pages/*.tmpl.html")
-    if err != nil {
-        return nil, err
-    }
-    for _, page := range pages {
-        name := filepath.Base(page)
-        ts, err := template.New(name).Funcs(functions).ParseFiles("./ui/html/base.tmpl.html")
-        if err != nil {
-            return nil, err
-        }
-        ts, err = ts.ParseGlob("./ui/html/partials/*.tmpl.html")
-        if err != nil {
-            return nil, err
-        }
-        ts, err = ts.ParseFiles(page)
-        if err != nil {
-            return nil, err
-        }
-        cache[name] = ts
-    }
-    return cache, nil
-}
-
-func (app *application) newCommonData(r *http.Request) views.CommonData {
-    return views.CommonData {
-        CurrentYear: time.Now().Year(),
-        Flash: app.sessionManager.PopString(r.Context(), "flash"),
-        IsAuthenticated: app.isAuthenticated(r),
-        CSRFToken: nosurf.Token(r),
-        CurrentUser: app.getCurrentUser(r),
-        IsHtmx: r.Header.Get("Hx-Request") == "true",
-    }
-}
-
-func (app *application) newTemplateData(r *http.Request) templateData {
-    return templateData {
-        CurrentYear: time.Now().Year(),
-        Flash: app.sessionManager.PopString(r.Context(), "flash"),
-        IsAuthenticated: app.isAuthenticated(r),
-        CSRFToken: nosurf.Token(r),
-        CurrentUser: app.getCurrentUser(r),
-    }
-}
diff --git a/db/create-session-table-sqlite.sql b/db/create-session-table-sqlite.sql
deleted file mode 100644
index 5dba4f5..0000000
--- a/db/create-session-table-sqlite.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-CREATE TABLE sessions (
-    token CHAR(43) primary key,
-    data BLOB NOT NULL,
-    expiry TEXT NOT NULL
-);
diff --git a/db/create-tables-sqlite.sql b/db/create-tables-sqlite.sql
index 499e068..7b6a121 100644
--- a/db/create-tables-sqlite.sql
+++ b/db/create-tables-sqlite.sql
@@ -9,10 +9,24 @@ CREATE TABLE users (
     Created datetime NOT NULL
 );
 
+CREATE TABLE websites (
+    Id integer primary key autoincrement,
+    ShortId integer UNIQUE NOT NULL,
+    Name varchar(256) NOT NULL,
+    SiteUrl varchar(512) NOT NULL,
+    AuthorName varchar(512) NOT NULL,
+    UserId integer NOT NULL,
+    Created datetime NOT NULL,
+    Deleted datetime,
+    FOREIGN KEY (UserId) REFERENCES users(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT
+);
+
 CREATE TABLE guestbooks (
     Id integer primary key autoincrement,
     ShortId integer UNIQUE NOT NULL,
-    SiteUrl varchar(512) NOT NULL,
+    WebsiteId integer UNIQUE NOT NULL,
     UserId integer NOT NULL,
     Created datetime NOT NULL,
     IsDeleted boolean NOT NULL DEFAULT FALSE,
@@ -20,6 +34,9 @@ CREATE TABLE guestbooks (
     FOREIGN KEY (UserId) REFERENCES users(Id)
         ON DELETE RESTRICT
         ON UPDATE RESTRICT
+    FOREIGN KEY (WebsiteId) REFERENCES websites(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT
 );
 
 CREATE TABLE guestbook_comments (
@@ -44,3 +61,9 @@ CREATE TABLE guestbook_comments (
         ON DELETE RESTRICT
         ON UPDATE RESTRICT
 );
+
+CREATE TABLE sessions (
+    token CHAR(43) primary key,
+    data BLOB NOT NULL,
+    expiry TEXT NOT NULL
+);
diff --git a/internal/forms/forms.go b/internal/forms/forms.go
index fd811f4..8d5664f 100644
--- a/internal/forms/forms.go
+++ b/internal/forms/forms.go
@@ -3,23 +3,29 @@ package forms
 import "git.32bit.cafe/32bitcafe/guestbook/internal/validator"
 
 type UserRegistrationForm struct {
-    Name        string  `schema:"username"`
-    Email       string  `schema:"email"`
-    Password    string  `schema:"password"`
-    validator.Validator `schema:"-"`
+	Name                string `schema:"username"`
+	Email               string `schema:"email"`
+	Password            string `schema:"password"`
+	validator.Validator `schema:"-"`
 }
 
 type UserLoginForm struct {
-    Email       string  `schema:"email"`
-    Password    string  `schema:"password"`
-    validator.Validator `schema:"-"`
+	Email               string `schema:"email"`
+	Password            string `schema:"password"`
+	validator.Validator `schema:"-"`
 }
 
 type CommentCreateForm struct {
-    AuthorName  string  `schema:"authorname"`
-    AuthorEmail string  `schema:"authoremail"`
-    AuthorSite  string  `schema:"authorsite"`
-    Content     string  `schema:"content,required"`
-    validator.Validator `schema:"-"`
+	AuthorName          string `schema:"authorname"`
+	AuthorEmail         string `schema:"authoremail"`
+	AuthorSite          string `schema:"authorsite"`
+	Content             string `schema:"content,required"`
+	validator.Validator `schema:"-"`
 }
 
+type WebsiteCreateForm struct {
+	Name                string `schema:"sitename"`
+	SiteUrl             string `schema:"siteurl"`
+	AuthorName          string `schema:"authorname"`
+	validator.Validator `schema:"-"`
+}
diff --git a/internal/models/guestbook.go b/internal/models/guestbook.go
index 133330a..a216572 100644
--- a/internal/models/guestbook.go
+++ b/internal/models/guestbook.go
@@ -8,8 +8,8 @@ import (
 type Guestbook struct {
 	ID        int64
 	ShortId   uint64
-	SiteUrl   string
 	UserId    int64
+	WebsiteId int64
 	Created   time.Time
 	IsDeleted bool
 	IsActive  bool
@@ -19,10 +19,10 @@ type GuestbookModel struct {
 	DB *sql.DB
 }
 
-func (m *GuestbookModel) Insert(shortId uint64, siteUrl string, userId int64) (int64, error) {
-	stmt := `INSERT INTO guestbooks (ShortId, SiteUrl, UserId, Created, IsDeleted, IsActive)
+func (m *GuestbookModel) Insert(shortId uint64, userId int64, websiteId int64) (int64, error) {
+	stmt := `INSERT INTO guestbooks (ShortId, UserId, WebsiteId, Created, IsDeleted, IsActive)
     VALUES(?, ?, ?, ?, FALSE, TRUE)`
-	result, err := m.DB.Exec(stmt, shortId, siteUrl, userId, time.Now().UTC())
+	result, err := m.DB.Exec(stmt, shortId, userId, websiteId, time.Now().UTC())
 	if err != nil {
 		return -1, err
 	}
@@ -34,11 +34,11 @@ func (m *GuestbookModel) Insert(shortId uint64, siteUrl string, userId int64) (i
 }
 
 func (m *GuestbookModel) Get(shortId uint64) (Guestbook, error) {
-	stmt := `SELECT Id, ShortId, SiteUrl, UserId, Created, IsDeleted, IsActive FROM guestbooks
+	stmt := `SELECT Id, ShortId, UserId, WebsiteId, Created, IsDeleted, IsActive FROM guestbooks
     WHERE ShortId = ?`
 	row := m.DB.QueryRow(stmt, shortId)
 	var g Guestbook
-	err := row.Scan(&g.ID, &g.ShortId, &g.SiteUrl, &g.UserId, &g.Created, &g.IsDeleted, &g.IsActive)
+	err := row.Scan(&g.ID, &g.ShortId, &g.UserId, &g.WebsiteId, &g.Created, &g.IsDeleted, &g.IsActive)
 	if err != nil {
 		return Guestbook{}, err
 	}
@@ -47,7 +47,7 @@ func (m *GuestbookModel) Get(shortId uint64) (Guestbook, error) {
 }
 
 func (m *GuestbookModel) GetAll(userId int64) ([]Guestbook, error) {
-	stmt := `SELECT Id, ShortId, SiteUrl, UserId, Created, IsDeleted, IsActive FROM guestbooks
+	stmt := `SELECT Id, ShortId, UserId, WebsiteId, Created, IsDeleted, IsActive FROM guestbooks
     WHERE UserId = ?`
 	rows, err := m.DB.Query(stmt, userId)
 	if err != nil {
@@ -56,7 +56,7 @@ func (m *GuestbookModel) GetAll(userId int64) ([]Guestbook, error) {
 	var guestbooks []Guestbook
 	for rows.Next() {
 		var g Guestbook
-		err = rows.Scan(&g.ID, &g.ShortId, &g.SiteUrl, &g.UserId, &g.Created, &g.IsDeleted, &g.IsActive)
+		err = rows.Scan(&g.ID, &g.ShortId, &g.UserId, &g.WebsiteId, &g.Created, &g.IsDeleted, &g.IsActive)
 		if err != nil {
 			return nil, err
 		}
diff --git a/internal/models/guestbookcomment.go b/internal/models/guestbookcomment.go
index 05442f5..e936304 100644
--- a/internal/models/guestbookcomment.go
+++ b/internal/models/guestbookcomment.go
@@ -6,110 +6,110 @@ import (
 )
 
 type GuestbookComment struct {
-    ID int64
-    ShortId uint64
-    GuestbookId int64
-    ParentId int64
-    AuthorName string
-    AuthorEmail string
-    AuthorSite string
-    CommentText string
-    PageUrl string
-    Created time.Time
-    IsPublished bool
-    IsDeleted bool
+	ID          int64
+	ShortId     uint64
+	GuestbookId int64
+	ParentId    int64
+	AuthorName  string
+	AuthorEmail string
+	AuthorSite  string
+	CommentText string
+	PageUrl     string
+	Created     time.Time
+	IsPublished bool
+	IsDeleted   bool
 }
 
 type GuestbookCommentModel struct {
-    DB *sql.DB
+	DB *sql.DB
 }
 
 func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
-    authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
-    stmt := `INSERT INTO guestbook_comments (ShortId, GuestbookId, ParentId, AuthorName,
+	authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
+	stmt := `INSERT INTO guestbook_comments (ShortId, GuestbookId, ParentId, AuthorName,
     AuthorEmail, AuthorSite, CommentText, PageUrl, Created, IsPublished, IsDeleted)
     VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE)`
-    result, err := m.DB.Exec(stmt, shortId, guestbookId, parentId, authorName, authorEmail,
-	authorSite, commentText, pageUrl, time.Now().UTC(), isPublished)
-    if err != nil {
-	return -1, err
-    }
-    id, err := result.LastInsertId()
-    if err != nil {
-	return -1, err
-    }
-    return id, nil
+	result, err := m.DB.Exec(stmt, shortId, guestbookId, parentId, authorName, authorEmail,
+		authorSite, commentText, pageUrl, time.Now().UTC(), isPublished)
+	if err != nil {
+		return -1, err
+	}
+	id, err := result.LastInsertId()
+	if err != nil {
+		return -1, err
+	}
+	return id, nil
 }
 
 func (m *GuestbookCommentModel) Get(shortId uint64) (GuestbookComment, error) {
-    stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite,
+	stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite,
     CommentText, PageUrl, Created, IsPublished, IsDeleted FROM guestbook_comments WHERE ShortId = ?`
-    row := m.DB.QueryRow(stmt, shortId)
-    var c GuestbookComment
-    err := row.Scan(&c.ID, &c.ShortId, &c.GuestbookId, &c.ParentId, &c.AuthorName, &c.AuthorEmail, &c.AuthorSite, &c.CommentText, &c.PageUrl, &c.Created, &c.IsPublished, &c.IsDeleted)
-    if err != nil {
-	return GuestbookComment{}, err
-    }
-    return c, nil
+	row := m.DB.QueryRow(stmt, shortId)
+	var c GuestbookComment
+	err := row.Scan(&c.ID, &c.ShortId, &c.GuestbookId, &c.ParentId, &c.AuthorName, &c.AuthorEmail, &c.AuthorSite, &c.CommentText, &c.PageUrl, &c.Created, &c.IsPublished, &c.IsDeleted)
+	if err != nil {
+		return GuestbookComment{}, err
+	}
+	return c, nil
 }
 
 func (m *GuestbookCommentModel) GetAll(guestbookId int64) ([]GuestbookComment, error) {
-    stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite,
+	stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite,
     CommentText, PageUrl, Created, IsPublished, IsDeleted 
 	    FROM guestbook_comments 
 	    WHERE GuestbookId = ? AND IsDeleted = FALSE AND IsPublished = TRUE
 	    ORDER BY Created DESC`
-    rows, err := m.DB.Query(stmt, guestbookId)
-    if err != nil {
-	return nil, err
-    }
-    var comments []GuestbookComment
-    for rows.Next() {
-	var c GuestbookComment
-	err = rows.Scan(&c.ID, &c.ShortId, &c.GuestbookId, &c.ParentId, &c.AuthorName, &c.AuthorEmail, &c.AuthorSite, &c.CommentText, &c.PageUrl, &c.Created, &c.IsPublished, &c.IsDeleted)
+	rows, err := m.DB.Query(stmt, guestbookId)
 	if err != nil {
-	    return nil, err
+		return nil, err
 	}
-	comments = append(comments, c)
-    }
-    if err = rows.Err(); err != nil {
-	return nil, err
-    }
-    return comments, nil
+	var comments []GuestbookComment
+	for rows.Next() {
+		var c GuestbookComment
+		err = rows.Scan(&c.ID, &c.ShortId, &c.GuestbookId, &c.ParentId, &c.AuthorName, &c.AuthorEmail, &c.AuthorSite, &c.CommentText, &c.PageUrl, &c.Created, &c.IsPublished, &c.IsDeleted)
+		if err != nil {
+			return nil, err
+		}
+		comments = append(comments, c)
+	}
+	if err = rows.Err(); err != nil {
+		return nil, err
+	}
+	return comments, nil
 }
 
 func (m *GuestbookCommentModel) GetQueue(guestbookId int64) ([]GuestbookComment, error) {
-    stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite,
+	stmt := `SELECT Id, ShortId, GuestbookId, ParentId, AuthorName, AuthorEmail, AuthorSite,
     CommentText, PageUrl, Created, IsPublished, IsDeleted 
 	    FROM guestbook_comments 
 	    WHERE GuestbookId = ? AND IsDeleted = FALSE AND IsPublished = FALSE
 	    ORDER BY Created DESC`
-    rows, err := m.DB.Query(stmt, guestbookId)
-    if err != nil {
-	return nil, err
-    }
-    var comments []GuestbookComment
-    for rows.Next() {
-	var c GuestbookComment
-	err = rows.Scan(&c.ID, &c.ShortId, &c.GuestbookId, &c.ParentId, &c.AuthorName, &c.AuthorEmail, &c.AuthorSite, &c.CommentText, &c.PageUrl, &c.Created, &c.IsPublished, &c.IsDeleted)
+	rows, err := m.DB.Query(stmt, guestbookId)
 	if err != nil {
-	    return nil, err
+		return nil, err
 	}
-	comments = append(comments, c)
-    }
-    if err = rows.Err(); err != nil {
-	return nil, err
-    }
-    return comments, nil
+	var comments []GuestbookComment
+	for rows.Next() {
+		var c GuestbookComment
+		err = rows.Scan(&c.ID, &c.ShortId, &c.GuestbookId, &c.ParentId, &c.AuthorName, &c.AuthorEmail, &c.AuthorSite, &c.CommentText, &c.PageUrl, &c.Created, &c.IsPublished, &c.IsDeleted)
+		if err != nil {
+			return nil, err
+		}
+		comments = append(comments, c)
+	}
+	if err = rows.Err(); err != nil {
+		return nil, err
+	}
+	return comments, nil
 }
 
 func (m *GuestbookCommentModel) UpdateComment(comment *GuestbookComment) error {
-    stmt := `UPDATE guestbook_comments (CommentText, PageUrl, IsPublished, IsDeleted)
+	stmt := `UPDATE guestbook_comments (CommentText, PageUrl, IsPublished, IsDeleted)
 		VALUES (?, ?, ?, ?)
 		WHERE Id = ?`
-    _, err := m.DB.Exec(stmt, comment.CommentText, comment.PageUrl, comment.IsPublished, comment.IsDeleted, comment.ID)
-    if err != nil {
-	return err
-    }
-    return nil
+	_, err := m.DB.Exec(stmt, comment.CommentText, comment.PageUrl, comment.IsPublished, comment.IsDeleted, comment.ID)
+	if err != nil {
+		return err
+	}
+	return nil
 }
diff --git a/internal/models/website.go b/internal/models/website.go
new file mode 100644
index 0000000..1b9da9f
--- /dev/null
+++ b/internal/models/website.go
@@ -0,0 +1,102 @@
+package models
+
+import (
+	"database/sql"
+	"time"
+)
+
+type Website struct {
+	ID         int64
+	ShortId    uint64
+	Name       string
+	SiteUrl    string
+	AuthorName string
+	UserId     int64
+	Created    time.Time
+	Deleted    time.Time
+	Guestbook  Guestbook
+}
+
+type WebsiteModel struct {
+	DB *sql.DB
+}
+
+func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
+	stmt := `INSERT INTO websites (ShortId, Name, SiteUrl, AuthorName, UserId, Created)
+			VALUES (?, ?, ?, ?, ?, ?)`
+	result, err := m.DB.Exec(stmt, shortId, siteName, siteUrl, authorName, userId, time.Now().UTC())
+	if err != nil {
+		return -1, err
+	}
+	id, err := result.LastInsertId()
+	if err != nil {
+		return -1, err
+	}
+	return id, nil
+}
+
+func (m *WebsiteModel) Get(shortId uint64) (Website, error) {
+	stmt := `SELECT w.Id, w.ShortId, w.Name, w.SiteUrl, w.AuthorName, w.UserId, w.Created, w.Deleted,
+	g.Id, g.ShortId, g.Created, g.IsDeleted, g.IsActive
+	FROM websites AS w INNER JOIN guestbooks AS g ON w.Id = g.WebsiteId
+	WHERE w.ShortId = ?`
+	row := m.DB.QueryRow(stmt, shortId)
+	var t sql.NullTime
+	var w Website
+	err := row.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created, &t,
+		&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsDeleted, &w.Guestbook.IsActive)
+	if err != nil {
+		return Website{}, err
+	}
+	// handle if Deleted is null
+	if t.Valid {
+		w.Deleted = t.Time
+	}
+	return w, nil
+}
+
+func (m *WebsiteModel) GetById(id int64) (Website, error) {
+	stmt := `SELECT w.Id, w.ShortId, w.Name, w.SiteUrl, w.AuthorName, w.UserId, w.Created, w.Deleted,
+	g.Id, g.ShortId, g.Created, g.IsDeleted, g.IsActive
+	FROM websites AS w INNER JOIN guestbooks AS g ON w.Id = g.WebsiteId
+	WHERE w.Id = ?`
+	row := m.DB.QueryRow(stmt, id)
+	var t sql.NullTime
+	var w Website
+	err := row.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created, &t,
+		&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsDeleted, &w.Guestbook.IsActive)
+	if err != nil {
+		return Website{}, err
+	}
+	// handle if Deleted is null
+	if t.Valid {
+		w.Deleted = t.Time
+	}
+	return w, nil
+}
+
+func (m *WebsiteModel) GetAll(userId int64) ([]Website, error) {
+	stmt := `SELECT w.Id, w.ShortId, w.Name, w.SiteUrl, w.AuthorName, w.UserId, w.Created, w.Deleted,
+	g.Id, g.ShortId, g.Created, g.IsDeleted, g.IsActive
+	FROM websites AS w INNER JOIN guestbooks AS g ON w.Id = g.WebsiteId
+	WHERE w.UserId = ?`
+	rows, err := m.DB.Query(stmt, userId)
+	if err != nil {
+		return nil, err
+	}
+	var websites []Website
+	for rows.Next() {
+		var t sql.NullTime
+		var w Website
+		err := rows.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created, &t,
+			&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsDeleted, &w.Guestbook.IsActive)
+		if err != nil {
+			return nil, err
+		}
+		websites = append(websites, w)
+	}
+	if err = rows.Err(); err != nil {
+		return nil, err
+	}
+	return websites, nil
+}
diff --git a/ui/html/base.tmpl.html b/ui/html/base.tmpl.html
deleted file mode 100644
index 1a88342..0000000
--- a/ui/html/base.tmpl.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{{ define "base" }}
-
-
-    
-        {{ template "title" }} - webweav.ing
-        
-        
-        
-        
-    
-    
-        
-        {{ template "nav" . }}
-        
-            {{ with .Flash }}
-                {{ . }}
-            {{ end }}
-            {{ template "main" . }}
-        
-        
-    
-
-{{ end }}
diff --git a/ui/html/htmx/guestbookcreate.part.html b/ui/html/htmx/guestbookcreate.part.html
deleted file mode 100644
index 8f4988c..0000000
--- a/ui/html/htmx/guestbookcreate.part.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/ui/html/htmx/guestbookcreatebutton.part.html b/ui/html/htmx/guestbookcreatebutton.part.html
deleted file mode 100644
index 4c13ddc..0000000
--- a/ui/html/htmx/guestbookcreatebutton.part.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/html/htmx/guestbooklist.part.html b/ui/html/htmx/guestbooklist.part.html
deleted file mode 100644
index e67ec68..0000000
--- a/ui/html/htmx/guestbooklist.part.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/ui/html/htmx/newguestbook.part.html b/ui/html/htmx/newguestbook.part.html
deleted file mode 100644
index 89bbb56..0000000
--- a/ui/html/htmx/newguestbook.part.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{{ with .Guestbook }}
-
-    {{ with .SiteUrl }}{{ . }}{{ else }}Untitled{{ end }}
-
-{{ end }}
diff --git a/ui/html/pages/commentcreate.view.tmpl.html b/ui/html/pages/commentcreate.view.tmpl.html
deleted file mode 100644
index 56ecba8..0000000
--- a/ui/html/pages/commentcreate.view.tmpl.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{{ define "title" }}New Comment{{ end }}
-{{ define "main" }}
-
-{{ end }}
diff --git a/ui/html/pages/guestbook.view.tmpl.html b/ui/html/pages/guestbook.view.tmpl.html
deleted file mode 100644
index 36815d2..0000000
--- a/ui/html/pages/guestbook.view.tmpl.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{{ define "title" }} Guestbook View {{ end }}
-{{ define "main" }}
-Guestbook for {{ .Guestbook.SiteUrl }}
-
-    New Comment
-
-{{ range .Comments }}
-    
-        
 {{ .AuthorName }} 
-        {{ .Created.Local.Format "01-02-2006 03:04PM" }}
-        
-            {{ .CommentText }}
-        
-    
 
-{{ else }}
-No comments yet!
-{{ end }}
-{{ end }}
diff --git a/ui/html/pages/guestbookcreate.view.tmpl.html b/ui/html/pages/guestbookcreate.view.tmpl.html
deleted file mode 100644
index 313bb3a..0000000
--- a/ui/html/pages/guestbookcreate.view.tmpl.html
+++ /dev/null
@@ -1,4 +0,0 @@
-{{ define "title" }}Create a Guestbook{{ end }}
-{{ define "main" }}
-{{ template "guestbookcreate" }}
-{{ end }}
diff --git a/ui/html/pages/guestbooklist.view.tmpl.html b/ui/html/pages/guestbooklist.view.tmpl.html
deleted file mode 100644
index 59857e4..0000000
--- a/ui/html/pages/guestbooklist.view.tmpl.html
+++ /dev/null
@@ -1,14 +0,0 @@
-{{ define "title" }} Guestbooks  {{ end }}
-{{ define "main" }}
-Guestbooks run by {{ .User.Username }}
-
-    
-
-
-{{ end }}
diff --git a/ui/html/pages/home.tmpl.html b/ui/html/pages/home.tmpl.html
deleted file mode 100644
index eab8f4e..0000000
--- a/ui/html/pages/home.tmpl.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{{ define "title" }}Home{{ end }}
-{{ define "main" }}
-{{ if .IsAuthenticated }}
-Tools
-
-    Guestbooks
-
-{{ else }}
-Welcome
-Welcome to webweav.ing, a collection of webmastery tools created by the 32-Bit Cafe.
-{{ end }}
-{{ end }}
diff --git a/ui/html/pages/login.view.tmpl.html b/ui/html/pages/login.view.tmpl.html
deleted file mode 100644
index 7c49690..0000000
--- a/ui/html/pages/login.view.tmpl.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{{define "title"}}Login{{end}}
-{{define "main"}}
-
-{{end}}
diff --git a/ui/html/pages/user.view.tmpl.html b/ui/html/pages/user.view.tmpl.html
deleted file mode 100644
index 88f1d30..0000000
--- a/ui/html/pages/user.view.tmpl.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{{ define "title" }}{{ .User.Username }}{{ end }}
-{{ define "main" }}
-{{ .User.Username }}
-{{ .User.Email }}
-{{ end }}
diff --git a/ui/html/pages/usercreate.view.tmpl.html b/ui/html/pages/usercreate.view.tmpl.html
deleted file mode 100644
index bea95fb..0000000
--- a/ui/html/pages/usercreate.view.tmpl.html
+++ /dev/null
@@ -1,30 +0,0 @@
-{{ define "title" }}User Registration{{ end }}
-{{ define "main" }}
-
-{{ end }}
diff --git a/ui/html/pages/userlist.view.tmpl.html b/ui/html/pages/userlist.view.tmpl.html
deleted file mode 100644
index 69fb054..0000000
--- a/ui/html/pages/userlist.view.tmpl.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{{ define "title" }}Users{{ end }}
-{{ define "main" }}
-    Users
-    {{ range .Users }}
-        
-        {{ .Username }}
-        
-    {{ end }}
-{{ end }}
diff --git a/ui/html/partials/guestbookcreate.part.tmpl.html b/ui/html/partials/guestbookcreate.part.tmpl.html
deleted file mode 100644
index 55ce6a4..0000000
--- a/ui/html/partials/guestbookcreate.part.tmpl.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{{ define "guestbookcreate" }}
-
-{{ end }}
diff --git a/ui/html/partials/nav.tmpl.html b/ui/html/partials/nav.tmpl.html
deleted file mode 100644
index 7fcf69e..0000000
--- a/ui/html/partials/nav.tmpl.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{{ define "nav" }}
-
-{{ end }}
diff --git a/ui/views/common.templ b/ui/views/common.templ
index b89b543..3f081a3 100644
--- a/ui/views/common.templ
+++ b/ui/views/common.templ
@@ -30,14 +30,13 @@ templ commonHeader() {
 templ topNav(data CommonData) {