2026-01-18 21:00:09 +00:00
|
|
|
|
APP_NAME="TryPost"
|
2026-01-15 01:13:44 +00:00
|
|
|
|
APP_ENV=local
|
|
|
|
|
|
APP_KEY=
|
|
|
|
|
|
APP_DEBUG=true
|
|
|
|
|
|
APP_URL=http://localhost
|
|
|
|
|
|
|
2026-06-14 12:31:00 +00:00
|
|
|
|
# Public base URL inbound webhooks (e.g. Telegram) are registered on.
|
|
|
|
|
|
# Defaults to APP_URL; set a tunnel URL (e.g. ngrok) for local development.
|
|
|
|
|
|
WEBHOOK_URL=
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Self-hosted mode (skips payment requirements)
|
|
|
|
|
|
SELF_HOSTED=true
|
|
|
|
|
|
|
MCP: workspace settings, viewer read access, and token access (#241)
* Add workspace MCP settings and token access controls.
Ship MCP settings UI, OAuth revoke/list helpers, Passport deploy wiring,
and workspace.token:mcp gating so assistants can connect without pulling
in welcome/onboarding from the parent epic.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Type MCP client config shapes instead of string checks.
Encode http/config-root on each advanced client and tighten primary
client ids so snippet generation does not branch on magic strings.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Polish MCP settings follow-ups from review.
Translate Ukrainian MCP copy, deep-link ChatGPT into connector
creation, drop an unused asset and revoke arg, and assert PATs are
rejected on the MCP endpoint.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Harden MCP connected clients, revoke scope, and OAuth consent.
List recoverable sessions with live refresh tokens, revoke only PATs,
throttle registration alone, and block viewers from authorizing MCP.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Simplify MCP OAuth route throttling to a single middleware group.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Allow workspace viewers read-only MCP access with web policy writes.
Mirror the web app: MCP connects on view + OAuth mcp:use, write tools
enforce createPost/update/delete/manageAccounts/manageTeam, and demotion
to Viewer keeps grants. Cover role denials, consent, and disconnect.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Harden MCP tool authz with shared workspace helpers.
Route ApiKey tools through AuthorizesMcpTool, fail closed on null user
or policy argument, and resolve the current workspace before mutating.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Drop redundant string casts on validated request data.
Enum::from and validated() fields are already strings, so the casts
add noise without changing behavior.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Show only the current user's MCP connections in settings.
Match API keys privacy: list and disconnect your own OAuth clients,
not teammates' across the account.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Cover LoadWorkspaceFromToken gaps and harden AuthorizesMcpTool tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Drop redundant is_string guard before UpdatePostTool find.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Refactor AppSidebar to always show MCP link and simplify route middleware definition in ai.php. The MCP link is now consistently displayed regardless of the current workspace state, and the route middleware syntax has been streamlined.
* Refresh MCP connected clients with Inertia usePoll.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Bump laravel/mcp to 0.9.1 and add the TryPost server icon.
Requires laravel/boost 2.5 for the Icon attribute; expose images/trypost/icon.png on TryPostServer.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Drop no-op ReflectionClass import in TryPostServerTest.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 12:54:51 +00:00
|
|
|
|
# Passport OAuth keys (API tokens / MCP). Prefer env vars over key files so
|
|
|
|
|
|
# every node behind a load balancer shares the same key pair. Use literal \n
|
|
|
|
|
|
# for newlines in the PEM. When unset, Passport falls back to storage/oauth-*.key
|
|
|
|
|
|
# (generate with: php artisan passport:keys).
|
|
|
|
|
|
# PASSPORT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
|
|
|
|
|
# PASSPORT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
|
|
|
|
|
|
|
fix: Stripe webhook setup completion, notifications routing, billing UI
- Fix StripeEventListener: mark setup as Completed when subscription.created webhook fires
- Fix notifications routes: move outside subscribed middleware (non-critical feature)
- Fix NotificationBell: guard response.ok before parsing JSON
- Fix StripeEventListener: use data_get() for payload access
- Rewrite billing page to use SettingsLayout with download buttons on invoices
- Remove duplicate Unit/Listeners/StripeEventListenerTest (consolidated into Feature)
- Add comprehensive Stripe webhook tests (14 scenarios: happy path, setup transitions, edge cases, error handling)
- Update billing i18n: remove "no credit card" text, add status key
- Move auth layout logo to top-left corner
- Redesign onboarding Role page with compact list layout
- Add persona i18n translations (EN, PT-BR, ES)
- Update README with API, MCP, tech stack, quick start
2026-03-31 16:52:36 +00:00
|
|
|
|
TELESCOPE_ENABLED=false
|
|
|
|
|
|
|
2026-01-15 01:13:44 +00:00
|
|
|
|
APP_LOCALE=en
|
|
|
|
|
|
APP_FALLBACK_LOCALE=en
|
|
|
|
|
|
APP_FAKER_LOCALE=en_US
|
|
|
|
|
|
|
|
|
|
|
|
APP_MAINTENANCE_DRIVER=file
|
|
|
|
|
|
|
|
|
|
|
|
BCRYPT_ROUNDS=12
|
|
|
|
|
|
|
|
|
|
|
|
LOG_CHANNEL=stack
|
|
|
|
|
|
LOG_STACK=single
|
|
|
|
|
|
LOG_DEPRECATIONS_CHANNEL=null
|
|
|
|
|
|
LOG_LEVEL=debug
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Database (PostgreSQL or MySQL)
|
|
|
|
|
|
# PostgreSQL: DB_CONNECTION=pgsql, DB_PORT=5432, DB_USERNAME=postgres
|
|
|
|
|
|
# MySQL: DB_CONNECTION=mysql, DB_PORT=3306, DB_USERNAME=root
|
|
|
|
|
|
DB_CONNECTION=pgsql
|
|
|
|
|
|
DB_HOST=127.0.0.1
|
|
|
|
|
|
DB_PORT=5432
|
|
|
|
|
|
DB_DATABASE=trypost
|
|
|
|
|
|
DB_USERNAME=postgres
|
|
|
|
|
|
DB_PASSWORD=
|
2026-01-15 01:13:44 +00:00
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Session
|
2026-01-15 01:13:44 +00:00
|
|
|
|
SESSION_DRIVER=database
|
2026-01-18 21:00:09 +00:00
|
|
|
|
SESSION_LIFETIME=1440
|
2026-01-15 01:13:44 +00:00
|
|
|
|
SESSION_ENCRYPT=false
|
|
|
|
|
|
SESSION_PATH=/
|
|
|
|
|
|
SESSION_DOMAIN=null
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Broadcasting, Queue, Cache
|
|
|
|
|
|
BROADCAST_CONNECTION=reverb
|
|
|
|
|
|
QUEUE_CONNECTION=redis
|
|
|
|
|
|
CACHE_STORE=redis
|
2026-01-15 01:13:44 +00:00
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# File Storage
|
|
|
|
|
|
# Options: local, s3, r2 (or any S3-compatible: MinIO, DigitalOcean Spaces, etc.)
|
|
|
|
|
|
FILESYSTEM_DISK=local
|
2026-01-15 01:13:44 +00:00
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Redis
|
2026-01-15 01:13:44 +00:00
|
|
|
|
REDIS_HOST=127.0.0.1
|
|
|
|
|
|
REDIS_PASSWORD=null
|
|
|
|
|
|
REDIS_PORT=6379
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Mail
|
|
|
|
|
|
MAIL_MAILER=smtp
|
2026-01-15 01:13:44 +00:00
|
|
|
|
MAIL_HOST=127.0.0.1
|
|
|
|
|
|
MAIL_PORT=2525
|
|
|
|
|
|
MAIL_USERNAME=null
|
|
|
|
|
|
MAIL_PASSWORD=null
|
2026-01-18 21:00:09 +00:00
|
|
|
|
MAIL_ENCRYPTION=null
|
2026-01-15 01:13:44 +00:00
|
|
|
|
MAIL_FROM_ADDRESS="hello@example.com"
|
|
|
|
|
|
MAIL_FROM_NAME="${APP_NAME}"
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Reverb (WebSockets)
|
|
|
|
|
|
REVERB_APP_ID=1001
|
|
|
|
|
|
REVERB_APP_KEY=your-reverb-key
|
|
|
|
|
|
REVERB_APP_SECRET=your-reverb-secret
|
|
|
|
|
|
REVERB_HOST="localhost"
|
|
|
|
|
|
REVERB_PORT=8080
|
|
|
|
|
|
REVERB_SCHEME=http
|
|
|
|
|
|
|
|
|
|
|
|
# AWS S3 (set FILESYSTEM_DISK=s3)
|
2026-01-15 01:13:44 +00:00
|
|
|
|
AWS_ACCESS_KEY_ID=
|
|
|
|
|
|
AWS_SECRET_ACCESS_KEY=
|
|
|
|
|
|
AWS_DEFAULT_REGION=us-east-1
|
|
|
|
|
|
AWS_BUCKET=
|
2026-01-18 21:00:09 +00:00
|
|
|
|
AWS_URL=
|
2026-01-15 01:13:44 +00:00
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Cloudflare R2 (set FILESYSTEM_DISK=r2)
|
|
|
|
|
|
R2_ACCESS_KEY_ID=
|
|
|
|
|
|
R2_SECRET_ACCESS_KEY=
|
|
|
|
|
|
R2_ENDPOINT=
|
|
|
|
|
|
R2_REGION=auto
|
|
|
|
|
|
R2_BUCKET=
|
|
|
|
|
|
R2_URL=
|
|
|
|
|
|
|
2026-05-19 15:38:29 +00:00
|
|
|
|
# DigitalOcean Spaces (set FILESYSTEM_DISK=spaces)
|
|
|
|
|
|
SPACES_ACCESS_KEY_ID=
|
|
|
|
|
|
SPACES_SECRET_ACCESS_KEY=
|
|
|
|
|
|
SPACES_ENDPOINT=
|
|
|
|
|
|
SPACES_REGION=
|
|
|
|
|
|
SPACES_BUCKET=
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# ============================================
|
|
|
|
|
|
# Social Platform Credentials
|
|
|
|
|
|
# ============================================
|
|
|
|
|
|
# Get your API keys from each platform's developer portal
|
|
|
|
|
|
|
|
|
|
|
|
# LinkedIn (https://developer.linkedin.com)
|
|
|
|
|
|
LINKEDIN_CLIENT_ID=
|
|
|
|
|
|
LINKEDIN_CLIENT_SECRET=
|
|
|
|
|
|
LINKEDIN_CLIENT_REDIRECT="${APP_URL}/accounts/linkedin/callback"
|
2026-06-10 18:02:00 +00:00
|
|
|
|
# LINKEDIN_SCOPES="openid,profile,email,w_member_social"
|
|
|
|
|
|
# LINKEDIN_PAGE_SCOPES="openid,profile,email,w_organization_social,r_organization_social,rw_organization_admin,w_member_social"
|
2026-01-17 02:46:30 +00:00
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# X / Twitter (https://developer.twitter.com)
|
|
|
|
|
|
X_CLIENT_ID=
|
|
|
|
|
|
X_CLIENT_SECRET=
|
|
|
|
|
|
X_CLIENT_REDIRECT="${APP_URL}/accounts/x/callback"
|
|
|
|
|
|
|
|
|
|
|
|
# TikTok (https://developers.tiktok.com)
|
|
|
|
|
|
TIKTOK_CLIENT_ID=
|
|
|
|
|
|
TIKTOK_CLIENT_SECRET=
|
|
|
|
|
|
TIKTOK_CLIENT_REDIRECT="${APP_URL}/accounts/tiktok/callback"
|
|
|
|
|
|
|
|
|
|
|
|
# Facebook (https://developers.facebook.com)
|
|
|
|
|
|
FACEBOOK_CLIENT_ID=
|
|
|
|
|
|
FACEBOOK_CLIENT_SECRET=
|
|
|
|
|
|
FACEBOOK_CLIENT_REDIRECT="${APP_URL}/accounts/facebook/callback"
|
|
|
|
|
|
|
|
|
|
|
|
# Instagram (https://developers.facebook.com)
|
|
|
|
|
|
INSTAGRAM_CLIENT_ID=
|
|
|
|
|
|
INSTAGRAM_CLIENT_SECRET=
|
|
|
|
|
|
INSTAGRAM_CLIENT_REDIRECT="${APP_URL}/accounts/instagram/callback"
|
|
|
|
|
|
|
|
|
|
|
|
# Threads (https://developers.facebook.com)
|
|
|
|
|
|
THREADS_CLIENT_ID=
|
|
|
|
|
|
THREADS_CLIENT_SECRET=
|
|
|
|
|
|
THREADS_CLIENT_REDIRECT="${APP_URL}/accounts/threads/callback"
|
|
|
|
|
|
|
2026-03-31 00:18:07 +00:00
|
|
|
|
# Google (https://console.cloud.google.com)
|
|
|
|
|
|
# Used for YouTube social account connection AND Google login/signup
|
2026-05-04 21:53:21 +00:00
|
|
|
|
GOOGLE_AUTH_ENABLED=false
|
2026-01-18 21:00:09 +00:00
|
|
|
|
GOOGLE_CLIENT_ID=
|
|
|
|
|
|
GOOGLE_CLIENT_SECRET=
|
|
|
|
|
|
GOOGLE_CLIENT_REDIRECT="${APP_URL}/accounts/youtube/callback"
|
2026-03-31 00:18:07 +00:00
|
|
|
|
GOOGLE_AUTH_CALLBACK="${APP_URL}/auth/google/callback"
|
2026-01-18 21:00:09 +00:00
|
|
|
|
|
2026-05-04 21:53:21 +00:00
|
|
|
|
# GitHub (https://github.com/settings/developers)
|
|
|
|
|
|
# Used for GitHub login/signup
|
|
|
|
|
|
GITHUB_AUTH_ENABLED=false
|
|
|
|
|
|
GITHUB_CLIENT_ID=
|
|
|
|
|
|
GITHUB_CLIENT_SECRET=
|
|
|
|
|
|
GITHUB_AUTH_CALLBACK="${APP_URL}/auth/github/callback"
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Pinterest (https://developers.pinterest.com)
|
|
|
|
|
|
PINTEREST_CLIENT_ID=
|
|
|
|
|
|
PINTEREST_CLIENT_SECRET=
|
|
|
|
|
|
PINTEREST_CLIENT_REDIRECT="${APP_URL}/accounts/pinterest/callback"
|
|
|
|
|
|
|
2026-06-14 01:01:37 +00:00
|
|
|
|
# Telegram (single shared bot — create one via https://t.me/BotFather)
|
|
|
|
|
|
# After setting these, run: php artisan telegram:set-webhook
|
|
|
|
|
|
TELEGRAM_BOT_TOKEN=
|
|
|
|
|
|
TELEGRAM_BOT_USERNAME=
|
|
|
|
|
|
TELEGRAM_WEBHOOK_SECRET=
|
|
|
|
|
|
|
2026-06-16 18:28:58 +00:00
|
|
|
|
# Discord (single shared app+bot — create one via https://discord.com/developers/applications)
|
|
|
|
|
|
# OAuth2 → add the redirect below; Bot → enable "Server Members Intent" for mention search.
|
|
|
|
|
|
DISCORD_CLIENT_ID=
|
|
|
|
|
|
DISCORD_CLIENT_SECRET=
|
|
|
|
|
|
DISCORD_BOT_TOKEN=
|
|
|
|
|
|
DISCORD_CLIENT_REDIRECT="${APP_URL}/accounts/discord/callback"
|
|
|
|
|
|
|
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 12:25:08 +00:00
|
|
|
|
# AI Services
|
|
|
|
|
|
OPENAI_API_KEY=
|
2026-05-06 22:46:28 +00:00
|
|
|
|
ANTHROPIC_API_KEY=
|
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 12:25:08 +00:00
|
|
|
|
GEMINI_API_KEY=
|
|
|
|
|
|
ELEVENLABS_API_KEY=
|
|
|
|
|
|
|
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 23:59:03 +00:00
|
|
|
|
# AI Provider Selection
|
|
|
|
|
|
# text: openai | anthropic | gemini | xai | groq | mistral | deepseek | ...
|
|
|
|
|
|
# image: openai | gemini | xai
|
|
|
|
|
|
# audio: openai | elevenlabs
|
|
|
|
|
|
AI_TEXT_PROVIDER=openai
|
2026-05-06 22:46:28 +00:00
|
|
|
|
AI_TEXT_MODEL=gpt-5.4
|
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 23:59:03 +00:00
|
|
|
|
AI_IMAGE_PROVIDER=openai
|
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 12:25:08 +00:00
|
|
|
|
AI_AUDIO_PROVIDER=elevenlabs
|
|
|
|
|
|
|
2026-05-06 22:46:28 +00:00
|
|
|
|
# ============================================
|
|
|
|
|
|
# Stripe (Cashier — billing)
|
|
|
|
|
|
# ============================================
|
|
|
|
|
|
# Required when SELF_HOSTED=false. Get keys at https://dashboard.stripe.com/apikeys
|
|
|
|
|
|
STRIPE_KEY=
|
|
|
|
|
|
STRIPE_SECRET=
|
|
|
|
|
|
STRIPE_WEBHOOK_SECRET=
|
2026-05-21 23:18:21 +00:00
|
|
|
|
# Set to false to allow generic signup trial without requiring a card.
|
|
|
|
|
|
REQUIRE_CARD_FOR_TRIAL=true
|
2026-07-09 18:18:00 +00:00
|
|
|
|
# Free trial length in days, used only for the no-card generic trial above.
|
feat: per-workspace pricing, onboarding, and billing overhaul
Pricing
- Bill per workspace ($12/mo or $120/yr each); Stripe quantity tracks the
workspace count and syncs on workspace create/delete.
- 2,500 AI credits per workspace, pooled at the account level; monthly reset
on the billing anniversary, annual granted upfront (no rollover).
- One social account per network per workspace; remove all count-based limits
(workspace/social/member) and the legacy plan tiers (single Workspace plan).
Onboarding (cloud only: SELF_HOSTED=false + PostHog)
- Replace the /subscribe plan picker with /onboarding persona selection
(Creator/Freelancer/Startup/Agency/Small business/Other), saved on the user
(users.persona) and mirrored to PostHog, then Stripe Checkout on the monthly
price. 8-day trial so Stripe displays 7.
Billing screen
- Remove the Change Plan dialog (dead with a single plan); add an annual-upgrade
banner for monthly subscribers (swapToYearly).
- Current-plan card shows the workspace count instead of the plan name.
System AI
- Brand analyzer / workspace autofill is always allowed and never debits credits
(system feature, not the user's usage).
Self-hosted (SELF_HOSTED=true) bypasses all billing, credit, limit, network,
and onboarding logic.
2026-06-21 23:40:03 +00:00
|
|
|
|
CASHIER_TRIAL_DAYS=8
|
2026-07-09 18:18:00 +00:00
|
|
|
|
# Stripe Coupon ID (amount_off, duration=once) so the first invoice at
|
|
|
|
|
|
# checkout comes out to $1 instead of the full monthly price.
|
|
|
|
|
|
STRIPE_FIRST_MONTH_COUPON_ID=
|
2026-05-06 22:46:28 +00:00
|
|
|
|
|
|
|
|
|
|
# Stripe Plan Price IDs (one per plan × interval). Used by PlanSeeder.
|
feat: per-workspace pricing, onboarding, and billing overhaul
Pricing
- Bill per workspace ($12/mo or $120/yr each); Stripe quantity tracks the
workspace count and syncs on workspace create/delete.
- 2,500 AI credits per workspace, pooled at the account level; monthly reset
on the billing anniversary, annual granted upfront (no rollover).
- One social account per network per workspace; remove all count-based limits
(workspace/social/member) and the legacy plan tiers (single Workspace plan).
Onboarding (cloud only: SELF_HOSTED=false + PostHog)
- Replace the /subscribe plan picker with /onboarding persona selection
(Creator/Freelancer/Startup/Agency/Small business/Other), saved on the user
(users.persona) and mirrored to PostHog, then Stripe Checkout on the monthly
price. 8-day trial so Stripe displays 7.
Billing screen
- Remove the Change Plan dialog (dead with a single plan); add an annual-upgrade
banner for monthly subscribers (swapToYearly).
- Current-plan card shows the workspace count instead of the plan name.
System AI
- Brand analyzer / workspace autofill is always allowed and never debits credits
(system feature, not the user's usage).
Self-hosted (SELF_HOSTED=true) bypasses all billing, credit, limit, network,
and onboarding logic.
2026-06-21 23:40:03 +00:00
|
|
|
|
STRIPE_WORKSPACE_MONTHLY=
|
|
|
|
|
|
STRIPE_WORKSPACE_YEARLY=
|
2026-05-06 22:46:28 +00:00
|
|
|
|
|
|
|
|
|
|
# Laravel Nightwatch (production telemetry — disabled by default in dev)
|
|
|
|
|
|
NIGHTWATCH_ENABLED=false
|
|
|
|
|
|
NIGHTWATCH_TOKEN=
|
|
|
|
|
|
|
|
|
|
|
|
# Platform feature flags (all default to true; set to false to hide a platform)
|
|
|
|
|
|
# TIKTOK_ENABLED=true
|
|
|
|
|
|
# PINTEREST_ENABLED=true
|
|
|
|
|
|
# MASTODON_ENABLED=true
|
|
|
|
|
|
# BLUESKY_ENABLED=true
|
2026-06-14 01:01:37 +00:00
|
|
|
|
# TELEGRAM_ENABLED=true
|
2026-05-06 22:46:28 +00:00
|
|
|
|
|
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 12:25:08 +00:00
|
|
|
|
# Media Services
|
|
|
|
|
|
UNSPLASH_ACCESS_KEY=
|
|
|
|
|
|
UNSPLASH_SECRET_KEY=
|
|
|
|
|
|
GIPHY_API_KEY=
|
|
|
|
|
|
|
2026-03-31 00:32:43 +00:00
|
|
|
|
# Google Tag Manager (optional - analytics)
|
|
|
|
|
|
GTM_ID=
|
|
|
|
|
|
|
2026-05-07 15:42:35 +00:00
|
|
|
|
# PostHog (optional - analytics; off by default, self-hosted installs can ignore)
|
|
|
|
|
|
POSTHOG_ENABLED=false
|
2026-03-31 00:18:07 +00:00
|
|
|
|
POSTHOG_API_KEY=
|
|
|
|
|
|
POSTHOG_HOST=https://us.i.posthog.com
|
|
|
|
|
|
|
2026-01-18 21:00:09 +00:00
|
|
|
|
# Vite
|
|
|
|
|
|
VITE_APP_NAME="${APP_NAME}"
|
|
|
|
|
|
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
|
|
|
|
|
|
VITE_REVERB_HOST="${REVERB_HOST}"
|
|
|
|
|
|
VITE_REVERB_PORT="${REVERB_PORT}"
|
|
|
|
|
|
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
2026-05-07 15:42:35 +00:00
|
|
|
|
VITE_POSTHOG_ENABLED="${POSTHOG_ENABLED}"
|
2026-03-31 00:18:07 +00:00
|
|
|
|
VITE_POSTHOG_API_KEY="${POSTHOG_API_KEY}"
|
|
|
|
|
|
VITE_POSTHOG_HOST="${POSTHOG_HOST}"
|