2026-01-15 01:13:44 +00:00
|
|
|
<?php
|
|
|
|
|
|
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 03:20:43 +00:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
2026-01-15 01:13:44 +00:00
|
|
|
return [
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Third Party Services
|
|
|
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
| This file is for storing the credentials for third party services such
|
|
|
|
|
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
|
|
|
|
| location for this type of information, allowing packages to have
|
|
|
|
|
| a conventional file to locate the various service credentials.
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
'postmark' => [
|
|
|
|
|
'key' => env('POSTMARK_API_KEY'),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
'resend' => [
|
|
|
|
|
'key' => env('RESEND_API_KEY'),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
'ses' => [
|
|
|
|
|
'key' => env('AWS_ACCESS_KEY_ID'),
|
|
|
|
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
|
|
|
|
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
'slack' => [
|
|
|
|
|
'notifications' => [
|
|
|
|
|
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
|
|
|
|
|
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
'linkedin' => [
|
|
|
|
|
'client_id' => env('LINKEDIN_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('LINKEDIN_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('LINKEDIN_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
'linkedin-openid' => [
|
|
|
|
|
'client_id' => env('LINKEDIN_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('LINKEDIN_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('LINKEDIN_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-01-15 17:24:39 +00:00
|
|
|
'x' => [
|
2026-01-15 01:13:44 +00:00
|
|
|
'client_id' => env('X_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('X_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('X_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
'tiktok' => [
|
|
|
|
|
'client_id' => env('TIKTOK_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('TIKTOK_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('TIKTOK_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-01-15 17:24:39 +00:00
|
|
|
// Google OAuth (used for YouTube)
|
|
|
|
|
'google' => [
|
|
|
|
|
'client_id' => env('GOOGLE_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('GOOGLE_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-03-31 00:18:07 +00:00
|
|
|
// Google OAuth (used for login/signup)
|
|
|
|
|
'google-auth' => [
|
|
|
|
|
'client_id' => env('GOOGLE_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('GOOGLE_AUTH_CALLBACK'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-05-04 21:42:25 +00:00
|
|
|
// GitHub OAuth (used for login/signup)
|
|
|
|
|
'github' => [
|
|
|
|
|
'client_id' => env('GITHUB_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('GITHUB_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('GITHUB_AUTH_CALLBACK'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-01-16 15:36:52 +00:00
|
|
|
// Facebook Pages
|
2026-01-15 17:24:39 +00:00
|
|
|
'facebook' => [
|
|
|
|
|
'client_id' => env('FACEBOOK_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('FACEBOOK_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-01-16 15:36:52 +00:00
|
|
|
// Instagram
|
|
|
|
|
'instagram' => [
|
|
|
|
|
'client_id' => env('INSTAGRAM_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('INSTAGRAM_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('INSTAGRAM_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-01-15 17:24:39 +00:00
|
|
|
// Threads
|
|
|
|
|
'threads' => [
|
|
|
|
|
'client_id' => env('THREADS_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('THREADS_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('THREADS_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-01-18 16:10:01 +00:00
|
|
|
// Pinterest
|
|
|
|
|
'pinterest' => [
|
|
|
|
|
'client_id' => env('PINTEREST_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('PINTEREST_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('PINTEREST_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
feat(channels): add Discord as a social channel
Connect a Discord server via OAuth (bot authorization) and schedule/publish
messages to its channels, with mentions and rich embeds.
- Connect: custom Socialite Discord provider (bot scope) maps the authorized
guild to a SocialAccount; throws if no server was authorized.
- Publish: DiscordPublisher posts via the global bot token, validates the chosen
channel belongs to the connected guild (anti cross-guild), optimizes media,
builds allowed_mentions only from explicit mention chips (no accidental pings),
and renders rich embeds.
- Compose: per-post channel picker (live lookup), mention autocomplete and an
embed editor, gated by a required-channel compliance rule; Discord post preview.
- Enum/config/content-type wiring, ConnectionVerifier health check, throttled
lookup endpoints, i18n (en/es/pt-BR), and tests.
Operators must create a Discord application and set DISCORD_CLIENT_ID,
DISCORD_CLIENT_SECRET, DISCORD_BOT_TOKEN and DISCORD_CLIENT_REDIRECT.
2026-06-16 17:44:00 +00:00
|
|
|
// Discord
|
|
|
|
|
'discord' => [
|
|
|
|
|
'client_id' => env('DISCORD_CLIENT_ID'),
|
|
|
|
|
'client_secret' => env('DISCORD_CLIENT_SECRET'),
|
|
|
|
|
'redirect' => env('DISCORD_CLIENT_REDIRECT'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-03-31 00:32:43 +00:00
|
|
|
'gtm' => [
|
|
|
|
|
'id' => env('GTM_ID'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-03-31 00:18:07 +00:00
|
|
|
'posthog' => [
|
2026-05-07 15:42:35 +00:00
|
|
|
'enabled' => (bool) env('POSTHOG_ENABLED', false),
|
2026-03-31 00:18:07 +00:00
|
|
|
'api_key' => env('POSTHOG_API_KEY'),
|
|
|
|
|
'host' => env('POSTHOG_HOST', 'https://us.i.posthog.com'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-04-15 13:20:37 +00:00
|
|
|
'unsplash' => [
|
|
|
|
|
'access_key' => env('UNSPLASH_ACCESS_KEY'),
|
|
|
|
|
'secret_key' => env('UNSPLASH_SECRET_KEY'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-04-15 14:02:10 +00:00
|
|
|
'giphy' => [
|
|
|
|
|
'api_key' => env('GIPHY_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
|
|
|
'openai' => [
|
|
|
|
|
'api_key' => env('OPENAI_API_KEY'),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
'gemini' => [
|
|
|
|
|
'api_key' => env('GEMINI_API_KEY'),
|
|
|
|
|
],
|
|
|
|
|
|
2026-01-15 01:13:44 +00:00
|
|
|
];
|