feat: Step 1 - Project setup & smoke test

Initialize Next.js 16 (App Router) project with all core dependencies:
- Next.js, React 19, TypeScript configuration
- Mantine UI components (@mantine/core, @mantine/hooks)
- ATproto SDK for Bluesky integration
- SurrealDB client (updated to latest non-deprecated version)
- Vercel AI SDK with Google AI provider
- Deepgram SDK for voice-to-text
- React Three Fiber for 3D visualization
- UMAP.js for dimensionality reduction
- Magnitude test framework for E2E testing
- Playwright for browser automation

Created basic app structure with homepage displaying "Ponderants" text.
Configured magnitude.config.ts for testing framework.
Added .example.env with all required environment variables.

Test: Smoke test verifies app boots and renders homepage.
Status: ✓ Test passed (8.4s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-08 20:36:34 +00:00
parent e867e626fe
commit e544c95f2f
15 changed files with 7079 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
{
"permissions": {
"allow": [
"Bash(pnpm install:*)",
"Bash(pnpm add:*)"
],
"deny": [],
"ask": []
}
}

22
.example.env Normal file
View File

@@ -0,0 +1,22 @@
# SurrealDB Configuration
SURREALDB_URL=ws://localhost:8000/rpc
SURREALDB_NS=ponderants
SURREALDB_DB=main
SURREALDB_USER=root
SURREALDB_PASS=root
# JWT Secret for SurrealDB token minting
JWT_SECRET=your-secret-key-here-change-in-production
# Google AI API Key (for Gemini embeddings and chat)
GOOGLE_AI_API_KEY=your-google-ai-api-key
# Deepgram API Key (for voice-to-text)
DEEPGRAM_API_KEY=your-deepgram-api-key
# ATproto OAuth Configuration
ATPROTO_CLIENT_ID=http://localhost:3000/client-metadata.json
ATPROTO_REDIRECT_URI=http://localhost:3000/api/auth/callback
# Anthropic API Key (for Magnitude testing)
ANTHROPIC_API_KEY=your-anthropic-api-key

41
.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
# playwright
/test-results/
/playwright-report/
/playwright/.cache/

8
app/globals.css Normal file
View File

@@ -0,0 +1,8 @@
@import '@mantine/core/styles.css';
body {
margin: 0;
padding: 0;
background-color: #181a1d; /* Our darkest gray */
color: #e9ecef; /* Our lightest gray */
}

32
app/layout.tsx Normal file
View File

@@ -0,0 +1,32 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { MantineProvider, ColorSchemeScript } from "@mantine/core";
import { theme } from "./theme";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Ponderants",
description: "Your AI Thought Partner",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<head>
{/* Enforce dark scheme as per our theme */}
<ColorSchemeScript forceColorScheme="dark" />
</head>
<body className={inter.className}>
<MantineProvider theme={theme} forceColorScheme="dark">
{children}
</MantineProvider>
</body>
</html>
);
}

14
app/page.tsx Normal file
View File

@@ -0,0 +1,14 @@
import { Stack, Title, Paper, Button, Center } from '@mantine/core';
export default function Home() {
return (
<Center h="100vh">
<Paper w={400} p="xl">
<Stack align="center">
<Title order={1}>Ponderants</Title>
<Button>Test Button</Button>
</Stack>
</Paper>
</Center>
);
}

67
app/theme.ts Normal file
View File

@@ -0,0 +1,67 @@
'use client';
import { createTheme, MantineColorsTuple } from '@mantine/core';
// Define a rich 10-shade grayscale palette
const ponderGray: MantineColorsTuple = [
'#f8f9fa', // lightest
'#e9ecef',
'#dee2e6',
'#ced4da',
'#adb5bd',
'#868e96',
'#495057',
'#343a40',
'#212529',
'#181a1d', // darkest
];
export const theme = createTheme({
primaryColor: 'gray',
// Use our custom gray palette
colors: {
gray: ponderGray,
},
// Set default dark mode and grayscale for the "minimalist" look
defaultRadius: 'md',
fontFamily: 'Inter, sans-serif',
// Enforce dark mode
forceColorScheme: 'dark',
// Set default component props for a consistent look
components: {
Button: {
defaultProps: {
variant: 'filled',
color: 'gray',
radius: 'xl',
},
},
Paper: {
defaultProps: {
shadow: 'xs',
p: 'md',
radius: 'md',
withBorder: true,
},
styles: {
root: {
backgroundColor: '#212529', // gray.8
borderColor: '#495057', // gray.6
},
},
},
TextInput: {
defaultProps: {
variant: 'filled',
radius: 'xl',
},
},
Textarea: {
defaultProps: {
variant: 'filled',
radius: 'lg',
},
},
},
});

