From 51a8916a4ca3d791704c2345ebe771c90cb9ad50 Mon Sep 17 00:00:00 2001 From: tedspare Date: Tue, 18 Nov 2025 16:05:05 -0500 Subject: [PATCH] Scaffold web app --- README.md | 50 +++++++++++++- biome.json | 3 + next-env.d.ts | 6 ++ next.config.ts | 15 +++++ package.json | 40 ++++++++++++ postcss.config.mjs | 1 + prisma.config.ts | 9 +++ prisma/auth.prisma | 72 +++++++++++++++++++++ prisma/schema.prisma | 18 ++++++ prisma/seed.ts | 14 ++++ public/fonts/PlusJakartaSans-Bold.ttf | Bin 0 -> 94784 bytes src/app/(app)/ai.tsx | 34 ++++++++++ src/app/(app)/chat.tsx | 90 ++++++++++++++++++++++++++ src/app/(app)/layout.tsx | 17 +++++ src/app/(app)/page.tsx | 5 ++ src/app/(landing)/signin/page.tsx | 5 ++ src/app/api/auth/[...auth]/route.ts | 3 + src/app/api/events/route.ts | 1 + src/app/icon.tsx | 30 +++++++++ src/app/layout.tsx | 14 ++++ src/app/opengraph-image.tsx | 41 ++++++++++++ src/app/styles.css | 3 + src/app/twitter-image.tsx | 1 + src/lib/agents/todo.ts | 33 ++++++++++ src/lib/auth/actions.ts | 5 ++ src/lib/auth/client.ts | 19 ++++++ src/lib/auth/server.ts | 14 ++++ src/lib/components/ChatBox.tsx | 51 +++++++++++++++ src/lib/components/Message.tsx | 52 +++++++++++++++ src/lib/components/Nav.tsx | 17 +++++ src/lib/components/SignIn.tsx | 11 ++++ src/lib/components/SignOut.tsx | 15 +++++ src/lib/db.ts | 3 + src/lib/env.ts | 19 ++++++ src/lib/events/client.ts | 7 ++ src/lib/events/server.ts | 8 +++ src/lib/events/types.ts | 6 ++ src/lib/tools/createTodo.ts | 22 +++++++ src/lib/tools/getTodoList.ts | 31 +++++++++ tsconfig.json | 24 +++++++ 40 files changed, 808 insertions(+), 1 deletion(-) create mode 100644 biome.json create mode 100644 next-env.d.ts create mode 100644 next.config.ts create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 prisma.config.ts create mode 100644 prisma/auth.prisma create mode 100644 prisma/schema.prisma create mode 100644 prisma/seed.ts create mode 100644 public/fonts/PlusJakartaSans-Bold.ttf create mode 100644 src/app/(app)/ai.tsx create mode 100644 src/app/(app)/chat.tsx create mode 100644 src/app/(app)/layout.tsx create mode 100644 src/app/(app)/page.tsx create mode 100644 src/app/(landing)/signin/page.tsx create mode 100644 src/app/api/auth/[...auth]/route.ts create mode 100644 src/app/api/events/route.ts create mode 100644 src/app/icon.tsx create mode 100644 src/app/layout.tsx create mode 100644 src/app/opengraph-image.tsx create mode 100644 src/app/styles.css create mode 100644 src/app/twitter-image.tsx create mode 100644 src/lib/agents/todo.ts create mode 100644 src/lib/auth/actions.ts create mode 100644 src/lib/auth/client.ts create mode 100644 src/lib/auth/server.ts create mode 100644 src/lib/components/ChatBox.tsx create mode 100644 src/lib/components/Message.tsx create mode 100644 src/lib/components/Nav.tsx create mode 100644 src/lib/components/SignIn.tsx create mode 100644 src/lib/components/SignOut.tsx create mode 100644 src/lib/db.ts create mode 100644 src/lib/env.ts create mode 100644 src/lib/events/client.ts create mode 100644 src/lib/events/server.ts create mode 100644 src/lib/events/types.ts create mode 100644 src/lib/tools/createTodo.ts create mode 100644 src/lib/tools/getTodoList.ts create mode 100644 tsconfig.json diff --git a/README.md b/README.md index 3b18e51..1c4d3a3 100644 --- a/README.md +++ b/README.md @@ -1 +1,49 @@ -hello world +# Create Rubric App + +This project is bootstrapped with [`create-rubric-app`](https://github.com/RubricLab/create-rubric-app). + +## Getting Started + +### 1. Install dependencies + +```sh +npm i +``` + +```sh +bun i +``` + +### 2. Set up the DB + +```sh +npm run db:push +``` + +```sh +bun db:push +``` + +### 3. Run the development server + +```sh +npm run dev +``` + +```sh +bun dev +``` + +Open [localhost:3000](http://localhost:3000) in your browser to see the result. + +You can start modifying the UI by editing [src/app/page.tsx](./src/app/(app)/page.tsx). The page auto-updates as you edit the file. + +### Deployment + +To serve your app to users, simply deploy the Next.js app eg. on [Railway](https://railway.app/new) or [Vercel](https://deploy.new/). + +To persist data, you'll need a database. Both [Railway](https://docs.railway.app/databases/postgresql) and [Vercel](https://vercel.com/docs/storage/vercel-postgres) provide Postgres DBs. + +## Learn More + +To learn more about this project, take a look at this [blog post](https://rubriclabs.com/blog/create-rubric-app). diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..e8d99dd --- /dev/null +++ b/biome.json @@ -0,0 +1,3 @@ +{ + "extends": ["@rubriclab/config/biome"] +} diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..830fb59 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..0f34b5f --- /dev/null +++ b/next.config.ts @@ -0,0 +1,15 @@ +import type { NextConfig } from 'next' + +export default { + reactStrictMode: true, + transpilePackages: [ + '@rubriclab/actions', + '@rubriclab/agents', + '@rubriclab/auth', + '@rubriclab/blocks', + '@rubriclab/chains', + '@rubriclab/events', + '@rubriclab/shapes', + '@rubriclab/webhooks' + ] +} satisfies NextConfig diff --git a/package.json b/package.json new file mode 100644 index 0000000..955c54a --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "dependencies": { + "@prisma/client": "^6.14.0", + "@rubriclab/agents": "^0.0.58", + "@rubriclab/auth": "^0.0.50", + "@rubriclab/events": "^0.0.37", + "@t3-oss/env-nextjs": "^0.13.8", + "dotenv": "^17.2.1", + "next": "^15.5.1", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "description": "This project was bootstrapped with create-rubric-app", + "devDependencies": { + "@rubriclab/config": "^0.0.22", + "@types/node": "^24.3.0", + "@types/react": "^19.1.11", + "@types/react-dom": "^19.1.8", + "prisma": "^6.14.0", + "typescript": "^5.9.2", + "zod": "^4.1.3" + }, + "license": "go nuts", + "name": "my-app", + "private": true, + "scripts": { + "bleed": "bun x npm-check-updates -u --dep prod,dev,optional,peer", + "build": "next build", + "check": "bun x biome check .", + "clean": "rm -rf .next && rm -rf node_modules", + "db:generate": "prisma generate", + "db:push": "bun --env-file=.env prisma generate && prisma db push", + "db:seed": "prisma db seed", + "db:studio": "prisma studio", + "dev": "next dev", + "format": "bun x biome check --write .", + "start": "next start" + }, + "version": "0.0.0" +} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..fc6c4d8 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1 @@ +export { default } from '@rubriclab/config/postcss' diff --git a/prisma.config.ts b/prisma.config.ts new file mode 100644 index 0000000..8e9db6e --- /dev/null +++ b/prisma.config.ts @@ -0,0 +1,9 @@ +import 'dotenv/config' +import { defineConfig } from 'prisma/config' + +export default defineConfig({ + migrations: { + seed: 'bun run prisma/seed.ts' + }, + schema: 'prisma' +}) diff --git a/prisma/auth.prisma b/prisma/auth.prisma new file mode 100644 index 0000000..5919aae --- /dev/null +++ b/prisma/auth.prisma @@ -0,0 +1,72 @@ +model User { + id String @id @default(nanoid(6)) + email String @unique + + oAuth2AuthenticationAccounts OAuth2AuthenticationAccount[] + oAuth2AuthorizationAccounts OAuth2AuthorizationAccount[] + apiKeyAuthorizationAccounts ApiKeyAuthorizationAccount[] + + sessions Session[] + + tasks Task[] +} + +model OAuth2AuthenticationRequest { + token String @id + callbackUrl String + expiresAt DateTime +} + +model OAuth2AuthorizationRequest { + token String @id + userId String + callbackUrl String + expiresAt DateTime +} + +model MagicLinkRequest { + token String @id + email String + expiresAt DateTime +} + +model OAuth2AuthenticationAccount { + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + provider String + accountId String + accessToken String + refreshToken String + expiresAt DateTime + + @@id([userId, provider, accountId]) +} + +model OAuth2AuthorizationAccount { + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + provider String + accountId String + accessToken String + refreshToken String + expiresAt DateTime + + @@id([userId, provider, accountId]) +} + +model ApiKeyAuthorizationAccount { + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + provider String + accountId String + apiKey String + + @@id([userId, provider, accountId]) +} + +model Session { + key String @id @default(cuid()) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + expiresAt DateTime +} diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..a6210d5 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,18 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Task { + id Int @id @default(autoincrement()) + title String + createdAt DateTime @default(now()) + status Boolean @default(false) + + user User? @relation(fields: [userId], references: [id]) + userId String? +} diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..374c587 --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,14 @@ +#!/usr/bin/env bun + +import db from '~/db' + +async function seed() { + await db.task.create({ + data: { + status: false, + title: 'Create your first task' + } + }) +} + +seed() diff --git a/public/fonts/PlusJakartaSans-Bold.ttf b/public/fonts/PlusJakartaSans-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..386d3a6dacedacb3fb68ecf65acce0f301685363 GIT binary patch literal 94784 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 literal 0 HcmV?d00001 diff --git a/src/app/(app)/ai.tsx b/src/app/(app)/ai.tsx new file mode 100644 index 0000000..c9e187d --- /dev/null +++ b/src/app/(app)/ai.tsx @@ -0,0 +1,34 @@ +'use server' + +import { executeTodoAgent } from '~/agents/todo' +import env from '~/env' +import { publish } from '~/events/server' + +export async function sendMessage({ userId, message }: { userId: string; message: string }) { + const { response } = await executeTodoAgent({ + messages: [{ content: message, role: 'user' }], + onEvent: async events => { + switch (events.type) { + case 'assistant_message': { + await publish({ + channel: userId, + eventType: events.type, + payload: events + }) + break + } + case 'function_call': { + await publish({ + channel: userId, + eventType: events.name, + payload: events + }) + break + } + } + }, + openAIKey: env.OPENAI_API_KEY + }) + + console.log(response) +} diff --git a/src/app/(app)/chat.tsx b/src/app/(app)/chat.tsx new file mode 100644 index 0000000..cfb546c --- /dev/null +++ b/src/app/(app)/chat.tsx @@ -0,0 +1,90 @@ +'use client' + +import { useState } from 'react' +import type { TodoAgentResponseEvent, TodoAgentToolEvent } from '~/agents/todo' +import { useSession } from '~/auth/client' +import { ChatBox } from '~/components/ChatBox' +import { AssistantMessage, ToolMessage, UserMessage } from '~/components/Message' + +import { useEvents } from '~/events/client' +import { sendMessage } from './ai' + +type Message = + | TodoAgentToolEvent + | TodoAgentResponseEvent + | { + id: string + type: 'user_message' + message: string + } + +function MessageSwitch({ message }: { message: Message }) { + switch (message.type) { + case 'user_message': { + return {message.message} + } + + case 'assistant_message': { + return {message.message.response} + } + case 'function_call': { + return ( + + ) + } + } +} + +function ChatMessages({ + userId, + messages, + addMessage +}: { + userId: string + messages: Message[] + addMessage: (message: Message) => void +}) { + useEvents({ + id: userId, + on: { + assistant_message: addMessage + } + }) + + return ( +
+ {messages.map(message => ( + + ))} +
+ ) +} + +export default function Chat() { + const { userId } = useSession() + const [messages, setMessages] = useState([]) + + function addMessage(message: Message) { + setMessages(prev => [...prev, message]) + } + + function handleSubmit(message: string) { + addMessage({ + id: Date.now().toString(), + message, + type: 'user_message' + }) + sendMessage({ message, userId }) + } + + return ( +
+ + +
+ ) +} diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx new file mode 100644 index 0000000..30354ff --- /dev/null +++ b/src/app/(app)/layout.tsx @@ -0,0 +1,17 @@ +import { getSession } from '~/auth/actions' +import { ClientAuthProvider } from '~/auth/client' +import { Nav } from '~/components/Nav' + +export default async function AppLayout({ children }: { children: React.ReactNode }) { + return ( + // @ts-expect-error: Auth Package Bug + +
+
+
+ ) +} diff --git a/src/app/(app)/page.tsx b/src/app/(app)/page.tsx new file mode 100644 index 0000000..744f3c5 --- /dev/null +++ b/src/app/(app)/page.tsx @@ -0,0 +1,5 @@ +import Chat from './chat' + +export default function Page() { + return +} diff --git a/src/app/(landing)/signin/page.tsx b/src/app/(landing)/signin/page.tsx new file mode 100644 index 0000000..2f898e3 --- /dev/null +++ b/src/app/(landing)/signin/page.tsx @@ -0,0 +1,5 @@ +import { SignInWithGithubButton } from '~/components/SignIn' + +export default function SignInPage() { + return +} diff --git a/src/app/api/auth/[...auth]/route.ts b/src/app/api/auth/[...auth]/route.ts new file mode 100644 index 0000000..e772cb1 --- /dev/null +++ b/src/app/api/auth/[...auth]/route.ts @@ -0,0 +1,3 @@ +import { routes } from '~/auth/server' + +export const { GET } = routes diff --git a/src/app/api/events/route.ts b/src/app/api/events/route.ts new file mode 100644 index 0000000..f96bd80 --- /dev/null +++ b/src/app/api/events/route.ts @@ -0,0 +1 @@ +export { GET, maxDuration } from '~/events/server' diff --git a/src/app/icon.tsx b/src/app/icon.tsx new file mode 100644 index 0000000..9e70457 --- /dev/null +++ b/src/app/icon.tsx @@ -0,0 +1,30 @@ +import { ImageResponse } from 'next/og' + +export const contentType = 'image/png' +export const size = { + height: 32, + width: 32 +} + +export default async function Icon() { + return new ImageResponse( +
+ R +
, + { + ...size + } + ) +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..bb1ec7c --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,14 @@ +import './styles.css' + +export const metadata = { + description: 'Generated by Create Rubric App', + title: 'Create Rubric App' +} + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/src/app/opengraph-image.tsx b/src/app/opengraph-image.tsx new file mode 100644 index 0000000..d1e6475 --- /dev/null +++ b/src/app/opengraph-image.tsx @@ -0,0 +1,41 @@ +import { readFile } from 'node:fs/promises' +import { ImageResponse } from 'next/og' + +export const alt = 'Create Rubric App' +export const size = { + height: 630, + width: 1200 +} + +export const contentType = 'image/png' + +export default async function Image() { + const interSemiBold = await readFile('public/fonts/PlusJakartaSans-Bold.ttf') + + return new ImageResponse( +
+ R +
, + { + ...size, + fonts: [ + { + data: interSemiBold, + name: 'Inter', + style: 'normal', + weight: 400 + } + ] + } + ) +} diff --git a/src/app/styles.css b/src/app/styles.css new file mode 100644 index 0000000..cca18ce --- /dev/null +++ b/src/app/styles.css @@ -0,0 +1,3 @@ +/** biome-ignore-all lint/suspicious/noUnknownAtRules: Tailwind Grammar */ + +@import "tailwindcss"; diff --git a/src/app/twitter-image.tsx b/src/app/twitter-image.tsx new file mode 100644 index 0000000..90779fd --- /dev/null +++ b/src/app/twitter-image.tsx @@ -0,0 +1 @@ +export { alt, contentType, default, size } from './opengraph-image' diff --git a/src/lib/agents/todo.ts b/src/lib/agents/todo.ts new file mode 100644 index 0000000..a416c02 --- /dev/null +++ b/src/lib/agents/todo.ts @@ -0,0 +1,33 @@ +import { createAgent, createResponseFormat, noTabs } from '@rubriclab/agents' +import { z } from 'zod/v4' +import createTodo from '~/tools/createTodo' +import getTodoList from '~/tools/getTodoList' + +const responseFormat = createResponseFormat({ + name: 'todo_agent_response_format', + schema: z.object({ + response: z.string() + }) +}) + +const systemPrompt = noTabs` + You are a todo agent. + The user will ask you to do CRUD operations against a TODO database. + You should use tools to help them. +` + +const { executeAgent, eventTypes, __ToolEvent, __ResponseEvent } = createAgent({ + model: 'gpt-4.1-mini', + responseFormat, + systemPrompt, + tools: { + createTodo, + getTodoList + } +}) + +export { eventTypes as todoAgentEventTypes } +export { executeAgent as executeTodoAgent } + +export type TodoAgentToolEvent = typeof __ToolEvent +export type TodoAgentResponseEvent = typeof __ResponseEvent diff --git a/src/lib/auth/actions.ts b/src/lib/auth/actions.ts new file mode 100644 index 0000000..aa760fb --- /dev/null +++ b/src/lib/auth/actions.ts @@ -0,0 +1,5 @@ +'use server' + +import { actions } from './server' + +export const { signIn, signOut, sendMagicLink, getAuthConstants, getSession } = actions diff --git a/src/lib/auth/client.ts b/src/lib/auth/client.ts new file mode 100644 index 0000000..1156d65 --- /dev/null +++ b/src/lib/auth/client.ts @@ -0,0 +1,19 @@ +'use client' + +import type { Prisma } from '@prisma/client' +import { CreateAuthContext } from '@rubriclab/auth/client' + +export const { ClientAuthProvider, useSession } = + CreateAuthContext< + Prisma.SessionGetPayload<{ + include: { + user: { + include: { + apiKeyAuthorizationAccounts: true + oAuth2AuthenticationAccounts: true + oAuth2AuthorizationAccounts: true + } + } + } + }> + >() diff --git a/src/lib/auth/server.ts b/src/lib/auth/server.ts new file mode 100644 index 0000000..7f1e9fe --- /dev/null +++ b/src/lib/auth/server.ts @@ -0,0 +1,14 @@ +import { createAuth, createGithubAuthenticationProvider, prismaAdapter } from '@rubriclab/auth' +import db from '~/db' +import env from '~/env' + +export const { routes, actions, __types } = createAuth({ + authUrl: env.NEXT_PUBLIC_AUTH_URL, + databaseProvider: prismaAdapter(db), + oAuth2AuthenticationProviders: { + github: createGithubAuthenticationProvider({ + githubClientId: env.GITHUB_CLIENT_ID, + githubClientSecret: env.GITHUB_CLIENT_SECRET + }) + } +}) diff --git a/src/lib/components/ChatBox.tsx b/src/lib/components/ChatBox.tsx new file mode 100644 index 0000000..0982808 --- /dev/null +++ b/src/lib/components/ChatBox.tsx @@ -0,0 +1,51 @@ +'use client' + +import { type KeyboardEvent, useState } from 'react' + +export function ChatBox({ + submit, + placeholder = 'Type a message...' +}: { + submit: (message: string) => void + placeholder?: string +}) { + const [message, setMessage] = useState(placeholder) + + return ( +
+
+