Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
push:
branches: [main, dev]
branches: [production, dev]
pull_request:
branches: [main, dev]
branches: [production, dev]

jobs:
build:
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/pr-target-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ name: PR Target Check

on:
pull_request:
branches: [main]
branches: [production]

jobs:
check-source-branch:
runs-on: ubuntu-latest
steps:
- name: Only allow PRs from dev to main
if: github.head_ref != 'dev'
- name: Only allow PRs from dev or release branches to production
if: github.head_ref != 'dev' && !startsWith(github.head_ref, 'release/')
run: |
echo "::error::PRs targeting 'main' are only allowed from the 'dev' branch."
echo "::error::PRs targeting 'production' are only allowed from 'dev' or 'release/*' branches."
echo "Please target 'dev' instead, or merge your branch into 'dev' first."
echo ""
echo " Source: ${{ github.head_ref }}"
echo " Target: ${{ github.base_ref }}"
exit 1
- name: PR source branch is valid
if: github.head_ref == 'dev'
run: echo "PR from 'dev' to 'main' — allowed."
if: github.head_ref == 'dev' || startsWith(github.head_ref, 'release/')
run: echo "PR from '${{ github.head_ref }}' to 'production' — allowed."
119 changes: 97 additions & 22 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
# CLAUDE.md — OGCOPS

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What is this?
OGCOPS is a free, open-source OG image generator and social media preview checker. Built with Astro + React Islands, deployed to Vercel.
OGCOPS is a free, open-source OG image generator and social media preview checker. Built with Astro SSR + React Islands, deployed to Vercel at og.codercops.com. GitHub: github.com/codercops/ogcops. MIT licensed.

## Commands
```bash
npm run dev # Start dev server
npm run build # Production build
npm run preview # Preview production build
npm run test # Run vitest
npm run test:watch # Watch mode
npm run check # Type-check (astro check + tsc)
npm run dev # Start dev server (port 4321)
npm run build # Production build
npm run preview # Preview production build
npm run test # Run vitest (single run)
npm run test:watch # Watch mode
npm run test:ui # Vitest UI
npm run check # Type-check (astro check + tsc --noEmit)
npm run lint # Astro linting
npm run generate:favicons # Generate favicon assets
```

## Architecture
Expand All @@ -19,20 +24,39 @@ npm run check # Type-check (astro check + tsc)
- **Satori** runs client-side for instant SVG preview (zero server calls during editing)
- **Satori + resvg-wasm** runs server-side for PNG generation (`/api/og`)
- **No database** — state lives in URL query params + client-side useReducer
- **CORS-open API** for developer use
- **CORS-open API** — no API key, no rate limits

## Key Directories
- `src/templates/` — 109 templates across 12 categories. Each template is a `.ts` file exporting a `TemplateDefinition`.
- `src/lib/` — Core engine (og-engine.ts, font-loader.ts, meta-fetcher.ts, meta-analyzer.ts)
- `src/components/editor/` — React components for the OG image editor
- `src/components/preview/` — React components for the social media preview checker
- `src/pages/api/` — API endpoints (og, preview, templates)
- `src/templates/` — 120 templates across 12 categories. Each is a `.ts` file exporting a `TemplateDefinition`.
- `src/lib/` — Core engine (og-engine.ts, font-loader.ts, meta-fetcher.ts, meta-analyzer.ts, api-validation.ts)
- `src/lib/ai/` — AI integration (types, providers, storage, validation, prompts, generate, autofill, recommender)
- `src/components/editor/` — React components for the OG image editor (includes AI components)
- `src/components/preview/` — React components for the social media preview checker (includes AIAnalyzer)
- `src/pages/api/` — API endpoints
- `src/pages/api/ai/` — AI proxy endpoints (generate, validate, autofill)
- `src/styles/` — CSS files (global.css, editor.css, preview.css, api-docs.css, ai.css)
- `public/fonts/` — Bundled .woff fonts (Inter, Playfair Display, JetBrains Mono)
- `tests/` — Vitest tests (api/, ai/, lib/, templates/)

## Conventions
- CSS custom properties only (no Tailwind). Accent: `#E07A5F`.
- TypeScript strict mode. Path alias `@/*` → `src/*`.
- Fonts bundled as `.woff` in `public/fonts/`.
- Templates follow `TemplateDefinition` interface in `src/templates/types.ts`.
## Pages & API Endpoints

**Pages:**
- `/` — Homepage
- `/create/` — OG image editor
- `/templates` — Template gallery
- `/preview` — Social media preview checker
- `/api-docs` — API documentation

**API (all CORS-open, no auth):**
- `GET /api/og?template={id}&...` — Generate PNG (1200x630, 24h cache)
- `GET /api/preview?url={url}` — Fetch and analyze a URL's meta tags
- `GET /api/templates` — List all templates as JSON
- `GET /api/templates/[id]/thumbnail.png` — Template thumbnail (1-week cache)

