feat(api): .NET 10 multi-tenant REST API
Full backend implementation: - Multi-tenant cafe/restaurant management (menus, orders, tables, staff) - POS order flow with ZarinPal and Snappfood payment integration - OTP authentication via Kavenegar SMS - QR digital menu with public discover/finder endpoints - Customer loyalty, coupons, CRM - PostgreSQL via EF Core, Redis for caching/sessions - Background jobs, webhook handlers - Full migration history Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Meezi.Infrastructure.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Meezi.API.Hubs;
|
||||
|
||||
[AllowAnonymous]
|
||||
public class GuestOrderHub : Hub
|
||||
{
|
||||
public static string OrderGroup(string orderId) => $"guest-order:{orderId}";
|
||||
|
||||
public async Task JoinOrder(string orderId, string trackingToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(orderId) || string.IsNullOrWhiteSpace(trackingToken))
|
||||
throw new HubException("Invalid order.");
|
||||
|
||||
var db = Context.GetHttpContext()?.RequestServices.GetRequiredService<AppDbContext>();
|
||||
if (db is null)
|
||||
throw new HubException("Unavailable.");
|
||||
|
||||
var valid = await db.Orders.AsNoTracking()
|
||||
.AnyAsync(o => o.Id == orderId && o.GuestTrackingToken == trackingToken);
|
||||
|
||||
if (!valid)
|
||||
throw new HubException("Forbidden.");
|
||||
|
||||
await Groups.AddToGroupAsync(Context.ConnectionId, OrderGroup(orderId));
|
||||
}
|
||||
|
||||
public Task LeaveOrder(string orderId) =>
|
||||
Groups.RemoveFromGroupAsync(Context.ConnectionId, OrderGroup(orderId));
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Meezi.Core.Constants;
|
||||
|
||||
namespace Meezi.API.Hubs;
|
||||
|
||||
[Authorize]
|
||||
public class KdsHub : Hub
|
||||
{
|
||||
public static string GroupName(string cafeId) => $"cafe:{cafeId}";
|
||||
|
||||
public async Task JoinCafe(string cafeId)
|
||||
{
|
||||
var claimCafeId = Context.User?.FindFirst(MeeziClaimTypes.CafeId)?.Value;
|
||||
if (string.IsNullOrEmpty(claimCafeId) || claimCafeId != cafeId)
|
||||
throw new HubException("Forbidden");
|
||||
|
||||
await Groups.AddToGroupAsync(Context.ConnectionId, GroupName(cafeId));
|
||||
}
|
||||
|
||||
public Task LeaveCafe(string cafeId) =>
|
||||
Groups.RemoveFromGroupAsync(Context.ConnectionId, GroupName(cafeId));
|
||||
}
|
||||
Reference in New Issue
Block a user