@prism/core - Foundational infrastructure for Next.js applications built with TypeScript, Tailwind CSS, Drizzle ORM, and AI capabilities.
A Next.js monorepo that can be used as a standalone package by apps in separate repositories. Uses pnpm workspaces (pnpm-workspace.yaml) to manage multiple applications and shared packages.
prism/
βββ packages/
β βββ ui/ # Shared UI components
β βββ database/ # Database layer (Drizzle ORM + Neon PostgreSQL)
β βββ intelligence/ # AI tasks and utilities
β βββ logger/ # Logging infrastructure
β βββ utilities/ # Shared utility functions
β βββ admin/ # System sheet page + Prism admin demos (registry)
β βββ authentication/ # Authentication utilities
βββ apps/
β βββ web/ # Sample application (generated apps go here)
βββ tools/ # CLI tools and generator
βββ package.json # @prism/core configuration
- Node.js >= 25.0.0 (see
enginesinpackage.jsonand.nvmrc) - pnpm 10.x (
corepack enablethencorepack prepare pnpm@10.28.0 --activate, or install globally)
Install all dependencies for the monorepo:
pnpm installThis will install dependencies for all workspaces (apps and packages).
Run the web app in development mode:
pnpm run devThis will:
- Kill any existing dev servers on port 3000
- Start the web app
- Web app: http://localhost:3000
Or run the web app:
# Web app (http://localhost:3000)
pnpm run dev:webNote: The apps/web directory is kept as a sample. You can generate new apps using prism generate <app-name> (after pnpm run setup) or pnpm run prism generate <app-name>, which will create them in the apps/ directory.
pnpm run dev- Run web app in development mode (kills existing servers first)pnpm run dev:web- Run web app only (port 3000)pnpm run dev:kill- Kill all development servers on port 3000
pnpm run build- Build all appspnpm run build:web- Build web app only
pnpm run start- Start all production serverspnpm run start:web- Start web app (port 3000)
pnpm run typecheck- Run TypeScript type checking across all workspacespnpm run lint- Run ESLint across all workspacespnpm run lint:fix- Run ESLint with auto-fixpnpm run format- Format code with Prettierpnpm run format:check- Check code formattingpnpm run quality- Run typecheck, lint, format, and testspnpm run quality:quick- Run typecheck, lint, and format (no tests)
pnpm run test- Run all testspnpm run test:run- Run all tests oncepnpm run test:ui- Run tests with Vitest UI (web app)pnpm run test:coverage- Generate coverage report (web app)
pnpm run database:generate- Generate database migrationspnpm run database:migrate- Run database migrationspnpm run database:push- Push schema changes to databasepnpm run database:studio- Open Drizzle Studio (database GUI)
pnpm run clean- Clean build artifactspnpm run watch- Watch TypeScript files
- Framework: Next.js 16.0.3 (App Router)
- Language: TypeScript 5.9.3 (target: ES2022)
- Styling: Tailwind CSS 4.1.17
- Monorepo: pnpm workspaces
- apps/web: Sample Next.js application (reference implementation)
- apps/*: Generated apps (created via
prism generate <name>orpnpm run prism generate <name>)
- packages/ui: Shared UI components (PrismButton, PrismCard, PrismIcon, layout wrappers, read-only chip class bundles, β¦)
- Radix UI primitives
- Class Variance Authority for variants
- Material Symbols Rounded icons (via Google Fonts)
- packages/database: Database layer
- Drizzle ORM 0.44.7
- Neon PostgreSQL with @neondatabase/serverless
- packages/utilities: Shared utility functions
cn()- Tailwind class name merger
- Testing: Vitest 4.0.10 with React Testing Library
- Linting: ESLint 9.39.1 with Next.js config
- Formatting: Prettier 3.6.2
- Git Hooks: Husky 9.1.7 with lint-staged
- Fonts: Satoshi (variable font) via
next/font/local
This project uses Vitest for testing. Tests should be placed in files ending with .test.ts or .test.tsx.
# Run tests
pnpm run test
# Run tests with UI
pnpm run test:ui
# Run tests with coverage
pnpm run test:coverageThis project uses Drizzle ORM with Neon PostgreSQL. The database schema is defined in packages/database/source/schema.ts.
import { db } from "@database";
// Both apps can import from the shared database package
const data = await db.query.users.findMany();# Generate migrations from schema changes
pnpm run database:generate
# Apply migrations
pnpm run database:migrate
# Push schema changes directly (development)
pnpm run database:push
# Open Drizzle Studio GUI
pnpm run database:studioApps in separate repositories can import Prism Core as a dependency. The generator handles this automatically:
Option 1: Git Submodule (Recommended - One Deployable Repo)
# Direct mode (recommended after pnpm run setup)
prism generate my-app --path ../my-app
# Or via package.json script
pnpm run prism generate my-app --path ../my-appThis automatically:
- Adds Prism as a git submodule inside your app at
./prism - Uses
file:./prism/packages/...dependencies for fast iteration - Creates a single deployable repo (your app + Prism submodule)
- Allows committing Prism changes from within your app
After updating the submodule, run pnpm run prism:sync from your app root to align scripts, Cursor commands, and shared dependency ranges. Details: SYNC-Prism.md.
Option 2: Git Dependency (Alternative for Deployment)
# Direct mode (recommended after pnpm run setup)
prism generate my-app --path ../my-app --prism-repo "git+https://github.com/thushana/prism.git"
# Or via package.json script
pnpm run prism generate my-app --path ../my-app --prism-repo "git+https://github.com/thushana/prism.git"This creates a deployable app that Vercel can build. Prism will be cloned from GitHub during the build process. Note: You won't be able to commit Prism changes from within your app with this approach.
Import in your app:
// Import UI components
import { PrismButton, PrismCard } from "@prism/core/ui";
// Import database
import { db } from "@prism/core/database";
// Import AI utilities
import { getAIModel } from "@prism/core/intelligence";
// Import logger
import { logger } from "@prism/core/logger";
// Import utilities
import { cn } from "@prism/core/utilities";
// Import admin package (system sheet page + demos; see packages/admin)
import { SystemSheetPage } from "@prism/core/admin";
// Import authentication utilities
import { requireApiAuthentication } from "@prism/core/authentication";Apps within this monorepo can use direct package imports:
// Import UI components
import { PrismButton, PrismCard } from "@ui";
// Import database
import { db } from "@database";
// Import utilities
import { cn } from "@utilities";
// Import logger (client-side)
import { logger, logSuccess } from "@logger/client";
// Import logger (server-side)
import { serverLogger as logger, logStart } from "@logger/server";
// Import admin (system sheet + component demos)
import { SystemSheetPage } from "@admin";
// Import authentication
import { requireApiAuthentication } from "@authentication/api";Prism includes a shared development information page that shows environment details, git status, dependencies, and more.
Add to your app:
// app/dev-sheet/page.tsx
import { DevSheetPage } from "@dev-sheet";
import type { DevSheetData } from "@dev-sheet";
import { headers } from "next/headers";
export const dynamic = "force-dynamic";
async function fetchDevSheetData(): Promise<DevSheetData | null> {
try {
// Construct absolute URL for server component fetch
// In server components, relative URLs don't work with fetch()
const headersList = await headers();
const host = headersList.get("host") || "localhost:3001";
const protocol = process.env.VERCEL_URL
? "https"
: host.includes("localhost")
? "http"
: "https";
const baseUrl = `${protocol}://${host}`;
const res = await fetch(`${baseUrl}/api/dev-sheet`, {
cache: "no-store",
});
if (!res.ok) return null;
const json = await res.json();
return json?.success ? json.data : null;
} catch {
return null;
}
}
export default async function Page() {
// Hide in production unless explicitly enabled
if (
process.env.NODE_ENV === "production" &&
process.env.ENABLE_DEV_SHEET !== "true"
) {
return null;
}
const data = await fetchDevSheetData();
return <DevSheetPage data={data} />;
}Note: Your app needs to implement an /api/dev-sheet route that returns development data. See the generator templates for a reference implementation.
Prism Core uses the exports field in package.json to expose packages as subpath imports (e.g., @prism/core/ui).
Important Notes:
-
TypeScript Source Files: The exports point directly to TypeScript source files (
.ts), not compiled JavaScript. This works because:- Next.js/Turbopack handles TypeScript compilation and bundling
- TypeScript path mappings in
tsconfig.jsonresolve these imports - This is designed for monorepo/internal use or apps using TypeScript with proper tooling
-
For External Consumers: If you plan to publish this package or use it in apps without TypeScript tooling:
- Consider adding a build step to compile TypeScript to JavaScript
- Update exports to point to compiled
.jsfiles - Or ensure consuming apps have TypeScript configured with path mapping support
-
Current Exports:
@prism/core/ui- UI components@prism/core/database- Database layer@prism/core/intelligence- AI utilities@prism/core/logger- Logging infrastructure@prism/core/utilities- Utility functions@prism/core/dev-sheet- Development info page
Each package follows the same structure:
packages/[package-name]/
βββ source/ # Source files
β βββ index.ts # Main export file
βββ package.json # Package configuration
βββ tsconfig.json # TypeScript configuration
This monorepo is designed to deploy each app independently on Vercel. See DEPLOYMENT-Prism.md for detailed instructions.
- Web App: Deploy from
apps/webroot directory (sample) - Generated Apps: Deploy from
apps/<app-name>root directory
Each app can be deployed independently from the same GitHub repository by setting different root directories in Vercel.
- Web:
yourdomain.comorwww.yourdomain.com - Generated apps: Configure per app in Vercel
Neon PostgreSQL is used for both development and production:
- Configure via
DATABASE_URLenvironment variable - Use pooled connection for runtime queries
- Use unpooled connection (
DATABASE_URL_UNPOOLED) for migrations - Serverless-friendly with Neon's serverless driver
Copy .env.example to .env and fill in your environment variables. Never commit .env or any files containing secrets. (In the TimeTraveler app, use the repository root .env; this file is for Prism-only checkouts.)
Environment variables can be set per-app in Vercel or at the root level for all apps.
Configure log levels using environment variables:
- Server-side:
LOG_LEVEL(default: "info" in production, "debug" in development) - Client-side:
NEXT_PUBLIC_LOG_LEVEL(default: "info" in production, "debug" in development)
Valid log levels: error, warn, info, http, verbose, debug, silly
Example .env:
LOG_LEVEL=debug
NEXT_PUBLIC_LOG_LEVEL=debugSee docs/LOGGER-Prism.md for full logger documentation.
- pnpm workspaces
- Turborepo - Consider for larger monorepos
- Make changes in the appropriate workspace
- Run
pnpm run qualityto ensure code quality - Commit with descriptive messages (see
.cursor/commands/COMMITMESSAGE.md) - Pre-commit hooks will automatically format and lint your code
This project is private and not licensed for public use.