Shipflash logoDocs

Contact

Contact owns public lead messages, signed-in contact forms, message validation, rate limiting, persistence, admin replies, and user message history.

On this page

Where to look

AreaPaths
Public routesrc/app/(marketing)/contact/page.tsx
API routesrc/app/api/contact/route.ts
Dashboard routessrc/app/(dashboard)/communications/inbox/page.tsx, src/app/(dashboard)/account/messages/page.tsx
Serversrc/features/contact/server/actions.ts, services.ts, queries.ts, repository.ts, rate-limit.ts
Shared schemasrc/features/contact/shared/schemas.ts
UIsrc/features/contact/ui/form.tsx, messages-dashboard.tsx, message-reply-thread.tsx, user-message-history.tsx
Databasecontact_messages, contact_message_replies

Code-backed contact map

Public and signed-in entrypoints

Marketing and dashboard contact surfaces submit to a server-owned contact flow.

  • src/app/(marketing)/contact/page.tsx
  • src/app/api/contact/route.ts
  • src/features/contact/ui/form.tsx

Validation, rate limiting, and persistence

Contact messages validate payloads, enforce public rate limits, write through the repository, and queue notifications.

  • src/features/contact/shared/schemas.ts
  • src/features/contact/server/rate-limit.ts
  • src/features/contact/server/services.ts
  • src/features/contact/server/repository.ts

Admin inbox and user replies

Admins triage and reply from the communications inbox while signed-in users review their message history and replies from the account area.

  • src/app/(dashboard)/communications/inbox/page.tsx
  • src/app/(dashboard)/account/messages/page.tsx
  • src/features/contact/server/queries.ts
  • src/features/contact/server/actions.ts
  • src/features/contact/ui/messages-dashboard.tsx
  • src/features/contact/ui/message-reply-thread.tsx
  • src/features/contact/ui/user-message-history.tsx

Contact message flow

  1. 1

    Validate the submitted message

    The public API and signed-in form use contact-owned schemas before persistence.

    • src/app/api/contact/route.ts
    • src/features/contact/shared/schemas.ts
  2. 2

    Rate-limit public writes

    The service checks the public contact rate-limit policy before storing a message.

    • src/features/contact/server/rate-limit.ts
    • src/features/contact/server/services.ts
  3. 3

    Persist and notify

    Messages are stored through the repository and related notifications are queued through the notification boundary.

    • src/features/contact/server/repository.ts
    • src/features/contact/server/services.ts
  4. 4

    Triage and reply

    Admin inbox queries and actions own filtering, status changes, priority, replies, and dashboard counts while users can review the resulting thread.

    • src/features/contact/server/queries.ts
    • src/features/contact/server/actions.ts

Public contact rate limit

Source: src/features/contact/server/services.ts

Public contact writes are limited by IP and email before persistence or notifications run.

ts
async function enforcePublicContactRateLimit(params: {
  clientIp: string | null;
  email: string;
  requestId: string;
  start: number;
}): Promise<PublicContactServiceResult | null> {
  const ratePolicy = getRateLimitPolicy("public_contact");
  const rateLimit = await checkRateLimit({
    key: buildRateLimitKey({
      prefix: ratePolicy.prefix,
      ip: params.clientIp,
      identifier: params.email,
    }),
    limit: ratePolicy.limit,
    windowSeconds: ratePolicy.windowSeconds,
  });

  if (rateLimit.allowed) {
    return null;
  }

Contact rules

  • Validate public form input at the server boundary.
  • Rate-limit public writes.
  • Require Turnstile for the public contact API when configured.
  • Keep recipient routing server-owned.
  • Do not expose internal admin state on public pages.