chore: reverting domains

This commit is contained in:
Paulo Castellano 2026-03-31 11:35:49 -03:00
parent c149eda2b0
commit 176929aa12
19 changed files with 198 additions and 253 deletions

View file

@ -44,7 +44,7 @@ ## Skills Activation
- `cashier-stripe-development` — Handles Laravel Cashier Stripe integration including subscriptions, webhooks, Stripe Checkout, invoices, charges, refunds, trials, coupons, metered billing, and payment failure handling. Triggered when a user mentions Cashier, Billable, IncompletePayment, stripe_id, newSubscription, Stripe subscriptions, or billing. Also applies when setting up webhooks, handling SCA/3DS payment failures, testing with Stripe test cards, or troubleshooting incomplete subscriptions, CSRF webhook errors, or migration publish issues.
- `laravel-best-practices` — Apply this skill whenever writing, reviewing, or refactoring Laravel PHP code. This includes creating or modifying controllers, models, migrations, form requests, policies, jobs, scheduled commands, service classes, and Eloquent queries. Triggers for N+1 and query performance issues, caching strategies, authorization and security patterns, validation, error handling, queue and job configuration, route definitions, and architectural decisions. Also use for Laravel code reviews and refactoring existing Laravel code to follow best practices. Covers any task involving Laravel backend PHP code patterns.
- `configuring-horizon` — Use this skill whenever the user mentions Horizon by name in a Laravel context. Covers the full Horizon lifecycle: installing Horizon (horizon:install, Sail setup), configuring config/horizon.php (supervisor blocks, queue assignments, balancing strategies, minProcesses/maxProcesses), fixing the dashboard (authorization via Gate::define viewHorizon, blank metrics, horizon:snapshot scheduling), and troubleshooting production issues (worker crashes, timeout chain ordering, LongWaitDetected notifications, waits config). Also covers job tagging and silencing. Do not use for generic Laravel queues without Horizon, SQS or database drivers, standalone Redis setup, Linux supervisord, Telescope, or job batching.
- `mcp-development` — Use this skill for Laravel MCP development only. Trigger when creating or editing MCP tools, resources, prompts, or servers in Laravel projects. Covers: artisan make:mcp-\* generators, mcp:inspector, routes/ai.php, Tool/Resource/Prompt classes, schema validation, shouldRegister(), OAuth setup, URI templates, read-only attributes, and MCP debugging. Do not use for non-Laravel MCP projects or generic AI features without MCP.
- `mcp-development` — Use this skill for Laravel MCP development only. Trigger when creating or editing MCP tools, resources, prompts, or servers in Laravel projects. Covers: artisan make:mcp-* generators, mcp:inspector, routes/ai.php, Tool/Resource/Prompt classes, schema validation, shouldRegister(), OAuth setup, URI templates, read-only attributes, and MCP debugging. Do not use for non-Laravel MCP projects or generic AI features without MCP.
- `socialite-development` — Manages OAuth social authentication with Laravel Socialite. Activate when adding social login providers; configuring OAuth redirect/callback flows; retrieving authenticated user details; customizing scopes or parameters; setting up community providers; testing with Socialite fakes; or when the user mentions social login, OAuth, Socialite, or third-party authentication.
- `wayfinder-development` — Use this skill for Laravel Wayfinder which auto-generates typed functions for Laravel controllers and routes. ALWAYS use this skill when frontend code needs to call backend routes or controller actions. Trigger when: connecting any React/Vue/Svelte/Inertia frontend to Laravel controllers, routes, building end-to-end features with both frontend and backend, wiring up forms or links to backend endpoints, fixing route-related TypeScript errors, importing from @/actions or @/routes, or running wayfinder:generate. Use Wayfinder route functions instead of hardcoded URLs. Covers: wayfinder() vite plugin, .url()/.get()/.post()/.form(), query params, route model binding, tree-shaking. Do not use for backend-only task
- `pest-testing` — Use this skill for Pest PHP testing in Laravel projects only. Trigger whenever any test is being written, edited, fixed, or refactored — including fixing tests that broke after a code change, adding assertions, converting PHPUnit to Pest, adding datasets, and TDD workflows. Always activate when the user asks how to write something in Pest, mentions test files or directories (tests/Feature, tests/Unit, tests/Browser), or needs browser testing, smoke testing multiple pages for JS errors, or architecture tests. Covers: it()/expect() syntax, datasets, mocking, browser testing (visit/click/fill), smoke testing, arch(), Livewire component tests, RefreshDatabase, and all Pest 4 features. Do not use for factories, seeders, migrations, controllers, models, or non-test PHP code.
@ -116,7 +116,7 @@ ## Tinker
- Execute PHP in app context for debugging and testing code. Do not create models without user approval, prefer tests with factories instead. Prefer existing Artisan commands over custom tinker code.
- Always use single quotes to prevent shell expansion: `php artisan tinker --execute 'Your::code();'`
- Double quotes for PHP strings inside: `php artisan tinker --execute 'User::where("active", true)->count();'`
- Double quotes for PHP strings inside: `php artisan tinker --execute 'User::where("active", true)->count();'`
=== php rules ===
@ -222,7 +222,6 @@ ## Pest
# Inertia + Vue
Vue components must have a single root element.
- IMPORTANT: Activate `inertia-vue-development` when working with Inertia Vue client-side patterns.
</laravel-boost-guidelines>

