Last updated: 2026-09-21.
This document explains how user-generated content (UGC) in NavTrail is moderated. It exists to document our published moderation policy and to give users a clear picture of what they can expect. A copy is hosted publicly at https://navtrail.app/moderation (alongside the privacy policy).
If you have a question about a specific moderation decision or want to report content that the in-app flow doesn't cover, email contact@navtrail.app.
The following feature areas accept content from users:
| Feature | Free-text fields | Lifetime |
|---|---|---|
| Community POIs (camping, springs, viewpoints, refuges, tyre-repair shops) | name (≤ 80 chars), description (≤ 800 chars) | Permanent until reported / deleted by creator |
| Hazard reports (fallen trees, landslides, etc.) | description (≤ 280 chars, optional) | 4 hours TTL, then auto-deleted |
| SOS alerts | description (≤ 280 chars, optional), contact_hint (≤ 80 chars, optional) | 24 hours TTL, then auto-resolved |
| Convoy messages (Quick-Comms) | fixed presets, or free text (≤ 80 chars), sent only inside a convoy — a private group joined with a code given to you directly | Transient: shown briefly on the map, never stored on our servers |
| Convoy nicknames | nickname (≤ 8 chars, visible only to fellow convoy members) | 48 hours after last activity |
| Photos | An optional photo on a point of interest you created (1 per point), and up to 2 photos on your own saved route. Optional caption (≤ 200 chars). | Until deleted by the person who added it, or hidden after reports |
| Published routes ("Public tracks") | route name (≤ 120 chars), description (≤ 800 chars, optional), a difficulty label, and the recorded route itself, exactly as recorded | Until unpublished by the creator, or hidden after reports |
| Travel-partner trips (the trips board) | title (≤ 80 chars), description (≤ 600 chars), the message of a request to join (≤ 300 chars), up to 3 photos, an optional vehicle profile (make and model ≤ 60 chars, modifications ≤ 200 chars, one photo). Contact details are rejected by the server. | Until deleted by the poster or removed by the operator; a finished trip leaves the board 60 days after its last day |
| Travel-partner conversations | messages (≤ 1000 chars) between a trip's poster and one person who asked to join, opened only after the poster replied; a phone number the sender chooses to share; a convoy code | Read-only 30 days after the trip, deleted 90 days after it |
| Partner ratings | 1–5 stars, "would travel again" yes/no, an optional private note (≤ 300 chars, read by the operator only) | Until the account is deleted |
| Username (public handle) | username (3–20 chars, letters/numbers/underscore; shown on your POIs, hazards, and SOS alerts in place of an anonymous ID) | Permanent until the account is deleted |
Everything else (downloaded map regions, tire-pressure calculator inputs, etc.) is stored only on the user's device. Saved GPS tracks are backed up privately to their owner's account and are visible to nobody else — unless the owner explicitly publishes a track, which is the deliberate, per-track act that turns it into the user-generated content listed above. Nothing is ever published automatically.
Who can see a photo. A photo added to a point of interest is public, because points of interest are themselves a shared community layer — anyone using NavTrail can see them. A photo added to one of your saved routes is private to you while the route is private: it is backed up to your own account and restored on a new device, and it is not included when you share that route with someone by link. If you publish the route in Public tracks, its photos become public with it — the publish dialog states this before you confirm — and they become private again the moment you unpublish.
Only the person who created a point of interest can add a photo to it, and only they can remove it. This is enforced on the server, not merely hidden in the app.
Location data in photos. Photos are re-encoded on your device before they are stored or uploaded, which discards the metadata the original file carried — including the exact GPS coordinates a camera records. We do this so that publishing a photo cannot accidentally publish where you live.
contact_hint field on SOS alerts may contain the reporter's own contact info (e.g. their own phone number) but not anyone else's.NavTrail uses three complementary moderation layers, backed by an account model that strengthened in v1.2: browsing and posting POIs/hazards are anonymous by default, but a user can create a permanent, email-verified account — and sending an SOS now requires one. Because a verified email is needed to send an SOS, account-level enforcement (including removing the account of anyone who sends false SOS alerts) is a real deterrent, alongside the server-side controls below.
Every POI name/description, hazard description, and SOS description/contact-hint passes through a server-side wordlist filter before insertion. The filter uses whole-word matching with Romanian diacritic folding (ă/â/î/ș/ț → a/a/i/s/t) to catch common bypass attempts. Content that matches the wordlist is rejected with the error content_blocked_profanity; the user sees a localized message asking them to rephrase.
Implementation: BEFORE INSERT triggers on pois, reports, sos_alerts in supabase/migrations/0010_ugc_moderation.sql.
The wordlist is intentionally narrow (severe slurs + common vulgarities, ~25 terms across Romanian and English). We err on the side of letting borderline content through; the report-and-auto-hide path below is the second line of defence.
Every UGC surface has a "🚩 Report content" action visible to all users except the creator:
Reports are immutable and visible only to the reporter (a user cannot see who else has reported a row). One report per user per row is enforced at the database layer.
When the count of distinct reporters for a given row reaches 3:
is_hidden flag flips to true; the POI disappears from the map for everyone except its creator. A 24-hour age safeguard prevents griefing of brand-new POIs.status flips to RESOLVED; the marker drops out of bbox queries and Realtime UPDATE removes it from open clients' maps.resolved_at is stamped with the current time; same removal effect.is_hidden flips to true at 3 unique reporters, with no age delay. The route disappears from Public tracks and its GPX file stops being downloadable — for everyone, immediately. The creator's own copy of their recording is never touched; hiding removes a route from discovery, it does not delete anyone's data.Triggers run as SECURITY DEFINER functions and stamp resolved_by_user_id = NULL so the audit log distinguishes system-resolution from human-resolution.
Implementation: poi_auto_hide_on_reports, report_auto_resolve_on_reports, sos_auto_resolve_on_reports.
Photo captions pass through the same server-side wordlist filter as every other free-text field. The image itself is not inspected automatically. We want to be direct about that rather than imply a capability we do not have: no automated system reviews the picture content.
What protects the community instead is a combination of measures:
Even content that nobody reports doesn't live forever:
Expired/resolved rows are purged by pg_cron jobs every 15 minutes to 1 hour, depending on the table.
Any user can block another user from the app. Blocking hides everything that person has contributed — including content they posted before you blocked them — from your view: their points of interest, their photos, their published routes and their travel-partner trips, and it closes any conversation between you on the trips board, in both directions. It takes effect immediately and applies wherever that content would otherwise appear.
Blocking is private. The person you block is not told, and nothing about them changes for anyone else. You can see who you have blocked, and unblock them, at any time in the app's settings; unblocking restores their content to your view, because nothing was deleted.
For content that bypasses the automated layers (a single highly-toxic post that doesn't trip the wordlist and isn't seen by 3 other users), the operator (Constantin, contact@navtrail.app) reserves the right to:
These actions are taken in response to email reports at contact@navtrail.app or to proactive observation by the operator. Operator actions are logged but not publicly visible.
You can:
contact@navtrail.app with your user ID (visible in Settings → About) and we'll purge it within 30 days.If you find abusive content that wasn't auto-hidden by the in-app report action:
contact@navtrail.app directly with a screenshot. We commit to first response within 48 hours and removal of clearly-violating content within 7 days.This policy may change as the app grows. Material changes will be announced in the app's release notes and reflected in the "last updated" date at the top of this document. The current version always lives at https://navtrail.app/moderation.