Commit graph

15 commits

Author SHA1 Message Date
Paulo Castellano
028fe1fefd feat: add image title and body fields to AI post creation and register PostTemplateSeeder in local environments 2026-05-03 10:06:02 -03:00
Paulo Castellano
1e1519876d feat: replace legacy AI assistant with modular post content generation, review, and template management system 2026-05-03 09:36:50 -03:00
Paulo Castellano
3c3b170b21 feat: @mentions in comments, AI Action layer + MCP tools, settings tabs
Mentions in post comments
- @mention autocomplete (workspace members, current user excluded) with
  marker syntax @[uuid] persisted, display names rendered via CommentBody
  chips; live edit replaces markers with names and converts back on save.
- NotifyMentions action with workspace-scoped membership check, dedupes
  same user, only newly-added mentions on update.
- Email + in-app via SendNotification job, respecting per-user
  notification_preferences.mentioned_in_comment.
- Heartbeat-based presence (Cache, 60s TTL, 30s ping) so online recipients
  get only the in-app notification — no email noise.
- Real-time bell on workspace.{id}.user.{id} private channel
  (NotificationCreated event), scoped channel name avoids client-side
  filtering and lays out a convention for future workspace channels.
- Mailable localized via lang/{en,es,pt-BR}/mail.php; Maizzle source
  template for the email is committed and built into resources/views/mail.

AI generation refactor (Action layer + MCP)
- Extracted Actions/Ai/Generate{Image,Video} with QuotaExhaustedException
  so agent tools and MCP tools share a single domain entry point.
- Mcp/Tools/Ai/Generate{Image,Video}Tool registered in TryPostServer; both
  return MediaResource payloads.
- Orientation::imageApiSize maps non-OpenAI ratios to 1:1/2:3/3:2.
- config/ai.php is now the single source of truth driven by env, removing
  the trypost.ai shim. Default text/image providers flipped to OpenAI.

Settings/UX
- /settings/workspace split into shadcn Tabs (Workspace / Brand / Users)
  with three components.
- /assets and the in-editor MediaPicker open the ImagePreviewDialog
  lightbox on image click while preserving action button behaviour.
- Comments tab landed via ?tab=comments&comment=<id> from notification
  click (scroll-to + temporary highlight).
- Mention autocomplete popover flips above when near the viewport bottom.
- Real social platform PNGs replace Tabler brand glyphs in schedule
  pills and post list, with hover tooltip carrying display_name + handle.

Bug fixes
- AcceptInvite: controller now passes workspace + role payload that the
  Vue page expects; login/register CTAs preselect the invite email.
- WorkspaceInvite mailable: stopped referencing nonexistent
  $invite->workspace and $invite->role; column added to the migration,
  Invite model casts role to WorkspaceRole, CreateInvite persists it.
- PostCommentCreated: added broadcastAs so .PostCommentCreated actually
  matches the Echo listener; payload now includes mentioned_users so
  receivers render the chip correctly without a refetch.
- Preview components for X/Pinterest/Threads/Bluesky/LinkedIn/Mastodon/
  TikTok/YouTube switched from item.type === 'image' to
  !isVideoMedia(item) so media without a persisted type still renders.
- UpdatePostRequest now accepts media.*.{type,mime_type,size,...} so the
  posts.media JSON keeps the metadata that the previews need.
- Removed throttle:6,1 from social connect routes (was 429ing legitimate
  OAuth retries).
- Used MediaType enum cases instead of literal 'image'/'video' strings
  when creating media rows.

Tests
- MentionParser unit tests, NotifyMentions feature tests including
  online/offline channel selection and preference gating, MCP AI tool
  happy paths, MentionedInComment mailable rendering, AcceptInvite +
  search-members + index mentioned_users path. 1229 passing.
