ADI576 commited on
Commit
4609934
·
1 Parent(s): 90b2b1e

Deploy ProFlo shop, admin, cashier + API (Docker Space)

Browse files
Files changed (39) hide show
  1. README.md +6 -6
  2. apps/admin-web/.env.example +1 -1
  3. apps/admin-web/app/admin/dashboard/page.tsx +1 -1
  4. apps/admin-web/app/admin/page.tsx +1 -1
  5. apps/admin-web/app/globals.css +1 -1
  6. apps/admin-web/app/layout.tsx +2 -2
  7. apps/admin-web/app/page.tsx +1 -1
  8. apps/admin-web/lib/apparel.ts +1 -1
  9. apps/admin-web/lib/receipt.ts +3 -3
  10. apps/admin-web/next-env.d.ts +1 -1
  11. apps/cashier-web/app/gate/page.tsx +1 -1
  12. apps/cashier-web/app/layout.tsx +2 -2
  13. apps/cashier-web/app/page.tsx +2 -2
  14. apps/cashier-web/next-env.d.ts +1 -1
  15. apps/customer-web/.env.example +2 -2
  16. apps/customer-web/app/globals.css +1 -1
  17. apps/customer-web/app/layout.tsx +1 -1
  18. apps/customer-web/app/page.tsx +2 -2
  19. apps/customer-web/app/shop/components/ShopShell.tsx +4 -4
  20. apps/customer-web/app/shop/context/ShopContext.tsx +3 -3
  21. apps/customer-web/app/shop/lib/apparel.ts +1 -1
  22. apps/customer-web/app/shop/lib/receiptDownload.ts +3 -3
  23. apps/customer-web/app/shop/page.tsx +3 -3
  24. apps/customer-web/lib/cartBackup.ts +1 -1
  25. apps/customer-web/lib/offlineCartQueue.ts +1 -1
  26. apps/customer-web/next-env.d.ts +1 -1
  27. deploy/huggingface-admin/Dockerfile +1 -1
  28. deploy/huggingface-admin/README.md +3 -3
  29. deploy/huggingface-admin/push.ps1 +6 -6
  30. deploy/huggingface-cashier/Dockerfile +1 -1
  31. deploy/huggingface-cashier/README.md +3 -3
  32. deploy/huggingface-cashier/push.ps1 +6 -6
  33. deploy/huggingface/README.md +6 -6
  34. deploy/huggingface/push.ps1 +5 -5
  35. package.json +1 -1
  36. packages/shared/src/apparel.ts +1 -1
  37. render.yaml +1 -1
  38. services/api/.env.example +2 -2
  39. services/api/src/index.ts +3 -3
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: SeamLine
3
  emoji: 🛒
4
  colorFrom: green
5
  colorTo: blue
@@ -9,15 +9,15 @@ health_check: /health
9
  pinned: false
10
  ---
11
 
12
- # SeamLine — Full checkout platform
13
 
14
  All apps run in one Docker Space behind nginx on port **7860**.
15
 
16
  | App | URL |
17
  |-----|-----|
