Commit graph

11 commits

Author SHA1 Message Date
Paulo Castellano
d84666360a refactor(linkedin): infer post format from media + unify account connection
Collapse LinkedIn to one content type per account kind (linkedin_post, linkedin_page_post). Publishers infer the publish format from the attached media — text, single image/video, multi-image carousel, or PDF document — matching how facebook_post/x_post already work; PDF is exclusive of any other attachment. Removes the editor variant picker, keeping only the PDF document title field. Includes a data migration collapsing the retired carousel/document content types.

Replace the two LinkedIn account cards with a single Connect LinkedIn button: one unified OAuth grant (linkedin-openid driver, union of scopes) then a post-callback identity picker to post as the personal profile (linkedin) or a company page the member administers (linkedin-page). The chosen organization is validated against the admin-verified list from the OAuth grant. Per-capability gating via LINKEDIN_ENABLED / LINKEDIN_PAGE_ENABLED supports profile-only or org-only self-hosting. Removes LinkedInPageController, LinkedInTokenSynchronizer, the standalone linkedin-page connect routes, and the unused redirect_page config.
2026-06-24 21:05:09 -03:00
Paulo Castellano
9f5bacc03f refactor(ai): introduce GeneratorFormat enum and drop stringly-typed format
Replace the 'single'/'carousel' string format threaded through the AI
generation path with a typed GeneratorFormat enum (PostContentGenerator,
PostContentHumanizer, PostContentStreamer, StreamPostCreation,
RunGenerateNode, deriveFormat).

Remove generatorFormat() from AiContentTemplate and the three templates —
it conflated style and format (returning 'tweet_card'). The tweet-card
check now lives on ContentStyle via isTweetCard(), and the humanizer skip
on ContentStyle::humanizes(), so the style declares its own behaviour
instead of callers comparing magic strings.
2026-06-18 11:11:23 -03:00
Paulo Castellano
7fd84507b3 feat(automations): generate node supports the 3 content styles 2026-06-17 20:03:00 -03:00
Paulo Castellano
605261e1b8 Back fixed-set automation strings with enums and consts
Replace magic strings across the automation domain with backed PHP enums
(HttpMethod, AuthType, DelayUnit, ScheduleField) and mirrored TS consts
(http-method, auth-type, delay-unit, schedule-field, condition-operator,
publish-mode), plus the existing Condition\Handle / Operator / Publish\Mode.

Also:
- require scheduled_offset via concrete-index required_if instead of
  defaulting to 60 when the publish mode is scheduled
- fail the webhook node explicitly when the resolved url is empty
- localize node failure messages (fetch_rss/http/webhook)
- cast resolver/strtoupper inputs to string so a present-null config value
  degrades gracefully instead of crashing
- list automations with config('app.pagination.default'), drop the perPage param
2026-06-13 15:04:24 -03:00
Paulo Castellano
ed5a757c4f Drop no-op log in Generate node
The no-active-accounts branch only logged and took no action; the
platforms loop already handles an empty active-account set.
2026-06-13 14:03:59 -03:00
Paulo Castellano
478cad9f27 Tighten automation conventions: pagination, imports, i18n, enums
- Pagination: drop the perPage override from ListAutomations and the
  hardcoded page size from GetAutomationInvocations; both use
  config('app.pagination.default'). Document the rule in CLAUDE.md.
- Imports: import DomainException / InvalidArgumentException / Throwable
  instead of inline backslash references across the automation actions.
- i18n: move the hardcoded Fetch RSS and HTTP Request failure strings to
  automations.errors.* in all three locales.
- Publish: require scheduled_offset when mode is scheduled (validation)
  and drop the magic 60-minute default in the node. Fixes the required_if
  rules to reference the concrete node index instead of a wildcard that
  never resolved (also repairs the trigger cron rule).
- Condition handles: back the yes/no output handles with a shared
  Condition\Handle enum (PHP) and ConditionHandle const (TS).
