A sourced, editorial history app
Today In Time
A small daily collection of real stories from this date in history, with source provenance, adjustable tone, saved reading, quizzes, and a companion widget.
- Client
- Dependency-free SwiftUI iPhone app
- Corpus
- Bundled, validated editorial JSON records
- State
- Local preferences, saved stories, feedback, and quiz history
- Extension
- One-event-per-day widget data slice
The project
What it does
Today In Time treats historical material as an editorial product rather than an infinite scraped feed. Each event has a stable record contract, publishable status, tone, category, narrative fields, and one or more sources. The app can present an uplifting, balanced, or more unflinching selection without hiding where the story came from.
The runtime is intentionally simple and offline-friendly. A bundled corpus is decoded into a stable HistoricalEvent model, then reused by the feed, detail, Explore, Saved, and Quiz experiences. A smaller generated slice feeds the widget, and CI prevents that slice from drifting away from the main corpus.
Built around
Product principles
Editorial, not scraped
Records are sourced, reviewed, status-gated, and shaped for a calm reading experience.
Tone without erasure
Uplifting, balanced, and somber preferences change selection while preserving provenance.
Offline by construction
The main reading experience ships with the app instead of depending on a network request.
One contract, many surfaces
Feed, detail, search, saved stories, quizzes, notifications, and the widget share the same event model.
System architecture
How the system moves
The editorial corpus is validated before it reaches Xcode. At runtime, one loader and one normalized model insulate every view from the source JSON shape, while local stores preserve user choices without requiring an account.
Editorial record to daily reading
-
01 · Editorial
Sourced event records
Each record carries date, narrative, category, tone, status, and provenance.
-
02 · Data gate
Validation and widget slice
Scripts reject invalid records and regenerate the smaller one-per-day widget corpus.
-
03 · Bundle
Local JSON resources
The validated main corpus and widget slice ship inside their respective targets.
-
04 · Model
DataLoader and HistoricalEvent
Fallback fields, aliases, and publishability rules become one stable app model.
-
05 · Experience
Feed, detail, Explore, Quiz
SwiftUI surfaces select stories by date, tone, category, and user intent.
-
06 · Personal state
Saved, feedback, widget
Local stores remember reading choices and share the daily record with the widget.
The source corpus is an input artifact, not a live content API. That keeps reading fast and predictable, while CI holds the app and widget to the same editorial contract.
Keep exploring