Files
webmail/lib/demo/fixtures/mailboxes.ts
T
Linus Rath 4c0017d0c1 feat: rework the demo around one persona with two accounts and a shared mailbox
The demo user becomes Nora Lindqvist, engineering lead at Meridian Labs,
in the week of a product launch. The fixtures tell one story across mail,
contacts, calendar, tasks and files, and exercise the features the
screenshots and the public demo should show:

- a second, mail-only login (her personal domain) and the shared Support
  mailbox delegated to the work account, so the account switcher, the
  shared section and the merged inbox have real content
- raw headers the way Stalwart writes them: the sender check fails on
  the phishing mail, newsletters carry a one-click unsubscribe, one mail
  asks for a read receipt, and spam scores show in the details
- an iMIP invitation with a served .ics, an event waiting for the answer
  on the calendar, and RSVP patches applied in the demo client
- @mentions as mailto links in a received mail, a verification code
  twelve minutes old, nested folders, named tags on the mail, contact
  groups, a scheduled message and tasks switched on
- every attachment and file backed by real bytes under public/demo,
  generated by `scripts/demo-assets/generate.mjs`; contact photos are
  bundled portraits instead of requests to randomuser.me
- folder counts computed from the mail instead of hand-kept numbers

Demo login seeds the tags, templates and merged-inbox settings once per
device and switches the cross-account gate on for the session; "Reset"
restores them. `bulwark-demo-simulate=off` in localStorage stops the
simulated incoming mail for screenshot runs.
2026-10-18 19:48:11 +02:00

93 lines
3.7 KiB
TypeScript

import type { Mailbox } from '@/lib/jmap/types';
const RIGHTS_SYSTEM = { mayReadItems: true, mayAddItems: true, mayRemoveItems: true, maySetSeen: true, maySetKeywords: true, mayCreateChild: true, mayRename: false, mayDelete: false, maySubmit: true };
const RIGHTS_CUSTOM = { ...RIGHTS_SYSTEM, mayRename: true, mayDelete: true };
// Counts are left at zero here; DemoJMAPClient recomputes them from the mail
// when it starts, so they can never drift from the fixtures.
const COUNTS = { totalEmails: 0, unreadEmails: 0, totalThreads: 0, unreadThreads: 0 };
const system = (id: string, name: string, role: string, sortOrder: number, parentId?: string): Mailbox =>
({ id, name, role, sortOrder, ...COUNTS, myRights: RIGHTS_SYSTEM, isSubscribed: true, ...(parentId ? { parentId } : {}) });
const custom = (id: string, name: string, sortOrder: number, parentId?: string): Mailbox =>
({ id, name, sortOrder, ...COUNTS, myRights: RIGHTS_CUSTOM, isSubscribed: true, ...(parentId ? { parentId } : {}) });
// ── Work account (the primary login) ─────────────────────────
export const MB = {
inbox: 'demo-mailbox-inbox',
drafts: 'demo-mailbox-drafts',
sent: 'demo-mailbox-sent',
archive: 'demo-mailbox-archive',
archive2025: 'demo-mailbox-archive-2025',
archive2024: 'demo-mailbox-archive-2024',
junk: 'demo-mailbox-junk',
trash: 'demo-mailbox-trash',
projects: 'demo-mailbox-projects',
beacon: 'demo-mailbox-projects-beacon',
website: 'demo-mailbox-projects-website',
receipts: 'demo-mailbox-receipts',
travel: 'demo-mailbox-travel',
newsletters: 'demo-mailbox-newsletters',
} as const;
export function createDemoMailboxes(): Mailbox[] {
return [
system(MB.inbox, 'Inbox', 'inbox', 1),
system(MB.drafts, 'Drafts', 'drafts', 2),
system(MB.sent, 'Sent', 'sent', 3),
system(MB.archive, 'Archive', 'archive', 4),
custom(MB.archive2025, '2025', 1, MB.archive),
custom(MB.archive2024, '2024', 2, MB.archive),
system(MB.junk, 'Spam', 'junk', 5),
system(MB.trash, 'Trash', 'trash', 6),
custom(MB.projects, 'Projects', 10),
custom(MB.beacon, 'Beacon', 1, MB.projects),
custom(MB.website, 'Website redesign', 2, MB.projects),
custom(MB.receipts, 'Receipts', 11),
custom(MB.travel, 'Travel', 12),
custom(MB.newsletters, 'Newsletters', 13),
];
}
// ── Shared Support mailbox (delegated to the work login) ─────
// Bare ids as the owner account holds them; the client namespaces them
// `demo-support:<id>` when it lists them next to the user's own folders.
export const SUPPORT_ACCOUNT_ID = 'demo-support';
export const SUPPORT_ACCOUNT_NAME = 'Support';
export const SMB = {
inbox: 'demo-support-inbox',
sent: 'demo-support-sent',
resolved: 'demo-support-resolved',
} as const;
export function createDemoSupportMailboxes(): Mailbox[] {
return [
system(SMB.inbox, 'Inbox', 'inbox', 1),
system(SMB.sent, 'Sent', 'sent', 2),
custom(SMB.resolved, 'Resolved', 10),
];
}
// ── Personal account (the second login) ──────────────────────
export const PMB = {
inbox: 'demo-personal-inbox',
drafts: 'demo-personal-drafts',
sent: 'demo-personal-sent',
archive: 'demo-personal-archive',
junk: 'demo-personal-junk',
trash: 'demo-personal-trash',
family: 'demo-personal-family',
} as const;
export function createDemoPersonalMailboxes(): Mailbox[] {
return [
system(PMB.inbox, 'Inbox', 'inbox', 1),
system(PMB.drafts, 'Drafts', 'drafts', 2),
system(PMB.sent, 'Sent', 'sent', 3),
system(PMB.archive, 'Archive', 'archive', 4),
system(PMB.junk, 'Spam', 'junk', 5),
system(PMB.trash, 'Trash', 'trash', 6),
custom(PMB.family, 'Family', 10),
];
}