**AI API (BYOK — user provides their own API key):**
- `POST /api/ai/generate` — Proxy text generation to any supported provider
- `POST /api/ai/validate` — Validate an AI provider API key
- `POST /api/ai/autofill` — Analyze a URL and auto-fill template fields via AI

## Reference Files
- Template interface: `src/templates/types.ts`
Expand All @@ -41,20 +65,71 @@ npm run check # Type-check (astro check + tsc)
- OG engine: `src/lib/og-engine.ts`
- API validation schemas: `src/lib/api-validation.ts`
- Template registry: `src/templates/registry.ts`
- AI types & provider configs: `src/lib/ai/types.ts`, `src/lib/ai/providers.ts`
- AI validation schemas: `src/lib/ai/validation.ts`
- AI prompt builders: `src/lib/ai/prompts.ts`
- AI context & hook: `src/components/editor/AIContext.tsx`

## Template System

120 templates across 12 categories: blog, product, saas, github, event, podcast, developer, newsletter, quote, ecommerce, job, tutorial.

## Template Contribution
1. Create `src/templates/{category}/{id}.ts`
2. Export a `TemplateDefinition`
3. Register in `src/templates/{category}/index.ts`
**Adding a template:**
1. Create `src/templates/{category}/{id}.ts` exporting a `TemplateDefinition`
2. Register in `src/templates/{category}/index.ts`
3. Add import + registration in `src/templates/registry.ts`
4. Run `npm run test` to verify

**Template field types:** text, textarea, color, select, number, toggle, image.
**Field groups:** Content, Style, Brand.

## AI Integration (BYOK)

OGCOPS supports AI-powered features using a Bring Your Own Key (BYOK) model. Users configure their own API keys in the browser; keys are stored in localStorage and passed through server-side proxy endpoints (never stored server-side).

**Supported providers:** OpenAI, Anthropic, Google (Gemini), Groq, OpenRouter.
**Three API formats:** OpenAI-compatible (OpenAI/Groq/OpenRouter), Anthropic, Google Gemini.

**AI Features:**
- **AI Copy Generator** — Generate title/subtitle/field suggestions inline in the editor
- **Smart Autofill** — Paste a URL to auto-select a template and fill all fields
- **AI Template Recommender** — Natural language template search in the template panel
- **AI Meta Analyzer** — AI-powered analysis of meta tag quality in the preview checker

**Key files:**
- `src/lib/ai/` — All AI logic (types, providers, storage, validation, prompts, generate, autofill, recommender)
- `src/components/editor/AIContext.tsx` — React context providing `generate()`, `isConfigured`, `openSettings`
- `src/components/editor/AISettingsModal.tsx` — Provider/key/model configuration modal
- `src/components/editor/AIGenerateButton.tsx` + `AISuggestionPicker.tsx` — Inline copy generation
- `src/components/editor/AIAutofill.tsx` — Smart autofill from URL
- `src/components/editor/AITemplateSearch.tsx` — AI template recommender
- `src/components/preview/AIAnalyzer.tsx` — AI meta tag analysis
- `src/styles/ai.css` — All AI component styles


## Conventions
- CSS custom properties only (no Tailwind). Accent: `#E07A5F`.
- TypeScript strict mode. Path alias `@/*` → `src/*`.
- Fonts bundled as `.woff` in `public/fonts/` (Inter Regular/Medium/SemiBold/Bold, Playfair Display Regular/Bold, JetBrains Mono Regular/Bold).
- Node 22 (`.nvmrc`).
- Testing: Vitest with node environment. Tests in `tests/**/*.test.ts`. Globals enabled.

## CI/CD
- Runs on push to `production`/`dev` and PRs to those branches
- Steps: `npm run check` → `npm run test` → `npm run build`
- **Branch strategy:** `dev` is the default branch. PRs target `dev`. Releases go `dev` → `production`. Direct PRs to `production` are blocked unless from `dev`.

## Environment Variables (`.env.local`, all optional)
- `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN` — Optional visitor counter

## Gotchas / Constraints
- Satori does **not** support CSS grid — only flexbox
- Every `div` must have `display: 'flex'` explicitly in its style
- No CSS classes in satori JSX — inline styles only
- Font files must be listed in `astro.config.mjs` `includeFiles` array for Vercel deployment
- WASM imports need `optimizeDeps.exclude` in the Vite config
- `renderToPng` returns `ArrayBuffer` (not `Buffer`) for `BodyInit` compatibility
- Canvas is always 1200x630px

## Do NOT
- Add Tailwind CSS — the project uses CSS custom properties only
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ npm run build # Full production build
1. Fork the repo and create a branch: `git checkout -b feat/my-feature`
2. Make your changes
3. Ensure `npm run check` and `npm run test` pass
4. Push and open a PR against `main`
4. Push and open a PR against `dev`
5. Fill out the [PR template](.github/PULL_REQUEST_TEMPLATE.md) — screenshots are required for visual changes
6. Wait for review

Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ OGCOPS is different:
## Quick Start

