AI-powered content transformation platform that converts newsletters and articles into platform-optimized social media posts.
Generate platform-ready posts from one input in under a minute, with consistent voice and lower content ops effort.
| Feature | Description |
|---|---|
| Multi-Platform Generation | Create optimized posts for LinkedIn, X (Twitter), and Instagram from a single input |
| Smart URL Extraction | Extract content from any URL using Jina Reader with automatic cleaning |
| Batched AI Processing | Cost-optimized API calls - generates for all platforms in a single request |
| Voice & Tone Control | Customize output style with configurable tone presets |
| Post Management | Save, edit, and organize generated content with Appwrite backend |
| One-Click Sharing | Share directly to social platforms or copy to clipboard |
| Freemium Model | Free tier (3/day) with Pro subscriptions via Stripe |
| Mobile-First Design | Responsive UI with bottom sheet navigation on mobile/tablet |
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLIENT (React 19 + Vite 7) │
├─────────────────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Pages/ │ │ Components/ │ │ Hooks/ │ │ Config/ │ │
│ │ GeneratorV2 │ │ shadcn/ui │ │ useContent │ │ app.config │ │
│ │ Settings │ │ Radix UI │ │ Generation │ │ env.config │ │
│ │ Landing │ │ Mobile UI │ │ useAuth │ │ platforms │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ EDGE FUNCTIONS (Vercel) │
├─────────────────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ /api/openrouter ││ /api/extract │ │ /api/stripe │ │ /api/share │ │
│ │ Proxy to ││ Jina Reader │ │ Checkout │ │ LinkedIn │ │
│ │ OpenRouter ││ Extraction │ │ Portal │ │ Share │ │
│ └──────────────┘ └──────────────┘ │ Webhook │ └──────────────┘ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ OpenRouter │ │ Appwrite │ │ Stripe │
│ AI │ │ Auth + DB │ │ Payments │
│ │ │ Auth + DB │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
User Input → URL Extraction (optional) → AI Generation → Display → Save/Share
│ │ │ │ │
└──────────────┴──────────────────────────┴────────────┴──────────┘
All operations use React hooks
with optimistic UI updates
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | React 19, TypeScript 5.9, Vite 7 | Modern SPA with strict type safety |
| Styling | TailwindCSS 3.4, shadcn/ui, Radix | Accessible, composable components |
| State | Custom hooks, React Context | Encapsulated business logic |
| Backend | Vercel Edge Functions | Serverless API with low latency |
| Database | Appwrite Cloud | Managed database + document permissions |
| Auth | Appwrite Auth | Magic link authentication |
| AI | OpenRouter | Content transformation |
| Payments | Stripe | Subscription management |
| Testing | Vitest, Testing Library | Unit tests with 29 test cases |
| CI/CD | GitHub Actions | Automated lint, type-check, test, deploy |
- Node.js 20+
- npm or yarn
- Appwrite account
- OpenRouter API key
# Clone repository
git clone https://github.com/codeme-ne/Blogpost-zu-Socialmedia-Beitrag.git
cd Blogpost-zu-Socialmedia-Beitrag
# Install dependencies
npm install
# Configure environment
cp .env.example .env
# Edit .env with your API keys
# Start development server
npm run dev:full# Required - Appwrite (client)
VITE_APPWRITE_ENDPOINT=https://fra.cloud.appwrite.io/v1
VITE_APPWRITE_PROJECT_ID=your-project-id
# Required - Appwrite (server)
APPWRITE_ENDPOINT=https://fra.cloud.appwrite.io/v1
APPWRITE_PROJECT_ID=your-project-id
APPWRITE_API_KEY=standard_your-api-key
# Required - AI
OPENROUTER_API_KEY=sk-or-v1-...
# Required - Payments
STRIPE_SECRET_KEY=sk_...
STRIPE_WEBHOOK_SECRET=whsec_...
VITE_STRIPE_PAYMENT_LINK_MONTHLY=https://buy.stripe.com/...
VITE_STRIPE_PAYMENT_LINK_YEARLY=https://buy.stripe.com/...If you want to manage Appwrite resources via an MCP-enabled IDE/LLM, see docs/Appwrite-MCP.md.
| Command | Description |
|---|---|
npm run dev:full |
Start frontend (5173) + API (3010) |
npm run build |
TypeScript + Vite production build |
npm run test |
Run Vitest in watch mode |
npm run test:coverage |
Generate coverage report |
npm run lint |
ESLint check |
npm run type-check |
TypeScript strict check |
src/
├── api/ # API client wrappers (openrouter, extract, appwrite)
├── components/ # UI components (shadcn/ui based)
│ ├── ui/ # Base components (Button, Card, Dialog...)
│ ├── common/ # Shared components (UrlExtractor, PlatformSelector)
│ ├── mobile/ # Mobile-specific (BottomSheet)
│ └── modals/ # Modal dialogs (Upgrade, Login)
├── config/ # Centralized configuration
├── hooks/ # Business logic hooks
│ ├── useContentGeneration.ts # AI generation orchestration
│ ├── useUrlExtraction.ts # Content extraction
│ ├── useSubscription.ts # Access control
│ └── useAuth.ts # Authentication
├── pages/ # Route components
├── libs/ # Utilities (promptBuilder, api-client)
└── test/ # Test files
api/ # Vercel Edge Functions
├── openrouter/ # OpenRouter AI proxy
├── stripe/ # Payment endpoints
└── extract.ts # URL extraction
Multi-platform requests use a single API call, reducing costs by ~67%:
// src/hooks/useContentGeneration.ts
if (selectedPlatforms.length > 1) {
const batchedResult = await batchedPostsFromContent(inputText, selectedPlatforms)
if (batchedResult) {
newPosts = batchedResult // Single API call for all platforms
} else {
newPosts = await executeParallelGeneration(inputText, selectedPlatforms) // Fallback
}
}Single source of truth pattern via is_active boolean:
// src/hooks/useSubscription.ts
const hasAccess = subscription?.is_active === true
const hasUsageRemaining = () => {
if (hasAccess) return true
return localStorage usage < config.limits.freeGenerationsPerDay
}OpenRouter API key never exposed to client - all requests proxied through edge:
// api/openrouter/v1/chat.ts
export const config = { runtime: 'edge' }
// Uses OPENROUTER_API_KEY from server environment29 test cases covering core functionality:
npm run test:run
# Output:
✓ src/test/utils/validation.test.ts (8 tests)
✓ src/test/api/claude.test.ts (10 tests)
✓ src/test/hooks/useContentGeneration.test.ts (11 tests)
Test Files 3 passed (3)
Tests 29 passed (29)Test categories:
- Hooks: Generation lifecycle, error handling, state management
- API: Response parsing, error recovery, validation
- Utils: Input validation, content normalization
- Connect repository to Vercel
- Configure environment variables in dashboard
- Deploy triggers automatically on push to
main
CI/CD pipeline includes:
- ESLint validation
- TypeScript type checking
- Test suite (29 tests)
- Coverage reporting
- Production build verification
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/openrouter/v1/chat |
POST | Bearer | OpenRouter AI proxy |
/api/extract |
POST | - | URL content extraction |
/api/stripe/create-checkout |
POST | Bearer | Stripe checkout session |
/api/stripe/create-portal |
POST | Bearer | Customer portal link |
/api/stripe-webhook-simplified |
POST | Signature | Webhook handler |
- Contributing Guide
- Code of Conduct
- Security Policy
- Bug Report Template
- Feature Request Template
- Pull Request Template
Lukas Zangerl
- GitHub: @codeme-ne
- LinkedIn: Connect
Built with React 19 · TypeScript · Vercel Edge · OpenRouter
