Modules Documentation
Validation rules
Required fields, formats, ranges.
Complete
A CalendarEvent passes through three validation tiers before publication: structural (required fields + format), editorial (3-gate verification), and integrity (cross-references resolve, timezones are valid, dates are coherent). All three must pass.
Structural validation
- Required: id, slug, title.en + title.ar, shortDescription.en + .ar, organizerName, organizerType, country, mode, startDate, timezone, category, status, audiences (≥1), stageRelevance (≥1), verificationStatus.
- At least one of: websiteUrl, registrationUrl, applyUrl, contactEmail. Without an outbound channel, the event cannot funnel and shouldn’t be published.
- slug is unique across the entire dataset, kebab-case, ASCII only.
- startDate, endDate, applicationDeadline, registrationDeadline are valid ISO 8601 with explicit timezone offset.
- timezone is an IANA zone identifier (e.g. "Africa/Cairo", "Asia/Riyadh"). Not "GMT+3" — that loses DST awareness.
Editorial verification — the 3 gates
- Gate 1 — Source authority. sourceUrl points to an authoritative channel: organizer’s own domain, official social account (verified), or a confirmed press release. Aggregator pages do not count.
- Gate 2 — Detail accuracy. Date, city, venue, organizer name, deadlines are confirmed against the source. If the source URL’s content disagrees with the entry, the entry is wrong, not the source.
- Gate 3 — Ecosystem relevance. The event is genuinely about MENA startups / founders / investors / ecosystem operators. Generic tech conferences, corporate sales events, or non-MENA events fail this gate even if their facts are correct.
Integrity validation
- endDate ≥ startDate (when endDate is set).
- applicationDeadline ≤ startDate (you can’t apply after the event starts — except for rolling cohorts, where deadline can be missing).
- mode='physical' requires venue OR (city+country). mode='online' requires onlineUrl. mode='hybrid' requires both.
- Every relatedXxxId resolves to an existing record in its module. Stale IDs are stripped at render time.
- lastVerifiedAt must be set whenever verificationStatus transitions to "verified".
