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
42 changes: 38 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ npm run generate:favicons # Generate favicon assets
## Key Directories
- `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/components/editor/` — React components for the OG image editor
- `src/components/preview/` — React components for the social media preview checker
- `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/styles/` — CSS files (global.css, editor.css, preview.css, api-docs.css)
- `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/, lib/, templates/)
- `tests/` — Vitest tests (api/, ai/, lib/, templates/)

## Pages & API Endpoints

Expand All @@ -51,13 +53,22 @@ npm run generate:favicons # Generate favicon assets
- `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`
- Reference template: `src/templates/blog/minimal-dark.ts`
- Shared utilities: `src/templates/utils.ts` (truncate, autoFontSize, commonFields)
- 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

Expand All @@ -72,6 +83,29 @@ npm run generate:favicons # Generate favicon assets
**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/*`.
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.
2 changes: 1 addition & 1 deletion src/components/BackToTop.astro
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<style>
.back-to-top {
position: fixed;
bottom: 90px;
bottom: 80px;
right: var(--space-xl, 24px);
z-index: 8000;
width: 40px;
Expand Down
58 changes: 58 additions & 0 deletions src/components/FeedbackButton.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!-- Feedback button: fixed bottom-right, opens GitHub issues -->
<a
href="https://github.com/codercops/ogcops/issues/new/choose"
target="_blank"
rel="noopener"
class="feedback-btn"
aria-label="Send feedback"
title="Send feedback"
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
<span class="feedback-btn-label">Feedback</span>
</a>

<style>
.feedback-btn {
position: fixed;
bottom: var(--space-xl, 24px);
right: var(--space-xl, 24px);
z-index: 8000;
display: flex;
align-items: center;
gap: 6px;
padding: 8px 14px;
background: var(--bg-elevated, #fff);
border: 1px solid var(--border, #e5e5e5);
border-radius: var(--radius-full, 999px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
color: var(--text-muted, #666);
font-size: 12px;
font-weight: 500;
text-decoration: none;
cursor: pointer;
transition: color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.feedback-btn:hover {
color: var(--accent-primary, #e07a5f);
border-color: var(--accent-primary, #e07a5f);
box-shadow: 0 4px 12px rgba(224, 122, 95, 0.15);
}

.feedback-btn svg {
flex-shrink: 0;
}

@media (max-width: 480px) {
.feedback-btn {
right: var(--space-md, 12px);
padding: 8px 12px;
}

.feedback-btn-label {
display: none;
}
}
</style>
Loading
Loading