production

$ cat system.md

For the curious. How we're preserving Ge'ez script and East African languages for the next generation.

fidel-family — stats
$ fidel-family --stats --all

admin panel

18
prisma.models
12
trpc.routers
80+
trpc.procedures
22
api.routes
1,084
audio.slots

mobile app

15
expo.screens
23
react.components
93
illustrations
22
character.poses
4
ui.languages

web learning app

15
learning.pages
12
learning.components
4
learning.games
7
learning.lib.modules
4
content.languages

admin.dependencies

framework

  • Next.js14.x
    App Router, RSC, middleware
  • React18.x
    Server + client components
  • TypeScriptstrict
    End-to-end type safety

data

  • PostgreSQL/Neon
    Serverless Postgres, branching
  • Prisma5.x
    18 models, typed queries
  • Cloudflare R2S3 API
    Images, audio, book assets

api

  • tRPC11.x
    80+ procedures across 12 routers
  • Zod3.x
    Runtime validation, shared schemas
  • superjson
    Date serialization, never fileData

auth

  • Clerk6.x
    Google OAuth, invite-only
  • Role system
    Admin, Contributor, Author roles

ai

  • Google Imagen 4
    Text-to-image book illustrations
  • Gemini 2.5 Flash
    Reference-based style matching
  • sharp0.34
    Resize + WebP optimization

payments

  • Stripe
    Book purchases, author Connect payouts
  • Lulu API
    Print-on-demand hardcovers

audio + media

  • Web Audio APInative
    Browser recording via MediaRecorder
  • @react-pdf/renderer4.x
    Print-ready book PDFs

email

  • Resend
    Invite emails, feedback notifications

ui

  • Tailwindv3
    Utility-first, dark mode
  • Radix/shadcn
    Accessible primitives
  • Lucide icons
    Tree-shakeable

infra

  • VercelEdge+Node
    Zero-config deploys from master
  • GA4 G-tag
    via @next/third-parties

mobile.dependencies

mobile framework

  • ExpoSDK 54
    Managed workflow, OTA updates
  • React Native0.81
    New Architecture ready
  • React19.x
    New compiler
  • Expo Routerv6
    File-based navigation

graphics

  • Skia@shopify
    GPU-accelerated 2D canvas for particles
  • Reanimated4.x
    60fps gesture-driven animations
  • react-native-svg15.x
    Stroke tracing canvas

mobile audio

  • expo-audio1.x
    Playback with music ducking

storage

  • expo-sqlite16.x
    Offline progress, content cache

payments

  • RevenueCat9.x
    Tip jar — coffee, injera, feast

observability

  • Sentry7.x
    Crash reporting, source maps
  • expo-updates29.x
    Over-the-air updates

web.dependencies

web client

  • IndexedDBnative
    Content cache, progress, ETag tracking
  • Web Audio APInative
    Hybrid AudioContext + HTMLAudioElement
  • HTML5 Canvasnative
    Stroke tracing with accuracy zones

shared code

  • @fidel/sharedworkspace
    npm workspace, types + game logic + i18n strings
  • content-sync.ts
    ETag-cached REST consumer
  • progress.ts
    4 IndexedDB stores

web games

  • Matching
    Drag-to-match vocab
  • Sound Quiz
    Audio-first identification
  • Bubble Pop
    Tap-to-pop timed
  • Memory Pairs
    Flip-to-match

architecture

architecture.ts
1
storage: r2 + postgres

Book assets (illustrations, covers, narration, music) in Cloudflare R2. Legacy audio as Postgres bytea. sharp optimizes all images to WebP before upload.

2
api: trpc + zod

12 routers, 80+ procedures. Input schemas defined once, shared between client and server. superjson for serialization — but never serialize fileData (breaks it).

3
auth: invite-first

No self-registration. Admin invites users via UI with role assignment (Admin/Contributor/Author). UserInvite consumed on first login. Falls back to ADMIN_EMAILS env.

4
ai: imagen + gemini

Book illustrations via Google Imagen 4 (text-to-image) or Gemini 2.5 Flash (reference-based). 5 prompt templates with auto-filled variables. House style prefix ensures consistency.

