diff --git a/README.md b/README.md
index 607ee31..96adb11 100644
--- a/README.md
+++ b/README.md
@@ -39,4 +39,6 @@ Check out our [Next.js deployment documentation](https://nextjs.org/docs/deploym
```sql
CREATE TABLE aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, address TEXT NOT NULL, alias TEXT NOT NULL, pending INTEGER DEFAULT 0, temporary INTEGER DEFAULT 0);
CREATE TABLE temp_alias_requests (key TEXT PRIMARY KEY, address TEXT NOT NULL, alias TEXT NOT NULL, expires INTEGER NOT NULL);
+
+CREATE TABLE api_keys (id INTEGER PRIMARY KEY AUTOINCREMENT, address TEXT NOT NULL, token TEXT NOT NULL);
```
diff --git a/src/app/admin/aliases/page.tsx b/src/app/(dashboard)/admin/aliases/page.tsx
similarity index 100%
rename from src/app/admin/aliases/page.tsx
rename to src/app/(dashboard)/admin/aliases/page.tsx
diff --git a/src/app/admin/audit/page.tsx b/src/app/(dashboard)/admin/audit/page.tsx
similarity index 100%
rename from src/app/admin/audit/page.tsx
rename to src/app/(dashboard)/admin/audit/page.tsx
diff --git a/src/app/admin/users/page.tsx b/src/app/(dashboard)/admin/users/page.tsx
similarity index 100%
rename from src/app/admin/users/page.tsx
rename to src/app/(dashboard)/admin/users/page.tsx
diff --git a/src/app/(dashboard)/api-keys/page.tsx b/src/app/(dashboard)/api-keys/page.tsx
new file mode 100644
index 0000000..2fafa82
--- /dev/null
+++ b/src/app/(dashboard)/api-keys/page.tsx
@@ -0,0 +1,19 @@
+import { Button, Flex, Heading, Text } from "@radix-ui/themes";
+import { ExternalLinkIcon } from "lucide-react";
+import Link from "next/link";
+
+export default function ApiKeys() {
+ return (
+ <>
+
+
+ API keys
+ Generate long lasting API keys that can be used to perform certain actions programatically.
+
+
+
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/app/favicon.ico b/src/app/(dashboard)/favicon.ico
similarity index 100%
rename from src/app/favicon.ico
rename to src/app/(dashboard)/favicon.ico
diff --git a/src/app/globals.css b/src/app/(dashboard)/globals.css
similarity index 100%
rename from src/app/globals.css
rename to src/app/(dashboard)/globals.css
diff --git a/src/app/layout.tsx b/src/app/(dashboard)/layout.tsx
similarity index 100%
rename from src/app/layout.tsx
rename to src/app/(dashboard)/layout.tsx
diff --git a/src/app/page.tsx b/src/app/(dashboard)/page.tsx
similarity index 100%
rename from src/app/page.tsx
rename to src/app/(dashboard)/page.tsx
diff --git a/src/app/self-service/page.tsx b/src/app/(dashboard)/self-service/page.tsx
similarity index 100%
rename from src/app/self-service/page.tsx
rename to src/app/(dashboard)/self-service/page.tsx
diff --git a/src/app/(swagger)/api-doc/page.tsx b/src/app/(swagger)/api-doc/page.tsx
new file mode 100644
index 0000000..0259c5f
--- /dev/null
+++ b/src/app/(swagger)/api-doc/page.tsx
@@ -0,0 +1,11 @@
+import { getApiDocs } from '@/lib/swagger';
+import ReactSwagger from './swagger';
+
+export default async function IndexPage() {
+ const spec = await getApiDocs();
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/(swagger)/api-doc/swagger.tsx b/src/app/(swagger)/api-doc/swagger.tsx
new file mode 100644
index 0000000..35c8675
--- /dev/null
+++ b/src/app/(swagger)/api-doc/swagger.tsx
@@ -0,0 +1,14 @@
+'use client';
+
+import SwaggerUI from 'swagger-ui-react';
+import 'swagger-ui-react/swagger-ui.css';
+
+type Props = {
+ spec: Record,
+};
+
+function ReactSwagger({ spec }: Props) {
+ return ;
+}
+
+export default ReactSwagger;
diff --git a/src/app/(swagger)/layout.tsx b/src/app/(swagger)/layout.tsx
new file mode 100644
index 0000000..0e06e54
--- /dev/null
+++ b/src/app/(swagger)/layout.tsx
@@ -0,0 +1,13 @@
+export default async function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/src/app/api/test/route.ts b/src/app/api/test/route.ts
new file mode 100644
index 0000000..475f931
--- /dev/null
+++ b/src/app/api/test/route.ts
@@ -0,0 +1,15 @@
+/**
+ * @swagger
+ * /api/test:
+ * get:
+ * description: Returns the hello world
+ * responses:
+ * 200:
+ * description: Hello World!
+ */
+export async function GET(_request: Request) {
+ // Do whatever you want
+ return new Response('Hello World!', {
+ status: 200,
+ });
+}
\ No newline at end of file
diff --git a/src/lib/components/ui/NavigationPanel.tsx b/src/lib/components/ui/NavigationPanel.tsx
index ef61263..f0ac510 100644
--- a/src/lib/components/ui/NavigationPanel.tsx
+++ b/src/lib/components/ui/NavigationPanel.tsx
@@ -2,7 +2,7 @@
import { isAdmin } from "@/lib/util";
import { Avatar, Button, Card, Flex, IconButton, Popover, ScrollArea, Text, Tooltip } from "@radix-ui/themes";
-import { BookUserIcon, HomeIcon, ScrollTextIcon, Users2Icon } from "lucide-react";
+import { BookUserIcon, HomeIcon, KeyRoundIcon, ScrollTextIcon, Users2Icon } from "lucide-react";
import { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import dayjs from "dayjs";
@@ -67,6 +67,14 @@ export default function NavigationPanel({ mobileUi }: { mobileUi?: boolean }) {
+
+
+
+
+
+
+
+
{isAdmin(session.data) && (
<>
diff --git a/src/lib/swagger.ts b/src/lib/swagger.ts
new file mode 100644
index 0000000..5c94c37
--- /dev/null
+++ b/src/lib/swagger.ts
@@ -0,0 +1,25 @@
+import { createSwaggerSpec } from 'next-swagger-doc';
+
+export const getApiDocs = async () => {
+ const spec = createSwaggerSpec({
+ apiFolder: 'src/app/api', // define api folder under app folder
+ definition: {
+ openapi: '3.0.0',
+ info: {
+ title: 'Maddy Panel API',
+ version: '1.0',
+ },
+ components: {
+ securitySchemes: {
+ BearerAuth: {
+ type: 'http',
+ scheme: 'bearer',
+ bearerFormat: 'JWT',
+ },
+ },
+ },
+ security: [],
+ },
+ });
+ return spec;
+};
\ No newline at end of file