2026-06-13 13:59:52 -03:00
Paulo Castellano
a09b1f45c2 Structure brand voice and make generated copy platform-aware
Replace free-text brand_tone/brand_voice_notes with a single structured
brand_voice_traits JSON column backed by the BrandVoiceTrait enum, exposed
as choice-chip pills in the brand settings UI and autofillable from a site.
Brand voice and visuals become per-automation toggles on the Generate node.

Unify the image controls into one 0-10 picker (0 = text-only, 1 = single,
2+ = carousel) and feed the generator the most restrictive selected network
so copy fits every platform. Pass that same platform context through the
humanizer pass — extracted into a shared ResolvesPlatformCopyBudget trait —
so the rewrite can no longer drift past the character cap the generator
respected, in both the automation and manual creation flows.

Persist the trigger node's schedule editor fields on save (they were
silently dropped by validated() for lacking validation rules).
2026-06-12 17:09:39 -03:00
Paulo Castellano
9a692b4608 Enhance automation functionality: Introduce workflow variables and improve node validation
- Added support for workflow variables in automations, allowing users to define reusable values.
- Implemented validation for Generate nodes to ensure intended image counts align with selected accounts.
- Updated automation models and requests to handle new variables, including encryption for sensitive data.
- Enhanced UI to display variables and their management within the automation editor.
- Improved error handling for webhook and HTTP nodes to prevent requests to invalid URLs.
- Refactored various components for better context resolution during automation runs.
2026-06-11 15:47:29 -03:00
Paulo Castellano
4efaa0bf99 Harden automations module: full-post generation, reliable runs, editor UX
Generation
- Generate node now produces the full post (text + AI image + carousel)
  via a shared PostImagePipeline extracted from StreamPostCreation
- Generate config UI mirrors the /posts/create wizard (carousel slide
  count, include-image toggle); drop the decorative format/unsplash keys

Flow correctness
- RSS/HTTP nodes expose named has-items (default) and no-items output
  handles, labeled and colored like the Condition node
- AdvanceAutomationRun records a no_matching_edge terminal instead of
  completing silently; "0 new items" feedback in the test panel
- Manual/test runs no longer persist the production dedup watermark

Run reliability
- Pause truly halts in-flight runs (production only; manual test runs
  always run regardless of automation status)
- ProcessAutomationNode::failed() marks the run failed
- automation:recover-stuck-runs and automation:prune-dry-runs commands

Webhook / HTTP
- Branded User-Agent (config-driven) on outbound webhook + http_request
- Webhook fails on invalid JSON instead of silently sending {}
- HTTP custom headers editor; CodeMirror-based CodeEditor for JSON

Editor UX
- Header Test button only opens the panel; the panel has a Run button
  (saves first) and owns the with-real-data toggle
- Clicking a node closes the test panel and opens its config
- Node cards: max-width + truncate so long URLs don't grow the node
2026-06-10 20:45:01 -03:00
Paulo Castellano
21b14f7893 Merge main into feat/automations-module
Conflict resolutions + integration fixes:
- CreatePost: kept the branch's merge-into-existing meta persistence (equivalent
  to main's #86 replace on create, and what the automations flow was built on).
- FacebookSettings.vue: kept both new defaults (previewOnly + meta).
- RunGenerateNode + GenerateNodeConfig.vue: ContentType::InstagramCarousel was
  removed on main (#80); an IG carousel is now a multi-image instagram_feed, so
  the carousel-capable list uses InstagramFeed.
- GenerateNodeTest: fixtures use the ContentType enum and the new instagram_feed
  carousel signal.
2026-06-10 17:09:54 -03:00
Paulo Castellano
b23ab0166e feat(automations): implement automation features and UI enhancements
- Added new automation-related routes and controllers for managing automations.
- Introduced automation nodes in the UI with distinct styles and interactions.
- Updated sidebar to include navigation for automations.
- Enhanced post creation logic to support automation metadata.
- Refactored content type and platform enums into types for better type safety.
- Added localization for automation-related terms in English, Spanish, and Portuguese.
- Improved error handling in various components to accommodate new features.
2026-05-24 09:17:19 -03:00