5
books: author workflow

DRAFT → SUBMITTED → IN_REVIEW → APPROVED → PUBLISHED. Multilingual text + narration + music per page. Stripe payments for purchases, Connect for author payouts.

6
print: lulu pod

Print-on-demand hardcovers via Lulu API. PDF generation with @react-pdf/renderer + Fidel Family Sans. Inventory tracking with stock vs print-on-demand fulfillment.

7
sync: etag-cached REST

Mobile app polls /api/v1/content/ endpoints. ETag + If-None-Match headers for bandwidth-efficient change detection. 22 API routes, all public content GET-only.

8
canvas: stroke-editor

Admin draws Ge’ez letter strokes on HTML canvas. Stroke data saved as JSON per form. 33 consonants × 7 forms = 231 stroke sequences.

9
i18n: multi-language

Four languages: Tigrinya, Amharic, English, and Oromo. All content — packs, fidel, books, locale — fully translated. Audio in ti/am/en; Oromo audio in progress.

10
offline: bundled + synced

All content ships in the APK. SQLite cache fills on first sync. Admin API merges overrides in background. Network failures never block the app.

11
render: skia particles

GPU-accelerated particle effects via @shopify/react-native-skia. Confetti, fireflies, celebration bursts. Error boundary silently disables on unsupported devices.

12
privacy: coppa-compliant

Zero PII stored. No analytics, no ads, no social features. Progress tracked locally in SQLite only. Parental gate (math CAPTCHA) for settings.

content.system

Vocabulary Packs

N packs × 10 items × 4 languages

160+slots

Animals, Family, Body Parts, Foods, and more. Each item has names and pronunciation guides in ti/am/en/om.

Fidel (Ge’ez Script)

33 consonants × 7 vowel forms × 4 languages

924slots

Full Ge’ez syllabary. Each form has character, names, pronunciation, stroke data, and audio in all four languages.

Children’s Books

Multilingual pages × AI illustrations

7+slots

Picture books with text in ti/am/en/om, AI-generated illustrations (Imagen 4 + Gemini), narration audio, background music. Free or paid via Stripe.

Locale Strings

N keys × 4 languages

N

UI strings for the mobile app. Key-value pairs in en/ti/am/om. Admin-editable, versioned, served via content API.

recording.lifecycle()

recording-flow.ts
1
Contributor records audio

Browser mic via MediaRecorder API. Space bar to start/stop. Preview before saving.

2
Audio saved to R2 + Postgres

Uploaded to Cloudflare R2 with fallback to Postgres bytea. Status: PENDING. MIME type preserved.

3
Admin reviews recording

Queue-based review at /admin/recordings. Play, compare, approve or reject with notes.

4
Recording activated

Approved → isActive: true. Previous active recording for same item+language → isActive: false.

5
Mobile app fetches approved audio

GET /api/v1/content/packs returns only isActive recordings. ETag caching minimizes bandwidth.

api.v1.content

mobile-sync.ts
$ fidel-family api --list-endpoints
pathmethodcachepurpose
/api/v1/content/manifestGETETagContent hashes for change detection. Mobile checks this first.
/api/v1/content/packsGETETagAll packs + items + approved audio URLs.
/api/v1/content/fidelGETETagConsonants + vowel forms + stroke data + audio.
/api/v1/content/localeGETETagUI strings grouped by language (en/ti/am/om).
/api/v1/content/booksGETETagPublished book catalog with pricing and metadata.
/api/v1/content/books/[id]GETETagBook pages, illustrations, narration, music.
/api/v1/content/announcementsGETETagIn-app event announcements with illustrations.
/api/v1/feedbackPOSTUser feedback with device info. Triggers admin email.

// All endpoints public. GET-only. CORS enabled for mobile app.

// 304 Not Modified when ETag matches. Zero bandwidth wasted.

mobile --verbose

Toddler-optimized UX

140px touch targets, audio-first design, no text-only content. High contrast watercolor illustrations replace emoji.

Offline-first architecture

