chore: remove admin SPA and update to two-app production setup
Remove apps/admin/ entirely — platform admin functionality now lives in apps/app/ under /platform/* routes for super_admin users. Production URL scheme changed: - Organizer app: crewli.app (was app.crewli.app) - Portal: portal.crewli.app (unchanged) - API: api.crewli.app (unchanged) - admin.crewli.app and app.crewli.app retired Backend: - Removed FRONTEND_ADMIN_URL config and admin cookie (crewli_admin_token) from SetAuthCookie, CookieBearerToken, cors.php, app.php - Updated .env and .env.example (two origins, no port 5173) - Updated cookie test: admin origin test → unknown origin fallback test Infrastructure: - Makefile: removed admin target - deploy/nginx: updated CSP comment, removed admin vhost - Updated README.md, CLAUDE.md, and all dev-docs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,14 +55,12 @@ MAIL_FROM_ADDRESS="noreply@crewli.app"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
# CORS + Sanctum — SPA origins (no trailing slash; must match the browser URL)
|
||||
FRONTEND_ADMIN_URL=http://localhost:5173
|
||||
FRONTEND_APP_URL=http://localhost:5174
|
||||
FRONTEND_PORTAL_URL=http://localhost:5175
|
||||
SANCTUM_STATEFUL_DOMAINS=localhost:5173,localhost:5174,localhost:5175
|
||||
SANCTUM_STATEFUL_DOMAINS=localhost:5174,localhost:5175
|
||||
|
||||
# --- Production (crewli.app) — uncomment and adjust hostnames if you use this layout:
|
||||
# --- Production (crewli.app) — uncomment and adjust hostnames:
|
||||
# APP_URL=https://api.crewli.app
|
||||
# FRONTEND_ADMIN_URL=https://admin.crewli.app
|
||||
# FRONTEND_APP_URL=https://app.crewli.app
|
||||
# FRONTEND_APP_URL=https://crewli.app
|
||||
# FRONTEND_PORTAL_URL=https://portal.crewli.app
|
||||
# SANCTUM_STATEFUL_DOMAINS=admin.crewli.app,app.crewli.app,portal.crewli.app
|
||||
# SANCTUM_STATEFUL_DOMAINS=crewli.app,portal.crewli.app
|
||||
|
||||
@@ -10,7 +10,6 @@ use Symfony\Component\HttpFoundation\Cookie;
|
||||
trait SetAuthCookie
|
||||
{
|
||||
private const COOKIE_MAP = [
|
||||
'admin' => 'crewli_admin_token',
|
||||
'app' => 'crewli_app_token',
|
||||
'portal' => 'crewli_portal_token',
|
||||
];
|
||||
@@ -23,14 +22,9 @@ trait SetAuthCookie
|
||||
?? $request->headers->get('Referer')
|
||||
?? '';
|
||||
|
||||
$adminUrl = config('app.frontend_admin_url', 'http://localhost:5173');
|
||||
$appUrl = config('app.frontend_app_url', 'http://localhost:5174');
|
||||
$portalUrl = config('app.frontend_portal_url', 'http://localhost:5175');
|
||||
|
||||
if ($this->originMatches($origin, $adminUrl)) {
|
||||
return self::COOKIE_MAP['admin'];
|
||||
}
|
||||
|
||||
if ($this->originMatches($origin, $appUrl)) {
|
||||
return self::COOKIE_MAP['app'];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
final class CookieBearerToken
|
||||
{
|
||||
private const COOKIE_NAMES = [
|
||||
'crewli_admin_token',
|
||||
'crewli_app_token',
|
||||
'crewli_portal_token',
|
||||
];
|
||||
@@ -59,7 +58,6 @@ final class CookieBearerToken
|
||||
$originPort = parse_url($origin, PHP_URL_PORT);
|
||||
|
||||
$map = [
|
||||
'admin' => [config('app.frontend_admin_url', 'http://localhost:5173'), 'crewli_admin_token'],
|
||||
'app' => [config('app.frontend_app_url', 'http://localhost:5174'), 'crewli_app_token'],
|
||||
'portal' => [config('app.frontend_portal_url', 'http://localhost:5175'), 'crewli_portal_token'],
|
||||
];
|
||||
|
||||
@@ -123,7 +123,6 @@ return [
|
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||
],
|
||||
|
||||
'frontend_admin_url' => env('FRONTEND_ADMIN_URL', 'http://localhost:5173'),
|
||||
'frontend_app_url' => env('FRONTEND_APP_URL', 'http://localhost:5174'),
|
||||
'frontend_portal_url' => env('FRONTEND_PORTAL_URL', 'http://localhost:5175'),
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ return [
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
'allowed_origins' => [
|
||||
env('FRONTEND_ADMIN_URL', 'http://localhost:5173'),
|
||||
env('FRONTEND_APP_URL', 'http://localhost:5174'),
|
||||
env('FRONTEND_PORTAL_URL', 'http://localhost:5175'),
|
||||
],
|
||||
|
||||
@@ -79,17 +79,17 @@ final class HttpOnlyCookieAuthTest extends TestCase
|
||||
$this->assertEquals('strict', strtolower($cookie->getSameSite()));
|
||||
}
|
||||
|
||||
public function test_login_sets_admin_cookie_for_admin_origin(): void
|
||||
public function test_login_sets_app_cookie_for_unknown_origin(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->postJson('/api/v1/auth/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
], ['Origin' => 'http://localhost:5173']);
|
||||
], ['Origin' => 'http://localhost:9999']);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertCookie('crewli_admin_token');
|
||||
$response->assertCookie('crewli_app_token');
|
||||
}
|
||||
|
||||
public function test_login_sets_portal_cookie_for_portal_origin(): void
|
||||
|
||||
Reference in New Issue
Block a user