AI Prompts Manager test
# AI Prompt Manager โ Full-Stack Web Application Development Prompt
----
## ๐ฏ Project Overview
You are an expert full-stack engineer and UI/UX designer. Build a **production-ready AI Prompt Manager web application** that allows users to create, organize, search, share, and manage AI prompts. The application must be beautiful, responsive, accessible, and scalable to support unlimited prompts.
----
## ๐๏ธ Tech Stack & Infrastructure
### Frontend
- **Framework**: Next.js 14+ (App Router)
- **Language**: TypeScript (strict mode)
- **Styling**: Tailwind CSS v3+ with a custom design system
- **UI Components**: shadcn/ui (built on Radix UI primitives) for accessible, composable components
- **Icons**: Lucide React
- **Fonts**: Use Google Fonts โ pair a refined serif or geometric display font (e.g., *DM Serif Display* or *Playfair Display*) with a clean sans-serif body font (e.g., *DM Sans* or *Outfit*)
- **Animations**: Framer Motion for page transitions and micro-interactions
- **Form Handling**: React Hook Form + Zod for schema validation
- **State Management**: Zustand for global UI state; React Query (TanStack Query) for server state and caching
- **Toast Notifications**: Sonner
### Backend
- **API**: Next.js Route Handlers (REST API within the same project)
- **ORM**: Drizzle ORM (type-safe, lightweight)
- **Database**: Vercel Postgres (Neon-based)
- **File Storage**: Cloudflare R2 (S3-compatible) via AWS SDK v3
- **Auth** *(optional but recommended)*: NextAuth.js v5 or Clerk for user authentication
### DevOps / Deployment
- **Hosting**: Vercel (with Edge Runtime where appropriate)
- **Environment Variables**: Managed via Vercel dashboard and `.env.local`
---
## ๐๏ธ Database Schema (Vercel Postgres via Drizzle ORM)
Design the following tables. Use UUIDs as primary keys.
### `prompts` table
```sql
id UUID PRIMARY KEY DEFAULT gen_random_uuid()
title VARCHAR(255) NOT NULL
description TEXT
content TEXT NOT NULL -- The actual prompt text
category VARCHAR(100)
tags TEXT[] -- Array of tag strings
model VARCHAR(100) -- e.g. "GPT-4o", "Claude 3.5", "Gemini 1.5"
variables JSONB -- Placeholder variables: [{name, description, default}]
attachments JSONB -- Array of R2 file metadata: [{key, name, url, size, type}]
is_public BOOLEAN DEFAULT false -- Controls share visibility
share_token UUID DEFAULT gen_random_uuid() -- Unique token for share links
use_count INTEGER DEFAULT 0 -- Track how many times prompt was copied/used
created_at TIMESTAMPTZ DEFAULT now()
updated_at TIMESTAMPTZ DEFAULT now()
```
### `categories` table
```sql
id UUID PRIMARY KEY DEFAULT gen_random_uuid()
name VARCHAR(100) NOT NULL UNIQUE
color VARCHAR(7) -- Hex color for category badge
icon VARCHAR(50) -- Lucide icon name
created_at TIMESTAMPTZ DEFAULT now()
```
---
## โ๏ธ Cloudflare R2 Integration
- Use `@aws-sdk/client-s3` and `@aws-sdk/s3-request-presigner` for R2 (S3-compatible API)
- Generate **presigned URLs** server-side for secure uploads and downloads
- Store file metadata (key, name, size, MIME type, public URL) in the `attachments` JSONB column of the prompt
- Support file types: images (PNG, JPG, WEBP), text files (TXT, MD), JSON, and PDFs
- Maximum file size: 10MB per file, up to 5 attachments per prompt
- On prompt deletion, delete associated R2 files via the S3 API
- Implement a `/api/upload` route handler that:
1. Validates file type and size
2. Generates a unique R2 object key: `prompts/{promptId}/{timestamp}-{filename}`
3. Returns a presigned PUT URL + the final public URL to the client
---
## ๐ API Routes (Next.js Route Handlers)
Implement the following REST endpoints:
### Prompts
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/prompts` | List/search prompts with pagination |
| POST | `/api/prompts` | Create a new prompt |
| GET | `/api/prompts/[id]` | Get a single prompt by ID |
| PUT | `/api/prompts/[id]` | Update a prompt |
| DELETE | `/api/prompts/[id]` | Delete a prompt + R2 files |
| POST | `/api/prompts/[id]/copy` | Increment use_count, return prompt text |
| GET | `/api/prompts/share/[token]` | Fetch a prompt by share token (public) |
### Search (GET `/api/prompts`)
Support these query parameters:
- `q` โ Full-text search across `title`, `description`, `content`, `tags`
- `category` โ Filter by category name
- `model` โ Filter by AI model
- `tags` โ Comma-separated tag filter
- `sort` โ `created_at`, `updated_at`, `use_count`, `title`
- `order` โ `asc` | `desc`
- `page` โ Page number (default: 1)
- `limit` โ Items per page (default: 20, max: 100)
Implement **full-text search** using Postgres `tsvector` and `to_tsquery`, or use `ILIKE` for simpler implementation. Also use Drizzle's `sql` template for complex queries.
### Upload
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/upload/presign` | Get a presigned R2 upload URL |
| DELETE | `/api/upload/[key]` | Delete a file from R2 |
### Categories
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/categories` | List all categories |
| POST | `/api/categories` | Create a category |
| DELETE | `/api/categories/[id]` | Delete a category |
---
## ๐จ Design System & UI Theme
### Color Palette
```css
/* Use these as CSS variables in globals.css */
--background: #FAFAF8; /* warm off-white */
--surface: #FFFFFF; /* pure white for cards */
--surface-elevated: #F5F4F0; /* slightly warm grey for hover states */
--border: #E8E6E0; /* warm light border */
--border-muted: #F0EEE9; /* subtle border */
--text-primary: #1A1917; /* near-black warm */
--text-secondary: #6B6860; /* medium warm grey */
--text-muted: #A09D97; /* light warm grey */
--accent: #2563EB; /* blue accent */
--accent-hover: #1D4ED8;
--accent-subtle: #EFF6FF; /* light blue bg */
--success: #16A34A;
--warning: #D97706;
--destructive: #DC2626;
--shadow-sm: 0 1px 2px rgba(26,25,23,0.06);
--shadow-md: 0 4px 12px rgba(26,25,23,0.08);
--shadow-lg: 0 8px 24px rgba(26,25,23,0.10);
```
### Typography Scale
- **Display** (app name, hero): 2.25remโ3rem, display font, weight 600โ700
- **Heading 1**: 1.875rem, weight 600
- **Heading 2**: 1.5rem, weight 600
- **Heading 3**: 1.25rem, weight 500
- **Body**: 0.9375rem, weight 400, line-height 1.6
- **Label**: 0.8125rem, weight 500, tracking 0.01em
- **Caption/Meta**: 0.75rem, weight 400, text-muted
### Component Tokens
- **Border radius**: cards `rounded-xl`, inputs `rounded-lg`, badges `rounded-full`, buttons `rounded-lg`
- **Card style**: `bg-white border border-[--border] shadow-[--shadow-sm] rounded-xl`
- **Focus rings**: 2px offset, accent color, accessible
---
## ๐งฉ Application Pages & Components
### 1. Layout Components
#### `<Header />`
- Logo/brand mark on the left: "PromptVault" (or your chosen name) with a small geometric icon
- Center: Global search bar (visible on desktop; collapses to icon on mobile)
- Right: "New Prompt" CTA button + optional user avatar/auth state
- Sticky on scroll with a subtle frosted glass effect (`backdrop-blur-sm bg-white/80 border-b`)
- Height: 64px desktop, 56px mobile
#### `<Footer />`
- 3-column layout on desktop, stacked on mobile
- Column 1: Brand + tagline + "Built for AI creators"
- Column 2: Quick links (All Prompts, Categories, What's New)
- Column 3: Tech stack badges (Vercel, Cloudflare R2, Postgres) and GitHub link
- Bottom bar: copyright + version number
- Background: `--surface-elevated`, top border
#### `<Sidebar />` *(collapsible on mobile)*
- Category list with colored dots and prompt counts
- Tag cloud section
- "Starred" / "Recent" quick filters
- Collapse button on desktop (icon-only mode)
---
### 2. Main Pages
#### `/` โ Dashboard / Home
- **Stats bar**: Total prompts, categories, most-used prompt, prompts this week
- **Pinned/Starred prompts** horizontal scroll row
- **Recent prompts** grid (last 6)
- **Popular prompts** sorted by `use_count`
- Empty state: Illustrated empty state with "Create your first prompt" CTA
#### `/prompts` โ All Prompts (List/Grid View)
- **View toggle**: Grid (cards) โ List (table-like rows)
- **Search bar** (prominent, full-width on mobile) with real-time filtering
- **Filter toolbar**: Category dropdown, Model filter, Tags multi-select, Sort dropdown
- **Active filter chips** showing applied filters with ร to remove each
- **Prompt cards** (see PromptCard component below)
- **Pagination** with page numbers + prev/next; or infinite scroll (your choice)
- Results count: "Showing 24 of 147 prompts"
#### `/prompts/new` โ Create Prompt
Full-page form (see Prompt Form below)
#### `/prompts/[id]` โ View Prompt
- Prompt detail view with full content
- Metadata panel: model, category, tags, created/updated dates, use count
- Attachments section
- Action buttons: Edit, Delete, Copy, Share
- Related prompts suggestions at bottom
#### `/prompts/[id]/edit` โ Edit Prompt
Same form as Create, pre-populated
#### `/share/[token]` โ Public Share Page
- Minimal, branded read-only view of a shared prompt
- Prominent "Copy Prompt" button
- "Create your own on PromptVault" CTA
- No auth required
---
### 3. Core Components
#### `<PromptCard />`
The primary display unit. Design two variants:
**Grid variant** (default):
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ [Category badge] [Model tag] โ
โ โ
โ Title (2-line clamp) โ
โ Description (3-line clamp) โ
โ โ
โ [Tag] [Tag] [Tag] +2 more โ
โ โ
โ โโ โโ โโ โโ โโ โโ โโ โโ โโ โ
โ ๐ Copy ๐ Share โ Edit โ
โ 3 days ago โ 47 uses โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
**List variant**:
- Single row with title, description snippet, category, tags, date, use count, actions
Card behaviors:
- Hover: lift shadow, slight scale (1.01), border color change
- Keyboard navigable
- Long-press / right-click context menu (Edit, Copy, Share, Delete)
#### `<PromptForm />` โ Create/Edit Form
Sections:
1. **Basic Info**
- Title (required, max 255 chars, character counter)
- Description (optional, textarea, max 500 chars)
- Category (select with "Add new" inline option)
- Tags (multi-tag input with autocomplete from existing tags)
- Target AI Model (select: GPT-4o, GPT-4-turbo, Claude 3.5 Sonnet, Claude 3 Opus, Gemini 1.5 Pro, Llama 3, Mistral Large, Custom...)
2. **Prompt Content** (required)
- Large textarea with monospace font option toggle
- Live character/token estimator (1 token โ 4 chars)
- Syntax highlighting for `{{variable}}` placeholders (highlight in accent color)
- "Preview with variables" mode
3. **Variables** (dynamic list)
- Detect `{{variable_name}}` patterns in content and auto-suggest
- For each variable: name (auto-filled), description, default value
- Add/remove variable rows
4. **Attachments** (file upload)
- Drag-and-drop zone + click to browse
- File type/size validation with inline error messages
- Upload progress indicator per file
- Thumbnail preview for images, icon+name for other types
- Remove attachment button
5. **Settings**
- Public / Private toggle with explanation tooltip
- Regenerate share link button
Form UX:
- Autosave draft to `localStorage` every 30 seconds
- Dirty state tracking with "Unsaved changes" indicator
- Discard changes confirmation dialog
- Keyboard shortcut: `Ctrl/Cmd + S` to save
#### `<SearchBar />`
- Instant search with 300ms debounce
- Search tokens: `in:title "exact phrase"`, `tag:marketing`, `model:gpt4`
- Recent searches stored in localStorage (last 10)
- Highlighted search matches in results
- `Cmd+K` / `Ctrl+K` keyboard shortcut to focus globally
#### `<ShareModal />`
- Shareable URL: `https://yourdomain.com/share/{token}`
- One-click copy URL button
- QR code generation (use `qrcode.react` library)
- Toggle public/private visibility
- "Link expires" option (optional enhancement)
- Social share buttons (Twitter/X, LinkedIn, copy link)
#### `<CopyButton />`
- Copies the raw prompt text to clipboard
- Animated checkmark feedback (0.5s)
- Increments `use_count` via API call in background
- Show toast: "Prompt copied to clipboard!"
- Option: "Copy with variables filled" if variables exist
#### `<DeleteConfirmDialog />`
- shadcn/ui `AlertDialog`
- Shows prompt title in the warning
- Lists associated attachments that will be deleted from R2
- Requires typing prompt title to confirm (for extra safety)
- Loading state on confirm button
#### `<CategoryBadge />`
- Colored pill with category name
- Color from `categories.color` field
- Click to filter by that category
#### `<TagBadge />`
- Neutral grey pill
- Click to filter by tag
#### `<EmptyState />`
- Illustrated SVG (geometric/abstract, matching theme)
- Context-aware messages (no prompts, no search results, no category prompts)
- Primary CTA button
---
### 4. Search Implementation
Implement a robust, fast search experience:
**Backend (Postgres full-text search)**:
```sql
-- Add a generated tsvector column for fast FTS
ALTER TABLE prompts ADD COLUMN search_vector tsvector
GENERATED ALWAYS AS (
setweight(to_tsvector('english', coalesce(title, '')), 'A') ||
setweight(to_tsvector('english', coalesce(description, '')), 'B') ||
setweight(to_tsvector('english', coalesce(content, '')), 'C') ||
setweight(to_tsvector('english', array_to_string(tags, ' ')), 'B')
) STORED;
CREATE INDEX prompts_search_vector_idx ON prompts USING GIN(search_vector);
```
**Frontend**:
- Debounced search input (300ms)
- Optimistic UI: show skeleton cards immediately
- URL sync: push search params to URL so results are shareable/bookmarkable (`/prompts?q=marketing&category=Sales`)
- Highlight matched terms in card titles/descriptions using a `<Highlight>` utility component
---
## ๐ฑ Responsive Design Breakpoints
Follow Tailwind's breakpoint system:
| Breakpoint | Width | Layout |
|------------|-------|--------|
| Mobile (default) | < 640px | Single column, bottom nav, full-width search |
| sm | 640px+ | 2-col grid |
| md | 768px+ | Sidebar appears, 2โ3 col grid |
| lg | 1024px+ | Sidebar + 3-col grid |
| xl | 1280px+ | Sidebar + 4-col grid, expanded stats |
Mobile-specific:
- Sidebar becomes a bottom sheet / drawer (use `vaul` library)
- FAB (floating action button) for "New Prompt" in bottom-right corner
- Search expands to full-screen overlay on tap
- Card actions collapse into a "โฎ" overflow menu
---
## โฟ Accessibility Requirements
- **WCAG 2.1 AA** compliance minimum
- All interactive elements have `aria-label` or visible label
- Focus management: trap focus in modals/dialogs; restore focus on close
- Keyboard navigation: all actions reachable without a mouse
- `role="status"` on search results count for screen reader announcements
- Color contrast ratio: โฅ 4.5:1 for normal text, โฅ 3:1 for large text
- `prefers-reduced-motion`: disable animations when user prefers
- `prefers-color-scheme`: implement a dark mode toggle (dark theme palette required)
- Skip-to-main-content link as first focusable element
- All images have meaningful `alt` text; decorative images use `alt=""`
---
## ๐ Dark Mode
Implement a dark mode using Tailwind's `class` strategy:
```css
/* Dark mode palette */
--background: #121210;
--surface: #1C1C1A;
--surface-elevated:#242420;
--border: #2E2D29;
--text-primary: #F0EDE8;
--text-secondary: #9C9890;
--text-muted: #6B6860;
--accent: #3B82F6;
```
- Persist user preference in `localStorage`
- Smooth transition: `transition-colors duration-200`
- Dark mode toggle button in the Header (sun/moon icon)
---
## โก Performance Requirements
- **Lighthouse score**: โฅ 90 on Performance, Accessibility, Best Practices, SEO
- **Core Web Vitals**: LCP < 2.5s, CLS < 0.1, FID < 100ms
- Use `next/image` for all images with proper `width`/`height` and `loading="lazy"`
- Implement **React Query** with stale-while-revalidate caching (staleTime: 60s)
- Paginate prompts (20 per page) โ never load all prompts at once
- Use `Suspense` + `loading.tsx` for streaming SSR
- Debounce search and filter inputs (300ms)
- Virtualize long lists with `@tanstack/react-virtual` if showing 100+ items at once
---
## ๐ Security
- Validate all inputs server-side with **Zod schemas** (never trust client)
- Sanitize prompt content to prevent XSS when rendering
- Rate limit API routes: max 100 req/min per IP using Vercel Edge middleware
- Presigned R2 URLs expire in 15 minutes
- Share tokens are UUID v4 โ unguessable
- Use `helmet`-equivalent HTTP headers via `next.config.js` headers
- Environment variables: never expose `CLOUDFLARE_R2_SECRET` or `DATABASE_URL` to client
---
## ๐ Project Structure
```
/
โโโ app/
โ โโโ layout.tsx # Root layout with Header + Footer
โ โโโ page.tsx # Dashboard
โ โโโ prompts/
โ โ โโโ page.tsx # All Prompts list
โ โ โโโ new/page.tsx # Create Prompt
โ โ โโโ [id]/
โ โ โโโ page.tsx # View Prompt
โ โ โโโ edit/page.tsx # Edit Prompt
โ โโโ share/[token]/page.tsx # Public share page
โ โโโ api/
โ โโโ prompts/
โ โ โโโ route.ts # GET (list), POST (create)
โ โ โโโ [id]/
โ โ โโโ route.ts # GET, PUT, DELETE
โ โ โโโ copy/route.ts # POST increment use_count
โ โโโ categories/route.ts
โ โโโ upload/
โ โ โโโ presign/route.ts
โ โ โโโ [key]/route.ts
โ โโโ share/[token]/route.ts
โโโ components/
โ โโโ layout/
โ โ โโโ Header.tsx
โ โ โโโ Footer.tsx
โ โ โโโ Sidebar.tsx
โ โโโ prompts/
โ โ โโโ PromptCard.tsx
โ โ โโโ PromptForm.tsx
โ โ โโโ PromptDetail.tsx
โ โ โโโ PromptGrid.tsx
โ โ โโโ PromptList.tsx
โ โโโ search/
โ โ โโโ SearchBar.tsx
โ โ โโโ SearchResults.tsx
โ โโโ ui/ # shadcn/ui components
โ โโโ modals/
โ โ โโโ ShareModal.tsx
โ โ โโโ DeleteConfirmDialog.tsx
โ โโโ common/
โ โโโ CopyButton.tsx
โ โโโ CategoryBadge.tsx
โ โโโ TagBadge.tsx
โ โโโ EmptyState.tsx
โโโ lib/
โ โโโ db/
โ โ โโโ index.ts # Drizzle client
โ โ โโโ schema.ts # Table definitions
โ โโโ r2/
โ โ โโโ client.ts # S3/R2 client setup
โ โโโ validations/
โ โ โโโ prompt.ts # Zod schemas
โ โโโ utils/
โ โโโ format.ts # Date, number formatters
โ โโโ search.ts # Search helpers
โโโ hooks/
โ โโโ usePrompts.ts # React Query hooks
โ โโโ useSearch.ts
โ โโโ useDebounce.ts
โ โโโ useClipboard.ts
โโโ store/
โ โโโ ui.ts # Zustand store (sidebar, theme, etc.)
โโโ types/
โ โโโ index.ts # Shared TypeScript types
โโโ drizzle.config.ts
```
---
## ๐ง Environment Variables
```env
# Vercel Postgres
DATABASE_URL=
# Cloudflare R2
CLOUDFLARE_R2_ACCOUNT_ID=
CLOUDFLARE_R2_ACCESS_KEY_ID=
CLOUDFLARE_R2_SECRET_ACCESS_KEY=
CLOUDFLARE_R2_BUCKET_NAME=
CLOUDFLARE_R2_PUBLIC_URL= # Public bucket URL or custom domain
# App
NEXT_PUBLIC_APP_URL= # e.g. https://promptvault.app
```
---
## ๐ Implementation Instructions
Build this application **step by step** in the following order:
1. **Project setup**: `npx create-next-app@latest --typescript --tailwind --app` + install all dependencies
2. **Database**: Write Drizzle schema โ run `drizzle-kit push` โ seed with 5โ10 sample prompts
3. **API layer**: Implement all route handlers with Zod validation (start with CRUD, then search, then upload)
4. **R2 integration**: Set up S3 client โ implement presign endpoint โ test uploads
5. **Core UI components**: Build design system tokens โ Header โ Footer โ Sidebar โ PromptCard
6. **Pages**: Dashboard โ Prompts list โ Create/Edit form โ View page โ Share page
7. **Search**: Implement Postgres FTS โ wire up SearchBar with debounce โ URL sync
8. **Polish**: Dark mode โ animations โ mobile responsiveness โ accessibility audit
9. **Testing**: Add error boundaries โ loading states โ empty states โ edge cases
---
## โ
Definition of Done
The application is complete when:
- [ ] All CRUD operations work end-to-end (create, read, update, delete prompts)
- [ ] Search returns relevant results across title, description, content, and tags
- [ ] Files upload to Cloudflare R2 and URLs are stored in Postgres
- [ ] Copy button copies prompt text to clipboard and increments use_count
- [ ] Share link generates a publicly accessible, read-only prompt view
- [ ] Responsive layout works correctly on 320px, 768px, and 1440px viewports
- [ ] Dark mode toggles correctly and persists across sessions
- [ ] Lighthouse accessibility score โฅ 90
- [ ] All forms validate input and show inline error messages
- [ ] Deleting a prompt removes associated R2 files
- [ ] Header and footer are present on all pages
- [ ] Empty states and loading states are implemented throughout
- [ ] No TypeScript errors (`tsc --noEmit` passes)
- [ ] Search results are paginated and URL-synced
---
*Prompt authored for PromptVault โ AI Prompt Manager ยท v1.0*Similar category and model suggestions.