Thanks for your interest in contributing to SpecMirror. This guide will help you get started.
- Code of Conduct
- Getting Started
- Development Setup
- Project Structure
- Making Changes
- Commit Conventions
- Pull Request Process
- Code Style
- Edge Functions
- Design System
- Reporting Issues
Be respectful, constructive, and collaborative. We're building tools for engineers — let's treat each other like the professionals we are.
- Fork the repository
- Clone your fork locally
- Create a feature branch from
main - Make your changes
- Submit a pull request
- Node.js 18+ (or Bun)
- npm, pnpm, or bun for package management
# Clone the repo
git clone https://github.com/your-username/specmirror.git
cd specmirror
# Install dependencies
npm install
# Start the dev server
npm run devThe app will be available at http://localhost:5173.
The project uses Lovable Cloud for backend services. Environment variables are managed automatically in the Lovable environment. For local development, create a .env.local file:
VITE_SUPABASE_URL=<your-backend-url>
VITE_SUPABASE_PUBLISHABLE_KEY=<your-anon-key>
src/
├── components/ # Reusable UI components
│ └── ui/ # shadcn/ui primitives (do not edit directly)
├── contexts/ # React context providers (auth, etc.)
├── hooks/ # Custom React hooks
├── integrations/ # Backend client configuration (auto-generated, do not edit)
├── lib/ # Utility functions (crypto, helpers)
├── pages/ # Route-level page components
└── index.css # Design tokens and global styles
supabase/
└── functions/ # Backend edge functions
| File | Purpose | Editable? |
|---|---|---|
src/integrations/supabase/client.ts |
Backend client | ❌ Auto-generated |
src/integrations/supabase/types.ts |
Database types | ❌ Auto-generated |
src/index.css |
Design tokens | ✅ With care |
tailwind.config.ts |
Tailwind theme | ✅ With care |
supabase/functions/* |
Edge functions | ✅ |
- Check existing issues and PRs to avoid duplicate work
- For significant changes, open an issue first to discuss the approach
- Keep PRs focused — one feature or fix per PR
feature/add-slack-integration
fix/share-link-expiry
refactor/dashboard-layout
docs/update-readme
We follow Conventional Commits:
feat: add encrypted link expiry selector
fix: resolve share dialog not closing on success
refactor: extract spec renderer into standalone component
docs: add contributing guidelines
chore: update dependencies
- Use present tense ("add feature" not "added feature")
- Use lowercase for the description
- Keep the subject line under 72 characters
- Reference issue numbers where applicable:
feat: add export to PDF (#42)
- Update tests if your change affects existing behavior
- Run the linter before submitting:
npm run lint - Build successfully:
npm run build - Write a clear PR description explaining:
- What the change does
- Why it's needed
- How to test it
- Screenshots for UI changes
- Request review from at least one maintainer
- Address feedback promptly — we aim to merge within 48 hours of approval
- Strict mode is enabled — no
anytypes without justification - Use explicit return types on exported functions
- Prefer
interfaceovertypefor object shapes - Use barrel exports sparingly
- Functional components only
- Prefer composition over prop drilling — use context where appropriate
- Keep components small and focused (under ~150 lines)
- Co-locate component-specific hooks and utilities
// ✅ Good — focused, typed, readable
interface SpecCardProps {
title: string;
status: "draft" | "approved";
onShare: () => void;
}
const SpecCard = ({ title, status, onShare }: SpecCardProps) => {
return (
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">{title}</CardTitle>
{status === "approved" && (
<Badge className="text-emerald-400">Approved</Badge>
)}
</CardHeader>
</Card>
);
};- Always use semantic design tokens — never hardcode colors
- Use
text-foreground,bg-background,border-border, etc. - Custom colors belong in
index.cssas CSS variables, then referenced intailwind.config.ts - SpecMirror is dark mode only — do not add light mode variants
// ❌ Wrong
<div className="bg-black text-white border-gray-700">
// ✅ Correct
<div className="bg-card text-foreground border-border">Edge functions live in supabase/functions/ and run on Deno.
- Each function gets its own directory with an
index.ts - Always include CORS headers for browser requests
- Validate all input — never trust client data
- Use environment variables for secrets (never hardcode)
- Handle errors gracefully with appropriate HTTP status codes
// Standard edge function structure
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers":
"authorization, x-client-info, apikey, content-type",
};
serve(async (req) => {
if (req.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}
try {
// Your logic here
return new Response(JSON.stringify({ data }), {
headers: { ...corsHeaders, "Content-Type": "application/json" },
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
});SpecMirror uses a strict dark-mode design system. Key tokens:
| Token | Value | Usage |
|---|---|---|
--background |
zinc-950 | Page background |
--primary |
indigo-500 | Buttons, links, accents |
--accent |
emerald-400 | Success states, approved badges |
--foreground |
white/zinc-100 | Primary text |
--muted |
zinc-400 | Secondary text |
When adding new UI components:
- Start with shadcn/ui primitives where possible
- Follow the existing Linear-inspired aesthetic
- Use
framer-motionfor animations - Test at common viewport sizes (mobile, tablet, desktop)
Include:
- Steps to reproduce
- Expected vs actual behavior
- Browser and OS
- Screenshots or screen recordings
- Console errors (if any)
Include:
- The problem you're trying to solve
- Your proposed solution
- Alternative approaches you've considered
- Who benefits from this change
A quick reference for contributors:
| Layer | Technology | Notes |
|---|---|---|
| Framework | React 18 + TypeScript 5 | Strict mode, functional components only |
| Build | Vite 5 | HMR, fast builds |
| Styling | Tailwind CSS v3 | Semantic design tokens, dark mode only |
| UI Primitives | shadcn/ui | Do not edit src/components/ui/ directly |
| Animations | Framer Motion | Used for page transitions and micro-interactions |
| Backend | Lovable Cloud | Edge functions (Deno), auth, Postgres database, storage |
| AI | SpecAI via Lovable AI Gateway | Spec and PRD generation with confidence scoring |
| Encryption | AES-256-GCM | Web Crypto API, client-side only — keys never leave the browser |
| Testing | Vitest (unit) + Playwright (e2e) | npm test / npx playwright test |
| Linting | ESLint | npm run lint |
| Deployment | Lovable Cloud | Auto-deployed on push |
Open a Discussion or reach out to the maintainers. We're happy to help you find the right place to contribute.
Welcome aboard — let's build better specs together.