Job alerts

Build double-opt-in email alerts and signed-in alert management without mixing token models.

Cavuno supports two alert experiences. Anonymous email alerts use confirmation and HMAC manage tokens; signed-in candidates manage alerts under board.me.alerts. These tokens are not board-user sessions.

Prerequisites

  • board.context().features.jobAlerts is true.
  • A consent checkbox that is not preselected.
  • Routes for the confirmation and email-management links Cavuno sends.
  • A server-owned candidate session for board.me.alerts.

Subscribe and confirm an email

ts
// src/data/job-alerts.ts
import { board } from '../lib/board';
export async function subscribeToRemoteEngineering(email: string) {
return board.jobAlerts.subscribe({
email,
consent: true,
frequency: 'weekly',
filters: {
jobFunctions: ['engineering'],
remoteOptions: ['remote'],
},
context: { source: 'jobs-search' },
});
}
export function confirmJobAlert(token: string) {
return board.jobAlerts.confirm({ token });
}

The subscription result reports created or duplicate and whether confirmation is required. Confirmation always returns HTTP 200; branch on status, which can be confirmed, already_confirmed, expired, or not_found.

Build the email management page

ts
export async function loadAlertManagement(
subscription: string,
token: string,
) {
return board.jobAlerts.manage({ subscription, token });
}
export async function updateAlertPreference(input: {
subscriptionId: string;
preferenceId: string;
token: string;
frequency: 'weekly';
}) {
return board.jobAlerts.updatePreference({
...input,
filters: { remoteOptions: ['remote'] },
});
}

Preference updates are full replacements. Restate frequency and every filter the subscriber wants to keep.

Weekly is the only supported alert cadence. Do not render a daily selector or preserve a legacy daily value when replacing a preference.

Build signed-in alerts

ts
const options = {
cache: 'no-store' as const,
headers: { authorization: `Bearer ${accessToken}` },
};
const alert = await board.me.alerts.create(
{
label: 'Remote engineering',
frequency: 'weekly',
jobFunctions: ['engineering'],
remoteOptions: ['remote'],
},
options,
);

Use the returned alert.id for retrieve, update, and remove calls.

Expected result

Anonymous subscribe and confirmation calls return explicit status objects for every normal branch. Signed-in creation returns an active alert that appears in board.me.alerts.list().

Verify the result

  • The subscription form is absent when job alerts are disabled.
  • New subscriptions cannot be created without explicit consent.
  • Expired and unknown confirmation tokens get distinct messages.
  • Anonymous manage URLs work without a board-user session.
  • Signed-in alert responses never enter a shared cache.

Errors and edge cases

  • Only job functions, place slugs, and remote options currently filter digest delivery. Seniority and salary values are stored but do not filter delivery.
  • Resend can return sent, not_found, already_confirmed, throttled, or send_failed.
  • Manage tokens grant access to one subscription. Treat them as secrets and keep them out of analytics and logs.
  • Do not exchange a manage token for a candidate session.

Production cautions

  • Explain cadence and consent next to the subscription control.
  • Use generic completion copy where revealing subscription existence would leak personal data.
  • Preserve the complete current preference on replacement updates.
  • Handle throttling without repeatedly calling resend.

Next, add signed-in communication with Messaging.