Coding
PromptBeginner5 minmarkdown
Markdown Converter
Agent skill for markdown-converter
7
This is a monorepo containing a Next.js application with Supabase, Prisma, and Sanity blog integration, managed with pnpm workspaces.
Sign in to like and favorite skills
This is a monorepo containing a Next.js application with Supabase, Prisma, and Sanity blog integration, managed with pnpm workspaces.
├── packages/ │ ├── web/ # Next.js app │ │ ├── app/ # App Router (Next.js 15+) │ │ │ └── blog/ # Blog routes (/blog, /blog/[slug], etc.) │ │ ├── lib/ │ │ │ ├── supabase/ # Supabase client configurations │ │ │ ├── sanity/ # Sanity client and configurations │ │ │ ├── prisma.ts # Prisma client singleton │ │ │ └── generated/prisma/ # Generated Prisma client │ │ ├── components/ │ │ │ └── blog/ # Blog components │ │ └── prisma/ │ │ └── schema.prisma # Database schema │ └── studio/ # Sanity Studio for content management │ ├── schemaTypes/ # Sanity schema definitions │ └── sanity.config.ts # Studio configuration ├── package.json # Root package.json with workspace scripts ├── pnpm-workspace.yaml # Workspace configuration └── .gitignore # Git ignore rules
pnpm dev # Start web package dev server pnpm --filter web dev # Alternative syntax
pnpm build # Build web package pnpm start # Start production server pnpm lint # Run linting
pnpm --filter web exec prisma db pull # Pull schema from Supabase pnpm --filter web exec prisma generate # Generate Prisma client pnpm --filter web exec prisma migrate dev # Run migrations
pnpm studio:dev # Start Sanity Studio development server pnpm studio:build # Build Sanity Studio pnpm studio:deploy # Deploy Studio to Sanity hosting
pnpm test # Run all tests pnpm test:watch # Run tests in watch mode pnpm test:ui # Open Vitest web UI pnpm test:coverage # Run tests with coverage
IMPORTANT: Always use import aliasing (
@/*) when importing files within the Next.js application. This project is configured with TypeScript path mapping for cleaner imports.
import { MyComponent } from '@/components/MyComponent/MyComponent'; import { prisma } from '@/lib/prisma'; import { createClient } from '@/lib/supabase/client'; import { client, urlFor } from '@/lib/sanity';
import { createClient } from '../../../lib/supabase/client'; import { prisma } from '../../lib/prisma'; import { client } from '../../../lib/sanity/client'; import Component from './components/MyComponent';
CRITICAL CONVENTIONS:
components/ ├── Button/ │ ├── Button.tsx # Named export: export const Button = () => {...} │ └── Button.test.tsx # Colocated test file ├── Modal/ │ ├── Modal.tsx # Named export: export const Modal = () => {...} │ └── Modal.test.tsx # Colocated test file └── Header/ ├── Header.tsx # Named export: export const Header = () => {...} └── Header.test.tsx # Colocated test file
components/ ├── Button.tsx # DON'T DO THIS ├── Modal.tsx # Should be in folders instead └── Header.tsx # Should be in folders instead
// components/Button/Button.tsx export const Button = ({ children, onClick }: ButtonProps) => { return ( <button onClick={onClick}> {children} </button> ); }; // Usage in other files import { Button } from '@/components/Button/Button';
@/lib/supabase/client - For client-side operations@/lib/supabase/server - For server-side operations with cookies@/lib/prisma@/lib/sanity/client - For fetching published content@/lib/sanity/previewClient - For draft content preview@/lib/sanity/image - For optimized image URLs@/lib/sanity/types - TypeScript types for blog content// API Route example import { prisma } from '@/lib/prisma'; import { createClient } from '@/lib/supabase/client'; import { client } from '@/lib/sanity'; import { postsQuery } from '@/lib/sanity/queries'; import { NextResponse } from 'next/server'; export async function GET() { // Use Supabase for real-time features const supabase = createClient(); const { data } = await supabase.from('users').select('*'); // Use Prisma for complex queries const userCount = await prisma.user.count(); // Use Sanity for blog content const posts = await client.fetch(postsQuery, { start: 0, end: 10 }); return NextResponse.json({ data, userCount, posts }); }
Environment variables are configured in:
.env.local - Next.js environment variables.env - Prisma environment variablesRequired variables:
Supabase:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYDATABASE_URL (for Prisma)DIRECT_URL (for Prisma migrations)Sanity:
NEXT_PUBLIC_SANITY_PROJECT_IDNEXT_PUBLIC_SANITY_DATASET (usually "production")SANITY_API_READ_TOKEN (optional, for preview mode)This project uses Vitest for testing with jsdom environment and comprehensive coverage reporting.
CRITICAL CONVENTIONS:
filename.test.ts naming convention - NEVER use __tests__ directories@/* import aliasing in test fileslib/ ├── utils.ts ├── utils.test.ts # Colocated with utils.ts ├── supabase/ │ ├── client.ts │ └── client.test.ts # Colocated with client.ts components/ ├── Button/ │ ├── Button.tsx # Named export component │ └── Button.test.tsx # Colocated test file
lib/ ├── utils.ts └── __tests__/ # DON'T DO THIS └── utils.test.ts # Should be colocated instead
describe, it, expect, vi available globally@/* paths work in testsTest API endpoint available at:
/api/test-prisma
The integrated Sanity blog provides:
/blog (listing), /blog/[slug] (posts), /blog/category/[slug], /blog/author/[slug]/studio when running pnpm studio:dev@/* paths@/ import aliasing - never relative importspnpm --filter web <command> or pnpm --filter studio <command>@/lib/prisma@/lib/sanity.env.local and .env/studio/api/test-prisma endpointfilename.test.ts naming - NEVER __tests__/ directories/MyComponent/MyComponent.tsx) with named exports/blog/* - posts, categories, and authors@/lib/sanity/queries for data fetching