2026-01-15 01:13:44 +00:00
|
|
|
<?php
|
|
|
|
|
|
2026-05-03 21:38:17 +00:00
|
|
|
use App\Http\Middleware\Api\LoadWorkspaceFromToken;
|
2026-05-19 14:45:16 +00:00
|
|
|
use App\Http\Middleware\App\EnsureRegistrationEnabled;
|
refactor: organize middleware/requests into App/ subdirs, add Resources, fix auth routes
- Move middleware to App/ subdir (HandleInertiaRequests, HandleAppearance,
EnsureSubscribed, EnsureUserSetupIsComplete) matching Sendkit pattern
- Move all Form Requests into organized subdirs (App/Post, App/Workspace,
App/Media, App/Invite, App/Settings, App/Auth)
- Create AuthUserResource and AuthWorkspaceResource for HandleInertiaRequests
shared data (role inside currentWorkspace, matching Sendkit pattern)
- Split auth.php into 3 route groups (no middleware, guest, auth) matching
Sendkit pattern exactly
- Fix UserFactory to include all nullable attributes (current_workspace_id,
stripe_id, pm_type, pm_last_four, trial_ends_at)
- Fix SocialAccountResource (display_name not name)
- Update frontend for new auth prop structure
- 702 tests passing (2 pre-existing Mastodon failures)
2026-03-30 00:13:30 +00:00
|
|
|
use App\Http\Middleware\App\HandleInertiaRequests;
|
refactor: auth split layout, subscribe redesign, onboarding, i18n, cookie locale
Auth pages:
- Create AuthSplitLayout with animated feature slides (6 slides, 3 languages)
- All auth pages use split layout (form left, visual right)
- Add show/hide password toggle with tooltip on Register
- Legal footer only shown on Register via showLegal prop
Subscribe page:
- Redesign to match auth card pattern (centered, clean)
- Platform icons, feature checklist, dynamic trial days (trialDays - 1)
- Add "Switch workspace" link
- Full i18n (en, es, pt-BR)
Onboarding:
- Rename URLs: step1 -> role, step2 -> connect
- Add enforceStep() to prevent skipping/going back steps
- Redirect /onboarding to /onboarding/role
- Redesign Step2 with AuthSplitLayout and compact platform list
- 21 tests covering all step enforcement scenarios
Workspaces page:
- Redesign with AuthSplitLayout (list with avatars, current badge)
Language system:
- Move locale from DB to cookie (forever, unencrypted, session.domain)
- Create SetLocale middleware (sets cookie if missing, validates against config)
- Rename lang/pt-br to lang/pt-BR
- Add dayjs es locale
Other:
- Copy utils.ts from sendkit (formatNumber, formatMoney, copyToClipboard)
- ConfirmDeleteModal with text confirmation (sendkit pattern)
- i18n for ConfirmDeleteModal internal strings (common.php)
- EmptyState component for posts index
- Exact match for "All" posts in sidebar
- Posts breadcrumbs show current status filter
- DialogFooter buttons aligned left
- API Keys page redesign with Table, DropdownMenu, EmptyState
- Extract CreateApiKeyDialog and InviteMemberDialog to components
- Remove API Keys from sidebar
- DropdownMenuItem destructive variant for Remove action
2026-03-30 14:53:42 +00:00
|
|
|
use App\Http\Middleware\App\SetLocale;
|
2026-01-15 01:13:44 +00:00
|
|
|
use Illuminate\Foundation\Application;
|
|
|
|
|
use Illuminate\Foundation\Configuration\Exceptions;
|
|
|
|
|
use Illuminate\Foundation\Configuration\Middleware;
|
|
|
|
|
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
|
2026-03-29 23:14:23 +00:00
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
|
2026-01-15 01:13:44 +00:00
|
|
|
|
|
|
|
|
return Application::configure(basePath: dirname(__DIR__))
|
|
|
|
|
->withRouting(
|
|
|
|
|
web: __DIR__.'/../routes/web.php',
|
2026-03-29 22:24:28 +00:00
|
|
|
api: __DIR__.'/../routes/api.php',
|
feat: complete create + publish post flow via MCP and REST API
Lets ChatGPT (MCP) and external clients (REST API) drive the full lifecycle of
a post — create with platform selection, attach media from URLs, schedule or
publish immediately, and fetch engagement metrics — without touching the web UI.
MCP tools added: UpdatePostTool, PublishPostTool, AttachMediaFromUrlTool,
ListContentTypesTool, GetPostMetricsTool, PreviewPostTool. CreatePostTool now
accepts platforms[] + scheduled_at + label_ids; ListPostsTool gains
status/search/limit filters.
REST endpoints added: POST /api/posts/{post}/media, GET /api/posts/{post}/metrics,
GET /api/posts/{post}/preview, GET /api/content-types.
Also fixes a silent CreatePost::execute bug — the action validated platforms[]
but ignored it, so REST callers never saw their selection persisted. Adds cross
validation rules (ContentTypeMatchesPlatform / ContentTypeMatchesPostPlatform)
so a LinkedIn account can't be saddled with x_post, and rejects inactive social
accounts during validation instead of failing silently downstream.
Shared services (PostMetricsFetcher, PostPreviewer, MediaAttacher) back both
MCP tools and REST controllers so behaviour stays aligned. New Resources
(PlatformContentTypesResource, PostMetricsResource, PostPreviewResource,
PostMediaAttachResource) keep controllers free of inline model mapping.
Suite: 1.332 passing, 0 failing — covers web (PostControllerTest), REST
(PostApiTest, PlatformApiTest, PostMediaApiTest), MCP (66 tool tests), and
the publish job (PublishToSocialPlatformTest).
Removes /docs from git tracking and TIKTOK_REVIEW_VIDEO_SCRIPT.md.
2026-05-04 11:12:28 +00:00
|
|
|
apiPrefix: 'api',
|
2026-01-15 01:13:44 +00:00
|
|
|
commands: __DIR__.'/../routes/console.php',
|
2026-01-15 17:24:39 +00:00
|
|
|
channels: __DIR__.'/../routes/channels.php',
|
2026-01-15 01:13:44 +00:00
|
|
|
health: '/up',
|
|
|
|
|
)
|
|
|
|
|
->withMiddleware(function (Middleware $middleware): void {
|
2026-03-29 22:59:17 +00:00
|
|
|
$middleware->trustProxies(at: '*');
|
|
|
|
|
|
2026-05-06 17:26:18 +00:00
|
|
|
$middleware->encryptCookies(except: ['sidebar_state', 'locale']);
|
2026-01-15 01:13:44 +00:00
|
|
|
|
|
|
|
|
$middleware->web(append: [
|
refactor: auth split layout, subscribe redesign, onboarding, i18n, cookie locale
Auth pages:
- Create AuthSplitLayout with animated feature slides (6 slides, 3 languages)
- All auth pages use split layout (form left, visual right)
- Add show/hide password toggle with tooltip on Register
- Legal footer only shown on Register via showLegal prop
Subscribe page:
- Redesign to match auth card pattern (centered, clean)
- Platform icons, feature checklist, dynamic trial days (trialDays - 1)
- Add "Switch workspace" link
- Full i18n (en, es, pt-BR)
Onboarding:
- Rename URLs: step1 -> role, step2 -> connect
- Add enforceStep() to prevent skipping/going back steps
- Redirect /onboarding to /onboarding/role
- Redesign Step2 with AuthSplitLayout and compact platform list
- 21 tests covering all step enforcement scenarios
Workspaces page:
- Redesign with AuthSplitLayout (list with avatars, current badge)
Language system:
- Move locale from DB to cookie (forever, unencrypted, session.domain)
- Create SetLocale middleware (sets cookie if missing, validates against config)
- Rename lang/pt-br to lang/pt-BR
- Add dayjs es locale
Other:
- Copy utils.ts from sendkit (formatNumber, formatMoney, copyToClipboard)
- ConfirmDeleteModal with text confirmation (sendkit pattern)
- i18n for ConfirmDeleteModal internal strings (common.php)
- EmptyState component for posts index
- Exact match for "All" posts in sidebar
- Posts breadcrumbs show current status filter
- DialogFooter buttons aligned left
- API Keys page redesign with Table, DropdownMenu, EmptyState
- Extract CreateApiKeyDialog and InviteMemberDialog to components
- Remove API Keys from sidebar
- DropdownMenuItem destructive variant for Remove action
2026-03-30 14:53:42 +00:00
|
|
|
SetLocale::class,
|
2026-01-15 01:13:44 +00:00
|
|
|
HandleInertiaRequests::class,
|
|
|
|
|
AddLinkHeadersForPreloadedAssets::class,
|
|
|
|
|
]);
|
2026-01-17 02:46:30 +00:00
|
|
|
|
|
|
|
|
$middleware->alias([
|
2026-05-03 21:38:17 +00:00
|
|
|
'workspace.token' => LoadWorkspaceFromToken::class,
|
2026-05-19 14:45:16 +00:00
|
|
|
'registration.enabled' => EnsureRegistrationEnabled::class,
|
2026-03-29 22:24:28 +00:00
|
|
|
]);
|
|
|
|
|
|
2026-03-29 22:59:17 +00:00
|
|
|
$middleware->preventRequestForgery(except: [
|
2026-03-29 22:24:28 +00:00
|
|
|
'stripe/*',
|
2026-01-17 02:46:30 +00:00
|
|
|
]);
|
2026-01-15 01:13:44 +00:00
|
|
|
})
|
|
|
|
|
->withExceptions(function (Exceptions $exceptions): void {
|
2026-03-29 23:14:23 +00:00
|
|
|
$exceptions->renderable(function (TooManyRequestsHttpException $e, Request $request) {
|
|
|
|
|
if ($request->expectsJson()) {
|
|
|
|
|
$retryAfter = $e->getHeaders()['Retry-After'] ?? null;
|
|
|
|
|
$message = $retryAfter
|
|
|
|
|
? "Rate limit exceeded. Please retry after {$retryAfter} seconds."
|
|
|
|
|
: 'Rate limit exceeded. Please try again later.';
|
|
|
|
|
|
|
|
|
|
return response()->json([
|
|
|
|
|
'name' => 'rate_limit_exceeded',
|
|
|
|
|
'message' => $message,
|
|
|
|
|
], 429)->withHeaders($e->getHeaders());
|
|
|
|
|
}
|
|
|
|
|
});
|
2026-05-24 12:17:19 +00:00
|
|
|
|
|
|
|
|
$exceptions->render(function (DomainException $e, Request $request) {
|
|
|
|
|
if ($request->expectsJson()) {
|
|
|
|
|
return response()->json(['message' => $e->getMessage()], 422);
|
|
|
|
|
}
|
|
|
|
|
});
|
2026-01-15 01:13:44 +00:00
|
|
|
})->create();
|