# niamhramadhaan/jemima architecture

> Architecture diagram of the GitHub repository niamhramadhaan/jemima, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-27). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/niamhramadhaan/jemima
- Repository: https://github.com/niamhramadhaan/jemima

## Overview

1. JEMIMA is a single-repo, locally hosted digital-signage app with three runtime pieces: a React/Vite TypeScript front end, a small Node/Express server for serving media files, and an optional Electron shell for kiosk/desktop deployment.

2. The main architecture boundary is between UI state and media assets. Business data such as screens, schedules, preferences, and theme selection live in browser localStorage via shared hooks/utilities, while actual media files live on disk in a project-root `media` folder and are streamed by the server.

3. The front end is route-based. `App.tsx` wires navigation and access flow, while `main.tsx` boots the app. Pages under `src/pages` represent the major product surfaces: dashboard, films/library, ingest, schedules, show builder, locations/screens, player views, settings, login, and onboarding/quick start.

4. The admin/control plane is centered on the Dashboard, Schedule, Films, Locations, and Settings pages. These screens let a user import files, assemble playback sequences, assign schedules to screens, inspect status, and change app-wide options without any backend API or database.

5. Playback is split into dedicated player surfaces: `Player`, `ScreenPlayer`, `PlayerConfig`, and related screen detail pages. This separation reflects the product model where the same app can act as both operator console and display player, with fullscreen/kiosk behavior emphasized for installed screens.

6. Scheduling is the core domain model. The `ShowBuilder` and `Schedule` pages create ordered sequences of media items, support time-based start behavior, loop vs one-shot modes, background audio, and conflict detection. The dashboard then consumes that schedule state to show now-playing, next-up, and completion status.

7. Media ingestion is filesystem-first rather than upload-based. `FilmIngest` reads local files from the content directory, supported media types are indexed into the library, and player views load those assets from the Node server rather than from a cloud store.

8. Shared UI is organized as a reusable shell plus feature components. `Layout`, `Sidebar`, `Topbar`, `Pagination`, `LocationTimeline`, `LocationsMap`, `SetlistModal`, and `ErrorBoundary` provide the app frame and operational widgets, while `src/components/ui` contains decorative theme-driven primitives like the highlighter and light rays.

9. Theme and configuration are treated as first-class app state. `themes.ts`, `src/lib/theme.ts`, and `src/config/app.ts` define the accent system and app constants, and the `useLocalStorage` hook plus `storage.ts`/`data.ts` helpers centralize persistence and retrieval of user preferences and domain records.

10. The Electron layer is a packaging boundary, not a separate product tier. `electron/main.cjs` and `electron/preload.cjs` wrap the same app for standalone kiosk use, embedding the Express server so a dedicated display machine can launch JEMIMA without running a separate browser and server setup.

11. Architecturally, there are no external cloud services, no database, and no real auth system. That keeps the system simple and local-first, but also means the repository’s state is intentionally per-device and best understood as a single-node signage controller with browser-based multi-screen views.

