- Register 'linkedin' FeatureGroup with routers.linkedin and
api.linkedin_image_generation routers
- Register 'facebook' FeatureGroup with
api.facebook_writer.routers:facebook_router
- Add 'linkedin' and 'facebook' profiles to PROFILE_GROUP_MAP
- Remove dead imports of linkedin_router, linkedin_image_router,
and facebook_router from app.py (router manager handles via
CORE_ROUTER_REGISTRY)
- Add LINKEDIN and FACEBOOK keys to frontend FEATURE_KEYS
- Add route priorities for /linkedin-writer and /facebook-writer
- Change route gates from feature='social' to feature='linkedin'
and feature='facebook' respectively
- Register 'backlinking' FeatureGroup in feature_registry.py with
routers=routers.backlink_outreach:router
- Add 'backlinking' profile to PROFILE_GROUP_MAP (core + backlinking)
- Add backlink_outreach to OPTIONAL_ROUTER_REGISTRY with
features={'all', 'backlinking'}
- Remove direct import/include of backlink_outreach from app.py
(router manager handles both 'all' and 'backlinking' modes)
- Add BACKLINKING key to FEATURE_KEYS and route priority in
frontend demoMode.ts
- Change frontend route gate from feature='seo' to feature='backlinking'
so ALWRITY_ENABLED_FEATURES=backlinking enables the route
#3 — Duplicate prospect handling: add_lead now checks (campaign_id, url)
before insert; bulk_add_leads skips existing URLs.
#8 — Atomic rate limiting: try_increment_* methods atomically check cap
and increment in a single session; router uses these before send.
#10 — Reply matching via Message-ID: sender generates Message-ID header,
stored on OutreachAttempt; reply monitor parses In-Reply-To/References;
poll_replies matches by message_id first, falls back to from_email.
#11 — Save-to-campaign uses existing store results instead of
re-running expensive deepDiscover.
#12 — Lead status Literal type: Pydantic models enforce valid status
values; backend validates via LEAD_VALID_STATUSES frozenset;
frontend API typed as LeadStatus union.
- Add BacklinkOutreachScraper (Exa + DuckDuckGo deep scraping)
- Extend DB and Pydantic models for lead enrichment columns
- Add StorageService methods for lead CRUD with auto-migration
- Add backend endpoints: deep discover, campaign detail, lead management
- Extend frontend API client and store with discovery + lead actions
- Create BacklinkOutreachDashboard component with campaigns/discover/leads tabs
- Register route at /backlink-outreach under SEO feature flag
- Add nav entry under Enterprise & Advanced in tool categories
- Fix text selection menu not showing: wire contentRef via inputRef on multiline TextField
- Fix blog title not truncating: add min-w-0 for flex item overflow
- Fix outline generation 500: escape curly braces in f-string prompt template
- Fix content generation 'NoneType not callable': replace SessionLocal() with get_session_for_user(), add db param to MediumBlogGenerator, fix signature mismatch in database_task_manager
- Fix writing assistant suggest 500: add auth + user_id to API endpoint and service, replace sync requests with httpx.AsyncClient
- Fix hallucination detector 404: explicitly include router in main.py and app.py
- Fix missing error_data in task failure responses
- Hide CopilotKit web inspector button
- Remove hardcoded fallback suggestions from SmartTypingAssist
- Fix stale closure refs in SmartTypingAssist handleTypingChange
- Add two-column editor layout, stats bar, section hover menu
- Various subscription, billing, and research module improvements
Backend:
- product_image_service.py: Replaced direct wavespeed_client.generate_image()
with generate_image() from main_image_generation (unified entry point)
- This ensures subscription pre-flight validation (_validate_image_operation)
and usage tracking (_track_image_operation_usage) are enforced
- Removed _generate_image_with_retry method and WaveSpeedClient dependency
- Animation/video/avatar services already route through ImageStudioManager - no changes needed
Frontend:
- useProductMarketing.ts: Added formatError() helper for 402/429 detection
across all 8 API operations
- useCampaignCreator.ts: Added formatError() helper for 402/429 detection
across all 13 API operations
- All error messages now surface subscription limits with upgrade prompts
Backend:
- New POST /api/image-studio/save-to-library endpoint
Saves generated base64 images to workspace disk and creates ContentAsset
record for the unified asset library. Returns asset_id, file_url, filename.
Frontend:
- Added saveImageToLibrary() to useImageStudio hook
- CreateStudio auto-saves generated images to asset library after creation
- All 8 API operations now use _formatErrorMessage() helper
for 402/429 subscription limit errors with upgrade prompts
instead of generic error messages