diff --git a/apps/bff/src/core/logging/logging.module.ts b/apps/bff/src/core/logging/logging.module.ts
index a46dbe47..60082ff1 100644
--- a/apps/bff/src/core/logging/logging.module.ts
+++ b/apps/bff/src/core/logging/logging.module.ts
@@ -1,7 +1,8 @@
import { Global, Module } from "@nestjs/common";
import { LoggerModule } from "nestjs-pino";
-const prettyLogsEnabled = process.env.PRETTY_LOGS === "true" || process.env.NODE_ENV !== "production";
+const prettyLogsEnabled =
+ process.env.PRETTY_LOGS === "true" || process.env.NODE_ENV !== "production";
@Global()
@Module({
@@ -10,6 +11,20 @@ const prettyLogsEnabled = process.env.PRETTY_LOGS === "true" || process.env.NODE
pinoHttp: {
level: process.env.LOG_LEVEL || "info",
name: process.env.APP_NAME || "customer-portal-bff",
+ /**
+ * Reduce noise from pino-http auto logging:
+ * - successful requests => debug (hidden when LOG_LEVEL=info)
+ * - 4xx => warn
+ * - 5xx / errors => error
+ *
+ * This keeps production logs focused on actionable events while still
+ * allowing full request logging by setting LOG_LEVEL=debug.
+ */
+ customLogLevel: (_req, res, err) => {
+ if (err || (res?.statusCode && res.statusCode >= 500)) return "error";
+ if (res?.statusCode && res.statusCode >= 400) return "warn";
+ return "debug";
+ },
autoLogging: {
ignore: req => {
const url = req.url || "";
diff --git a/apps/portal/src/app/(public)/layout.tsx b/apps/portal/src/app/(public)/layout.tsx
index 4b116e63..aa1e7f26 100644
--- a/apps/portal/src/app/(public)/layout.tsx
+++ b/apps/portal/src/app/(public)/layout.tsx
@@ -1,15 +1,11 @@
/**
* Public Layout
- *
- * Layout for public-facing pages (landing, auth, etc.)
- * Route groups in Next.js 15 require a layout file for standalone builds
+ *
+ * Shared shell for public-facing pages (landing, auth, etc.)
*/
-export default function PublicLayout({
- children,
-}: {
- children: React.ReactNode;
-}) {
- return <>{children}>;
-}
+import { PublicShell } from "@/components/templates";
+export default function PublicLayout({ children }: { children: React.ReactNode }) {
+ return
{title}
- {subtitle &&{subtitle}
} +{title}
+ {subtitle &&{subtitle}
} ); diff --git a/apps/portal/src/components/atoms/badge.tsx b/apps/portal/src/components/atoms/badge.tsx index 2364763e..7fdcabd6 100644 --- a/apps/portal/src/components/atoms/badge.tsx +++ b/apps/portal/src/components/atoms/badge.tsx @@ -7,14 +7,14 @@ const badgeVariants = cva( { variants: { variant: { - default: "bg-blue-600 text-white hover:bg-blue-700", - secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200", - success: "bg-green-100 text-green-800 hover:bg-green-200", - warning: "bg-yellow-100 text-yellow-800 hover:bg-yellow-200", - error: "bg-red-100 text-red-800 hover:bg-red-200", - info: "bg-blue-100 text-blue-800 hover:bg-blue-200", - outline: "border border-gray-300 bg-white text-gray-900 hover:bg-gray-50", - ghost: "text-gray-900 hover:bg-gray-100", + default: "bg-primary text-primary-foreground hover:bg-primary-hover", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + success: "bg-success-soft text-success hover:bg-success-soft/80", + warning: "bg-warning-soft text-foreground hover:bg-warning-soft/80", + error: "bg-destructive-soft text-destructive hover:bg-destructive-soft/80", + info: "bg-info-soft text-info hover:bg-info-soft/80", + outline: "border border-border bg-background text-foreground hover:bg-muted", + ghost: "text-foreground hover:bg-muted", }, size: { sm: "px-2 py-0.5 text-xs rounded", @@ -30,8 +30,7 @@ const badgeVariants = cva( ); interface BadgeProps - extends React.HTMLAttributes{helperText}
} - {error &&{error}
} + {helperText && !error &&{helperText}
} + {error &&{error}
} ); } diff --git a/apps/portal/src/components/atoms/empty-state.tsx b/apps/portal/src/components/atoms/empty-state.tsx index 668a4d24..e5820cfc 100644 --- a/apps/portal/src/components/atoms/empty-state.tsx +++ b/apps/portal/src/components/atoms/empty-state.tsx @@ -33,16 +33,20 @@ export function EmptyState({ className )} > - {icon &&diff --git a/apps/portal/src/components/atoms/error-state.tsx b/apps/portal/src/components/atoms/error-state.tsx index 01d5dcaf..daac3155 100644 --- a/apps/portal/src/components/atoms/error-state.tsx +++ b/apps/portal/src/components/atoms/error-state.tsx @@ -23,8 +23,8 @@ export function ErrorState({ const variantClasses = { page: "min-h-[400px] py-12", - card: "bg-white border border-red-200 rounded-[var(--cp-card-radius)] p-[var(--cp-card-padding)] shadow-[var(--cp-card-shadow)]", - inline: "bg-red-50 border border-red-200 rounded-md p-4", + card: "bg-card text-card-foreground border border-destructive/25 rounded-[var(--cp-card-radius)] p-[var(--cp-card-padding)] shadow-[var(--cp-card-shadow)]", + inline: "bg-destructive-soft border border-destructive/25 rounded-md p-4", }; const iconSizes = { @@ -47,21 +47,23 @@ export function ErrorState({ return (
{message}
++ {message} +
{onRetry && (