Back to Index

Case study · Mobile · Healthcare

Gloria

A React Native app for the staff, families, and administrators of residential-care communities. One codebase, three roles, and an approval step before anything reaches a family.

RoleLead mobile engineer
TimelineSep 2025 – present
StackExpo · React Native · TypeScript · Auth0 · Firebase · EAS
ClientGloriaTech LLC · me on the app, two backend engineers on the Spring API
Gloria on tablet and phone: staff resident roster and the family feed
Staff view on the tablet, family feed on the phone. One codebase, role-based screens.

The problem

Families with a parent in assisted living or memory care mostly hear nothing between visits. Facilities do have the information: photos, wellness notes, announcements, calendars, supply requests. It lives in shift notes and group texts, and it never reaches the people who want it most. Gloria is the channel. The facility pays per resident; staff post, families follow, and administrators keep an approval gate on anything that goes public.

The hard constraint is that one app has to serve all three roles without feeling like three apps stapled together, on a backend the app team does not own.

My role

I own the mobile app end to end: architecture, every screen, the auth and session layer, push notifications, the release pipeline, and the working relationship with the backend team. Backend changes go to them as written asks with file and line references; I do not touch their repository.

What I built

Architecture

Expo / React Native app Staff Family Admin Role guards · expo-router groups AuthContext · single-flight refresh Typed endpoint registry · authenticatedFetch Auth0password realm · JWT · refresh Spring APIresidents · updates · approvals Firebase Cloud MessagingAPNs + Android push

Gloria architecture: one Expo app with three role route groups talking to a Spring API through a typed fetch layer, Auth0 for identity and Firebase for push.

Difficult problems

Refresh races. Three screens mounting at once, each receiving a 403 on an expired token, each calling refresh. With rotating refresh tokens the second call invalidates the first and the user is logged out for no reason. The fix is small: one in-flight refresh promise that every caller awaits.

// contexts/AuthContext.tsx (shape, not the full file)
let inflight: Promise<Tokens> | null = null;
async function refreshToken() {
  if (inflight) return inflight;
  inflight = doRefresh().finally(() => { inflight = null; });
  return inflight;
}

Which notification is actionable. The backend emits two approval-shaped events: one tells an admin there is something to review, the other tells the author what happened. They look alike and route to different screens. Getting that wrong meant a denied update opened as if it were a published post. The app now reads the authoritative approval record before deciding what to open.

Reading line counts on iOS. To offer "Read more" on long posts you need to know how many lines the text would take. With a line clamp already applied, iOS reports the clamped count, so overflow can never be detected. The fix measures once without the clamp, then clamps.

Where admin comes from. The API has both a role and a "primary administrator" flag. An audit with citations into the backend showed every admin capability is authorized on the role alone; the flag is read nowhere. Treating the flag as admin in the app would have produced buttons that always fail. The app now derives admin from the role, and the flag waits for the backend to mean something.

gloriatech.co marketing site
The public site at gloriatech.co, also maintained by the studio.

Decisions and tradeoffs

Impact

1app for staff, families, and admins
Weeklyover-the-air releases to production
0backend changes needed for native login
Back to IndexNext: Avery & Aubrey's Way Portal
Download PDF