Bundled content loads instantly. SQLite caches API responses + ETags. Background sync merges updates. Network failures are invisible.

Co-play split-screen mode

Landscape-locked competitive game for twins sharing a tablet. Separate score tracking, turn-based play, winner celebration.

Skia particle system

GPU-accelerated confetti, fireflies, celebration bursts, ink trails. 6 presets with graceful degradation on unsupported devices.

Interactive stroke tracing

Draw Ge’ez characters on canvas. Zone-based accuracy validation (55% threshold). Multi-stroke support with real-time feedback.

Character sidekicks

Semay & Miriam — twin guides with 11 poses each (WebP optimized). Contextual reactions: clap on correct, encourage on retry.

Parental gate + tip jar

Math CAPTCHA locks settings. RevenueCat tip jar (3 tiers: $2.99/$4.99/$9.99). Supporter badge on dashboard. Zero pressure.

web --verbose

Offline content sync

IndexedDB caches all packs, fidel, books, announcements with ETag change detection. First load fetches from API, subsequent loads serve from cache.

4 learning games

Matching, Sound Quiz, Bubble Pop, Memory Pairs. All games use GameShell wrapper with score tracking, celebration confetti, and progress recording.

Interactive stroke tracing

HTML5 Canvas for drawing Ge’ez characters. Zone-based accuracy validation from shared stroke data. Visual feedback with color-coded accuracy.

Book reader

Page-by-page reader with cover, narration audio, background music, and language switching. Supports free and paid books with purchase verification.

Parental gate

Math CAPTCHA (addition/subtraction) protects parent dashboard and settings. Session-based unlock via sessionStorage.

Hostname routing

Middleware rewrites app.fidel.family to (learning) route group. Same Next.js app serves admin, marketing, store, and learning on different subdomains.

fidel.strokes

admin: stroke-editor

Admin draws letter strokes on an HTML5 canvas. Stroke order, direction, and control points saved as JSON per Fidel form. 33 consonants × 7 forms = 231 stroke sequences to record.

mobile: stroke-tracing

Children trace Ge'ez characters on a react-native-svg canvas. Zone-based accuracy validation — 55% of points must land in the center zone to accept. Multi-stroke support with real-time feedback and celebration particles on success.

security

clerkMiddleware()

Every protected route requires valid Clerk session. Role-based tRPC procedures: adminProcedure, authorProcedure, protectedProcedure. Zod validates all inputs.

auth: invite-first

No self-registration. Admins invite users via UI with role (Admin/Contributor/Author). UserInvite consumed on first login. Email from Clerk server-side — never client input.

payments: stripe webhooks

Book purchases via Stripe PaymentIntent. Webhook signature verification for payment_intent.succeeded and charge.refunded. Lulu webhooks HMAC-verified for print status.

cors: read-only API

Public /api/v1/ endpoints allow GET only. CORS headers permit cross-origin reads for the mobile app. Purchase/download mutations require Clerk auth.

coppa: zero PII

Mobile app stores no personally identifiable information. No analytics, no ads, no social features. Progress tracked locally in SQLite only. Designed for children under 13.

principles

  • #Every child deserves to hear their language. Ship audio, not excuses.
  • #Offline-first, always. Network failures are invisible to a toddler.
  • #Contributors record, admins review, authors publish. Trust the workflow.
  • #Four languages: ti/am/en/om. Every word, every book, every page.
  • #AI illustrates, humans curate. Imagen generates, authors approve.
  • #The mobile app is the product. The admin panel is the factory.
  • #No ads, no tracking, no social. COPPA compliance is a feature, not a constraint.
  • #From screen to hardcover. Print-on-demand means every book is real.
colophon

$ fidel-family --version

Built to preserve Ge'ez script and East African languages for the next generation.

Three apps. 1,000+ audio slots. AI-illustrated books. Four languages. One mission.

$ _

All this tech serves one goal: every child hears their language.

web + mobile + admin · 1,000+ audio slots · 4 languages · 33 Ge'ez consonants · AI-illustrated books · print-on-demand

invite-only · contributor, author & admin accounts