Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
BETTER_AUTH_SECRET=
BETTER_AUTH_URL=http://localhost:3000

POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=awaketh

NEXT_PUBLIC_GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
Comment on lines +1 to +9

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Files of interest ==\n'
git ls-files '.env.example' 'src/lib/auth.ts' 'src/**' | sed -n '1,200p'

printf '\n== Search for Turnstile env usage ==\n'
rg -n "TURNSTILE|turnstile|CF_TURNSTILE|cloudflare" . --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**'

printf '\n== .env.example ==\n'
cat -n .env.example

printf '\n== src/lib/auth.ts ==\n'
cat -n src/lib/auth.ts

Repository: Awaketh/awaketh

Length of output: 5541


Add the missing Turnstile env vars. .env.example should include CF_TURNSTILE_SECRET_KEY and NEXT_PUBLIC_CF_TURNSTILE_SITE_KEY; src/lib/auth.ts and the auth forms read both, so fresh setups can’t configure CAPTCHA end-to-end without them.

🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 5-5: [UnorderedKey] The POSTGRES_PASSWORD key should go before the POSTGRES_USER key

(UnorderedKey)


[warning] 6-6: [UnorderedKey] The POSTGRES_DB key should go before the POSTGRES_PASSWORD key

(UnorderedKey)


[warning] 9-9: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 9-9: [UnorderedKey] The GOOGLE_CLIENT_SECRET key should go before the NEXT_PUBLIC_GOOGLE_CLIENT_ID key

(UnorderedKey)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.env.example around lines 1 - 9, Add CF_TURNSTILE_SECRET_KEY and
NEXT_PUBLIC_CF_TURNSTILE_SITE_KEY to the environment variable template in
.env.example, alongside the existing authentication and public client
configuration entries, so both auth.ts and the authentication forms can be
configured for Turnstile.

Source: MCP tools

2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
restore-keys: bun-${{ runner.os }}-

- name: Install dependencies
run: bun install --frozen-lockfile
run: bun install --frozen-lockfile --ignore-scripts

- name: Run ${{ matrix.name }}
run: ${{ matrix.run }}
34 changes: 33 additions & 1 deletion .github/workflows/visual-snapshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,34 @@ concurrency:
env:
# Directory the Playwright capture writes to and sentry-cli uploads from.
SNAPSHOT_OUTPUT_DIR: snapshots
# CI-only database and auth config. prisma.config.ts builds the connection
# string from POSTGRES_* at load time, and the app queries the database when
# pages behind the session proxy are captured.
POSTGRES_USER: ci
POSTGRES_PASSWORD: ci
POSTGRES_DB: awaketh
BETTER_AUTH_URL: http://localhost:3000
BETTER_AUTH_SECRET: ci-only-secret-for-visual-snapshots

jobs:
visual:
runs-on: blacksmith-4vcpu-ubuntu-2404

services:
postgres:
image: postgres:17
env:
POSTGRES_USER: ci
POSTGRES_PASSWORD: ci
POSTGRES_DB: awaketh
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U ci -d awaketh"
--health-interval 5s
--health-timeout 5s
--health-retries 10

steps:
- uses: actions/checkout@v7
with:
Expand All @@ -30,7 +54,15 @@ jobs:
bun-version: latest

- name: Install dependencies
run: bun install --frozen-lockfile
run: bun install --frozen-lockfile --ignore-scripts
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# --ignore-scripts skips the postinstall hook, so generate the Prisma
# client explicitly; the build resolves src/generated/prisma from it.
- name: Generate Prisma client
run: bunx prisma generate

- name: Apply database migrations
run: bunx prisma migrate deploy

- name: Install Playwright browser
run: bunx playwright install --with-deps chromium
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ yarn-error.log*

# env files (can opt-in for committing if needed)
.env.sentry-build-plugin
.env
.env*
!.env.example

# vercel
.vercel
Expand All @@ -51,3 +52,4 @@ yarn-error.log*
# IDEA IDEs (For whoever uses these lol)
.idea
/src/generated/prisma

58 changes: 58 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
import { withSentryConfig } from '@sentry/nextjs';
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {/* config options here */};
const nextConfig: NextConfig = {
async redirects() {
return [
{
source: `/legal/terms`,
destination: `https://stegnet.com/terms`,
permanent: false,
},
{
source: `/legal/privacy`,
destination: `https://stegnet.com/privacy`,
permanent: false,
},
];
},
};