18
- | Customer shop | [/shop](https://adi576-seamline.hf.space/shop) |
19
- | Admin HQ | [/admin](https://adi576-seamline.hf.space/admin) |
20
- | Cashier terminal | [/cashier](https://adi576-seamline.hf.space/cashier) |
21
  | API (proxied) | `/checkout-api` |
22
 
23
  ## Required secrets
@@ -28,7 +28,7 @@ All apps run in one Docker Space behind nginx on port **7860**.
28
  | `JWT_SECRET` | Long random string |
29
  | `ADMIN_USERNAME` / `ADMIN_PASSWORD` | Staff login |
30
  | `MANAGER_USERNAME` / `MANAGER_PASSWORD` | Manager login |
31
- | `PUBLIC_API_URL` | `https://adi576-seamline.hf.space/checkout-api` |
32
 
33
  Optional: `DEFAULT_STORE_CODE`, `CASHIER_API_KEY` (+ same value as `NEXT_PUBLIC_CASHIER_API_KEY` at build if you protect cashier routes).
34
 
 
1
  ---
2
+ title: ProFlo
3
  emoji: 🛒
4
  colorFrom: green
5
  colorTo: blue
 
9
  pinned: false
10
  ---
11
 
12
+ # ProFlo — Full checkout platform
13
 
14
  All apps run in one Docker Space behind nginx on port **7860**.
15
 
16
  | App | URL |
17
  |-----|-----|
18
+ | Customer shop | [/shop](https://adi576-proflo.hf.space/shop) |
19
+ | Admin HQ | [/admin](https://adi576-proflo.hf.space/admin) |
20
+ | Cashier terminal | [/cashier](https://adi576-proflo.hf.space/cashier) |
21
  | API (proxied) | `/checkout-api` |
22
 
23
  ## Required secrets
 
28
  | `JWT_SECRET` | Long random string |
29
  | `ADMIN_USERNAME` / `ADMIN_PASSWORD` | Staff login |
30
  | `MANAGER_USERNAME` / `MANAGER_PASSWORD` | Manager login |
31
+ | `PUBLIC_API_URL` | `https://adi576-proflo.hf.space/checkout-api` |
32
 
33
  Optional: `DEFAULT_STORE_CODE`, `CASHIER_API_KEY` (+ same value as `NEXT_PUBLIC_CASHIER_API_KEY` at build if you protect cashier routes).
34
 
apps/admin-web/.env.example CHANGED
@@ -1,4 +1,4 @@
1
  NEXT_PUBLIC_API_BASE_URL=http://localhost:4000
2
 
3
- # Vercel: API_PROXY_TARGET=https://seamline.onrender.com
4
  # Vercel: NEXT_PUBLIC_API_BASE_URL=/checkout-api
 
1
  NEXT_PUBLIC_API_BASE_URL=http://localhost:4000
2
 
3
+ # Vercel: API_PROXY_TARGET=https://proflo.onrender.com
4
  # Vercel: NEXT_PUBLIC_API_BASE_URL=/checkout-api
apps/admin-web/app/admin/dashboard/page.tsx CHANGED
@@ -1241,7 +1241,7 @@ export default function AdminDashboardPage() {
1241
 
1242
  <label className="field">
1243
  <span>Brand</span>
1244
- <input value={brand} onChange={(e) => setBrand(e.target.value)} placeholder="e.g. SeamLine Basics" />
1245
  </label>
1246
 
1247
  <label className={`field${formErrors.category ? " field--invalid" : ""}`}>
 
1241
 
1242
  <label className="field">
1243
  <span>Brand</span>
1244
+ <input value={brand} onChange={(e) => setBrand(e.target.value)} placeholder="e.g. ProFlo Basics" />
1245
  </label>
1246
 
1247
  <label className={`field${formErrors.category ? " field--invalid" : ""}`}>
apps/admin-web/app/admin/page.tsx CHANGED
@@ -49,7 +49,7 @@ export default function AdminLoginPage() {
49
  return (
50
  <main className="loginPage">
51
  <div className="loginCard">
52
- <h1 className="loginTitle">SeamLine HQ</h1>
53
  <p className="loginHint">Sign in to the operations console</p>
54
 
55
  <form onSubmit={(e) => void onSubmit(e)} className="loginForm">
 
49
  return (
50
  <main className="loginPage">
51
  <div className="loginCard">
52
+ <h1 className="loginTitle">ProFlo HQ</h1>
53
  <p className="loginHint">Sign in to the operations console</p>
54
 
55
  <form onSubmit={(e) => void onSubmit(e)} className="loginForm">
apps/admin-web/app/globals.css CHANGED
@@ -1526,7 +1526,7 @@ button.secondary {
1526
  }
1527
 
1528
  /* ==========================================================================
1529
- SeamLine Operations Sidebar & Mobile Responsive Layout Redesign
1530
  ========================================================================== */
1531
 
1532
  /* Layout structure */
 
1526
  }
1527
 
1528
  /* ==========================================================================
1529
+ ProFlo Operations Sidebar & Mobile Responsive Layout Redesign
1530
  ========================================================================== */
1531
 
1532
  /* Layout structure */
apps/admin-web/app/layout.tsx CHANGED
@@ -3,8 +3,8 @@ import type { ReactNode } from "react";
3
  import "./globals.css";
4
 
5
  export const metadata: Metadata = {
6
- title: "SeamLine HQ",
7
- description: "SeamLine operations console"
8
  };
9
 
10
  export default function RootLayout({ children }: { children: ReactNode }) {
 
3
  import "./globals.css";
4
 
5
  export const metadata: Metadata = {
6
+ title: "ProFlo HQ",
7
+ description: "ProFlo operations console"
8
  };
9
 
10
  export default function RootLayout({ children }: { children: ReactNode }) {
apps/admin-web/app/page.tsx CHANGED
@@ -3,7 +3,7 @@ import Link from "next/link";
3
  export default function Home() {
4
  return (
5
  <main className="adminHome">
6
- <h1 className="adminHome__title">SeamLine HQ</h1>
7
  <p className="adminHome__text">Operations console for catalogue, counter tokens, receipts, and store KPIs.</p>
8
  <Link href="/admin" className="adminHome__link">
9
  Open admin sign-in
 
3
  export default function Home() {
4
  return (
5
  <main className="adminHome">
6
+ <h1 className="adminHome__title">ProFlo HQ</h1>
7
  <p className="adminHome__text">Operations console for catalogue, counter tokens, receipts, and store KPIs.</p>
8
  <Link href="/admin" className="adminHome__link">
9
  Open admin sign-in
apps/admin-web/lib/apparel.ts CHANGED
@@ -56,4 +56,4 @@ export const APPAREL_GENDERS = ["Unisex", "Men", "Women", "Kids"] as const;
56
 
57
  export const APPAREL_SEASONS = ["", "SS26", "AW26", "Core", "Clearance"] as const;
58
 
59
- export const BRAND_NAME = "SeamLine";
 
56
 
57
  export const APPAREL_SEASONS = ["", "SS26", "AW26", "Core", "Clearance"] as const;
58
 
59
+ export const BRAND_NAME = "ProFlo";
apps/admin-web/lib/receipt.ts CHANGED
@@ -41,7 +41,7 @@ export function receiptHtml(receipt: PaidReceipt): string {
41
  "<!DOCTYPE html>",
42
  '<html lang="en">',
43
  '<head><meta charset="utf-8"/>',
44
- `<title>SeamLine receipt ${escapeHtml(receipt.receiptNumber)}</title>`,
45
  "<style>",
46
  "body{font-family:system-ui,sans-serif;max-width:420px;margin:24px auto;color:#0f172a}",
47
  "h1{font-size:1.25rem;margin:0 0 4px}",
@@ -52,7 +52,7 @@ export function receiptHtml(receipt: PaidReceipt): string {
52
  ".totals div{display:flex;justify-content:space-between;padding:4px 0}",
53
  ".grand{font-weight:700;font-size:1.1rem;border-top:2px solid #0f172a;padding-top:8px;margin-top:8px}",
54
  "</style></head><body>",
55
- "<h1>SeamLine</h1>",
56
  `<p class="meta">Receipt ${escapeHtml(receipt.receiptNumber)} · ${escapeHtml(receipt.storeCode)}<br>${when}</p>`,
57
  `<table><tbody>${rows}</tbody></table>`,
58
  '<div class="totals">',
@@ -71,7 +71,7 @@ export function downloadReceiptHtml(receipt: PaidReceipt): void {
71
  const url = URL.createObjectURL(blob);
72
  const a = document.createElement("a");
73
  a.href = url;
74
- a.download = `seamline-receipt-${receipt.receiptNumber.replace(/[^a-zA-Z0-9_-]/g, "")}.html`;
75
  a.click();
76
  URL.revokeObjectURL(url);
77
  }
 
41
  "<!DOCTYPE html>",
42
  '<html lang="en">',
43
  '<head><meta charset="utf-8"/>',
44
+ `<title>ProFlo receipt ${escapeHtml(receipt.receiptNumber)}</title>`,
45
  "<style>",
46
  "body{font-family:system-ui,sans-serif;max-width:420px;margin:24px auto;color:#0f172a}",
47
  "h1{font-size:1.25rem;margin:0 0 4px}",
 
52
  ".totals div{display:flex;justify-content:space-between;padding:4px 0}",
53
  ".grand{font-weight:700;font-size:1.1rem;border-top:2px solid #0f172a;padding-top:8px;margin-top:8px}",
54
  "</style></head><body>",
55
+ "<h1>ProFlo</h1>",
56
  `<p class="meta">Receipt ${escapeHtml(receipt.receiptNumber)} · ${escapeHtml(receipt.storeCode)}<br>${when}</p>`,
57
  `<table><tbody>${rows}</tbody></table>`,
58
  '<div class="totals">',
 
71
  const url = URL.createObjectURL(blob);
72
  const a = document.createElement("a");
73
  a.href = url;
74
+ a.download = `proflo-receipt-${receipt.receiptNumber.replace(/[^a-zA-Z0-9_-]/g, "")}.html`;
75
  a.click();
76
  URL.revokeObjectURL(url);
77
  }
apps/admin-web/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/dev/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
 
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
apps/cashier-web/app/gate/page.tsx CHANGED
@@ -49,7 +49,7 @@ export default function GatePage() {
49
  return (
50
  <div className="shell">
51
  <header className="header">
52
- <p className="header__eyebrow">SeamLine</p>
53
  <h1 className="header__title">Exit gate</h1>
54
  <p className="header__sub">Scan the customer&apos;s exit QR after they have paid. Each code works once.</p>
55
  <Link href="/" className="gateBack">
 
49
  return (
50
  <div className="shell">
51
  <header className="header">
52
+ <p className="header__eyebrow">ProFlo</p>
53
  <h1 className="header__title">Exit gate</h1>
54
  <p className="header__sub">Scan the customer&apos;s exit QR after they have paid. Each code works once.</p>
55
  <Link href="/" className="gateBack">
apps/cashier-web/app/layout.tsx CHANGED
@@ -3,8 +3,8 @@ import type { ReactNode } from "react";
3
  import "./globals.css";
4
 
5
  export const metadata: Metadata = {
6
- title: "SeamLine Counter",
7
- description: "SeamLine cashier terminal"
8
  };
9
 
10
  export default function RootLayout({ children }: { children: ReactNode }) {
 
3
  import "./globals.css";
4
 
5
  export const metadata: Metadata = {
6
+ title: "ProFlo Counter",
7
+ description: "ProFlo cashier terminal"
8
  };
9
 
10
  export default function RootLayout({ children }: { children: ReactNode }) {
apps/cashier-web/app/page.tsx CHANGED
@@ -3,7 +3,7 @@
3
  import { useCallback, useEffect, useState } from "react";
4
  import Link from "next/link";
5
  import { apiBase, cashierHeaders } from "../lib/api";
6
- const RECENT_KEY = "seamline-cashier-recent";
7
  const MAX_RECENT = 8;
8
 
9
  type OrderLine = {
@@ -193,7 +193,7 @@ export default function CashierHomePage() {
193
  return (
194
  <div className="shell">
195
  <header className="header">
196
- <p className="header__eyebrow">SeamLine</p>
197
  <h1 className="header__title">Counter</h1>
198
  <p className="header__sub">
199
  Look up queue tokens or order IDs, verify the basket, then settle cash or card at the till.
 
3
  import { useCallback, useEffect, useState } from "react";
4
  import Link from "next/link";
5
  import { apiBase, cashierHeaders } from "../lib/api";
6
+ const RECENT_KEY = "proflo-cashier-recent";
7
  const MAX_RECENT = 8;
8
 
9
  type OrderLine = {
 
193
  return (
194
  <div className="shell">
195
  <header className="header">
196
+ <p className="header__eyebrow">ProFlo</p>
197
  <h1 className="header__title">Counter</h1>
198
  <p className="header__sub">
199
  Look up queue tokens or order IDs, verify the basket, then settle cash or card at the till.
apps/cashier-web/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/dev/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
 
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
apps/customer-web/.env.example CHANGED
@@ -2,8 +2,8 @@ NEXT_PUBLIC_API_BASE_URL=http://localhost:4000
2
 
3
  # --- Vercel production (avoids Brave/ad-block on onrender.com) ---
4
  # Set on Vercel (customer-web project):
5
- # API_PROXY_TARGET=https://seamline.onrender.com
6
  # NEXT_PUBLIC_API_BASE_URL=/checkout-api
7
  # On Render API, set PUBLIC_API_URL to:
8
- # https://seamline-customer-web.vercel.app/checkout-api
9
  # (so product image URLs load on the same origin)
 
2
 
3
  # --- Vercel production (avoids Brave/ad-block on onrender.com) ---
4
  # Set on Vercel (customer-web project):
5
+ # API_PROXY_TARGET=https://proflo.onrender.com
6
  # NEXT_PUBLIC_API_BASE_URL=/checkout-api
7
  # On Render API, set PUBLIC_API_URL to:
8
+ # https://proflo-customer-web.vercel.app/checkout-api
9
  # (so product image URLs load on the same origin)
apps/customer-web/app/globals.css CHANGED
@@ -2399,7 +2399,7 @@ a {
2399
  }
2400
 
2401
  /* ==========================================================================
2402
- SeamLine Luxury Boutique Styling & Variant Selection Styles
2403
  ========================================================================== */
2404
 
2405
  /* Modern layout and font adjustments */
 
2399
  }
2400
 
2401
  /* ==========================================================================
2402
+ ProFlo Luxury Boutique Styling & Variant Selection Styles
2403
  ========================================================================== */
2404
 
2405
  /* Modern layout and font adjustments */
apps/customer-web/app/layout.tsx CHANGED
@@ -3,7 +3,7 @@ import type { ReactNode } from "react";
3
  import "./globals.css";
4
 
5
  export const metadata: Metadata = {
6
- title: "SeamLine",
7
  description: "Fashion & merchandising at the speed of scan."
8
  };
9
 
 
3
  import "./globals.css";
4
 
5
  export const metadata: Metadata = {
6
+ title: "ProFlo",
7
  description: "Fashion & merchandising at the speed of scan."
8
  };
9
 
apps/customer-web/app/page.tsx CHANGED
@@ -3,9 +3,9 @@ import Link from "next/link";
3
  export default function Home() {
4
  return (
5
  <main className="landing">
6
- <p className="landing__eyebrow">SeamLine</p>
7
  <h1 className="landing__title">
8
- <span className="brandZipp">Seam in.</span> <span className="brandMart">Style out.</span>
9
  </h1>
10
  <p className="landing__text">Scan the store QR, grab what you need, and bounce — your bag stays synced while you shop.</p>
11
  <Link href="/shop" className="btnPrimary btnPrimary--full landing__cta">
 
3
  export default function Home() {
4
  return (
5
  <main className="landing">
6
+ <p className="landing__eyebrow">ProFlo</p>
7
  <h1 className="landing__title">
8
+ <span className="brandZipp">Scan in.</span> <span className="brandMart">Style out.</span>
9
  </h1>
10
  <p className="landing__text">Scan the store QR, grab what you need, and bounce — your bag stays synced while you shop.</p>
11
  <Link href="/shop" className="btnPrimary btnPrimary--full landing__cta">
apps/customer-web/app/shop/components/ShopShell.tsx CHANGED
@@ -41,9 +41,9 @@ export function ShopShell({ children }: { children: ReactNode }) {
41
  <div className="siteHeader__inner">
42
  {isHome ? (
43
  <>
44
- <Link href="/shop" className="siteHeader__brand" aria-label="SeamLine home">
45
- <span className="brandZipp">Seam</span>
46
- <span className="brandMart">Line</span>
47
  </Link>
48
  <nav className="siteHeader__nav" aria-label="Shop sections">
49
  <Link href="/shop/scan" className="siteHeader__pill">
@@ -108,7 +108,7 @@ export function ShopShell({ children }: { children: ReactNode }) {
108
  </span>
109
  <span className="siteFooter__muted">Bag syncs while this visit is active</span>
110
  </div>
111
- <p className="siteFooter__legal">© {new Date().getFullYear()} SeamLine · Fashion at the speed of scan</p>
112
  </div>
113
  </footer>
114
 
 
41
  <div className="siteHeader__inner">
42
  {isHome ? (
43
  <>
44
+ <Link href="/shop" className="siteHeader__brand" aria-label="ProFlo home">
45
+ <span className="brandZipp">Pro</span>
46
+ <span className="brandMart">Flo</span>
47
  </Link>
48
  <nav className="siteHeader__nav" aria-label="Shop sections">
49
  <Link href="/shop/scan" className="siteHeader__pill">
 
108
  </span>
109
  <span className="siteFooter__muted">Bag syncs while this visit is active</span>
110
  </div>
111
+ <p className="siteFooter__legal">© {new Date().getFullYear()} ProFlo · Fashion at the speed of scan</p>
112
  </div>
113
  </footer>
114
 
apps/customer-web/app/shop/context/ShopContext.tsx CHANGED
@@ -21,7 +21,7 @@ import {
21
  import { apiBase, type RecommendationProduct } from "../lib/shopConfig";
22
 
23
  export { apiBase, type RecommendationProduct } from "../lib/shopConfig";
24
- const SESSION_STORAGE_KEY = "seamline-shop-session-id";
25
 
26
  export type CartLine = {
27
  productId?: string;
@@ -171,7 +171,7 @@ export function ShopProvider({ children }: { children: ReactNode }) {
171
  try {
172
  const fromStorage =
173
  typeof window !== "undefined"
174
- ? localStorage.getItem("seamline-visit-phone")?.trim() ??
175
  localStorage.getItem("zippmart-visit-phone")?.trim() ??
176
  localStorage.getItem("supermart-visit-phone")?.trim() ??
177
  ""
@@ -488,7 +488,7 @@ export function ShopProvider({ children }: { children: ReactNode }) {
488
  setMessage(typeof data.message === "string" ? data.message : "No visit found");
489
  return false;
490
  }
491
- localStorage.setItem("seamline-visit-phone", t);
492
  setSessionId(data.sessionId);
493
  localStorage.setItem(SESSION_STORAGE_KEY, data.sessionId);
494
  setSessionBootstrapDone(true);
 
21
  import { apiBase, type RecommendationProduct } from "../lib/shopConfig";
22
 
23
  export { apiBase, type RecommendationProduct } from "../lib/shopConfig";
24
+ const SESSION_STORAGE_KEY = "proflo-shop-session-id";
25
 
26
  export type CartLine = {
27
  productId?: string;
 
171
  try {
172
  const fromStorage =
173
  typeof window !== "undefined"
174
+ ? localStorage.getItem("proflo-visit-phone")?.trim() ??
175
  localStorage.getItem("zippmart-visit-phone")?.trim() ??
176
  localStorage.getItem("supermart-visit-phone")?.trim() ??
177
  ""
 
488
  setMessage(typeof data.message === "string" ? data.message : "No visit found");
489
  return false;
490
  }
491
+ localStorage.setItem("proflo-visit-phone", t);
492
  setSessionId(data.sessionId);
493
  localStorage.setItem(SESSION_STORAGE_KEY, data.sessionId);
494
  setSessionBootstrapDone(true);
apps/customer-web/app/shop/lib/apparel.ts CHANGED
@@ -1 +1 @@
1
- export const BRAND_NAME = "SeamLine";
 
1
+ export const BRAND_NAME = "ProFlo";
apps/customer-web/app/shop/lib/receiptDownload.ts CHANGED
@@ -33,7 +33,7 @@ export function receiptHtml(receipt: PaidReceipt): string {
33
  "<!DOCTYPE html>",
34
  '<html lang="en">',
35
  '<head><meta charset="utf-8"/>',
36
- `<title>SeamLine receipt ${escapeHtml(receipt.receiptNumber)}</title>`,
37
  "<style>",
38
  "body{font-family:system-ui,sans-serif;max-width:420px;margin:24px auto;color:#0f172a}",
39
  "h1{font-size:1.25rem;margin:0 0 4px}",
@@ -44,7 +44,7 @@ export function receiptHtml(receipt: PaidReceipt): string {
44
  ".totals div{display:flex;justify-content:space-between;padding:4px 0}",
45
  ".grand{font-weight:700;font-size:1.1rem;border-top:2px solid #0f172a;padding-top:8px;margin-top:8px}",
46
  "</style></head><body>",
47
- "<h1>SeamLine</h1>",
48
  `<p class="meta">Receipt ${escapeHtml(receipt.receiptNumber)} · ${escapeHtml(receipt.storeCode)}<br>${when}</p>`,
49
  `<table><tbody>${rows}</tbody></table>`,
50
  '<div class="totals">',
@@ -73,7 +73,7 @@ export function downloadReceiptHtml(receipt: PaidReceipt): void {
73
  const url = URL.createObjectURL(blob);
74
  const a = document.createElement("a");
75
  a.href = url;
76
- a.download = `seamline-receipt-${receipt.receiptNumber.replace(/[^a-zA-Z0-9_-]/g, "")}.html`;
77
  a.click();
78
  URL.revokeObjectURL(url);
79
  }
 
33
  "<!DOCTYPE html>",
34
  '<html lang="en">',
35
  '<head><meta charset="utf-8"/>',
36
+ `<title>ProFlo receipt ${escapeHtml(receipt.receiptNumber)}</title>`,
37
  "<style>",
38
  "body{font-family:system-ui,sans-serif;max-width:420px;margin:24px auto;color:#0f172a}",
39
  "h1{font-size:1.25rem;margin:0 0 4px}",
 
44
  ".totals div{display:flex;justify-content:space-between;padding:4px 0}",
45
  ".grand{font-weight:700;font-size:1.1rem;border-top:2px solid #0f172a;padding-top:8px;margin-top:8px}",
46
  "</style></head><body>",
47
+ "<h1>ProFlo</h1>",
48
  `<p class="meta">Receipt ${escapeHtml(receipt.receiptNumber)} · ${escapeHtml(receipt.storeCode)}<br>${when}</p>`,
49
  `<table><tbody>${rows}</tbody></table>`,
50
  '<div class="totals">',
 
73
  const url = URL.createObjectURL(blob);
74
  const a = document.createElement("a");
75
  a.href = url;
76
+ a.download = `proflo-receipt-${receipt.receiptNumber.replace(/[^a-zA-Z0-9_-]/g, "")}.html`;
77
  a.click();
78
  URL.revokeObjectURL(url);
79
  }
apps/customer-web/app/shop/page.tsx CHANGED
@@ -39,7 +39,7 @@ export default function ShopHomePage() {
39
 
40
  useEffect(() => {
41
  if (typeof window === "undefined") return;
42
- setVisitPhone(localStorage.getItem("seamline-visit-phone") ?? localStorage.getItem("zippmart-visit-phone") ?? localStorage.getItem("supermart-visit-phone") ?? "");
43
  }, []);
44
 
45
  const loadCatalog = useCallback(async () => {
@@ -112,7 +112,7 @@ export default function ShopHomePage() {
112
  ? new URLSearchParams(window.location.search).get("store")?.trim()?.toUpperCase()
113
  : undefined;
114
  if (visitPhone.trim().length >= 10) {
115
- localStorage.setItem("seamline-visit-phone", visitPhone.trim());
116
  }
117
  await createSession(store ?? "BLR001", visitPhone.trim().length >= 10 ? visitPhone.trim() : undefined);
118
  }
@@ -217,7 +217,7 @@ export default function ShopHomePage() {
217
  onChange={(e) => setVisitPhone(e.target.value)}
218
  onBlur={() => {
219
  if (visitPhone.trim().length >= 10) {
220
- localStorage.setItem("seamline-visit-phone", visitPhone.trim());
221
  }
222
  }}
223
  />
 
39
 
40
  useEffect(() => {
41
  if (typeof window === "undefined") return;
42
+ setVisitPhone(localStorage.getItem("proflo-visit-phone") ?? localStorage.getItem("zippmart-visit-phone") ?? localStorage.getItem("supermart-visit-phone") ?? "");
43
  }, []);
44
 
45
  const loadCatalog = useCallback(async () => {
 
112
  ? new URLSearchParams(window.location.search).get("store")?.trim()?.toUpperCase()
113
  : undefined;
114
  if (visitPhone.trim().length >= 10) {
115
+ localStorage.setItem("proflo-visit-phone", visitPhone.trim());
116
  }
117
  await createSession(store ?? "BLR001", visitPhone.trim().length >= 10 ? visitPhone.trim() : undefined);
118
  }
 
217
  onChange={(e) => setVisitPhone(e.target.value)}
218
  onBlur={() => {
219
  if (visitPhone.trim().length >= 10) {
220
+ localStorage.setItem("proflo-visit-phone", visitPhone.trim());
221
  }
222
  }}
223
  />
apps/customer-web/lib/cartBackup.ts CHANGED
@@ -1,4 +1,4 @@
1
- const KEY = "seamline-cart-backup-v1";
2
 
3
  export type CartBackup = {
4
  savedAt: string;
 
1
+ const KEY = "proflo-cart-backup-v1";
2
 
3
  export type CartBackup = {
4
  savedAt: string;
apps/customer-web/lib/offlineCartQueue.ts CHANGED
@@ -1,4 +1,4 @@
1
- const QUEUE_KEY = "seamline-offline-cart-queue";
2
  const MAX = 25;
3
 
4
  export type QueuedCartAdd = { barcode: string; qty: number; enqueuedAt: string };
 
1
+ const QUEUE_KEY = "proflo-offline-cart-queue";
2
  const MAX = 25;
3
 
4
  export type QueuedCartAdd = { barcode: string; qty: number; enqueuedAt: string };
apps/customer-web/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/dev/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
 
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
deploy/huggingface-admin/Dockerfile CHANGED
@@ -9,7 +9,7 @@ RUN npm ci
9
 
10
  COPY apps/admin-web ./apps/admin-web
11
 
12
- ENV NEXT_PUBLIC_API_BASE_URL=https://adi576-seamline.hf.space/checkout-api
13
  RUN npm run build -w admin-web \
14
  && test -f apps/admin-web/.next/BUILD_ID \
15
  && test -d apps/admin-web/.next/standalone
 
9
 
10
  COPY apps/admin-web ./apps/admin-web
11
 
12
+ ENV NEXT_PUBLIC_API_BASE_URL=https://adi576-proflo.hf.space/checkout-api
13
  RUN npm run build -w admin-web \
14
  && test -f apps/admin-web/.next/BUILD_ID \
15
  && test -d apps/admin-web/.next/standalone
deploy/huggingface-admin/README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: SeamLine Admin
3
  emoji: 📊
4
  colorFrom: purple
5
  colorTo: red
@@ -8,13 +8,13 @@ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
- # SeamLine Admin HQ
12
 
13
  Staff and manager dashboard for catalogue, stock, orders, and store KPIs.
14
 
15
  Open **/admin** to sign in.
16
 
17
- Uses the API on the main SeamLine Space: `https://adi576-seamline.hf.space/checkout-api`
18
 
19
  ## Default logins
20
 
 
1
  ---
2
+ title: ProFlo Admin
3
  emoji: 📊
4
  colorFrom: purple
5
  colorTo: red
 
8
  pinned: false
9
  ---
10
 
11
+ # ProFlo Admin HQ
12
 
13
  Staff and manager dashboard for catalogue, stock, orders, and store KPIs.
14
 
15
  Open **/admin** to sign in.
16
 
17
+ Uses the API on the main ProFlo Space: `https://adi576-proflo.hf.space/checkout-api`
18
 
19
  ## Default logins
20
 
deploy/huggingface-admin/push.ps1 CHANGED
@@ -1,16 +1,16 @@
1
- # Push admin app to Hugging Face Space ADI576/zippmart_admin
2
 
3
  $ErrorActionPreference = "Stop"
4
  $Root = Resolve-Path (Join-Path $PSScriptRoot "..\..")
5
- $SpaceDir = Join-Path $env:TEMP "seamline-hf-admin"
6
- $SpaceUrl = "https://huggingface.co/spaces/ADI576/zippmart_admin"
7
 
8
  $SkipNames = @(".git", "node_modules", ".next", "dist")
9
 
10
  $Token = $env:HF_TOKEN
11
  if (-not $Token) { $Token = $env:HUGGING_FACE_HUB_TOKEN }
12
  if ($Token) {
13
- $SpaceUrl = "https://user:$Token@huggingface.co/spaces/ADI576/zippmart_admin"
14
  }
15
 
16
  if (Test-Path $SpaceDir) { Remove-Item -Recurse -Force $SpaceDir }
@@ -44,9 +44,9 @@ Copy-Item "$Root\deploy\huggingface-admin\Dockerfile" (Join-Path $SpaceDir "Dock
44
  Push-Location $SpaceDir
45
  git add -A
46
  if (-not (git diff --cached --quiet)) {
47
- git commit -m "Deploy SeamLine admin dashboard (Docker Space)"
48
  }
49
  git push
50
  Pop-Location
51
 
52
- Write-Host "Pushed. Open https://huggingface.co/spaces/ADI576/zippmart_admin"
 
1
+ # Push admin app to Hugging Face Space ADI576/proflo_admin
2
 
3
  $ErrorActionPreference = "Stop"
4
  $Root = Resolve-Path (Join-Path $PSScriptRoot "..\..")
5
+ $SpaceDir = Join-Path $env:TEMP "proflo-hf-admin"
6
+ $SpaceUrl = "https://huggingface.co/spaces/ADI576/proflo_admin"
7
 
8
  $SkipNames = @(".git", "node_modules", ".next", "dist")
9
 
10
  $Token = $env:HF_TOKEN
11
  if (-not $Token) { $Token = $env:HUGGING_FACE_HUB_TOKEN }
12
  if ($Token) {
13
+ $SpaceUrl = "https://user:$Token@huggingface.co/spaces/ADI576/proflo_admin"
14
  }
15
 
16
  if (Test-Path $SpaceDir) { Remove-Item -Recurse -Force $SpaceDir }
 
44
  Push-Location $SpaceDir
45
  git add -A
46
  if (-not (git diff --cached --quiet)) {
47
+ git commit -m "Deploy ProFlo admin dashboard (Docker Space)"
48
  }
49
  git push
50
  Pop-Location
51
 
52
+ Write-Host "Pushed. Open https://huggingface.co/spaces/ADI576/proflo_admin"
deploy/huggingface-cashier/Dockerfile CHANGED
@@ -9,7 +9,7 @@ RUN npm ci
9
 
10
  COPY apps/cashier-web ./apps/cashier-web
11
 
12
- ENV NEXT_PUBLIC_API_BASE_URL=https://adi576-seamline.hf.space/checkout-api
13
  RUN npm run build -w cashier-web \
14
  && test -f apps/cashier-web/.next/BUILD_ID \
15
  && test -d apps/cashier-web/.next/standalone
 
9
 
10
  COPY apps/cashier-web ./apps/cashier-web
11
 
12
+ ENV NEXT_PUBLIC_API_BASE_URL=https://adi576-proflo.hf.space/checkout-api
13
  RUN npm run build -w cashier-web \
14
  && test -f apps/cashier-web/.next/BUILD_ID \
15
  && test -d apps/cashier-web/.next/standalone
deploy/huggingface-cashier/README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: SeamLine Cashier
3
  emoji: 🧾
4
  colorFrom: blue
5
  colorTo: green
@@ -8,11 +8,11 @@ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
- # SeamLine Cashier Terminal
12
 
13
  In-store cashier terminal for order lookup and counter settlement.
14
 
15
- Uses the API on the main SeamLine Space: `https://adi576-seamline.hf.space/checkout-api`
16
 
17
  ## Optional secrets
18
 
 
1
  ---
2
+ title: ProFlo Cashier
3
  emoji: 🧾
4
  colorFrom: blue
5
  colorTo: green
 
8
  pinned: false
9
  ---
10
 
11
+ # ProFlo Cashier Terminal
12
 
13
  In-store cashier terminal for order lookup and counter settlement.
14
 
15
+ Uses the API on the main ProFlo Space: `https://adi576-proflo.hf.space/checkout-api`
16
 
17
  ## Optional secrets
18
 
deploy/huggingface-cashier/push.ps1 CHANGED
@@ -1,16 +1,16 @@
1
- # Push cashier app to Hugging Face Space ADI576/Zippmart_Cashier
2
 
3
  $ErrorActionPreference = "Stop"
4
  $Root = Resolve-Path (Join-Path $PSScriptRoot "..\..")
5
- $SpaceDir = Join-Path $env:TEMP "seamline-hf-cashier"
6
- $SpaceUrl = "https://huggingface.co/spaces/ADI576/Zippmart_Cashier"
7
 
8
  $SkipNames = @(".git", "node_modules", ".next", "dist")
9
 
10
  $Token = $env:HF_TOKEN
11
  if (-not $Token) { $Token = $env:HUGGING_FACE_HUB_TOKEN }
12
  if ($Token) {
13
- $SpaceUrl = "https://user:$Token@huggingface.co/spaces/ADI576/Zippmart_Cashier"
14
  }
15
 
16
  if (Test-Path $SpaceDir) { Remove-Item -Recurse -Force $SpaceDir }
@@ -44,9 +44,9 @@ Copy-Item "$Root\deploy\huggingface-cashier\Dockerfile" (Join-Path $SpaceDir "Do
44
  Push-Location $SpaceDir
45
  git add -A
46
  if (-not (git diff --cached --quiet)) {
47
- git commit -m "Deploy SeamLine cashier terminal (Docker Space)"
48
  }
49
  git push
50
  Pop-Location
51
 
52
- Write-Host "Pushed. Open https://huggingface.co/spaces/ADI576/Zippmart_Cashier"
 
1
+ # Push cashier app to Hugging Face Space ADI576/proflo_cashier
2
 
3
  $ErrorActionPreference = "Stop"
4
  $Root = Resolve-Path (Join-Path $PSScriptRoot "..\..")
5
+ $SpaceDir = Join-Path $env:TEMP "proflo-hf-cashier"
6
+ $SpaceUrl = "https://huggingface.co/spaces/ADI576/proflo_cashier"
7
 
8
  $SkipNames = @(".git", "node_modules", ".next", "dist")
9
 
10
  $Token = $env:HF_TOKEN
11
  if (-not $Token) { $Token = $env:HUGGING_FACE_HUB_TOKEN }
12
  if ($Token) {
13
+ $SpaceUrl = "https://user:$Token@huggingface.co/spaces/ADI576/proflo_cashier"
14
  }
15
 
16
  if (Test-Path $SpaceDir) { Remove-Item -Recurse -Force $SpaceDir }
 
44
  Push-Location $SpaceDir
45
  git add -A
46
  if (-not (git diff --cached --quiet)) {
47
+ git commit -m "Deploy ProFlo cashier terminal (Docker Space)"
48
  }
49
  git push
50
  Pop-Location
51
 
52
+ Write-Host "Pushed. Open https://huggingface.co/spaces/ADI576/proflo_cashier"
deploy/huggingface/README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: SeamLine
3
  emoji: 🛒
4
  colorFrom: green
5
  colorTo: blue
@@ -9,15 +9,15 @@ health_check: /health
9
  pinned: false
10
  ---
11
 
12
- # SeamLine — Full checkout platform
13
 
14
  All apps run in one Docker Space behind nginx on port **7860**.
15
 
16
  | App | URL |
17
  |-----|-----|
18
- | Customer shop | [/shop](https://adi576-seamline.hf.space/shop) |
19
- | Admin HQ | [/admin](https://adi576-seamline.hf.space/admin) |
20
- | Cashier terminal | [/cashier](https://adi576-seamline.hf.space/cashier) |
21
  | API (proxied) | `/checkout-api` |
22
 
23
  ## Required secrets
@@ -28,7 +28,7 @@ All apps run in one Docker Space behind nginx on port **7860**.
28
  | `JWT_SECRET` | Long random string |
29
  | `ADMIN_USERNAME` / `ADMIN_PASSWORD` | Staff login |
30
  | `MANAGER_USERNAME` / `MANAGER_PASSWORD` | Manager login |
31
- | `PUBLIC_API_URL` | `https://adi576-seamline.hf.space/checkout-api` |
32
 
33
  Optional: `DEFAULT_STORE_CODE`, `CASHIER_API_KEY` (+ same value as `NEXT_PUBLIC_CASHIER_API_KEY` at build if you protect cashier routes).
34
 
 
1
  ---
2
+ title: ProFlo
3
  emoji: 🛒
4
  colorFrom: green
5
  colorTo: blue
 
9
  pinned: false
10
  ---
11
 
12
+ # ProFlo — Full checkout platform
13
 
14
  All apps run in one Docker Space behind nginx on port **7860**.
15
 
16
  | App | URL |
17
  |-----|-----|
18
+ | Customer shop | [/shop](https://adi576-proflo.hf.space/shop) |
19
+ | Admin HQ | [/admin](https://adi576-proflo.hf.space/admin) |
20
+ | Cashier terminal | [/cashier](https://adi576-proflo.hf.space/cashier) |
21
  | API (proxied) | `/checkout-api` |
22
 
23
  ## Required secrets
 
28
  | `JWT_SECRET` | Long random string |
29
  | `ADMIN_USERNAME` / `ADMIN_PASSWORD` | Staff login |
30
  | `MANAGER_USERNAME` / `MANAGER_PASSWORD` | Manager login |
31
+ | `PUBLIC_API_URL` | `https://adi576-proflo.hf.space/checkout-api` |
32
 
33
  Optional: `DEFAULT_STORE_CODE`, `CASHIER_API_KEY` (+ same value as `NEXT_PUBLIC_CASHIER_API_KEY` at build if you protect cashier routes).
34
 
deploy/huggingface/push.ps1 CHANGED
@@ -3,18 +3,18 @@
3
 
4
  $ErrorActionPreference = "Stop"
5
  $Root = Resolve-Path (Join-Path $PSScriptRoot "..\..")
6
- $SpaceDir = Join-Path $env:TEMP "Zippmart-hf-space"
7
- $SpaceUrl = "https://huggingface.co/spaces/ADI576/Zippmart"
8
 
9
  $SkipNames = @(
10
  ".git", "node_modules", ".next", "dist",
11
- "worker"
12
  )
13
 
14
  $Token = $env:HF_TOKEN
15
  if (-not $Token) { $Token = $env:HUGGING_FACE_HUB_TOKEN }
16
  if ($Token) {
17
- $SpaceUrl = "https://user:$Token@huggingface.co/spaces/ADI576/Zippmart"
18
  }
19
 
20
  if (Test-Path $SpaceDir) { Remove-Item -Recurse -Force $SpaceDir }
@@ -40,7 +40,7 @@ Copy-Item "$Root\Dockerfile" (Join-Path $SpaceDir "Dockerfile") -Force
40
  Push-Location $SpaceDir
41
  git add -A
42
  if (-not (git diff --cached --quiet)) {
43
- git commit -m "Deploy Zippmart shop, admin, cashier + API (Docker Space)"
44
  }
45
  git push
46
  if ($LASTEXITCODE -ne 0) {
 
3
 
4
  $ErrorActionPreference = "Stop"
5
  $Root = Resolve-Path (Join-Path $PSScriptRoot "..\..")
6
+ $SpaceDir = Join-Path $env:TEMP "proflo-hf-space"
7
+ $SpaceUrl = "https://huggingface.co/spaces/ADI576/ProFlo"
8
 
9
  $SkipNames = @(
10
  ".git", "node_modules", ".next", "dist",
11
+ "worker", "docs", "nlp-lab", "infra", "proposals", "supabase"
12
  )
13
 
14
  $Token = $env:HF_TOKEN
15
  if (-not $Token) { $Token = $env:HUGGING_FACE_HUB_TOKEN }
16
  if ($Token) {
17
+ $SpaceUrl = "https://user:$Token@huggingface.co/spaces/ADI576/ProFlo"
18
  }
19
 
20
  if (Test-Path $SpaceDir) { Remove-Item -Recurse -Force $SpaceDir }
 
40
  Push-Location $SpaceDir
41
  git add -A
42
  if (-not (git diff --cached --quiet)) {
43
+ git commit -m "Deploy ProFlo shop, admin, cashier + API (Docker Space)"
44
  }
45
  git push
46
  if ($LASTEXITCODE -ne 0) {
package.json CHANGED
@@ -2,7 +2,7 @@
2
  "name": "checkout-system",
3
  "version": "1.0.0",
4
  "private": true,
5
- "description": "SeamLine apparel checkout platform monorepo",
6
  "workspaces": [
7
  "apps/*",
8
  "services/*",
 
2
  "name": "checkout-system",
3
  "version": "1.0.0",
4
  "private": true,
5
+ "description": "ProFlo apparel checkout platform monorepo",
6
  "workspaces": [
7
  "apps/*",
8
  "services/*",
packages/shared/src/apparel.ts CHANGED
@@ -56,7 +56,7 @@ export const APPAREL_GENDERS = ["Unisex", "Men", "Women", "Kids"] as const;
56
 
57
  export const APPAREL_SEASONS = ["", "SS26", "AW26", "Core", "Clearance"] as const;
58
 
59
- export const BRAND_NAME = "SeamLine";
60
 
61
  export function buildVariantSku(styleCode: string, color: string, size: string, barcode: string): string {
62
  const parts = [styleCode, color, size]
 
56
 
57
  export const APPAREL_SEASONS = ["", "SS26", "AW26", "Core", "Clearance"] as const;
58
 
59
+ export const BRAND_NAME = "ProFlo";
60
 
61
  export function buildVariantSku(styleCode: string, color: string, size: string, barcode: string): string {
62
  const parts = [styleCode, color, size]
render.yaml CHANGED
@@ -2,7 +2,7 @@
2
  # Docs: https://render.com/docs/blueprint-spec
3
  services:
4
  - type: web
5
- name: seamline-api
6
  runtime: node
7
  plan: free
8
  rootDir: services/api
 
2
  # Docs: https://render.com/docs/blueprint-spec
3
  services:
4
  - type: web
5
+ name: proflo-api
6
  runtime: node
7
  plan: free
8
  rootDir: services/api
services/api/.env.example CHANGED
@@ -37,9 +37,9 @@ DEFAULT_STORE_CODE=BLR001
37
  # 1. Sign up at resend.com (free tier: ~100 emails/day)
38
  # 2. Add and verify your domain, or use onboarding address for testing only
39
  # 3. Create an API key → set RESEND_API_KEY
40
- # 4. Set EMAIL_FROM to a verified sender, e.g. SeamLine <receipts@yourdomain.com>
41
  # RESEND_API_KEY=re_xxxxxxxx
42
- # EMAIL_FROM=SeamLine <onboarding@resend.dev>
43
 
44
  # Optional — generic webhook if you use Make/Zapier instead of Resend
45
  # RECEIPT_NOTIFY_WEBHOOK_URL=https://hooks.example.com/receipt
 
37
  # 1. Sign up at resend.com (free tier: ~100 emails/day)
38
  # 2. Add and verify your domain, or use onboarding address for testing only
39
  # 3. Create an API key → set RESEND_API_KEY
40
+ # 4. Set EMAIL_FROM to a verified sender, e.g. ProFlo <receipts@yourdomain.com>
41
  # RESEND_API_KEY=re_xxxxxxxx
42
+ # EMAIL_FROM=ProFlo <onboarding@resend.dev>
43
 
44
  # Optional — generic webhook if you use Make/Zapier instead of Resend
45
  # RECEIPT_NOTIFY_WEBHOOK_URL=https://hooks.example.com/receipt
services/api/src/index.ts CHANGED
@@ -287,11 +287,11 @@ function receiptEmailHtml(order: Order, receiptNumber: string): string {
287
  )
288
  .join("");
289
  return `<!DOCTYPE html><html><body style="font-family:sans-serif;color:#111">
290
- <h2>SeamLine receipt</h2>
291
  <p><strong>${receiptNumber}</strong> · ${order.storeCode}</p>
292
  <table cellpadding="6" cellspacing="0" border="0">${rows}</table>
293
  <p>Subtotal: ₹${order.subtotal.toFixed(2)}<br>Tax: ₹${order.taxTotal.toFixed(2)}<br><strong>Total: ₹${order.total.toFixed(2)}</strong></p>
294
- <p>Thank you for shopping with SeamLine.</p>
295
  </body></html>`;
296
  }
297
 
@@ -308,7 +308,7 @@ async function sendReceiptEmail(order: Order, receiptNumber: string): Promise<bo
308
  body: JSON.stringify({
309
  from: emailFrom,
310
  to: [to],
311
- subject: `Your SeamLine receipt ${receiptNumber}`,
312
  html: receiptEmailHtml(order, receiptNumber)
313
  })
314
  });
 
287
  )
288
  .join("");
289
  return `<!DOCTYPE html><html><body style="font-family:sans-serif;color:#111">
290
+ <h2>ProFlo receipt</h2>
291
  <p><strong>${receiptNumber}</strong> · ${order.storeCode}</p>
292
  <table cellpadding="6" cellspacing="0" border="0">${rows}</table>
293
  <p>Subtotal: ₹${order.subtotal.toFixed(2)}<br>Tax: ₹${order.taxTotal.toFixed(2)}<br><strong>Total: ₹${order.total.toFixed(2)}</strong></p>
294
+ <p>Thank you for shopping with ProFlo.</p>
295
  </body></html>`;
296
  }
297
 
 
308
  body: JSON.stringify({
309
  from: emailFrom,
310
  to: [to],
311
+ subject: `Your ProFlo receipt ${receiptNumber}`,
312
  html: receiptEmailHtml(order, receiptNumber)
313
  })
314
  });