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:
10
.claude/settings.local.json
Normal file
10
.claude/settings.local.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(pnpm install:*)",
|
||||||
|
"Bash(pnpm add:*)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
22
.example.env
Normal file
22
.example.env
Normal 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
41
.gitignore
vendored
Normal 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
8
app/globals.css
Normal 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
32
app/layout.tsx
Normal 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
14
app/page.tsx
Normal 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
67
app/theme.ts
Normal 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
7
magnitude.config.ts
Normal 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
6
next.config.mjs
Normal 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
46
package.json
Normal 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
6732
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
postcss.config.mjs
Normal file
17
postcss.config.mjs
Normal 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;
|
||||||
11
tests/magnitude/01-smoke.mag.ts
Normal file
11
tests/magnitude/01-smoke.mag.ts
Normal 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');
|
||||||
|
});
|
||||||
25
tests/magnitude/02-theme.mag.ts
Normal file
25
tests/magnitude/02-theme.mag.ts
Normal 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
41
tsconfig.json
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user