Main entry points: [`src/App.tsx`](https://github.com/niamhramadhaan/jemima/blob/main/src/App.tsx) (App), [`src/lib/storage.ts`](https://github.com/niamhramadhaan/jemima/blob/main/src/lib/storage.ts) (storage), [`server.cjs`](https://github.com/niamhramadhaan/jemima/blob/main/server.cjs) (server.cjs), [`electron/main.cjs`](https://github.com/niamhramadhaan/jemima/blob/main/electron/main.cjs) (electron main)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["React app"]
  node_main(("main.tsx<br/>bootstrap<br/>[main.tsx]"))
  node_app["App<br/>router<br/>[App.tsx]"]
  node_layout["Layout<br/>shell<br/>[Layout.tsx]"]
  node_sidebar["Sidebar<br/>nav<br/>[Sidebar.tsx]"]
  node_topbar["Topbar<br/>header<br/>[Topbar.tsx]"]
  node_dashboard["Dashboard<br/>control panel<br/>[Dashboard.tsx]"]
  node_films["Films<br/>[Films.tsx]"]
  node_ingest["Ingest<br/>[FilmIngest.tsx]"]
  node_schedule["Schedule<br/>playback plan<br/>[Schedule.tsx]"]
  node_builder["ShowBuilder<br/>sequence editor<br/>[ShowBuilder.tsx]"]
  node_locations["Locations<br/>screen admin<br/>[Locations.tsx]"]
  node_player["Player<br/>[Player.tsx]"]
  node_screenplayer["ScreenPlayer<br/>fullscreen player<br/>[ScreenPlayer.tsx]"]
  node_screen["ScreenDetail<br/>screen view<br/>[ScreenDetail.tsx]"]
  node_settings["Settings<br/>preferences<br/>[Settings.tsx]"]
end

subgraph group_server["Media server"]
  node_server["server.cjs<br/>media server<br/>[server.cjs]"]
end

subgraph group_desktop["Electron shell"]
  node_electronmain["electron main<br/>desktop shell<br/>[main.cjs]"]
  node_electronpreload["preload<br/>bridge<br/>[preload.cjs]"]
end

subgraph group_shared["Shared core"]
  node_storage[("storage<br/>local state<br/>[storage.ts]")]
  node_theme(("theme<br/>styling state<br/>[theme.ts]"))
  node_config["app config<br/>constants<br/>[app.ts]"]
end

node_main -->|"mounts"| node_app
node_app -->|"wraps"| node_layout
node_layout -->|"contains"| node_sidebar
node_layout -->|"contains"| node_topbar
node_app -->|"routes to"| node_dashboard
node_app -->|"routes to"| node_films
node_app -->|"routes to"| node_ingest
node_app -->|"routes to"| node_schedule
node_app -->|"routes to"| node_builder
node_app -->|"routes to"| node_locations
node_app -->|"routes to"| node_player
node_app -->|"routes to"| node_screenplayer
node_app -->|"routes to"| node_screen
node_app -->|"routes to"| node_settings
node_dashboard -->|"reads state"| node_storage
node_schedule -->|"persists"| node_storage
node_builder -->|"persists"| node_storage
node_films -->|"reads library"| node_storage
node_ingest -->|"indexes assets"| node_server
node_player -->|"streams media"| node_server
node_screenplayer -->|"streams media"| node_server
node_settings -->|"updates"| node_theme
node_settings -->|"uses"| node_config
node_electronmain -->|"embeds"| node_server
node_electronmain -->|"loads"| node_electronpreload
node_electronmain -->|"launches"| node_main
node_screen -->|"reads state"| node_storage

click node_main "https://github.com/niamhramadhaan/jemima/blob/main/src/main.tsx"
click node_app "https://github.com/niamhramadhaan/jemima/blob/main/src/App.tsx"
click node_layout "https://github.com/niamhramadhaan/jemima/blob/main/src/components/Layout.tsx"
click node_sidebar "https://github.com/niamhramadhaan/jemima/blob/main/src/components/Sidebar.tsx"
click node_topbar "https://github.com/niamhramadhaan/jemima/blob/main/src/components/Topbar.tsx"
click node_dashboard "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Dashboard.tsx"
click node_films "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Films.tsx"
click node_ingest "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/FilmIngest.tsx"
click node_schedule "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Schedule.tsx"
click node_builder "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/ShowBuilder.tsx"
click node_locations "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Locations.tsx"
click node_player "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Player.tsx"
click node_screenplayer "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/ScreenPlayer.tsx"
click node_screen "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/ScreenDetail.tsx"
click node_settings "https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Settings.tsx"
click node_storage "https://github.com/niamhramadhaan/jemima/blob/main/src/lib/storage.ts"
click node_theme "https://github.com/niamhramadhaan/jemima/blob/main/src/lib/theme.ts"
click node_config "https://github.com/niamhramadhaan/jemima/blob/main/src/config/app.ts"
click node_server "https://github.com/niamhramadhaan/jemima/blob/main/server.cjs"
click node_electronmain "https://github.com/niamhramadhaan/jemima/blob/main/electron/main.cjs"
click node_electronpreload "https://github.com/niamhramadhaan/jemima/blob/main/electron/preload.cjs"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_main,node_app,node_layout,node_sidebar,node_topbar,node_dashboard,node_films,node_ingest,node_schedule,node_builder,node_locations,node_player,node_screenplayer,node_screen,node_settings toneBlue
class node_server toneAmber
class node_electronmain,node_electronpreload toneMint
class node_storage,node_theme,node_config toneRose
```

## Components

### React app

Browser UI, route surfaces, shared state, and presentation components.

- [main.tsx](https://github.com/niamhramadhaan/jemima/blob/main/src/main.tsx): bootstrap · React entrypoint that mounts the app. · `src/main.tsx`
- [App](https://github.com/niamhramadhaan/jemima/blob/main/src/App.tsx): router · Top-level navigation and access flow. · `src/App.tsx`
- [Layout](https://github.com/niamhramadhaan/jemima/blob/main/src/components/Layout.tsx): shell · App frame and global layout wrapper. · `src/components/Layout.tsx`
- [Sidebar](https://github.com/niamhramadhaan/jemima/blob/main/src/components/Sidebar.tsx): nav · Primary navigation for operator screens. · `src/components/Sidebar.tsx`
- [Topbar](https://github.com/niamhramadhaan/jemima/blob/main/src/components/Topbar.tsx): header · Top-level status and actions bar. · `src/components/Topbar.tsx`
- [Dashboard](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Dashboard.tsx): control panel · Now-playing, next-up, and status overview. · `src/pages/Dashboard.tsx`
- [Films](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Films.tsx): library · Media library and asset browsing. · `src/pages/Films.tsx`
- [Ingest](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/FilmIngest.tsx): filesystem ingest · Imports local files into the library. · `src/pages/FilmIngest.tsx`
- [Schedule](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Schedule.tsx): playback plan · Builds and manages timed playback sequences. · `src/pages/Schedule.tsx`
- [ShowBuilder](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/ShowBuilder.tsx): sequence editor · Constructs ordered shows and playback modes. · `src/pages/ShowBuilder.tsx`
- [Locations](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Locations.tsx): screen admin · Manages screens and deployment locations. · `src/pages/Locations.tsx`
- [Player](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Player.tsx): player view · Dedicated playback surface for kiosk or display mode. · `src/pages/Player.tsx`
- [ScreenPlayer](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/ScreenPlayer.tsx): fullscreen player · Fullscreen screen-oriented playback surface. · `src/pages/ScreenPlayer.tsx`
- [ScreenDetail](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/ScreenDetail.tsx): screen view · Screen-specific detail and playback status. · `src/pages/ScreenDetail.tsx`
- [Settings](https://github.com/niamhramadhaan/jemima/blob/main/src/pages/Settings.tsx): preferences · App-wide options and theme selection. · `src/pages/Settings.tsx`

### Media server

Local Node server that serves on-disk media assets.

- [server.cjs](https://github.com/niamhramadhaan/jemima/blob/main/server.cjs): media server · Node/Express server that streams on-disk media. · `server.cjs`

### Electron shell

Optional kiosk/desktop packaging around the same app.

- [electron main](https://github.com/niamhramadhaan/jemima/blob/main/electron/main.cjs): desktop shell · Electron main process for standalone kiosk packaging. · `electron/main.cjs`
- [preload](https://github.com/niamhramadhaan/jemima/blob/main/electron/preload.cjs): bridge · Electron preload bridge for the renderer. · `electron/preload.cjs`

### Shared core

Persistence, theme, config, and domain helpers used across the app.

- [storage](https://github.com/niamhramadhaan/jemima/blob/main/src/lib/storage.ts): local state · LocalStorage-backed persistence and retrieval helpers. · `src/lib/storage.ts`
- [theme](https://github.com/niamhramadhaan/jemima/blob/main/src/lib/theme.ts): styling state · Theme and accent configuration helpers. · `src/lib/theme.ts`
- [app config](https://github.com/niamhramadhaan/jemima/blob/main/src/config/app.ts): constants · App-wide constants and configuration values. · `src/config/app.ts`

## Connections

- main.tsx → App: mounts · Bootstraps the routed app.
- App → Layout: wraps · Uses the shared application shell.
- Layout → Sidebar: contains · Primary navigation lives in the shell.
- Layout → Topbar: contains · Shell header and actions.
- App → Dashboard: routes to · Main operator overview.
- App → Films: routes to · Media library surface.
- App → Ingest: routes to · Filesystem-based import flow.
- App → Schedule: routes to · Scheduling and playback planning.
- App → ShowBuilder: routes to · Show composition editor.
- App → Locations: routes to · Screen and location management.
- App → Player: routes to · Operator/player surface.
- App → ScreenPlayer: routes to · Fullscreen playback surface.
- App → ScreenDetail: routes to · Screen detail view.
- App → Settings: routes to · Preferences and theme settings.
- Dashboard → storage: reads state · Consumes local schedule and screen state.
- Schedule → storage: persists · Stores show and schedule records locally.
- ShowBuilder → storage: persists · Stores ordered show definitions locally.
- Films → storage: reads library · Loads indexed media records.
- Ingest → server.cjs: indexes assets · Relies on the local media server and disk content.
- Player → server.cjs: streams media · Loads playable files from the Node server.
- ScreenPlayer → server.cjs: streams media · Fullscreen playback reads served assets.
- Settings → theme: updates · Changes app accent and presentation state.
- Settings → app config: uses · Reads app constants and configuration.
- electron main → server.cjs: embeds · Packages the local server inside the desktop shell.
- electron main → preload: loads · Initializes renderer bridge.
- electron main → main.tsx: launches · Starts the same React app in kiosk/desktop mode.
- ScreenDetail → storage: reads state · Uses local screen and playback records.
