An AI-powered LinkedIn distribution engine. Turn articles, launches, and hackathon recaps into on-brand LinkedIn posts, approve them, publish to a personal profile or company page, and pull performance back into a dashboard.
Stack: Next.js 16 (App Router) · Convex (data + functions + scheduler) · shadcn/ui + Tailwind v4 · OpenRouter Agent SDK · LinkedIn OAuth 2.0 + Posts API.
Dashboard — impressions, engagement, performance chart, recent posts, and activity.
Post performance — per-post metrics synced from the LinkedIn API.
Posts & schedule — manage drafts, approvals, scheduled, and published content.
New article / project / hackathon
↓
AI generates a LinkedIn post (OpenRouter)
↓
Your approval
↓
LinkedIn API (personal or company page)
↓
Published + performance synced back
- Content sources — store articles, projects, hackathons, and resources.
- AI composer — generate drafts from a source with your brand voice.
- Approval queue — review and edit before anything goes live.
- Scheduling — schedule posts; a Convex cron publishes them.
- Publishing — personal (w_member_social) and company page (w_organization_social) posts.
- Analytics — best-effort impressions/engagement synced from LinkedIn.
- Activity feed — audit trail of everything that happened.
npm install
npx convex dev # provisions/uses your dev deployment, writes .env.localLeave npx convex dev running in a terminal while developing.
Server-side secrets are stored on the Convex deployment (not in .env.local):
npx convex env set LINKEDIN_CLIENT_ID <your-client-id>
npx convex env set LINKEDIN_CLIENT_SECRET <your-client-secret>
npx convex env set OPENROUTER_API_KEY <your-openrouter-key>
npx convex env set APP_URL http://localhost:3000Optional overrides:
npx convex env set LINKEDIN_SCOPES "openid profile email w_member_social w_organization_social r_organization_social"
npx convex env set LINKEDIN_VERSION 202609
npx convex env set LINKEDIN_REDIRECT_URI https://<deployment>.convex.site/linkedin/callback
npx convex env set OPENROUTER_MODEL openai/gpt-4o-miniIn your LinkedIn developer app, add this Authorized redirect URL (Auth tab):
https://<your-deployment>.convex.site/linkedin/callback
Request the products you need (Sign In with LinkedIn using OpenID Connect, Share on LinkedIn, and Marketing Developer Platform for company pages/analytics).
npm run devOpen http://localhost:3000, go to LinkedIn → Connect, then create your first post in the Composer.
Populate the dashboard with realistic data for screenshots or demos. Everything
is tagged demo: true and never touches your real account or posts.
npx convex run seed:seedAll # reset + seed 2,400 posts
npx convex run seed:seedAll '{"total":5000}' # seed 5,000 posts
npx convex run seed:clearDemoData # remove all demo data- npm run dev— Next.js dev server
- npm run build— production build
- npm run lint— ESLint
- npm run typecheck— TypeScript
- npx convex dev --once— push backend changes once
- convex/schema.ts— tables: accounts, sources, posts, activities, settings.
- convex/http.ts— LinkedIn OAuth- /linkedin/connectand- /linkedin/callback.
- convex/linkedin.ts— publish, metrics sync, org refresh, version probing.
- convex/ai.ts— OpenRouter generation (- "use node").
- convex/crons.ts— publish scheduled posts (1 min) and sync metrics (6 h).
- convex/seed.ts— demo data seeding.
- app/dashboard/*— dashboard, composer, sources, approvals, posts, analytics, LinkedIn, settings.
- Impressions are only exposed for company page posts. Personal posts show
likes/comments unless the restricted r_member_socialscope is approved.
- Historical personal posts can't be imported without r_member_social; every post published through this app is stored in Convex with its metrics.
- LinkedIn API versions expire monthly. LINKEDIN_VERSIONdefaults to202609.