Skip to content

Commit d59c8ea

Browse files
committed
Stop leaking demo flag into the shipping codebase
Removes the orange "Demo menu" banner from the public menu and the "Demo mode / Reset now" header from the admin SPA. Drops `demoMode` from the catalog and `/me` API responses, the shared schemas, and the frontend store/types. Rewrites two demo-flavored chat strings to locale-neutral wording. Demo deployment still works via DEMO_MODE on the backend; it just no longer contaminates what self-hosted restaurants ship.
1 parent 8132b05 commit d59c8ea

13 files changed

Lines changed: 8 additions & 52 deletions

File tree

backend/src/routes/admin.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ admin.get('/catalog', ...base, async (c) => {
4141
const catalog = await buildCatalogFromDb(c.get('db'), {
4242
publicOnly: false,
4343
includeHidden: true,
44-
demoMode: isDemoMode(c.env),
4544
});
4645
if (!catalog) return c.json({ error: 'Not found' }, 404);
4746
return c.json(catalog);

backend/src/routes/catalog.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { attachDb, requireAdmin } from '../middleware/admin-guard';
66
import { RecordViewBodySchema } from '@menu/schemas';
77
import type { CatalogResponse } from '@menu/schemas';
88
import * as schema from '../db/schema';
9-
import { isDemoMode } from '../lib/demo';
109
import type { AppBindings, Env } from '../types';
1110

1211
export const catalogRoutes = new Hono<AppBindings>()
@@ -143,8 +142,6 @@ type BuildCatalogOptions = {
143142
publicOnly?: boolean;
144143
/** Admin preview endpoints may include entries hidden from public customers. */
145144
includeHidden?: boolean;
146-
/** Marks catalog as a public demo deployment. */
147-
demoMode?: boolean;
148145
};
149146

150147
function getCatalogSnapshotKey(): string {
@@ -251,7 +248,7 @@ export async function refreshCatalogArtifacts(
251248
): Promise<{ response: Response; body: string; generatedAt: string; cacheWarmed: boolean; snapshotWritten: boolean } | null> {
252249
await invalidateCatalogCache(requestUrl);
253250

254-
const catalog = await buildCatalogFromDb(db, { publicOnly: true, includeHidden: false, demoMode: isDemoMode(env) });
251+
const catalog = await buildCatalogFromDb(db, { publicOnly: true, includeHidden: false });
255252
if (!catalog) {
256253
await deleteCatalogSnapshot(env);
257254
return null;
@@ -295,7 +292,7 @@ export async function buildCatalogFromDb(
295292
db: DbInstance,
296293
options: BuildCatalogOptions = {},
297294
): Promise<CatalogResponse | null> {
298-
const { publicOnly = false, includeHidden = true, demoMode = false } = options;
295+
const { publicOnly = false, includeHidden = true } = options;
299296

300297
const [restaurant] = await db
301298
.select()
@@ -360,7 +357,6 @@ export async function buildCatalogFromDb(
360357
enabledLocales: restaurant.enabledLocales,
361358
disabledLocales: restaurant.disabledLocales,
362359
customLocales: restaurant.customLocales ?? [],
363-
demoMode,
364360
},
365361
},
366362
menus: menus.map((m) => ({

backend/src/routes/me.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export const meRoutes = new Hono<AppBindings>()
1313
*/
1414
.get('/', requireAuth, (c) => {
1515
const user = c.get('user');
16-
const demoMode = isDemoMode(c.env);
1716
const adminUids = c.env.ADMIN_EMAILS
1817
? new Set(c.env.ADMIN_EMAILS.split(',').map((s) => s.trim()).filter(Boolean))
1918
: new Set<string>();
@@ -22,7 +21,6 @@ export const meRoutes = new Hono<AppBindings>()
2221
uid: user.uid,
2322
email: user.email,
2423
name: user.name,
25-
isAdmin: demoMode || adminUids.has(user.uid),
26-
demoMode,
24+
isAdmin: isDemoMode(c.env) || adminUids.has(user.uid),
2725
});
2826
});

packages/schemas/src/catalog.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ export const CatalogRestaurantSchema = z.object({
7272
enabledLocales: z.array(z.string()).nullable().optional(),
7373
disabledLocales: z.array(z.string()).nullable().optional(),
7474
customLocales: z.array(z.object({ code: z.string(), name: z.string() })).nullable().optional(),
75-
demoMode: z.boolean().optional(),
7675
}).optional(),
7776
});
7877
export type CatalogRestaurant = z.infer<typeof CatalogRestaurantSchema>;

packages/schemas/src/responses.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export const MeResponseSchema = z.object({
3232
email: z.string().nullable().optional(),
3333
name: z.string().nullable().optional(),
3434
isAdmin: z.boolean(),
35-
demoMode: z.boolean().optional(),
3635
});
3736
export type MeResponse = z.infer<typeof MeResponseSchema>;
3837

web/src/app/[locale]/menu/MenuPageClient.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ beforeEach(() => {
6262
const menuData = {
6363
id: 'demo-restaurant',
6464
name: 'Trattoria Demo',
65-
features: { aiChat: true, demoMode: true },
65+
features: { aiChat: true },
6666
categories: [
6767
{
6868
id: 'cat-antipasti',

web/src/app/[locale]/menu/MenuPageClient.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,11 +230,6 @@ export default function MenuPageClient() {
230230

231231
return (
232232
<main className="min-h-screen bg-gray-100 pb-20">
233-
{data.features?.demoMode && (
234-
<div className="bg-orange-50 border-b border-orange-200 px-4 py-2 text-center text-xs font-medium text-orange-800">
235-
Demo menu. Changes made in admin reset automatically.
236-
</div>
237-
)}
238233
<div className="relative">
239234
{data.headerImage && (
240235
<div className="relative h-56 overflow-hidden">

web/src/app/admin/AdminContent.tsx

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useEffect, useState } from "react";
44
import Link from "next/link";
55
import { useSearchParams } from "next/navigation";
6-
import { getMe, resetDemoData, type MeResponse } from "@/lib/api";
6+
import { getMe, type MeResponse } from "@/lib/api";
77
import { useRestaurantStore, useCategories } from "@/stores/restaurantStore";
88

99
interface AuthState {
@@ -32,8 +32,6 @@ export default function AdminContent({
3232
user: null,
3333
isAdmin: false,
3434
});
35-
const [resettingDemo, setResettingDemo] = useState(false);
36-
3735
const { data, loadRestaurant } = useRestaurantStore();
3836
const categories = useCategories();
3937

@@ -75,16 +73,6 @@ export default function AdminContent({
7573
window.location.href = "/cdn-cgi/access/logout";
7674
};
7775

78-
const handleDemoReset = async () => {
79-
setResettingDemo(true);
80-
try {
81-
await resetDemoData();
82-
await loadRestaurant();
83-
} finally {
84-
setResettingDemo(false);
85-
}
86-
};
87-
8876
if (authState.loading) {
8977
return (
9078
<div style={{ height: "100vh", display: "flex", alignItems: "center", justifyContent: "center", background: "#FBFAF9", fontFamily: "system-ui, sans-serif" }}>
@@ -206,15 +194,6 @@ export default function AdminContent({
206194

207195
return (
208196
<div style={{ display: "flex", flexDirection: "column", height: "100vh", fontFamily: "system-ui, -apple-system, sans-serif", fontSize: 13, color: "#424242", background: "#FBFAF9" }}>
209-
{authState.user.demoMode && (
210-
<div style={{ background: "#FFF7ED", color: "#9A3412", borderBottom: "1px solid #FED7AA", padding: "8px 18px", display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }}>
211-
<strong style={{ fontSize: 12 }}>Demo mode</strong>
212-
<span style={{ fontSize: 12, flex: 1 }}>This admin is public. Data resets automatically, so do not enter real customer data.</span>
213-
<button onClick={handleDemoReset} disabled={resettingDemo} style={{ border: "1px solid #FDBA74", background: "#fff", color: "#9A3412", borderRadius: 5, padding: "4px 9px", fontSize: 12, fontWeight: 600, cursor: resettingDemo ? "default" : "pointer", opacity: resettingDemo ? 0.6 : 1 }}>
214-
{resettingDemo ? "Resetting..." : "Reset now"}
215-
</button>
216-
</div>
217-
)}
218197
<header style={{ height: 52, background: "#1F1A14", display: "flex", alignItems: "center", padding: "0 18px", gap: 20, flexShrink: 0 }}>
219198
<div style={{ flexShrink: 0, display: "flex", alignItems: "center", gap: 10 }}>
220199
<div style={{ width: 30, height: 30, borderRadius: 6, background: "#C47A4F", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 10.5, fontWeight: 800, letterSpacing: 0.3, flexShrink: 0 }}>

web/src/hooks/useStreamingChat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export function useStreamingChat(locale: string) {
9797

9898
const sendMessage = useCallback(async (content: string) => {
9999
if (!CHAT_WORKER_URL) {
100-
useChatStore.getState().appendToStream('La chat non è disponibile in questa demo.');
100+
useChatStore.getState().appendToStream('Chat is not available right now.');
101101
return;
102102
}
103103
const store = useChatStore.getState();

web/src/lib/api.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,6 @@ export function publishCatalog() {
256256
});
257257
}
258258

259-
export function resetDemoData() {
260-
return apiFetch(`/admin/demo/reset`, {
261-
method: 'POST',
262-
auth: true,
263-
});
264-
}
265-
266259
// ── Analytics ────────────────────────────────────────────────────────
267260

268261
export function getAnalytics(

0 commit comments

Comments
 (0)