Add complete Torbat Food hospitality frontend connected to backend APIs.

Introduces modules/hospitality with 54 routes, BFF proxy, capability-gated nav, CRUD factory, and architecture validation docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Mortezakoohjani 2026-07-26 20:54:26 +03:30
parent 9e1fcd9176
commit 065c053c16
249 changed files with 6015 additions and 1 deletions

View File

@ -0,0 +1,53 @@
import { NextRequest, NextResponse } from "next/server";
const UPSTREAM =
process.env.HOSPITALITY_SERVICE_URL ||
process.env.NEXT_PUBLIC_HOSPITALITY_API_URL ||
"http://localhost:8009";
async function proxy(req: NextRequest, pathSegments: string[]) {
const p = pathSegments.join("/");
const url = new URL(req.url);
const target = `${UPSTREAM.replace(/\/$/, "")}/${p}${url.search}`;
const headers = new Headers();
for (const h of ["authorization", "content-type", "x-tenant-id", "accept"]) {
const v = req.headers.get(h);
if (v) headers.set(h, v);
}
let body: ArrayBuffer | undefined;
if (req.method !== "GET" && req.method !== "HEAD") body = await req.arrayBuffer();
try {
const res = await fetch(target, { method: req.method, headers, body, cache: "no-store" });
const out = new Headers();
const ct = res.headers.get("content-type");
if (ct) out.set("content-type", ct);
return new NextResponse(await res.arrayBuffer(), { status: res.status, headers: out });
} catch (err) {
const detail = err instanceof Error ? err.message : "upstream_unreachable";
return NextResponse.json(
{ error: { code: "hospitality_proxy_error", message: `پروکسی تربت فود — ${detail}` } },
{ status: 502 }
);
}
}
export async function GET(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) {
const { path: p } = await ctx.params;
return proxy(req, p);
}
export async function POST(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) {
const { path: p } = await ctx.params;
return proxy(req, p);
}
export async function PATCH(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) {
const { path: p } = await ctx.params;
return proxy(req, p);
}
export async function PUT(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) {
const { path: p } = await ctx.params;
return proxy(req, p);
}
export async function DELETE(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) {
const { path: p } = await ctx.params;
return proxy(req, p);
}

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { AnalyticsPage as default } from "@/modules/hospitality/features/analyticsSnapshots";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { AuditLogsPage as default } from "@/modules/hospitality/features/events";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { BranchListPage as default } from "@/modules/hospitality/features/branches";

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { BranchesPage as default } from "@/modules/hospitality/features/venues";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { BundlesPage as default } from "@/modules/hospitality/features/tenantBundles";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { CapabilitiesPage as default } from "@/modules/hospitality/features/capabilities";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { CustomersPage as default } from "@/modules/hospitality/features/connectorRegistrationsCrm";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { DiningAreasPage as default } from "@/modules/hospitality/features/diningAreas";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { FloorMapPage as default } from "@/modules/hospitality/features/posFloorPlans";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { GuestsPage as default } from "@/modules/hospitality/features/qrMenuSessions";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { HealthPage as default } from "@/modules/hospitality/features/health";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { HospitalityHub as default } from "@/modules/hospitality/features/hub";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { CommunicationIntegrationPage as default } from "@/modules/hospitality/features/connectorCommunication";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { CrmIntegrationPage as default } from "@/modules/hospitality/features/connectorCrm";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { DeliveryIntegrationPage as default } from "@/modules/hospitality/features/connectorDelivery";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { LoyaltyIntegrationPage as default } from "@/modules/hospitality/features/connectorLoyalty";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { MarketplaceIntegrationPage as default } from "@/modules/hospitality/features/connectorDispatches";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { WebsiteIntegrationPage as default } from "@/modules/hospitality/features/connectorWebsite";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { InventoryPage as default } from "@/modules/hospitality/features/inventoryOverview";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { InvoicesPage as default } from "@/modules/hospitality/features/invoices";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { KitchenDisplayPage as default } from "@/modules/hospitality/features/kitchenTickets";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { KitchenPrepPage as default } from "@/modules/hospitality/features/kitchenTicketsPrep";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { KitchenQueuePage as default } from "@/modules/hospitality/features/kitchenTicketItems";

View File

@ -0,0 +1,5 @@
"use client";
import { HospitalityRootLayout } from "@/modules/hospitality/components/createPortalLayout";
export default HospitalityRootLayout;

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { AvailabilityPage as default } from "@/modules/hospitality/features/availabilityWindows";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { MenuCategoriesPage as default } from "@/modules/hospitality/features/menuCategories";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { MenuItemsPage as default } from "@/modules/hospitality/features/menuItems";

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { MediaLibraryPage as default } from "@/modules/hospitality/features/menuMediaRefs";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { ModifierOptionsPage as default } from "@/modules/hospitality/features/modifierOptions";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { ModifierGroupsPage as default } from "@/modules/hospitality/features/modifierGroups";

View File

@ -0,0 +1,3 @@
"use client";
export { DigitalMenuPage as default } from "@/modules/hospitality/features/menus";

View File

@ -0,0 +1,10 @@
import Link from "next/link";
import { Button, EmptyState } from "@/components/ds";
export default function HospitalityNotFound() {
return (
<div className="flex min-h-[50vh] items-center justify-center p-6">
<EmptyState title="صفحه یافت نشد" action={<Link href="/hospitality"><Button>بازگشت</Button></Link>} />
</div>
);
}

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

View File

@ -0,0 +1,3 @@
"use client";
export { NotificationsPage as default } from "@/modules/hospitality/features/notifications";

View File

@ -0,0 +1,7 @@
"use client";
import { ErrorState } from "@/components/ds";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorState message={error.message} onRetry={reset} />;
}

View File

@ -0,0 +1,5 @@
import { LoadingState } from "@/components/ds";
export default function Loading() {
return <LoadingState label="در حال بارگذاری تربت فود…" />;
}

Some files were not shown because too many files have changed in this diff Show More