View file

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
if (! function_exists('email_asset')) {
/**
* Generate an absolute URL for email assets.
*/
function email_asset(string $path): string
{
return rtrim(config('app.email_asset_url'), '/').'/'.ltrim($path, '/');
}
}

View file

@ -71,8 +71,7 @@
},
"autoload": {
"files": [
"app/Helpers/Upload.php",
"app/Helpers/Asset.php"
"app/Helpers/Upload.php"
],
"psr-4": {
"App\\": "app/",

View file

@ -56,8 +56,6 @@
'url' => env('APP_URL', 'https://trypost.it'),
'email_asset_url' => env('EMAIL_ASSET_URL', 'https://app.trypost.it'),
/*
|--------------------------------------------------------------------------
| Application Timezone

1
lang/php_en.json Normal file

File diff suppressed because one or more lines are too long

1
lang/php_es.json Normal file

File diff suppressed because one or more lines are too long

1
lang/php_pt-BR.json Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
<div class="my-12 sm:my-8 text-center">
<a href="https://trypost.it" target="_blank">
<img src="@{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost">
<img src="@{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost">
</a>
</div>

View file

@ -62,7 +62,7 @@
<td style="width: 552px; max-width: 100%">
<div class="sm-my-8" style="margin-top: 48px; margin-bottom: 48px; text-align: center">
<a href="https://trypost.it" target="_blank">
<img src="{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
<img src="{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
</a>
</div>
<table style="width: 100%" cellpadding="0" cellspacing="0" role="none">

View file

@ -59,7 +59,7 @@
<td style="width: 552px; max-width: 100%">
<div class="sm-my-8" style="margin-top: 48px; margin-bottom: 48px; text-align: center">
<a href="https://trypost.it" target="_blank">
<img src="{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
<img src="{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
</a>
</div>
<table style="width: 100%" cellpadding="0" cellspacing="0" role="none">

View file

@ -59,7 +59,7 @@
<td style="width: 552px; max-width: 100%">
<div class="sm-my-8" style="margin-top: 48px; margin-bottom: 48px; text-align: center">
<a href="https://trypost.it" target="_blank">
<img src="{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
<img src="{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
</a>
</div>
<table style="width: 100%" cellpadding="0" cellspacing="0" role="none">

View file

@ -62,7 +62,7 @@
<td style="width: 552px; max-width: 100%">
<div class="sm-my-8" style="margin-top: 48px; margin-bottom: 48px; text-align: center">
<a href="https://trypost.it" target="_blank">
<img src="{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
<img src="{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
</a>
</div>
<table style="width: 100%" cellpadding="0" cellspacing="0" role="none">

View file

@ -62,7 +62,7 @@
<td style="width: 552px; max-width: 100%">
<div class="sm-my-8" style="margin-top: 48px; margin-bottom: 48px; text-align: center">
<a href="https://trypost.it" target="_blank">
<img src="{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
<img src="{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
</a>
</div>
<table style="width: 100%" cellpadding="0" cellspacing="0" role="none">

View file

@ -62,7 +62,7 @@
<td style="width: 552px; max-width: 100%">
<div class="sm-my-8" style="margin-top: 48px; margin-bottom: 48px; text-align: center">
<a href="https://trypost.it" target="_blank">
<img src="{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
<img src="{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
</a>
</div>
<table style="width: 100%" cellpadding="0" cellspacing="0" role="none">

View file

@ -62,7 +62,7 @@
<td style="width: 552px; max-width: 100%">
<div class="sm-my-8" style="margin-top: 48px; margin-bottom: 48px; text-align: center">
<a href="https://trypost.it" target="_blank">
<img src="{{ email_asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
<img src="{{ asset('/images/emails/logo-header.png') }}" width="160" alt="Trypost" style="max-width: 100%; vertical-align: middle">
</a>
</div>
<table style="width: 100%" cellpadding="0" cellspacing="0" role="none">

View file

@ -3,15 +3,7 @@
declare(strict_types=1);
use App\Mcp\Servers\TryPostServer;
use Illuminate\Support\Facades\Route;
use Laravel\Mcp\Facades\Mcp;
Route::group(
[
'domain' => 'mcp.'.parse_url(config('app.url'), PHP_URL_HOST),
],
function () {
Mcp::web('/trypost', TryPostServer::class)
->middleware('mcp.auth');
}
);
Mcp::web('/mcp/trypost', TryPostServer::class)
->middleware('mcp.auth');

View file

@ -10,41 +10,35 @@
use App\Http\Controllers\Api\WorkspaceController;
use Illuminate\Support\Facades\Route;
Route::group(
[
'domain' => 'api.'.parse_url(config('app.url'), PHP_URL_HOST),
'middleware' => ['api.auth', 'throttle:api'],
],
function () {
// Posts
Route::get('/posts', [PostController::class, 'index'])->name('api.posts.index');
Route::post('/posts', [PostController::class, 'store'])->name('api.posts.store');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('api.posts.show');
Route::put('/posts/{post}', [PostController::class, 'update'])->name('api.posts.update');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('api.posts.destroy');
Route::prefix('api')->middleware(['api.auth', 'throttle:api'])->group(function () {
// Posts
Route::get('/posts', [PostController::class, 'index'])->name('api.posts.index');
Route::post('/posts', [PostController::class, 'store'])->name('api.posts.store');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('api.posts.show');
Route::put('/posts/{post}', [PostController::class, 'update'])->name('api.posts.update');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('api.posts.destroy');
// Workspace
Route::get('/workspace', [WorkspaceController::class, 'show'])->name('api.workspace.show');
// Workspace
Route::get('/workspace', [WorkspaceController::class, 'show'])->name('api.workspace.show');
// Hashtags
Route::get('/hashtags', [HashtagController::class, 'index'])->name('api.hashtags.index');
Route::post('/hashtags', [HashtagController::class, 'store'])->name('api.hashtags.store');
Route::put('/hashtags/{hashtag}', [HashtagController::class, 'update'])->name('api.hashtags.update');
Route::delete('/hashtags/{hashtag}', [HashtagController::class, 'destroy'])->name('api.hashtags.destroy');
// Hashtags
Route::get('/hashtags', [HashtagController::class, 'index'])->name('api.hashtags.index');
Route::post('/hashtags', [HashtagController::class, 'store'])->name('api.hashtags.store');
Route::put('/hashtags/{hashtag}', [HashtagController::class, 'update'])->name('api.hashtags.update');
Route::delete('/hashtags/{hashtag}', [HashtagController::class, 'destroy'])->name('api.hashtags.destroy');
// Labels
Route::get('/labels', [LabelController::class, 'index'])->name('api.labels.index');
Route::post('/labels', [LabelController::class, 'store'])->name('api.labels.store');
Route::put('/labels/{label}', [LabelController::class, 'update'])->name('api.labels.update');
Route::delete('/labels/{label}', [LabelController::class, 'destroy'])->name('api.labels.destroy');
// Labels
Route::get('/labels', [LabelController::class, 'index'])->name('api.labels.index');
Route::post('/labels', [LabelController::class, 'store'])->name('api.labels.store');
Route::put('/labels/{label}', [LabelController::class, 'update'])->name('api.labels.update');
Route::delete('/labels/{label}', [LabelController::class, 'destroy'])->name('api.labels.destroy');
// Social Accounts
Route::get('/social-accounts', [SocialAccountController::class, 'index'])->name('api.social-accounts.index');
Route::put('/social-accounts/{account}/toggle', [SocialAccountController::class, 'toggle'])->name('api.social-accounts.toggle');
// Social Accounts
Route::get('/social-accounts', [SocialAccountController::class, 'index'])->name('api.social-accounts.index');
Route::put('/social-accounts/{account}/toggle', [SocialAccountController::class, 'toggle'])->name('api.social-accounts.toggle');
// API Keys
Route::get('/api-keys', [ApiKeyController::class, 'index'])->name('api.api-keys.index');
Route::post('/api-keys', [ApiKeyController::class, 'store'])->name('api.api-keys.store');
Route::delete('/api-keys/{apiToken}', [ApiKeyController::class, 'destroy'])->name('api.api-keys.destroy');
}
);
// API Keys
Route::get('/api-keys', [ApiKeyController::class, 'index'])->name('api.api-keys.index');
Route::post('/api-keys', [ApiKeyController::class, 'store'])->name('api.api-keys.store');
Route::delete('/api-keys/{apiToken}', [ApiKeyController::class, 'destroy'])->name('api.api-keys.destroy');
});

View file

@ -30,167 +30,159 @@
use App\Http\Middleware\App\EnsureUserSetupIsComplete;
use Illuminate\Support\Facades\Route;
Route::group(
[
'domain' => 'app.'.parse_url(config('app.url'), PHP_URL_HOST),
'middleware' => ['web'],
],
function () {
Route::get('/', function () {
return redirect()->route('app.calendar');
})->name('app.home')->middleware(['auth', 'verified']);
Route::get('/', function () {
return redirect()->route('app.calendar');
})->name('app.home')->middleware(['auth', 'verified']);
// Subscription selection (requires auth but not subscription)
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('subscribe', [BillingController::class, 'subscribe'])->name('app.subscribe');
Route::post('billing/checkout', [BillingController::class, 'checkout'])->name('app.billing.checkout');
Route::get('billing/processing', [BillingController::class, 'processing'])->name('app.billing.processing');
});
// Subscription selection (requires auth but not subscription)
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('subscribe', [BillingController::class, 'subscribe'])->name('app.subscribe');
Route::post('billing/checkout', [BillingController::class, 'checkout'])->name('app.billing.checkout');
Route::get('billing/processing', [BillingController::class, 'processing'])->name('app.billing.processing');
});
// Onboarding routes
Route::middleware(['auth', 'verified'])->prefix('onboarding')->group(function () {
Route::get('/', fn () => redirect()->route('app.onboarding.role'));
Route::get('role', [OnboardingController::class, 'role'])->name('app.onboarding.role');
Route::post('role', [OnboardingController::class, 'storeRole'])->name('app.onboarding.role.store');
Route::get('connect', [OnboardingController::class, 'connect'])->name('app.onboarding.connect');
Route::post('connect', [OnboardingController::class, 'storeConnect'])->name('app.onboarding.connect.store');
Route::get('complete', [OnboardingController::class, 'complete'])->name('app.onboarding.complete');
});
// Onboarding routes
Route::middleware(['auth', 'verified'])->prefix('onboarding')->group(function () {
Route::get('/', fn () => redirect()->route('app.onboarding.role'));
Route::get('role', [OnboardingController::class, 'role'])->name('app.onboarding.role');
Route::post('role', [OnboardingController::class, 'storeRole'])->name('app.onboarding.role.store');
Route::get('connect', [OnboardingController::class, 'connect'])->name('app.onboarding.connect');
Route::post('connect', [OnboardingController::class, 'storeConnect'])->name('app.onboarding.connect.store');
Route::get('complete', [OnboardingController::class, 'complete'])->name('app.onboarding.complete');
});
// Social Connect routes
Route::middleware(['auth', 'verified', 'throttle:6,1'])->group(function () {
Route::get('connect/linkedin', [LinkedInController::class, 'connect'])->name('app.social.linkedin.connect');
Route::get('accounts/linkedin/callback', [LinkedInController::class, 'callback'])->name('app.social.linkedin.callback');
// Social Connect routes
Route::middleware(['auth', 'verified', 'throttle:6,1'])->group(function () {
Route::get('connect/linkedin', [LinkedInController::class, 'connect'])->name('app.social.linkedin.connect');
Route::get('accounts/linkedin/callback', [LinkedInController::class, 'callback'])->name('app.social.linkedin.callback');
Route::get('connect/linkedin-page', [LinkedInPageController::class, 'connect'])->name('app.social.linkedin-page.connect');
Route::get('accounts/linkedin-page/callback', [LinkedInPageController::class, 'callback'])->name('app.social.linkedin-page.callback');
Route::get('accounts/linkedin-page/select', [LinkedInPageController::class, 'selectPage'])->name('app.social.linkedin-page.select-page');
Route::post('accounts/linkedin-page/select', [LinkedInPageController::class, 'select'])->name('app.social.linkedin-page.select');
Route::get('connect/linkedin-page', [LinkedInPageController::class, 'connect'])->name('app.social.linkedin-page.connect');
Route::get('accounts/linkedin-page/callback', [LinkedInPageController::class, 'callback'])->name('app.social.linkedin-page.callback');
Route::get('accounts/linkedin-page/select', [LinkedInPageController::class, 'selectPage'])->name('app.social.linkedin-page.select-page');
Route::post('accounts/linkedin-page/select', [LinkedInPageController::class, 'select'])->name('app.social.linkedin-page.select');
Route::get('connect/x', [XController::class, 'connect'])->name('app.social.x.connect');
Route::get('accounts/x/callback', [XController::class, 'callback'])->name('app.social.x.callback');
Route::get('connect/x', [XController::class, 'connect'])->name('app.social.x.connect');
Route::get('accounts/x/callback', [XController::class, 'callback'])->name('app.social.x.callback');
Route::get('connect/tiktok', [TikTokController::class, 'connect'])->name('app.social.tiktok.connect');
Route::get('accounts/tiktok/callback', [TikTokController::class, 'callback'])->name('app.social.tiktok.callback');
Route::get('connect/tiktok', [TikTokController::class, 'connect'])->name('app.social.tiktok.connect');
Route::get('accounts/tiktok/callback', [TikTokController::class, 'callback'])->name('app.social.tiktok.callback');
Route::get('connect/youtube', [YouTubeController::class, 'connect'])->name('app.social.youtube.connect');
Route::get('accounts/youtube/callback', [YouTubeController::class, 'callback'])->name('app.social.youtube.callback');
Route::get('accounts/youtube/select', [YouTubeController::class, 'selectChannel'])->name('app.social.youtube.select-channel');
Route::post('accounts/youtube/select', [YouTubeController::class, 'select'])->name('app.social.youtube.select');
Route::get('connect/youtube', [YouTubeController::class, 'connect'])->name('app.social.youtube.connect');
Route::get('accounts/youtube/callback', [YouTubeController::class, 'callback'])->name('app.social.youtube.callback');
Route::get('accounts/youtube/select', [YouTubeController::class, 'selectChannel'])->name('app.social.youtube.select-channel');
Route::post('accounts/youtube/select', [YouTubeController::class, 'select'])->name('app.social.youtube.select');
Route::get('connect/facebook', [FacebookController::class, 'connect'])->name('app.social.facebook.connect');
Route::get('accounts/facebook/callback', [FacebookController::class, 'callback'])->name('app.social.facebook.callback');
Route::get('accounts/facebook/select', [FacebookController::class, 'selectPage'])->name('app.social.facebook.select-page');
Route::post('accounts/facebook/select', [FacebookController::class, 'select'])->name('app.social.facebook.select');
Route::get('connect/facebook', [FacebookController::class, 'connect'])->name('app.social.facebook.connect');
Route::get('accounts/facebook/callback', [FacebookController::class, 'callback'])->name('app.social.facebook.callback');
Route::get('accounts/facebook/select', [FacebookController::class, 'selectPage'])->name('app.social.facebook.select-page');
Route::post('accounts/facebook/select', [FacebookController::class, 'select'])->name('app.social.facebook.select');
Route::get('connect/instagram', [InstagramController::class, 'connect'])->name('app.social.instagram.connect');
Route::get('accounts/instagram/callback', [InstagramController::class, 'callback'])->name('app.social.instagram.callback');
Route::get('accounts/instagram/select', [InstagramController::class, 'selectAccount'])->name('app.social.instagram.select-account');
Route::post('accounts/instagram/select', [InstagramController::class, 'select'])->name('app.social.instagram.select');
Route::get('connect/instagram', [InstagramController::class, 'connect'])->name('app.social.instagram.connect');
Route::get('accounts/instagram/callback', [InstagramController::class, 'callback'])->name('app.social.instagram.callback');
Route::get('accounts/instagram/select', [InstagramController::class, 'selectAccount'])->name('app.social.instagram.select-account');
Route::post('accounts/instagram/select', [InstagramController::class, 'select'])->name('app.social.instagram.select');
Route::get('connect/threads', [ThreadsController::class, 'connect'])->name('app.social.threads.connect');
Route::get('accounts/threads/callback', [ThreadsController::class, 'callback'])->name('app.social.threads.callback');
Route::get('connect/threads', [ThreadsController::class, 'connect'])->name('app.social.threads.connect');
Route::get('accounts/threads/callback', [ThreadsController::class, 'callback'])->name('app.social.threads.callback');
Route::get('connect/pinterest', [PinterestController::class, 'connect'])->name('app.social.pinterest.connect');
Route::get('accounts/pinterest/callback', [PinterestController::class, 'callback'])->name('app.social.pinterest.callback');
Route::get('connect/pinterest', [PinterestController::class, 'connect'])->name('app.social.pinterest.connect');
Route::get('accounts/pinterest/callback', [PinterestController::class, 'callback'])->name('app.social.pinterest.callback');
Route::get('connect/bluesky', [BlueskyController::class, 'connect'])->name('app.social.bluesky.connect');
Route::post('connect/bluesky', [BlueskyController::class, 'store'])->name('app.social.bluesky.store');
Route::get('connect/bluesky', [BlueskyController::class, 'connect'])->name('app.social.bluesky.connect');
Route::post('connect/bluesky', [BlueskyController::class, 'store'])->name('app.social.bluesky.store');
Route::get('connect/mastodon', [MastodonController::class, 'connect'])->name('app.social.mastodon.connect');
Route::post('connect/mastodon', [MastodonController::class, 'authorizeInstance'])->name('app.social.mastodon.authorize');
Route::get('accounts/mastodon/callback', [MastodonController::class, 'callback'])->name('app.social.mastodon.callback');
});
Route::get('connect/mastodon', [MastodonController::class, 'connect'])->name('app.social.mastodon.connect');
Route::post('connect/mastodon', [MastodonController::class, 'authorizeInstance'])->name('app.social.mastodon.authorize');
Route::get('accounts/mastodon/callback', [MastodonController::class, 'callback'])->name('app.social.mastodon.callback');
});
// Routes that require active subscription and completed onboarding
Route::middleware(['auth', 'verified', 'subscribed', EnsureUserSetupIsComplete::class])->group(function () {
// Workspaces
Route::get('workspaces', [WorkspaceController::class, 'index'])->name('app.workspaces.index');
Route::get('workspaces/create', [WorkspaceController::class, 'create'])->name('app.workspaces.create');
Route::post('workspaces', [WorkspaceController::class, 'store'])->name('app.workspaces.store');
Route::post('workspaces/{workspace}/switch', [WorkspaceController::class, 'switch'])->name('app.workspaces.switch');
Route::delete('workspaces/{workspace}', [WorkspaceController::class, 'destroy'])->name('app.workspaces.destroy');
// Routes that require active subscription and completed onboarding
Route::middleware(['auth', 'verified', 'subscribed', EnsureUserSetupIsComplete::class])->group(function () {
// Workspaces
Route::get('workspaces', [WorkspaceController::class, 'index'])->name('app.workspaces.index');
Route::get('workspaces/create', [WorkspaceController::class, 'create'])->name('app.workspaces.create');
Route::post('workspaces', [WorkspaceController::class, 'store'])->name('app.workspaces.store');
Route::post('workspaces/{workspace}/switch', [WorkspaceController::class, 'switch'])->name('app.workspaces.switch');
Route::delete('workspaces/{workspace}', [WorkspaceController::class, 'destroy'])->name('app.workspaces.destroy');
// Workspace settings
Route::get('settings/workspace', [WorkspaceController::class, 'settings'])->name('app.workspace.settings');
Route::put('settings/workspace', [WorkspaceController::class, 'updateSettings'])->name('app.workspace.settings.update');
Route::post('settings/workspace/logo', [WorkspaceController::class, 'uploadLogo'])->name('app.workspace.upload-logo');
Route::delete('settings/workspace/logo', [WorkspaceController::class, 'deleteLogo'])->name('app.workspace.delete-logo');
// Workspace settings
Route::get('settings/workspace', [WorkspaceController::class, 'settings'])->name('app.workspace.settings');
Route::put('settings/workspace', [WorkspaceController::class, 'updateSettings'])->name('app.workspace.settings.update');
Route::post('settings/workspace/logo', [WorkspaceController::class, 'uploadLogo'])->name('app.workspace.upload-logo');
Route::delete('settings/workspace/logo', [WorkspaceController::class, 'deleteLogo'])->name('app.workspace.delete-logo');
// Social Accounts
Route::get('accounts', [SocialController::class, 'index'])->name('app.accounts');
Route::delete('accounts/{account}', [SocialController::class, 'disconnect'])->name('app.accounts.disconnect');
Route::put('accounts/{account}/toggle', [SocialController::class, 'toggleActive'])->name('app.accounts.toggle');
// Social Accounts
Route::get('accounts', [SocialController::class, 'index'])->name('app.accounts');
Route::delete('accounts/{account}', [SocialController::class, 'disconnect'])->name('app.accounts.disconnect');
Route::put('accounts/{account}/toggle', [SocialController::class, 'toggleActive'])->name('app.accounts.toggle');
// Calendar
Route::get('calendar', [PostController::class, 'calendar'])->name('app.calendar');
// Calendar
Route::get('calendar', [PostController::class, 'calendar'])->name('app.calendar');
// Posts
Route::get('posts/{status?}', [PostController::class, 'index'])->name('app.posts.index')->where('status', 'draft|scheduled|published');
Route::post('posts', [PostController::class, 'store'])->name('app.posts.store');
Route::get('posts/{post}/edit', [PostController::class, 'edit'])->name('app.posts.edit');
Route::put('posts/{post}', [PostController::class, 'update'])->name('app.posts.update');
Route::delete('posts/{post}', [PostController::class, 'destroy'])->name('app.posts.destroy');
// Posts
Route::get('posts/{status?}', [PostController::class, 'index'])->name('app.posts.index')->where('status', 'draft|scheduled|published');
Route::post('posts', [PostController::class, 'store'])->name('app.posts.store');
Route::get('posts/{post}/edit', [PostController::class, 'edit'])->name('app.posts.edit');
Route::put('posts/{post}', [PostController::class, 'update'])->name('app.posts.update');
Route::delete('posts/{post}', [PostController::class, 'destroy'])->name('app.posts.destroy');
// Media
Route::post('medias', [MediaController::class, 'store'])->name('app.medias.store');
Route::post('medias/chunked', [MediaController::class, 'storeChunked'])->name('app.medias.store-chunked');
Route::post('medias/reorder', [MediaController::class, 'reorder'])->name('app.medias.reorder');
Route::post('medias/{media}/duplicate', [MediaController::class, 'duplicate'])->name('app.medias.duplicate');
Route::delete('medias/{modelId}/{media}', [MediaController::class, 'destroy'])->name('app.medias.destroy');
// Media
Route::post('medias', [MediaController::class, 'store'])->name('app.medias.store');
Route::post('medias/chunked', [MediaController::class, 'storeChunked'])->name('app.medias.store-chunked');
Route::post('medias/reorder', [MediaController::class, 'reorder'])->name('app.medias.reorder');
Route::post('medias/{media}/duplicate', [MediaController::class, 'duplicate'])->name('app.medias.duplicate');
Route::delete('medias/{modelId}/{media}', [MediaController::class, 'destroy'])->name('app.medias.destroy');
// Members
Route::get('settings/members', fn () => redirect()->route('app.workspace.settings'))->name('app.members');
Route::post('settings/members/invites', [WorkspaceInviteController::class, 'store'])->name('app.invites.store');
Route::delete('settings/members/invites/{invite}', [WorkspaceInviteController::class, 'destroy'])->name('app.invites.destroy');
Route::delete('settings/members/{user}', [WorkspaceInviteController::class, 'removeMember'])->name('app.members.remove');
Route::put('settings/members/{user}/role', [WorkspaceInviteController::class, 'updateRole'])->name('app.members.update-role');
// Members
Route::get('settings/members', fn () => redirect()->route('app.workspace.settings'))->name('app.members');
Route::post('settings/members/invites', [WorkspaceInviteController::class, 'store'])->name('app.invites.store');
Route::delete('settings/members/invites/{invite}', [WorkspaceInviteController::class, 'destroy'])->name('app.invites.destroy');
Route::delete('settings/members/{user}', [WorkspaceInviteController::class, 'removeMember'])->name('app.members.remove');
Route::put('settings/members/{user}/role', [WorkspaceInviteController::class, 'updateRole'])->name('app.members.update-role');
// Hashtags
Route::get('hashtags', [WorkspaceHashtagController::class, 'index'])->name('app.hashtags.index');
Route::post('hashtags', [WorkspaceHashtagController::class, 'store'])->name('app.hashtags.store');
Route::put('hashtags/{hashtag}', [WorkspaceHashtagController::class, 'update'])->name('app.hashtags.update');
Route::delete('hashtags/{hashtag}', [WorkspaceHashtagController::class, 'destroy'])->name('app.hashtags.destroy');
// Hashtags
Route::get('hashtags', [WorkspaceHashtagController::class, 'index'])->name('app.hashtags.index');
Route::post('hashtags', [WorkspaceHashtagController::class, 'store'])->name('app.hashtags.store');
Route::put('hashtags/{hashtag}', [WorkspaceHashtagController::class, 'update'])->name('app.hashtags.update');
Route::delete('hashtags/{hashtag}', [WorkspaceHashtagController::class, 'destroy'])->name('app.hashtags.destroy');
// Labels
Route::get('labels', [WorkspaceLabelController::class, 'index'])->name('app.labels.index');
Route::post('labels', [WorkspaceLabelController::class, 'store'])->name('app.labels.store');
Route::put('labels/{label}', [WorkspaceLabelController::class, 'update'])->name('app.labels.update');
Route::delete('labels/{label}', [WorkspaceLabelController::class, 'destroy'])->name('app.labels.destroy');
// Labels
Route::get('labels', [WorkspaceLabelController::class, 'index'])->name('app.labels.index');
Route::post('labels', [WorkspaceLabelController::class, 'store'])->name('app.labels.store');
Route::put('labels/{label}', [WorkspaceLabelController::class, 'update'])->name('app.labels.update');
Route::delete('labels/{label}', [WorkspaceLabelController::class, 'destroy'])->name('app.labels.destroy');
// API Keys
Route::get('api-keys', [ApiKeyController::class, 'index'])->name('app.api-keys.index');
Route::post('api-keys', [ApiKeyController::class, 'store'])->name('app.api-keys.store');
Route::delete('api-keys/{apiToken}', [ApiKeyController::class, 'destroy'])->name('app.api-keys.destroy');
// API Keys
Route::get('api-keys', [ApiKeyController::class, 'index'])->name('app.api-keys.index');
Route::post('api-keys', [ApiKeyController::class, 'store'])->name('app.api-keys.store');
Route::delete('api-keys/{apiToken}', [ApiKeyController::class, 'destroy'])->name('app.api-keys.destroy');
// Billing
Route::get('settings/billing', [BillingController::class, 'index'])->name('app.billing.index');
Route::get('settings/billing/portal', [BillingController::class, 'portal'])->name('app.billing.portal');
// Billing
Route::get('settings/billing', [BillingController::class, 'index'])->name('app.billing.index');
Route::get('settings/billing/portal', [BillingController::class, 'portal'])->name('app.billing.portal');
// Notifications
Route::get('notifications', [NotificationController::class, 'index'])->name('app.notifications.index');
Route::put('notifications/{notification}/read', [NotificationController::class, 'markAsRead'])->name('app.notifications.read');
Route::post('notifications/read-all', [NotificationController::class, 'markAllAsRead'])->name('app.notifications.read-all');
Route::post('notifications/archive-all', [NotificationController::class, 'archiveAll'])->name('app.notifications.archive-all');
});
// Notifications
Route::get('notifications', [NotificationController::class, 'index'])->name('app.notifications.index');
Route::put('notifications/{notification}/read', [NotificationController::class, 'markAsRead'])->name('app.notifications.read');
Route::post('notifications/read-all', [NotificationController::class, 'markAllAsRead'])->name('app.notifications.read-all');
Route::post('notifications/archive-all', [NotificationController::class, 'archiveAll'])->name('app.notifications.archive-all');
});
// Settings (auth required)
Route::middleware(['auth'])->group(function () {
Route::get('settings/profile', [ProfileController::class, 'edit'])->name('app.profile.edit');
Route::put('settings/profile', [ProfileController::class, 'update'])->name('app.profile.update');
Route::post('settings/profile/photo', [ProfileController::class, 'uploadPhoto'])->name('app.profile.upload-photo');
Route::delete('settings/profile/photo', [ProfileController::class, 'deletePhoto'])->name('app.profile.delete-photo');
Route::put('settings/language', [ProfileController::class, 'updateLanguage'])->name('app.profile.language');
});
// Settings (auth required)
Route::middleware(['auth'])->group(function () {
Route::get('settings/profile', [ProfileController::class, 'edit'])->name('app.profile.edit');
Route::put('settings/profile', [ProfileController::class, 'update'])->name('app.profile.update');
Route::post('settings/profile/photo', [ProfileController::class, 'uploadPhoto'])->name('app.profile.upload-photo');
Route::delete('settings/profile/photo', [ProfileController::class, 'deletePhoto'])->name('app.profile.delete-photo');
Route::put('settings/language', [ProfileController::class, 'updateLanguage'])->name('app.profile.language');
});
Route::middleware(['auth', 'verified'])->group(function () {
Route::delete('settings/profile', [ProfileController::class, 'destroy'])->name('app.profile.destroy');
Route::get('settings/password', [PasswordController::class, 'edit'])->name('app.user-password.edit');
Route::put('settings/password', [PasswordController::class, 'update'])
->middleware('throttle:6,1')
->name('app.user-password.update');
Route::get('settings/notifications', [NotificationPreferenceController::class, 'edit'])->name('app.notifications.preferences');
Route::put('settings/notifications', [NotificationPreferenceController::class, 'update'])->name('app.notifications.preferences.update');
});
}
);
Route::middleware(['auth', 'verified'])->group(function () {
Route::delete('settings/profile', [ProfileController::class, 'destroy'])->name('app.profile.destroy');
Route::get('settings/password', [PasswordController::class, 'edit'])->name('app.user-password.edit');
Route::put('settings/password', [PasswordController::class, 'update'])
->middleware('throttle:6,1')
->name('app.user-password.update');
Route::get('settings/notifications', [NotificationPreferenceController::class, 'edit'])->name('app.notifications.preferences');
Route::put('settings/notifications', [NotificationPreferenceController::class, 'update'])->name('app.notifications.preferences.update');
});

View file

@ -14,59 +14,40 @@
use App\Http\Controllers\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;
Route::group(
[
'domain' => 'app.'.parse_url(config('app.url'), PHP_URL_HOST),
],
function () {
Route::get('/invites/{invite}', [AcceptInviteController::class, 'show'])->name('app.invites.show');
}
);
Route::get('/invites/{invite}', [AcceptInviteController::class, 'show'])->name('app.invites.show');
Route::group(
[
'domain' => 'app.'.parse_url(config('app.url'), PHP_URL_HOST),
'middleware' => ['guest'],
],
function () {
Route::get('/register', [RegisteredUserController::class, 'create'])->name('register');
Route::post('/register', [RegisteredUserController::class, 'store'])->name('register.store');
Route::middleware(['guest'])->group(function () {
Route::get('/register', [RegisteredUserController::class, 'create'])->name('register');
Route::post('/register', [RegisteredUserController::class, 'store'])->name('register.store');
Route::get('/login', [AuthenticatedSessionController::class, 'create'])->name('login');
Route::post('/login', [AuthenticatedSessionController::class, 'store'])->name('login.store');
Route::get('/login', [AuthenticatedSessionController::class, 'create'])->name('login');
Route::post('/login', [AuthenticatedSessionController::class, 'store'])->name('login.store');
Route::get('/forgot-password', [PasswordResetLinkController::class, 'create'])->name('password.request');
Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])->name('password.email');
Route::get('/forgot-password', [PasswordResetLinkController::class, 'create'])->name('password.request');
Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])->name('password.email');
Route::get('/reset-password/{token}', [NewPasswordController::class, 'create'])->name('password.reset');
Route::post('/reset-password', [NewPasswordController::class, 'store'])->name('password.store');
Route::get('/reset-password/{token}', [NewPasswordController::class, 'create'])->name('password.reset');
Route::post('/reset-password', [NewPasswordController::class, 'store'])->name('password.store');
Route::get('/auth/google/redirect', [SocialLoginController::class, 'redirect'])->name('auth.google.redirect');
Route::get('/auth/google/callback', [SocialLoginController::class, 'callback'])->name('auth.google.callback');
}
);
Route::get('/auth/google/redirect', [SocialLoginController::class, 'redirect'])->name('auth.google.redirect');
Route::get('/auth/google/callback', [SocialLoginController::class, 'callback'])->name('auth.google.callback');
});
Route::group(
[
'domain' => 'app.'.parse_url(config('app.url'), PHP_URL_HOST),
'middleware' => ['auth'],
],
function () {
Route::get('/register/success', SignupSuccessController::class)->name('register.success');
Route::middleware(['auth'])->group(function () {
Route::get('/register/success', SignupSuccessController::class)->name('register.success');
Route::get('/verify-email', EmailVerificationPromptController::class)->name('verification.notice');
Route::get('/verify-email', EmailVerificationPromptController::class)->name('verification.notice');
Route::get('/verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1'])
->name('verification.verify');
Route::get('/verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1'])
->name('verification.verify');
Route::post('/email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
->middleware('throttle:6,1')
->name('verification.send');
Route::post('/email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
->middleware('throttle:6,1')
->name('verification.send');
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])->name('logout');
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])->name('logout');
Route::post('/invites/{invite}/accept', [AcceptInviteController::class, 'accept'])->name('app.invites.accept');
Route::post('/invites/{invite}/decline', [AcceptInviteController::class, 'decline'])->name('app.invites.decline');
}
);
Route::post('/invites/{invite}/accept', [AcceptInviteController::class, 'accept'])->name('app.invites.accept');
Route::post('/invites/{invite}/decline', [AcceptInviteController::class, 'decline'])->name('app.invites.decline');
});