Safety · Moderation Policy

Moderation & Safety

Last updated: 2026-07-26 · Effective immediately

FUSE is a city-matched dating app designed for adults. This page describes how we keep the platform safe for the people on it — every section below maps to a real, shipped component of the FUSE service. Reviewers can cross-check each claim against the linked source file.

1. Automated Text Moderation

Every block of user-generated text on FUSE — chat messages, profile bios, and event descriptions — is scanned before it is saved. The text moderation layer is defined in lib/content-moderation.js and is backed by two operator-editable database tables created in migrations/0008_text_moderation_lists.sql:

Both lists are loaded by loadModerationLists() and held in a process-local cache with a 60-second TTL (configurable via MODERATION_CACHE_MS). The moderated entry points are:

The text-moderation layer is fail-open: if the database lookup or regex compilation fails for any reason, the layer logs a warning and returns { flagged: false } so a transient moderation outage cannot prevent users from sending messages. Failures are visible in the logs and do not silently bypass policy.

2. Automated Photo Moderation

Every avatar uploaded to FUSE is sent through an automated image-moderation check before it reaches the user's profile. The flow is in lib/content-moderation.js (moderatePhoto()):

Photo moderation is invoked from POST /api/profile/avatar in routes/profile.js. On a flag, the user is marked is_flagged with field avatar, the upload is rejected with HTTP 422, and the photo never reaches storage.

Like the text layer, photo moderation is fail-open when the provider is not configured: if MODERATION_PROVIDER is not set to rekognition, or the AWS credentials are missing, moderatePhoto() returns { flagged: false } and uploads proceed. The provider is also fail-open inside the try/catch around the AWS call: a Rekognition network error logs a warning and returns { flagged: false } rather than blocking uploads system-wide.

3. User Reports & The Admin Action Panel

Users can report another user from inside the app. The reporting endpoint is POST /api/reports in routes/reports.js, and every report must carry one of four reasons:

Self-reports and reporter-mismatch attempts are rejected at the route level (HTTP 400 and HTTP 403 respectively) so the queue is reserved for genuine signal. The persisted report schema (reporter, target, reason, context, status, reviewer attribution, and resolution note) is defined in migrations/0006_reports.sql and extended in migrations/0009_report_moderation.sql.

Trust & Safety reviewers work from an admin-only queue and action panel:

A remove decision does more than close the report: it calls setUserFlagged(targetId, { field: 'review', reason: note }), which sets users.is_flagged, users.flagged_field, and users.flagged_reason in a single transaction. Flagged users are then gated out of the feed, swipes, matches, and messages by the requireOnboarding middleware in routes/auth.js.

The same moderation surface is available inside the app for admin users via the in-app #moderation view in public/app.html, which renders the queue and the two-decision action panel.

4. 17+ Age Verification

FUSE carries the App Store age rating of 17+. The minimum age is a single source of truth: MIN_AGE = 17 in lib/age.js. All age gating reads from that constant.

The gate is enforced at three points:

Age is computed via UTC so daylight-saving shifts never produce a one-day miscalculation. The same age gate is described in our Privacy Policy → Age Gate, so reviewers see one consistent message in both documents.

FUSE is not designed or marketed for children. We do not knowingly collect data from minors; if we learn that an account belongs to someone below MIN_AGE, we delete the account and its data.

5. Crisis Resources

People using a dating app can be in moments of acute distress. FUSE surfaces a set of free, confidential crisis resources inside the app so help is one tap away. The in-app list lives in public/app.html as CRISIS_RESOURCES and is rendered in the #safety view (showSafety()). The list is also reachable from the chat view (the chat-safety-row) and from the profile view.

The four resources currently surfaced to FUSE users are:

The same resource list links are wired into the chat UI and the profile UI so a user who feels unsafe can reach help without leaving the conversation that prompted it.

6. Response SLA

FUSE commits to the following response times for moderation and safety actions. These are operational targets, not arbitrary claims — they map to routes/admin-moderation.js and the moderation queue UI in public/app.html.

Flagged Content Takedown

Content flagged by automated text or photo moderation is blocked at write time, so prohibited content never reaches another user. When a human report adds context, the moderation queue targets a first response within 24 hours.

User Report Review

User-submitted reports entered via POST /api/reports are reviewed by a Trust & Safety moderator within 24 hours. Decisions are approved (no policy violation) or removed (with note), and removal applies the is_flagged lockout.

If a report involves imminent safety risk, it is escalated ahead of the SLA. We do not promise an instant response, but we do promise the report is read and actioned within the window above. To submit a report outside the app, or to flag a moderation concern to Trust & Safety directly, email us at:

hello@fuse-2.polsia.app

© 2026 FUSE. All rights reserved.