2026-05-01 20:59:03 -03:00
Paulo Castellano
dafdd5da43 feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
  GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
  post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
  EmojiPicker (full Unicode set, search, categories, recently-used,
  light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
  content_types map) so the user can switch Feed/Reel/Story etc. and have
  it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
  types); replaces inline maps across 5 components, fixes
  instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
  platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
  on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
  (was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 14:53:49 -03:00
Paulo Castellano
b3b59b4d13 refactor: remove onboarding flow, implement brand analysis services, and replace setup middleware with account readiness checks 2026-04-16 23:05:51 -03:00
Paulo Castellano
b2bf5c2059 feat: complete AI assistant with custom services and brand config
Baseline snapshot of custom AI implementation before Laravel AI SDK migration.

Includes:
- Custom services: GeminiTextGenerationService, TextGenerationService (OpenAI), ImageGenerationService, AudioGenerationService, VideoGenerationService
- IntentDetector for content moderation via keyword matching
- AI enums: Intent, Orientation, UsageType
- Blade prompt templates: system.blade.php, image.blade.php, video.blade.php
- AiMessage with content_html accessor (markdown rendering)
- AiUsageLog for monthly quota tracking per account
- PostAssistantController with regex-based [GENERATE_*] parsing
- WritingAssistantTab with markdown rendering, add-to-post, attachments
- Workspace brand fields (name, description, tone, voice_notes) in system prompt
- Session state block injected into prompts (thread counts, quota remaining)
- AttachmentCollector pattern will replace the regex approach in Phase 2
- Post comments with replies, emoji reactions, real-time via Echo
- Assets page with Unsplash + Giphy integrations
2026-04-16 09:25:08 -03:00
Paulo Castellano
0f6ae9a4e6 feat: add PostCommentCreated broadcast event 2026-04-15 20:11:36 -03:00
Paulo Castellano
2da15df96c feat: introduce Account entity as billing owner and refactor architecture
- Create Account model as Cashier Billable entity (stripe, plan, subscription)
- Account owns workspaces and has an owner_id (User)
- User belongs to one Account via account_id
- Workspace belongs to Account via account_id, no longer has billing fields
- Remove Brand model entirely (workspaces serve as grouping)
- Rename brand_limit to workspace_limit in plans
- Workspace roles simplified: admin/member/viewer (owner via Account)
- Invites now belong to Account with workspaces JSON array
- Pennant features scope changed from Workspace to Account
- EnsureSubscribed middleware checks Account subscription
- All controllers updated: BillingController, OnboardingController,
  WorkspaceInviteController, SocialController, StripeEventListener
- Frontend: extract GoogleAuthButton component, create WorkspaceRole
  enum for type-safe role checks, fix all views for new architecture
- All 1101 tests passing
2026-04-14 22:22:04 -03:00
Paulo Castellano
1ff2f93c37 feat: move Billable from User to Workspace with plan support 2026-04-14 18:22:36 -03:00
Paulo Castellano
ceb7b92b74 feat: PostPlatform enum, failure email, DB indexes, rate limiting, tests
Publishing improvements:
- Create PostPlatformStatus enum (Pending, Publishing, Published, Failed)
- Update PostPlatform model, jobs, factories to use enum
- Add PostPublishFailed email notification when post fails to publish
- Maizzle template + blade for failure email with platform details
- PublishPost job: add $tries=3, $backoff=30, failed() method
- Fix broadcast event to serialize enum status value

Security:
- Add rate limiting (throttle:6,1) on social connect endpoints
- Fix MediaController::reorder IDOR vulnerability
- Fix Connect.vue broken import (storeStep2 -> storeConnect)
- Fix UpdatePost data_get() consistency

Database:
- Add composite index on post_platforms (post_id, enabled)
- Add index on post_platforms (social_account_id)

Tests:
- Add 3 tests for profile photo upload/delete
- Add 2 tests for media reorder (including IDOR check)
- Fix publish tests for PostPlatformStatus enum
- Add Mail::fake() to publish tests

Cleanup:
- Remove unused AppHeader.vue and AppHeaderLayout.vue
- Remove dead BillingController methods

All 733 tests passing.
2026-03-30 16:11:38 -03:00
Paulo Castellano
56b8c92e72 refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals

Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController

Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props

All 710 tests passing.
2026-03-30 00:20:43 -03:00
Paulo Castellano
caab35b678 Revert "fix: refresh postPlatform before broadcasting to ensure fresh post status"
This reverts commit 8eaa6fba4c.
2026-01-25 18:59:00 -03:00
Paulo Castellano
8eaa6fba4c fix: refresh postPlatform before broadcasting to ensure fresh post status 2026-01-25 18:46:29 -03:00
Paulo Castellano
7c00c3387e feat: Implement user onboarding, subscription management, and refactor social integrations with new UI components and mail templates. 2026-01-16 23:46:30 -03:00
Paulo Castellano
7867fcce02 feat: Implement real-time post status updates and configurable social platform enabling/disabling. 2026-01-16 12:36:52 -03:00