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