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
| Area | Maintainer reference |
|---|---|
| Public route | Implementation referencesrc/app/(marketing)/contact/page.tsx |
| API route | Implementation referencesrc/app/api/contact/route.ts |
| Dashboard routes | Implementation referencesrc/app/(dashboard)/communications/inbox/page.tsx, src/app/(dashboard)/account/messages/page.tsx |
| Server | Implementation referencesrc/features/contact/server/actions, services, queries, persistence |
| Shared schema | Implementation referencesrc/features/contact/shared/schemas.ts |
| UI | Implementation referencesrc/features/contact/ui/public, inbox, history |
| Database | contact_messages, contact_message_replies |
Implementation reference3 areas
These Product code locations explain how the documented behavior is implemented. Expand them when you are ready to customize or maintain this area.
Public and signed-in entrypoints
Marketing and dashboard contact surfaces submit to a server-owned contact flow.
src/app/(marketing)/contact/page.tsxsrc/app/api/contact/route.tssrc/features/contact/ui/public/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.tssrc/features/contact/server/services/rate-limit.tssrc/features/contact/server/services/submission.tssrc/features/contact/server/persistence/messages.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.tsxsrc/app/(dashboard)/account/messages/page.tsxsrc/features/contact/server/queries/messages.tssrc/features/contact/server/actions/messages.tssrc/features/contact/ui/inbox/dashboard.tsxsrc/features/contact/ui/inbox/reply-thread.tsxsrc/features/contact/ui/history/message-history.tsx
Reference paths are relative to the Shipflash-Product checkout.
Contact message flow
- 1
Validate the submitted message
The public API and signed-in form use contact-owned schemas before persistence.
Relevant Product code
src/app/api/contact/route.tssrc/features/contact/shared/schemas.ts
- 2
Rate-limit public writes
The service checks the public contact rate-limit policy before storing a message.
Relevant Product code
src/features/contact/server/services/rate-limit.tssrc/features/contact/server/services/submission.ts
- 3
Persist and notify
Messages are stored through the repository and related notifications are queued through the notification boundary.
Relevant Product code
src/features/contact/server/persistence/messages.tssrc/features/contact/server/services/submission.ts
- 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.
Relevant Product code
src/features/contact/server/queries/messages.tssrc/features/contact/server/actions/messages.ts
Public contact rate limit
Use this example as a starting point, then adapt it to your product's rules and configuration.
Public contact writes are limited by IP and email before persistence or notifications run.
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;
}Source reference
src/features/contact/server/services/submission.ts
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.