export default withSentryConfig(nextConfig, {
org: 'stegnet',
project: 'awaketh-web',
silent: !process.env.CI,
widenClientFileUpload: true,
authToken: process.env.SENTRY_AUTH_TOKEN,

sourcemaps: {
deleteSourcemapsAfterUpload: true,
Comment on lines +26 to +29

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files =="
git ls-files | rg '^(next\.config\.ts|\.github/workflows/visual-snapshots\.yml|node_modules/next/dist/docs/)' || true

echo
echo "== next.config.ts (lines around the referenced snippet) =="
if [ -f next.config.ts ]; then
  nl -ba next.config.ts | sed -n '1,120p'
fi

echo
echo "== workflow file (relevant sections) =="
if [ -f .github/workflows/visual-snapshots.yml ]; then
  nl -ba .github/workflows/visual-snapshots.yml | sed -n '1,240p'
fi

echo
echo "== Next.js docs presence =="
fd -a . node_modules/next/dist/docs 2>/dev/null | sed -n '1,80p' || true

echo
echo "== Sentry-related references =="
rg -n "withSentryConfig|SENTRY_AUTH_TOKEN|deleteSourcemapsAfterUpload|sourcemaps|authToken" -S . --glob '!node_modules/**' || true

Repository: Awaketh/awaketh

Length of output: 325


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== next.config.ts =="
sed -n '1,140p' next.config.ts | cat -n

echo
echo "== .github/workflows/visual-snapshots.yml =="
sed -n '1,260p' .github/workflows/visual-snapshots.yml | cat -n

echo
echo "== next docs lookup =="
find node_modules/next/dist/docs -maxdepth 2 -type f 2>/dev/null | sed -n '1,60p' || true

Repository: Awaketh/awaketh

Length of output: 4590


🌐 Web query:

Sentry Next.js withSentryConfig SENTRY_AUTH_TOKEN source map upload build time next.config.ts

💡 Result:

To configure Sentry source map uploads in your Next.js application using next.config.ts, you use the withSentryConfig wrapper and provide your Sentry authentication token via an environment variable. Configuration Steps: 1. Environment Variable: Set the SENTRY_AUTH_TOKEN environment variable in your CI/CD environment or your local.env file (e.g.,.env.sentry-build-plugin) to keep your token secret [1][2][3]. 2. Update next.config.ts: Wrap your configuration with withSentryConfig and pass the token from the environment variable [1][3]. import type { NextConfig } from "next"; import { withSentryConfig } from "@sentry/nextjs"; const nextConfig: NextConfig = { // Your existing Next.js config }; export default withSentryConfig(nextConfig, { org: "", project: "", authToken: process.env.SENTRY_AUTH_TOKEN, // Injects the token at build time }); Build Time Considerations: - Upload Timing: By default, if you are using Webpack, source maps are uploaded during the build process [4]. For faster builds in Next.js 15.4.1+, you can enable post-build uploading by setting useRunAfterProductionCompileHook: true [1][4]. Turbopack always uses this post-build upload mode [1][4]. - CI/CD: Ensure SENTRY_AUTH_TOKEN is defined in your build environment; otherwise, source maps will not be uploaded, and stack traces will remain minified [1][5]. - Troubleshooting: If stack traces are still minified, verify that your build process actually generates source maps, confirm your org and project slugs are correct, and ensure the auth token has the necessary permissions [1][5]. You can optionally set silent:!process.env.CI to limit log output to your CI environment [2][3].

Citations:


Pass SENTRY_AUTH_TOKEN to Build app. withSentryConfig consumes authToken during bun run build, so exporting it only for the later snapshot-upload step leaves source-map upload unauthenticated. .github/workflows/visual-snapshots.yml:38-39

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@next.config.ts` around lines 26 - 29, Update the Build app step in the visual
snapshots workflow to export SENTRY_AUTH_TOKEN before running bun run build,
ensuring withSentryConfig receives the token during the build. Keep the existing
snapshot-upload environment handling unchanged.

},

// Uncomment to route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
// This can increase your server load as well as your hosting bill.
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
},
"dependencies": {
"@base-ui/react": "^1.6.0",
"@better-auth/passkey": "^1.6.23",
"@icons-pack/react-simple-icons": "^13.13.0",
"@marsidev/react-turnstile": "1.5.3",
"@prisma/adapter-pg": "^7.8.0",
"@prisma/client": "^7.8.0",
"@sentry/nextjs": "^10",
Expand All @@ -35,6 +38,7 @@
"react": "19.2.7",
"react-dom": "19.2.7",
"shadcn": "^4.13.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0"
},
Expand Down
3 changes: 2 additions & 1 deletion prisma.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Prisma CLI config. Prisma 7 does not auto-load .env, so we load it here.
import 'dotenv/config';
import { defineConfig } from 'prisma/config';
import { buildConnectionString } from './src/lib/database/connection-string';

export default defineConfig({
schema: 'prisma/schema.prisma',
Expand All @@ -9,6 +10,6 @@ export default defineConfig({
},
datasource: {
// Prisma 7 keeps the connection URL out of schema.prisma; the CLI/Migrate reads it here.
url: process.env['DATABASE_URL'],
url: buildConnectionString(),
},
});
25 changes: 25 additions & 0 deletions prisma/migrations/20260715090009_0002/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- CreateTable
CREATE TABLE "passkey" (
"id" TEXT NOT NULL,
"name" TEXT,
"publicKey" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"credentialID" TEXT NOT NULL,
"counter" INTEGER NOT NULL,
"deviceType" TEXT NOT NULL,
"backedUp" BOOLEAN NOT NULL,
"transports" TEXT,
"createdAt" TIMESTAMP(3),
"aaguid" TEXT,

CONSTRAINT "passkey_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX "passkey_userId_idx" ON "passkey"("userId");

-- CreateIndex
CREATE INDEX "passkey_credentialID_idx" ON "passkey"("credentialID");

-- AddForeignKey
ALTER TABLE "passkey" ADD CONSTRAINT "passkey_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
21 changes: 21 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ model User {
sessions Session[]
accounts Account[]

passkeys Passkey[]

@@unique([email])
@@map("user")
}
Expand Down Expand Up @@ -72,3 +74,22 @@ model Verification {
@@index([identifier])
@@map("verification")
}

model Passkey {
id String @id
name String?
publicKey String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
credentialID String
counter Int
deviceType String
backedUp Boolean
transports String?
createdAt DateTime?
aaguid String?

@@index([userId])
@@index([credentialID])
@@map("passkey")
}
7 changes: 5 additions & 2 deletions sentry.edge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ if (

Sentry.init({
dsn:
process.env.NODE_ENV === 'production'
process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test'
? process.env.NEXT_PUBLIC_WEB_SENTRY_DSN
: '',
integrations: [
Sentry.consoleLoggingIntegration({ levels: ['log', 'warn', 'error'] }),
],

tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.25 : 1.0,
tracesSampleRate:
process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test'
? 0.25
: 1.0,

enableLogs: true,
attachStacktrace: true,
Expand Down
7 changes: 5 additions & 2 deletions sentry.server.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ if (

Sentry.init({
dsn:
process.env.NODE_ENV === 'production'
process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test'
? process.env.NEXT_PUBLIC_WEB_SENTRY_DSN
: '',
spotlight: process.env.NODE_ENV !== 'production',
integrations: [
Sentry.consoleLoggingIntegration({ levels: ['log', 'warn', 'error'] }),
],

tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.25 : 1.0,
tracesSampleRate:
process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test'
? 0.25
: 1.0,

enableLogs: true,
attachStacktrace: true,
Expand Down
22 changes: 22 additions & 0 deletions src/app/auth/sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { LoginForm } from '@/components/login-form';
import { GalleryVerticalEndIcon } from 'lucide-react';
import Link from 'next/link';

export default function LoginPage() {
return (
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
<div className="flex w-full max-w-sm flex-col gap-6">
<Link
href="/"
className="flex items-center gap-2 self-center font-medium"
>
<div className="flex size-6 items-center justify-center rounded-md bg-primary text-primary-foreground">
<GalleryVerticalEndIcon className="size-4" />
</div>
Awaketh
</Link>
<LoginForm />
</div>
</div>
);
}
24 changes: 24 additions & 0 deletions src/app/auth/sign-up/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use client';

import { SignupForm } from '@/components/signup-form';
import { GalleryVerticalEndIcon } from 'lucide-react';
import Link from 'next/link';

export default function SignupPage() {
return (
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
<div className="flex w-full max-w-sm flex-col gap-6">
<Link
href="/"
className="flex items-center gap-2 self-center font-medium"
>
<div className="flex size-6 items-center justify-center rounded-md bg-primary text-primary-foreground">
<GalleryVerticalEndIcon className="size-4" />
</div>
Awaketh
</Link>
<SignupForm />
</div>
</div>
);
}
16 changes: 16 additions & 0 deletions src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client';

import { authClient } from '@/lib/auth-client';

export default function Dashboard() {
const { data } = authClient.useSession();

const fullName = data?.user?.name;

return (
<div>
<h1>Dashboard</h1>
<p>Welcome to the dashboard, {fullName}!</p>
Comment on lines +8 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid rendering an undefined user name.

Before the session resolves, this displays Welcome to the dashboard, undefined!. Render a neutral loading/fallback greeting until fullName is available.

Proposed fix
-      <p>Welcome to the dashboard, {fullName}!</p>
+      <p>
+        {fullName
+          ? `Welcome to the dashboard, ${fullName}!`
+          : 'Welcome to the dashboard!'}
+      </p>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fullName = data?.user?.name;
return (
<div>
<h1>Dashboard</h1>
<p>Welcome to the dashboard, {fullName}!</p>
const fullName = data?.user?.name;
return (
<div>
<h1>Dashboard</h1>
<p>
{fullName
? `Welcome to the dashboard, ${fullName}!`
: 'Welcome to the dashboard!'}
</p>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/dashboard/page.tsx` around lines 8 - 13, Update the Dashboard
greeting that uses fullName so it renders a neutral loading or fallback greeting
when fullName is unavailable, while preserving the personalized welcome once the
user name is available.

</div>
);
}
2 changes: 2 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import { ThemeProvider } from '@/components/theme-provider';
import { Toaster } from '@/components/ui/sonner';
import './globals.css';

const geistSans = Geist({
Expand Down Expand Up @@ -37,6 +38,7 @@ export default function RootLayout({
disableTransitionOnChange
>
{children}
<Toaster />
</ThemeProvider>
</body>
</html>
Expand Down
Loading
Loading