Index: pages/+Layout.telefunc.ts
===================================================================
--- pages/+Layout.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
+++ pages/+Layout.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
@@ -0,0 +1,95 @@
+import * as drizzleQueries from "../database/drizzle/queries";
+import {ctx, getAuthState, requireUser} from "../server/telefunc/ctx";
+import {Abort} from "telefunc";
+
+export async function getAuthenticationState() {
+    const c = getAuthState();
+
+    return c;
+}
+
+export async function getPopupAllComponents({ componentType, q, limit }
+                                            : { componentType?: string; q?: string; limit?: number }) {
+    const c = ctx();
+
+    // getAllComponents
+}
+
+export async function getPopupAllApprovedBuilds({ limit, q }
+                                                 : { limit?: number; q?: string }) {
+    const context = ctx();
+
+    const approvedBuilds = await drizzleQueries.getApprovedBuilds(context.db, limit, q);
+
+    return approvedBuilds;
+}
+
+export async function getPopupHighestRankedBuilds({ limit }
+                                                  : { limit?: number }) {
+    const context = ctx();
+
+    const highestRankedBuilds = await drizzleQueries.getHighestRankedBuilds(context.db, limit);
+
+    return highestRankedBuilds;
+}
+
+// Shared
+
+export async function getPopupBuildDetails({ buildId }
+                                           : { buildId: number }) {
+    const context = ctx();
+
+    if(!Number.isInteger(buildId) || buildId <= 0) throw Abort();
+
+    const buildDetails = await drizzleQueries.getBuildDetails(context.db, buildId);
+
+    if(!buildDetails) throw Abort();
+
+    return buildDetails;
+}
+
+export async function togglePopupFavorite({ buildId }
+                                          : { buildId: number }) {
+    const { c, userId } = requireUser()
+
+    if (!Number.isInteger(buildId) || buildId <= 0) throw Abort();
+
+    const isFavorite = await drizzleQueries.toggleFavoriteBuild(c.db, userId, buildId);
+
+    return isFavorite.favorite;
+}
+
+export async function setPopupRating({ buildId, value }
+                                     : { buildId: number; value: number }) {
+    const { c, userId } = requireUser()
+
+    if (!Number.isInteger(buildId) || buildId <= 0) throw Abort();
+
+    const result = await drizzleQueries.setBuildRating(c.db, userId, buildId, value);
+
+    return { success: true };
+}
+
+export async function setPopupReview({ buildId, content }
+                                     : { buildId: number; content: string }) {
+    const { c, userId } = requireUser()
+
+    if (!Number.isInteger(buildId) || buildId <= 0) throw Abort();
+
+    const result = await drizzleQueries.setBuildReview(c.db, userId, buildId, content);
+
+    return { success: true };
+}
+
+export async function clonePopupBuild({ buildId }
+                                      : { buildId: number }) {
+    const { c, userId } = requireUser()
+
+    if (!Number.isInteger(buildId) || buildId <= 0) throw Abort();
+
+    const newBuildId = await drizzleQueries.cloneBuild(c.db, userId, buildId);
+
+    if (!newBuildId) throw Abort();
+
+    return newBuildId;
+}
Index: pages/auth/register/register.telefunc.ts
===================================================================
--- pages/auth/register/register.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
+++ pages/auth/register/register.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
@@ -0,0 +1,18 @@
+import * as drizzleQueries from "../../../database/drizzle/queries/users";
+import { ctx } from "../../../server/telefunc/ctx";
+import { Abort } from "telefunc";
+import bcrypt from "bcrypt";
+
+export async function registerNewUser({ username, email, password }
+                                      : { username: string; email: string; password: string }) {
+    const c = ctx();
+
+    if (c.session?.user?.id) throw Abort();
+
+    if(!username || !email || !password) throw Abort();
+
+    const passwordHash = await bcrypt.hash(password, 8);
+    await drizzleQueries.createUser(c.db, username, email, passwordHash);
+
+    return { success: true };
+}
Index: pages/dashboard/admin/adminDashboard.telefunc.ts
===================================================================
--- pages/dashboard/admin/adminDashboard.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
+++ pages/dashboard/admin/adminDashboard.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
@@ -0,0 +1,43 @@
+import * as drizzleQueries from "../../../database/drizzle/queries";
+import { requireAdmin } from "../../../server/telefunc/ctx";
+import {Abort} from "telefunc";
+
+export async function getAdminInfoAndData() {
+    const { c, userId } = await requireAdmin();
+
+    const admin = await drizzleQueries.getUserProfile(c.db, userId);
+
+    if (!admin) throw new Error();
+
+    const pendingBuilds = await drizzleQueries.getPendingBuilds(c.db);
+    const userBuilds = await drizzleQueries.getUserBuilds(c.db, userId);
+    // const componentSuggestions = await drizzleQueries.getComponentSuggestions(c.db);
+
+    return {
+        admin,
+        pendingBuilds,
+        userBuilds,
+        // componentSuggestions
+    };
+}
+
+export async function setPopupBuildApprovalStatus({ buildId, isApproved }
+                                                 : { buildId: number; isApproved: boolean }) {
+    const { c, userId } = await requireAdmin()
+
+    if (!Number.isInteger(buildId) || buildId <= 0) throw Abort();
+
+    const result = await drizzleQueries.setBuildApprovalStatus(c.db, buildId, isApproved);
+
+    if (!result) throw Abort();
+
+    return { success: true };
+}
+
+export async function setComponentSuggestionStatus({ suggestionId, status, adminComment }
+                                                : { suggestionId: number; status: string; adminComment: string }) {
+    const { c, userId } = await requireAdmin()
+
+
+    // setComponentSuggestionStatus
+}
Index: pages/dashboard/user/userDashboard.telefunc.ts
===================================================================
--- pages/dashboard/user/userDashboard.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
+++ pages/dashboard/user/userDashboard.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
@@ -0,0 +1,19 @@
+import * as drizzleQueries from "../../../database/drizzle/queries";
+import {requireUser} from "../../../server/telefunc/ctx";
+
+export async function getUserInfoAndData() {
+    const { c, userId } = requireUser()
+
+    const user = await drizzleQueries.getUserProfile(c.db, userId);
+
+    if (!user) throw new Error();
+
+    const userBuilds = await drizzleQueries.getUserBuilds(c.db, userId);
+    const favoriteBuilds = await drizzleQueries.getFavoriteBuilds(c.db, userId);
+
+    return {
+        user,
+        userBuilds,
+        favoriteBuilds
+    };
+}
Index: pages/index/Counter.tsx
===================================================================
--- pages/index/Counter.tsx	(revision c30935a5f027dac0916111525d007c79078ea267)
+++ 	(revision )
@@ -1,11 +1,0 @@
-import { useState } from "react";
-
-export function Counter() {
-  const [count, setCount] = useState(0);
-
-  return (
-    <button type="button" onClick={() => setCount((count) => count + 1)}>
-      Counter {count}
-    </button>
-  );
-}
Index: pages/index/approvedBuilds.telefunc.ts
===================================================================
--- pages/index/approvedBuilds.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
+++ pages/index/approvedBuilds.telefunc.ts	(revision 0d447f67907253e18370e3a36e37b0cf72ebb964)
@@ -0,0 +1,11 @@
+import * as drizzleQueries from "../../database/drizzle/queries";
+import { ctx } from "../../server/telefunc/ctx";
+
+export async function getApprovedBuildCards( { limit }
+                                       : { limit?: number }) {
+    const context = ctx();
+
+    const approvedBuilds = await drizzleQueries.getApprovedBuilds(context.db, limit);
+
+    return approvedBuilds;
+}
