Validates that MVP templates meet all integration requirements before deployment. Checks structure, content slots, brand tokens, Supabase schemas, Stripe config, auth flows, and code quality. Use after running template-scaffolding.
Ensure templates meet all integration requirements and quality standards before they can be used by the Co-CEO template integration skills. Validates structure, content slots, brand tokens, database schemas, payment config, authentication flows, and code quality.
Core principle: Templates must be integration-ready. A missing content slot breaks the copywriter skill. A missing RLS policy creates security vulnerabilities.
template-scaffolding skill creates templates# Check templates directory exists
ls -la templates/
# Expected templates:
# - templates/analytics-dashboard/
# - templates/productivity-tool/
# - templates/content-creator/
# - templates/utility-processor/
# - templates/digital-download/
CRITICAL: Before validating structure, verify the template has not been contaminated with features from other templates.
Check against: docs/template-integrity-checklist.md
Validation Steps:
# For digital-download - should only have main dashboard page:
ls -la templates/digital-download/frontend/app/\(dashboard\)/dashboard/
# Expected: page.tsx only
# ❌ CONTAMINATION if: calendar/, queue/, media/, connect/, analytics/ exist
# For content-creator - should have full content suite:
ls -la templates/content-creator/frontend/app/\(dashboard\)/dashboard/
# Expected: page.tsx, queue/, calendar/, media/, connect/, analytics/
# For analytics-dashboard - should have analytics pages only:
ls -la templates/analytics-dashboard/frontend/app/\(dashboard\)/dashboard/
# Expected: page.tsx, public/ (for public dashboards)
# ❌ CONTAMINATION if: queue/, calendar/, media/, connect/ exist
# Check digital-download for content-creator components:
find templates/digital-download -name "*.tsx" | xargs grep -l "RichTextEditor\|MediaUploader\|ContentCalendar\|workspace"
# Expected: no results
# ❌ CONTAMINATION if any matches found
# Check analytics-dashboard for content components:
find templates/analytics-dashboard -name "*.tsx" | xargs grep -l "RichTextEditor\|MediaUploader\|ContentCalendar"
# Expected: no results
# Digital-download should be single-user (no workspaces/teams):
grep -r "workspace\|team_member" templates/digital-download/supabase/migrations/
# Expected: no results (except in comments)
# Content-creator should have multi-tenant:
grep -r "workspace\|team_member" templates/content-creator/supabase/migrations/
# Expected: migrations defining these tables
# Review sidebar to ensure navigation matches template type
grep -A 20 "const navigation" templates/{template-name}/frontend/components/dashboard/Sidebar.tsx
Validation Rules:
If contamination found:
Every template must have the exact directory structure. Missing directories or files are blockers.
Required Structure:
templates/{template-name}/
├── manifest.json # REQUIRED
├── README.md # REQUIRED
├── frontend/ # REQUIRED
│ ├── package.json # REQUIRED
│ ├── next.config.js # REQUIRED
│ ├── tsconfig.json # REQUIRED
│ ├── tailwind.config.js # REQUIRED
│ ├── app/ # REQUIRED
│ │ ├── layout.tsx # REQUIRED
│ │ ├── page.tsx # REQUIRED
│ │ ├── (auth)/ # REQUIRED
│ │ │ ├── login/ # REQUIRED
│ │ │ ├── signup/ # REQUIRED
│ │ │ └── callback/ # REQUIRED
│ │ ├── (dashboard)/ # REQUIRED
│ │ │ ├── layout.tsx # REQUIRED
│ │ │ ├── page.tsx # REQUIRED
│ │ │ └── settings/ # REQUIRED
│ │ └── api/ # REQUIRED
│ │ └── stripe/ # REQUIRED
│ ├── components/ # REQUIRED
│ ├── lib/ # REQUIRED
│ │ ├── supabase/ # REQUIRED
│ │ └── stripe/ # REQUIRED
│ └── styles/ # REQUIRED
│ └── tokens.css # REQUIRED
├── supabase/ # REQUIRED
│ ├── config.toml # REQUIRED
│ └── migrations/ # REQUIRED
├── stripe/ # REQUIRED
│ └── products.json # REQUIRED
└── content/ # REQUIRED
└── slots.json # REQUIRED
Validation Command:
.claude/scripts/templates/check-structure.py templates/{template-name}
The manifest.json must contain all required fields:
{
"name": "string (required) - lowercase, hyphenated",
"displayName": "string (required) - human-readable",
"description": "string (required) - 50-200 chars",
"version": "string (required) - semver format",
"category": "string (required) - analytics|productivity|content",
"techStack": {
"frontend": "string (required)",
"database": "string (required)",
"auth": "string (required)",
"payments": "string (required)"
},
"features": "array (required) - min 3 items",
"brandTokens": "array (required) - CSS variable names",
"contentSlots": "number (required) - count of slots"
}
Validation Rules:
name matches directory nameversion follows semver (X.Y.Z)category is one of allowed valuestechStack has all 4 required fieldsfeatures has at least 3 itemsbrandTokens includes minimum tokens: --color-primary, --font-displaycontentSlots count matches actual slots in slots.jsonThe content/slots.json must be valid and complete:
Required Slot Categories:
landing - Hero headline, subheadline, CTA, featuresdashboard - Empty stateserrors - Error messages (generic, network)auth - Login/signup titlesValidation Rules:
type fieldmaxLength fielditemType definitioncontentSlotsValidation Command:
.claude/scripts/templates/check-content-slots.py templates/{template-name}/content/slots.json
The styles/tokens.css must define all required CSS variables:
Required Tokens:
:root {
/* Colors - REQUIRED */
--color-primary: ...;
--color-secondary: ...;
--color-accent: ...;
--color-background: ...;
--color-foreground: ...;
--color-muted: ...;
/* Semantic Colors - REQUIRED */
--color-success: ...;
--color-warning: ...;
--color-error: ...;
--color-info: ...;
/* Typography - REQUIRED */
--font-display: ...;
--font-body: ...;
--font-mono: ...;
/* Spacing Scale - REQUIRED */
--spacing-xs: ...;
--spacing-sm: ...;
--spacing-md: ...;
--spacing-lg: ...;
--spacing-xl: ...;
/* Border Radius - REQUIRED */
--radius-sm: ...;
--radius-md: ...;
--radius-lg: ...;
}
/* Dark Mode - REQUIRED */
.dark {
--color-background: ...;
--color-foreground: ...;
/* ... all color tokens must have dark variants */
}
Validation Rules:
brandTokens arrayValidation Command:
.claude/scripts/templates/check-brand-tokens.py templates/{template-name}
Migration files must be valid and complete:
Required Tables:
profiles - User profiles extending auth.usersteams - Multi-tenant supportteam_members - Team membershipcustomers - Stripe customer mappingsubscriptions - Subscription trackingRequired RLS Policies: Every table with user data MUST have Row Level Security:
ALTER TABLE public.{table} ENABLE ROW LEVEL SECURITY;
CREATE POLICY "..." ON public.{table} FOR SELECT USING (...);
CREATE POLICY "..." ON public.{table} FOR INSERT WITH CHECK (...);
CREATE POLICY "..." ON public.{table} FOR UPDATE USING (...);
CREATE POLICY "..." ON public.{table} FOR DELETE USING (...);
Validation Rules:
SET search_path = 'public'Validation Command:
.claude/scripts/templates/check-supabase-schema.py templates/{template-name}/supabase/migrations/
The stripe/products.json must follow best practices:
Required Structure:
{
"products": [
{
"id": "string (required)",
"name": "string (required)",
"description": "string (required)",
"features": ["array (required)"],
"prices": {
"monthly": { "amount": "number", "currency": "string" },
"yearly": { "amount": "number", "currency": "string" }
}
}
]
}
Validation Rules:
highlighted: truePortal Config (stripe/portal-config.json):
features objectAuth implementation must be complete and secure:
Required Files:
app/(auth)/login/page.tsx - Login page existsapp/(auth)/signup/page.tsx - Signup page existsapp/(auth)/callback/route.ts - OAuth callback handlerlib/supabase/client.ts - Browser clientlib/supabase/server.ts - Server clientlib/supabase/middleware.ts - Auth middlewareRequired Auth Features:
Validation Rules:
TypeScript and accessibility checks:
TypeScript:
cd templates/{template-name}/frontend && npx tsc --noEmit
any types without justificationAccessibility:
Linting:
cd templates/{template-name}/frontend && npx eslint app/ components/ --max-warnings 0
Template-specific components must exist:
Analytics Template:
Productivity Template:
Content Template:
Key flows should have tests:
Recommended Tests:
.claude/scripts/templates/validate-template.sh templates/analytics-dashboard
This master script runs all checks in sequence and reports:
Output Format:
# Template Validation Report
**Template:** analytics-dashboard
**Date:** 2025-12-30
**Overall Status:** ⚠️ WARNINGS (2 blockers, 3 warnings, 1 suggestion)
## ❌ Blockers (Must Fix)
### 1. Missing RLS policy on `analytics_events` table
- **Location:** supabase/migrations/00003_app_schema.sql
- **Issue:** Table has RLS enabled but no policies defined
- **Fix:** Add SELECT/INSERT policies with user_id check
### 2. Content slot count mismatch
- **Location:** content/slots.json, manifest.json
- **Issue:** Manifest says 42 slots, slots.json has 38
- **Fix:** Update manifest.contentSlots to 38
## ⚠️ Warnings (Should Fix)
### 1. No yearly discount badge
- **Location:** stripe/products.json
- **Issue:** Yearly pricing exists but no "Save X%" calculated
- **Suggestion:** Add `yearlyDiscount` field
...
## 💡 Suggestions (Optional)
### 1. Add loading skeleton for MetricChart
- Components would benefit from Suspense boundaries
Address blockers first, then warnings. Re-run validation after fixes.
All templates must pass with no blockers:
.claude/scripts/templates/validate-template.sh templates/analytics-dashboard
.claude/scripts/templates/validate-template.sh templates/productivity-tool
.claude/scripts/templates/validate-template.sh templates/content-creator
# Expected: All pass with "✅ PASS" status
Location: .claude/scripts/templates/
| Script | Purpose | Exit Codes |
|---|---|---|
validate-template.sh | Master validation runner | 0=pass, 1=warnings, 2=blockers |
check-structure.py | Directory structure validation | 0=pass, 1=missing files |
check-content-slots.py | Content slots JSON validation | 0=pass, 1=invalid |
check-brand-tokens.py | CSS token validation | 0=pass, 1=missing tokens |
check-supabase-schema.py | SQL migration validation | 0=pass, 1=invalid SQL |
check-stripe-config.py | Stripe products validation | 0=pass, 1=invalid config |
| Severity | Meaning | Action |
|---|---|---|
| BLOCKER | Template cannot be used | Must fix before any integration |
| WARNING | Template works but has issues | Fix before production use |
| SUGGESTION | Improvement opportunity | Optional enhancement |
Safe to auto-fix:
Never auto-fix:
Inputs:
template-scaffolding skilltemplates/Outputs:
Used by:
| Issue | Common Cause | Fix |
|---|---|---|
| Structure validation fails | Missing nested directory | Create missing dirs with proper files |
| Content slots mismatch | Added slots without updating manifest | Run check-content-slots.py --update-manifest |
| RLS policy missing | Forgot to add after table creation | Add policy in same migration file |
| TypeScript errors | Missing type definitions | Add proper interfaces |
| Hard-coded colors | Copied code without tokenizing | Replace with var(--color-*) |
| Auth callback fails | Wrong redirect URL | Use environment variable |