RepurposeAI is a Social Media Content Repurposing platform. A user supplies one long-form piece of content — a blog post, article, YouTube transcript, podcast transcript, or raw text — and the application uses a large language model (LLM) to repurpose it into platform-specific posts: a Twitter/X thread, a LinkedIn post, an Instagram caption with hashtags, a Facebook post, a YouTube Shorts/Reels script, and an email newsletter blurb.
The product is built for solo content marketers, social media managers, and founders who must produce output for six channels from a single long-form asset. Its core object is text being cut, stacked, and re-set for six different stages, and the interface treats that transformation as the visual subject rather than a neutral settings panel.
The application is delivered as a MERN-stack web application: a React 18 + Vite client, a Node.js + Express.js backend on PORT 8080, and MongoDB with Mongoose for persistence. Authentication uses JWT in an httpOnly cookie with bcrypt password hashing. The LLM API key lives in .env and is called only from the backend, never exposed to the frontend.
RepurposeAI is a single-tenant-per-user productivity application with two active human roles — Content Creator and Content Planner — who share one application-owned identity and one private workspace of projects, generated posts, and scheduled posts.
Current delivery comprises:
GET /auth/me returns the current user..env on the server only.User, Project, and GeneratedPost models.Provisioned infrastructure for this project comprises a shared backend process for application APIs and domain modules, a database for application-owned persistent data, a React frontend, a LiteLLM gateway through which the backend makes model-provider calls, and a PostgreSQL instance supporting LiteLLM that is kept separate from application-owned storage. The shared backend is reused for all feature APIs; the LiteLLM gateway is the backend's route to the model provider and does not change any access decision or add product behavior.
Removed from scope
RepurposeAI is delivered as a first-party web application with application-owned identity. A visitor reaches the public Landing page and may register or log in. Registration is self-service: name, email, and password, with the password bcrypt-hashed before storage. Login verifies the returning user and issues a JWT stored in an httpOnly cookie. Every protected page and every protected API call requires that authenticated session; the client's ProtectedRoute component guards the protected pages and the backend rejects unauthenticated requests.
All product work — content input, generation, results review, library management, scheduling, dashboard, and usage — happens inside the authenticated workspace and is scoped to the signed-in user. There is no differentiated permission model: the two accepted personas share the same application-owned identity and the same private data boundary, and no role-based visibility or permission control is introduced.
The LLM is a backend-only dependency. The frontend never receives the AI key; the backend calls the model provider through the provisioned LiteLLM gateway using the key from .env. The Content Calendar is explicitly scheduling data only — no real posting to any social platform occurs now or as part of this delivery.
User (name, email unique, password hashed, plan, monthlyUsage, createdAt).GET /auth/me restores the current user on reload.User.GET /auth/me to restore the current user.GET /auth/me resolves. Empty: blank form. Success: session cookie set, redirect to Dashboard. Error: invalid credentials or server error shown inline and via toast. Recovery: retry credentials or go to Register.GET /dashboard/stats for the signed-in user.Project and GeneratedPost.GET /dashboard/stats fails. Recovery: retry the request..txt/.docx/.pdf file (text extracted server-side via POST /upload), or a blog/article URL (main text scraped via POST /scrape). Settings: multi-select target platforms (Twitter/X thread, LinkedIn post, Instagram caption + hashtags, Facebook post, YouTube Shorts/Reels script, email newsletter blurb); tone (Professional, Casual, Witty, Inspirational, Educational); audience; language; length (short/medium/long); emoji toggle; hashtag toggle; optional CTA.POST /projects), then navigates to Project Results.Project (user ref, title, sourceType text|file|url, originalContent, settings {tone, audience, language, length, emojis, hashtags, cta}, createdAt); GeneratedPost records created by generation.GET /projects/:id.PATCH /posts/:id); regenerate a single platform (POST /projects/:id/regenerate/:platform); download a post as .txt.Project; GeneratedPost (platform, content, version, isEdited, scheduledAt, status draft|scheduled).PlatformCard per platform with copy button, inline edit control, regenerate control, character counter, and download-as-.txt action; Loader skeleton while results load; toast feedback on copy, save, regenerate, and download.GET /projects, each storing the original content and all generated outputs. Supports search, filter, rename, and delete.PATCH /projects/:id); delete a project (DELETE /projects/:id).Project; associated GeneratedPost records.PATCH /posts/:id/schedule); view scheduled posts in the monthly calendar.GeneratedPost with scheduledAt and status (draft|scheduled).scheduled. Error: schedule failure shown inline and via toast. Recovery: retry scheduling; the post remains draft until scheduling succeeds.User (plan, monthlyUsage).FR-1 — Registration. As a Content Creator or Content Planner, I should register with name, email, and password so that I can use the protected workspace. (explicit; required_inference for self-service enrollment)
User is created with a bcrypt-hashed password, unique email enforced, and an authenticated session is established.FR-2 — Login. As a Content Creator or Content Planner, I should log in with email and password so that I can resume my workspace. (explicit; required_inference for returning verification)
FR-3 — Logout. As a Content Creator or Content Planner, I should log out so that my session ends. (explicit)
POST /auth/logout.FR-4 — Current user. As a Content Creator or Content Planner, I should have the app fetch the current user so that my session is restored on reload. (explicit)
GET /auth/me.FR-5 — Protected routes. As a Content Creator or Content Planner, I should be kept out of protected pages until authenticated. (explicit)
ProtectedRoute redirects unauthenticated users to Login; the backend rejects unauthenticated API calls.FR-6 — Paste text input. As a Content Creator, I should paste long-form text as source content. (explicit)
originalContent with sourceType: text.FR-7 — File upload extraction. As a Content Creator, I should upload a .txt, .docx, or .pdf file and have its text extracted server-side. (explicit)
POST /upload.sourceType: file.FR-8 — URL scraping. As a Content Creator, I should enter a blog/article URL and have the main text scraped. (explicit)
POST /scrape.sourceType: url.FR-9 — Platform multi-select. As a Content Creator, I should select multiple target platforms: Twitter/X thread, LinkedIn post, Instagram caption + hashtags, Facebook post, YouTube Shorts/Reels script, and email newsletter blurb. (explicit)
FR-10 — Repurposing settings. As a Content Creator, I should configure tone (Professional, Casual, Witty, Inspirational, Educational), audience, language, length (short/medium/long), emoji and hashtag toggles, and an optional CTA. (explicit)
Project under settings {tone, audience, language, length, emojis, hashtags, cta}.FR-11 — Generation. As a Content Creator, I should submit the project and have the app generate one structured LLM call per selected platform returning JSON, enforcing platform rules (Twitter 280 chars per tweet with a numbered thread; LinkedIn hook + line breaks; Instagram caption + 15–30 hashtags; and the equivalent rules for the other platforms). (explicit)
POST /projects with source content, platforms, and settings.Project is created and a GeneratedPost per platform is stored with content, version, and status draft..env key.FR-12 — Results cards. As a Content Creator, I should see one card per platform on Project Results. (explicit)
PlatformCard per platform with content and character counter.FR-13 — Copy. As a Content Creator, I should copy a platform's content from its card. (explicit)
PlatformCard.FR-14 — Inline edit. As a Content Creator, I should inline-edit a generated post. (explicit)
PlatformCard; PATCH /posts/:id.isEdited set.FR-15 — Regenerate single platform. As a Content Creator, I should regenerate one platform without regenerating the others. (explicit)
PlatformCard; POST /projects/:id/regenerate/:platform.GeneratedPost is replaced with a new version.FR-16 — Character counter. As a Content Creator, I should see a character counter on each card so I can judge platform fit. (explicit)
FR-17 — Download as .txt. As a Content Creator, I should download a post as a .txt file. (explicit)
PlatformCard..txt file containing the post content is downloaded.FR-18 — Project library. As a Content Creator, I should have saved projects in a library, each storing the original content and all generated outputs. (explicit)
GET /projects.FR-19 — Rename. As a Content Creator, I should rename a saved project. (explicit)
PATCH /projects/:id.FR-20 — Search. As a Content Creator, I should search past projects. (explicit)
FR-21 — Filter. As a Content Creator, I should filter past projects. (explicit)
FR-22 — Delete. As a Content Creator, I should delete a past project. (explicit)
DELETE /projects/:id.FR-23 — Schedule a post. As a Content Planner, I should schedule a generated post to a date/time. (explicit)
PATCH /posts/:id/schedule.scheduledAt set and status becomes scheduled.draft.FR-24 — Monthly calendar view. As a Content Planner, I should view scheduled posts in a monthly calendar view. (explicit)
FR-25 — Scheduling data only. As a Content Planner, I should rely on the calendar as scheduling data only, with no real posting to social platforms. (explicit constraint)
FR-26 — Dashboard statistics. As a Content Planner, I should see total projects, posts generated, and most used platform as a Recharts chart. (explicit)
GET /dashboard/stats.FR-27 — Free-plan usage limit. As a Content Planner, I should have my generations tracked per user against a free-plan limit of 10 generations per month, enforced by the backend. (explicit; required_inference for enforcement mechanics)
monthlyUsage incremented per user; requests beyond 10 in the month are rejected with a clear message.FR-28 — Profile/Usage. As a Content Planner, I should see my plan and monthly usage. (explicit)
FR-29 — Dark/light mode. As a Content Creator or Content Planner, I should switch between dark and light mode. (explicit)
FR-30 — Responsive UI, skeletons, error states. As a Content Creator or Content Planner, I should have a fully responsive UI with loading skeletons and error states. (explicit)
FR-31 — Backend-only AI key. As the system, the LLM API key must be stored in .env and called only from the backend, never exposed to the frontend. (explicit constraint)
FR-32 — Consistent API responses and error handling. As the system, all REST API routes under /api should return consistent JSON { success, data, message } through a central error-handling middleware and async handler wrapper. (explicit)
.txt files; saves work as a project in the library and renames, searches, filters, and reuses past outputs.scheduled, dashboard totals and the most-used-platform chart reflect actual output, and usage is visible against the 10-per-month limit.User, and establishes the httpOnly-cookie JWT session.GET /auth/me to restore the current user; if unauthenticated, ProtectedRoute redirects to Login.POST /auth/logout and returning to the public surface..txt/.docx/.pdf file, which the backend extracts to text via POST /upload; or entering a blog/article URL, which the backend scrapes for main text via POST /scrape. Extraction and scrape show loading states; failures are reported and the Creator retries or switches mode.Project and makes one structured LLM call per selected platform through the backend-only key, requiring strict JSON, retrying on malformed output, and applying timeout handling and graceful fallback messages. Platform rules are enforced (Twitter 280 chars per tweet with a numbered thread; LinkedIn hook + line breaks; Instagram caption + 15–30 hashtags; and the equivalent rules for the other platforms).GeneratedPost with content, version, and status draft; monthlyUsage is incremented.PlatformCard and its character counter.PATCH /posts/:id saves the content and sets isEdited. Save failures are reported and edits are retained for retry.POST /projects/:id/regenerate/:platform; only that platform's post is replaced with a new version, and the regeneration counts against monthly usage. Failure or fallback messages are shown and the Creator may retry..txt.GET /projects, each storing the original content and all generated outputs.PATCH /projects/:id; the list reflects the new title.DELETE /projects/:id after confirmation; the project and its generated posts are removed.PATCH /posts/:id/schedule.scheduledAt and sets status to scheduled. Invalid date/time or failure is reported and the post remains draft.GET /dashboard/stats.The visual system follows the Paula Scher poster-grid direction: typography as the repurposing machine — one long read explodes into six loud platforms. The surface reads as a printed poster wall, not a SaaS dashboard.
Palette (light mode)
| Role | Hex |
|---|---|
| Background (warm paper) | #F4EFE6 |
| Surface | #FFFFFF |
| Text / primary (ink) | #111111 |
| Accent (Scher red) | #E63946 |
| Muted | #6B655C |
| Mustard (YouTube chip) | #F2B705 |
| Teal (LinkedIn chip) | #0E7C7B |
| Cobalt (Facebook chip) | #1B3A6B |
Proportion: ~70% paper, 20% ink type, 10% flat colour blocks. Scher red is the hot accent used for one hero band, active nav, character-counter overruns, and the Twitter platform chip. Secondary flat blocks appear only as platform-coded colour chips (LinkedIn teal, Facebook cobalt, Instagram red, YouTube mustard, email black, Twitter ink).
Palette (dark mode). Ground flips to ink #111111, text to paper #F4EFE6, with the same red accent #E63946.
Typography
-0.02em, stacked into 2–4 lines spanning the viewport edge-to-edge. Occasional single words rotated 90° in the margin, or a word pulled out at 2× the block size in the accent colour.clamp(56px, 12vw, 168px) for hero; h1 clamp(40px, 7vw, 96px); h2 clamp(28px, 4.5vw, 56px); h3 24px; body 17/28; small-caps label 12px tracked +0.12em. Line-height 0.92 on display, 1.65 on body.Shape language. Hard edges only — zero border-radius on cards, buttons, and inputs. Thick 3px ink rules separate sections; diagonal colour bands (clip-path polygon) slice across the page at 4–6° between major sections. Poster-grid cards with a 1px ink hairline and a 6px offset flat shadow in the platform's colour. Buttons are solid ink rectangles with all-caps Anton labels; the primary CTA is a red block with an ink 3px border. Platform chips are small square colour swatches, never pills.
Layout. A visible 12-column poster grid with a persistent left rail (72px) carrying a vertical rotated wordmark "REPURPOSE" and section numbers 01–06. Dashboard and results pages use dense asymmetric poster grids — one platform card can span 2 columns and 2 rows (the "lead" post) while the rest stack; the calendar is a strict 7-column table with ink rules and colour-coded event blocks. Empty states are giant outlined numerals ("00 projects").
Imagery. Typography is the imagery: no photography, no illustration, no 3D. Generative content is the source text itself — snippets of the pasted article set in Anton at 120px, cropped and bled off the edge as a background texture at 6% ink opacity. A halftone dot pattern (SVG) serves as an occasional section divider. Platform cards carry a large condensed initial ("T", "L", "I", "F", "Y", "E") in the platform's flat colour.
Readability rule. Headlines, wordmarks, labels, numbers, card text, and controls stay entirely inside the viewport and their container at 375px, 768px, and 1280px, wrapping or scaling to fit; decoration may bleed, but never covers readable text or controls.
The public entry is a full-bleed typographic composition on the warm paper ground — no gradient, no centred stack.
clamp(56px, 12vw, 168px), flush-left, running past the right column edge so the final "E" is clipped by the viewport — carried by decoration only, while the readable text stays whole by wrapping at 375px. Directly beneath, a red 3px-bordered band with the subline "SIX STAGES" in Archivo 700 at 28px.Nothing is centred; the composition is asymmetric and poster-like. The textarea and button are the accepted entry controls — they lead to Register/Login, not to an unauthenticated generation.
Interaction Model: Animated Motion Tempo: expressive Hero Dimensionality: flat
Landing Hero Motion Brief
cubic-bezier(0.2, 0.7, 0.2, 1), 420ms) as the page settles; the clipping card and its controls resolve into place; the outcome is a composed poster with Register and Login reachable..env and called only from the backend; it is never exposed to the frontend. (explicit)/api; central error-handling middleware; async handler wrapper; consistent JSON responses { success, data, message }. (explicit)VITE_API_URL=http://localhost:8080/api.PORT=8080, MONGO_URI, JWT_SECRET, JWT_EXPIRES_IN, AI_API_KEY, CLIENT_URL.User, Project, GeneratedPost)..env, called only from the backend via services/aiService.js with a dedicated system prompt per platform.repurpose-ai/ with client/ (src/components, pages, context, hooks, services, utils), server/ (config, controllers, models, routes, middleware, services, utils, server.js), and README.md.plan and monthlyUsage are stored on User and enforced server-side. (explicit).env key. (explicit; infrastructure)/api. (explicit)draft|scheduled).
Start repurposing
Paste one blog post, article, or transcript. RepurposeAI re-sets it for a Twitter/X thread, a LinkedIn post, an Instagram caption with hashtags, a Facebook post, a YouTube Shorts or Reels script, and an email newsletter blurb.

Start repurposing
Paste one blog post, article, or transcript. RepurposeAI re-sets it for a Twitter/X thread, a LinkedIn post, an Instagram caption with hashtags, a Facebook post, a YouTube Shorts or Reels script, and an email newsletter blurb.
No comments yet. Be the first!