System Overview
Datariot is a cross-platform educational short-video platform built with a modern mobile-first stack. It focuses on structured intellectual discourse and AI-guided synthesis of knowledge.
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | React Native 0.81 + Expo SDK 54 |
| Navigation | Expo Router v6 (file-based) |
| Backend | Supabase (PostgreSQL, Auth, Storage) |
| AI Engine | Orvelis AI — OpenAI GPT with automatic provider fallback |
| State | Zustand 4 |
Project Structure
The repository follows a monorepo-lite structure: one Expo application plus static sites, routed to subdomains via Vercel host-based rewrites.
/datariot
├── datariot-docs/ # This documentation site (docs.datariot.xyz)
├── datariot-info/ # Landing page assets (info.datariot.xyz)
├── datariot-xyz/ # Production web build of the Expo app (datariot.xyz)
├── src/ # Expo application source code
│ ├── app/ # Expo Router pages ((tabs), auth, chat, debate, ...)
│ ├── components/ # UI components
│ ├── design-system/# Design tokens & primitives
│ └── lib/ # Supabase client, AI client, hooks, utils
├── scripts/ # Seeding & maintenance scripts
├── docs.html # Root shell served at docs.datariot.xyz/
├── info.html # Root shell served at info.datariot.xyz/
├── xyz.html # Root shell served at datariot.xyz/
├── vercel.json # Host-based rewrite configuration
└── package.json # Main project dependencies
Local Development
Install dependencies and start the Expo development server. Node 18+ is recommended.
npm install
npm start # Expo dev server (Metro)
npm run web # Run in the browser
npm run android # Run on Android (device / emulator)
npm run ios # Run on iOS (simulator)
npm run lint # ESLint via expo lint
The start and platform scripts set
NODE_OPTIONS=--max-old-space-size=2048 to avoid Metro running out of memory on
large bundles. Use the start:lan / start:tunnel variants when
testing on a physical device.
Backend Setup (Supabase)
Follow these steps to initialize the database and services on Supabase. The full step-by-step guide
lives in SUPABASE_SETUP.md at the repository root.
1. Database Initialization
Run the SQL schema script in the Supabase SQL Editor to create all tables,
relationships, and RLS policies. Verify that automated triggers such as
create_profile_on_signup are registered — they provision a profiles row
when a new user signs up.
2. Storage Buckets
Create a public bucket named videos (allowed MIME types: video/*) for
hosting video assets.
| Operation | Policy |
|---|---|
| SELECT | Public (All) |
| INSERT | Authenticated User |
| UPDATE | Owner (File Creator) |
| DELETE | Owner / Admin |
Database Schema
The core tables are grouped below. For the full OpenAPI specification, refer to
full_db_schema.json at the repository root.
| Table | Description |
|---|---|
profiles |
User profiles, avatars, and logic scores. |
videos / views |
Video metadata, URLs, creator mapping, and view tracking. |
posts / comments |
Text posts and threaded comments, with post_likes and
comment_likes. |
chats / chat_participants / messages |
Direct and group messaging. |
intella_battles / intella_challenges |
Structured debate battles and challenges, with submissions, votes, reactions, and results. |
intella_leaderboard |
Calculated rankings for the Creator DNA section. |
impact_daily |
Daily impact score snapshots per user. |
later_actions / save_actions /
inspire_actions |
"Watch Later", save, and inspire interactions. |
followers / likes / notifications |
Social graph, reactions, and the notification feed. |
users / login_tokens |
Account records and one-time login codes. |
RPC Functions
Server-side logic is exposed through PostgreSQL functions, callable via
supabase.rpc(name, params). The most important ones:
| Function | Purpose |
|---|---|
get_videos_with_profiles |
Feed query joining videos with creator profiles. |
get_user_videos / submit_video /
create_video_safe |
Fetch and publish user videos with validation. |
search_videos_by_tags |
Tag-based video discovery. |
create_battle / finalize_battle /
cast_vote |
Debate battle lifecycle and voting. |
calculate_user_impact_score / update_daily_impact |
Impact score computation and daily snapshots. |
register_user / verify_login_code /
get_profile_by_email |
Account registration and passwordless login flow. |
create_profile_safe / is_chat_participant /
get_user_chat_ids |
Profile provisioning and chat access checks. |
AI Engine (Orvelis)
The Orvelis AI layer lives in src/lib/ai/client.ts. It powers daily insights and
personalized recommendations.
- The OpenAI client is initialized lazily (with
dangerouslyAllowBrowser, required for React Native / Expo) to avoid module load-time crashes in browsers. - Every AI call goes through a fallback helper: the primary provider is tried first with a 15-second timeout, then the secondary provider, before degrading to deterministic mock data.
- If API keys are missing, the engine logs a warning and serves fallback/mock responses instead of crashing.
The engine reads EXPO_PUBLIC_OPENAI_API_KEY and
EXPO_PUBLIC_ANTHROPIC_API_KEY from the environment. See
Environment Configuration.
Environment Configuration
Configuration is managed via .env in the repository root. Do not commit this file to
version control.
# Supabase
EXPO_PUBLIC_SUPABASE_URL=https://[YOUR_ID].supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=[YOUR_ANON_KEY]
SUPABASE_SERVICE_ROLE_KEY=[SECRET_ROLE_KEY] # backend/scripts only
# AI providers (Orvelis)
EXPO_PUBLIC_OPENAI_API_KEY=[OPENAI_KEY]
EXPO_PUBLIC_ANTHROPIC_API_KEY=[ANTHROPIC_KEY]
The service_role key bypasses all RLS policies. Never reference it from frontend
code or expose it in client builds — it is for trusted scripts and backend environments
only. Variables prefixed with EXPO_PUBLIC_ are bundled into client builds.
Vercel Rewrites
The platform uses host-based rewrites in vercel.json. For each subdomain the root path
/ is served from a root-level HTML shell, while all other paths resolve into the
matching directory.
- docs.datariot.xyz →
/docs.html, assets from/datariot-docs/ - info.datariot.xyz →
/info.html, assets from/datariot-info/ - datariot.xyz →
/xyz.html, Expo bundle and assets from/datariot-xyz/(/_expo/*,/assets/*); all other paths fall back to/xyz.htmlfor client-side routing