```bash
git clone https://github.com/codercops/ogcops.git
git clone -b dev https://github.com/codercops/ogcops.git
cd ogcops
npm install
npm run dev
Expand Down Expand Up @@ -114,6 +114,16 @@ The build output in `dist/` can be deployed to any Node.js hosting platform.

Contributions are welcome — templates, bug fixes, features, docs, and more. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and guidelines.

> **Important:** Always fork and branch from `dev` (the default branch). The `production` branch is for releases only. PRs targeting `production` directly will be closed.

```bash
# Fork the repo on GitHub, then:
git clone https://github.com/<your-username>/ogcops.git
cd ogcops
git checkout dev
git checkout -b your-feature-branch
```

- [Open an issue](https://github.com/codercops/ogcops/issues) — bug reports and feature requests
- [Start a discussion](https://github.com/codercops/ogcops/discussions) — questions, ideas, show & tell

Expand Down
162 changes: 162 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Release Process

This document describes the step-by-step process for creating a production release of OGCOPS.

## Branch Strategy

```
feature branches → PR to dev (upstream) → merge → PR to production → merge → release → sync back to dev
```

| Branch | Purpose |
|--------|---------|
| `dev` | Default branch. All feature PRs target this branch. |
| `production` | Stable release branch. Only accepts PRs from `dev`. |

## Versioning

We follow [Semantic Versioning](https://semver.org/):

- **`patch`** (1.0.0 → 1.0.1): Bug fixes, minor CSS tweaks
- **`minor`** (1.0.0 → 1.1.0): New features, new templates, UI improvements
- **`major`** (1.0.0 → 2.0.0): Breaking API changes, major redesigns

## Pre-Release Checklist

- [ ] All feature PRs merged into `dev`
- [ ] `npm run check` passes (TypeScript + Astro type-check)
- [ ] `npm run test` passes
- [ ] `npm run build` succeeds
- [ ] Manual testing on desktop and mobile
- [ ] No unresolved critical issues

## Release Steps

### 1. Verify dev is clean

```bash
cd ogcops
git fetch upstream
git checkout dev
git pull upstream dev
npm run check && npm run test && npm run build
```

### 2. Create a release PR (dev → production)

```bash
gh pr create \
--repo codercops/ogcops \
--head dev \
--base production \
--title "release: vX.Y.Z — Short description" \
--body "$(cat <<'EOF'
## Release vX.Y.Z

Brief summary of what's in this release.

### Fixes
- ...

### Enhancements
- ...

### Docs & Chores
- ...

### Test Plan
- [ ] ...

EOF
)"
```

### 3. Review and merge the PR

- Ensure CI passes on the PR
- Review the diff one final time
- **Squash and merge** into `production`

### 4. Create the GitHub Release

```bash
gh release create vX.Y.Z \
--repo codercops/ogcops \
--target production \
--title "vX.Y.Z — Short description" \
--notes "$(cat <<'EOF'
## What's Changed

### Fixes
- ...

### Enhancements
- ...

### Docs & Chores
- ...

**Full Changelog**: https://github.com/codercops/ogcops/compare/vPREVIOUS...vX.Y.Z

EOF
)"
```

### 5. Sync production back into dev

Since `dev` has branch protection, create a sync PR:

```bash
gh pr create \
--repo codercops/ogcops \
--head production \
--base dev \
--title "chore: sync production into dev after vX.Y.Z release" \
--body "Syncs production back into dev after the [vX.Y.Z release](https://github.com/codercops/ogcops/releases/tag/vX.Y.Z)."
```

Then **merge** this PR (use regular merge, NOT squash, to keep history aligned).

### 6. Update your fork

```bash
git fetch upstream
git checkout dev
git pull upstream dev
git push origin dev
```

## Quick Reference (Copy-Paste)

Replace `X.Y.Z` with the actual version and `PREVIOUS` with the last release tag.

```bash
# Step 1: Verify
npm run check && npm run test && npm run build

# Step 2: Release PR
gh pr create --repo codercops/ogcops --head dev --base production \
--title "release: vX.Y.Z — Description"

# Step 3: Merge the PR on GitHub (squash and merge)

# Step 4: Create release
gh release create vX.Y.Z --repo codercops/ogcops --target production \
--title "vX.Y.Z — Description" --generate-notes

# Step 5: Sync PR
gh pr create --repo codercops/ogcops --head production --base dev \
--title "chore: sync production into dev after vX.Y.Z release"

# Step 6: Merge the sync PR on GitHub (regular merge, NOT squash)

# Step 7: Update fork
git fetch upstream && git checkout dev && git pull upstream dev && git push origin dev
```

## Notes

- The `pr-target-check.yml` workflow enforces that only `dev` can PR into `production`.
- CI runs on all PRs to both `dev` and `production` branches.
- Vercel auto-deploys `production` after merge.
- Use `--generate-notes` flag on `gh release create` to auto-generate changelog from commits.
Loading
Loading