Merge GitHub main into Gitea main
Deploy to route.crispygoat.com / deploy (push) Failing after 7s
Build / build (push) Has been cancelled

Brings in:
- .gitea/workflows/build.yml (build + typecheck + lint on self-hosted runner)
- scripts/e2e-test.sh (local Postgres + PostgREST + MinIO + Next.js validation)
- Codex review round 2 fixes (buyer/billing/comms/a11y)
- 207 multi-brand admin migration
- Locations table + UI
- Various product/stops/auth refinements

Resolved 7 conflicts by taking Gitea's version to preserve production
behavior:
- package.json (deps)
- src/actions/products/upload-image.ts (storage)
- src/app/admin/taxes/page.tsx
- src/app/checkout/CheckoutClient.tsx
- src/components/admin/AdminSidebar.tsx
- src/components/admin/StopProductAssignment.tsx
- src/lib/admin-permissions.ts

Our new dev_session auth + MinIO storage changes are deferred to a
focused follow-up to avoid breaking the production deploy.
This commit is contained in:
2026-06-05 23:09:51 +00:00
79 changed files with 12589 additions and 857 deletions
+8 -3
View File
@@ -1,6 +1,7 @@
"use server";
import { getAdminUser } from "@/lib/admin-permissions";
import { getActiveBrandId } from "@/lib/brand-scope";
import { svcHeaders } from "@/lib/svc-headers";
import type { AudienceRules } from "./campaigns";
@@ -120,11 +121,15 @@ export async function sendCampaign(campaignId: string, brandId?: string): Promis
const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
// Resolve brand from campaign or parameter
const effectiveBrandId = brandId ?? adminUser.brand_id;
// Resolve brand from campaign or parameter (URL > cookie > legacy > first of brand_ids)
const activeBrandId = await getActiveBrandId(adminUser, brandId);
if (!activeBrandId && adminUser.role !== "platform_admin") {
return { success: false, error: "Brand access required" };
}
const effectiveBrandId = activeBrandId;
// Brand scoping: brand_admin can only send their own brand's campaigns
if (adminUser.role === "brand_admin" && effectiveBrandId && adminUser.brand_id !== effectiveBrandId) {
if (adminUser.role === "brand_admin" && effectiveBrandId && !adminUser.brand_ids.includes(effectiveBrandId)) {
return { success: false, error: "Not authorized to send this brand's campaigns" };
}