7
magnitude.config.ts Normal file
View File

@@ -0,0 +1,7 @@
export default {
project: 'Ponderants',
// This will be the base URL for all tests
url: 'http://localhost:3000',
// We will configure magnitude to find tests in this directory
tests: 'tests/magnitude/**/*.mag.ts',
};

6
next.config.mjs Normal file
View File

@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
// Add any future Next.js configurations here
};
export default nextConfig;

46
package.json Normal file
View File

@@ -0,0 +1,46 @@
{
"name": "ponderants",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "npx magnitude"
},
"dependencies": {
"@ai-sdk/google": "latest",
"@ai-sdk/react": "latest",
"@atproto/api": "latest",
"@deepgram/sdk": "latest",
"@mantine/core": "latest",
"@mantine/hooks": "latest",
"@react-three/drei": "latest",
"@react-three/fiber": "latest",
"ai": "latest",
"jsonwebtoken": "latest",
"next": "latest",
"react": "latest",
"react-dom": "latest",
"surrealdb": "latest",
"three": "latest",
"umap-js": "latest",
"zod": "latest"
},
"devDependencies": {
"@types/jsonwebtoken": "latest",
"@types/node": "latest",
"@types/react": "latest",
"@types/react-dom": "latest",
"eslint": "latest",
"eslint-config-next": "latest",
"jiti": "^2.6.1",
"magnitude-test": "latest",
"playwright": "^1.56.1",
"postcss": "latest",
"postcss-preset-mantine": "latest",
"postcss-simple-vars": "latest",
"typescript": "latest"
}
}

6732
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

17
postcss.config.mjs Normal file
View File

@@ -0,0 +1,17 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
'postcss-preset-mantine': {},
'postcss-simple-vars': {
variables: {
'mantine-breakpoint-xs': '36em',
'mantine-breakpoint-sm': '48em',
'mantine-breakpoint-md': '62em',
'mantine-breakpoint-lg': '75em',
'mantine-breakpoint-xl': '88em',
},
},
},
};
export default config;

View File

@@ -0,0 +1,11 @@
import { test } from 'magnitude-test';
test('Application boots and displays homepage', async (agent) => {
// Act: Navigate to the homepage (uses the default URL
// from magnitude.config.ts)
await agent.act('Navigate to the homepage');
// Check: Verify that the homepage text is visible
// This confirms the Next.js app is serving content.
await agent.check('The text "Ponderants" is visible on the screen');
});

View File

@@ -0,0 +1,25 @@
import { test } from 'magnitude-test';
test('Mantine theme is applied correctly', async (agent) => {
// Act: Navigate to the homepage
await agent.act('Navigate to the homepage');
// Check: Verify the Mantine components are rendered
await agent.check('The text "Ponderants" is visible as a title');
await agent.check('A "Test Button" is visible on the screen');
// Check: Verify the theme is applied.
// We check that the button has the specific visual properties
// defined in our theme (gray color, xl radius).
await agent.check(
'The "Test Button" has a gray background, indicating the theme\'s primaryColor is active'
);
await agent.check(
'The "Test Button" has rounded corners, indicating the theme\'s defaultRadius is active'
);
// Check: Verify the Paper component is rendered with its themed styles
await agent.check(
'The page content is inside a "Paper" component with a border'
);
});

41
tsconfig.json Normal file
View File

@@ -0,0 +1,41 @@
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
]
},
"target": "ES2017"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}