Skip to content

Project

Two Tails

An iPhone and iPad app for one household: shared lists, Google Calendar, workouts, and one screen for what today needs. List and workout edits save on the device first, then sync between members.

In development · Not on the App Store yet

Visit the Two Tails website

What This Demonstrates

The gap between saving an edit on one phone and sharing it with the household: the app says so when it is offline, uploads are waiting, or a change could not be saved or shared.

The App

Today
One screen for what is due, today's events and classes, and the day's workout. Fixed rules flag overlaps. A next-7-days view shows light days and moves an item only after you confirm.
Shared Lists
Keep groceries, chores, and errands in checklists the household can edit. Items can have due dates, notes, links, and repeat schedules. Shopping lists group by store section.
Calendar
Each member connects their own Google account and picks one calendar to view, create, and edit events. Google Calendar tokens and events stay on that device and in Google, with one exception: a class marked attended becomes a workout the household can see, with its title, times, and event id.
Workouts and Apple Health
Record sets, reps, weight, time, or distance, and see what you did last time while logging the next one. Connecting Apple Health is optional and read-only. It brings in workouts, daily steps, and each workout's active energy and average heart rate.

An Edit Should Not Wait for Wi-Fi

Lists and workouts save on the device first. Pending changes stay queued until the server accepts them. If the server rejects one as invalid, it leaves the queue and stays only on that device. A status line stays quiet while all is well and appears when the device is offline, uploads are waiting, or a change could not be saved or shared.

How It Is Built

  1. Save on the Device

    • Native SwiftUI app
    • Full local copy of household records

    An edit does not wait for a network connection.

  2. Queue the Change

    • Pending changes kept on the device
    • Retry after a connection failure

    The status line stays quiet while all is well. It appears when the device is offline, uploads are waiting, or a change could not be shared.

  3. Sync the Household

    • Production backend on AWS
    • Signed-in household members
    • Lists, workouts, and imported health data

    Push pending changes, then pull the household change feed. The server checks membership on every request and merges field by field. Calendar events take a separate path through Google.

The path for records the household shares.

What the Household Sees

  • Everyone in a household can see all fitness and health data that any member brings into Two Tails, including imported Apple Health data.
  • Anyone who joins later can also see the lists and workouts from before they joined.
  • The app says so before someone joins a household or connects Apple Health.

The product website holds its privacy policy, health data policy, and support information.

Current Limits

  • Two Tails is not on the App Store, so there is no public download yet. The website and the production backend are live; the app is not released.
  • Automated checks run on simulators and a local backend. They do not show how the app behaves on a physical iPhone or iPad, or with live Google, Apple Health, and notification services.
  • Physical-device testing is a separate step and is still open. Apple Health import has not run on a device yet.
  • Live sign-in and the production backend have no recorded end-to-end run from a device yet.

The app source is private; the files below build this portfolio page.

Inside the Build

The files that do the work, the choices behind them, and excerpts taken from the source each time the site builds.

Key Files

  • apps/portfolio/src/pages/TwoTails.tsx

    The portfolio page, product link, household visibility, and current limits

  • apps/portfolio/src/content/two-tails.ts

    Workflow descriptions, the sync diagram, and the visibility and limits text

  • apps/portfolio/src/content/projects.ts

    Discovery through the project library and search

  • docs/specs/two-tails.md

    The source record for the statements on this page

Decisions

  • Saving lists and workouts on the device first

    Over waiting for the server before saving an edit: household tasks still need to work without a connection.

  • A separate Google Calendar connection on each device

    Over copying calendar events into household sync: the server never receives Google Calendar tokens or calendar events; a class marked attended crosses over only as a workout.

  • A next-7-days plan built from fixed rules

    Over adding a generated note to the plan: the generated note failed its evaluation, so the plan was built without it.

The Household Sync Flow

apps/portfolio/src/content/two-tails.ts · line 27 · TypeScript

export const twoTailsArchitecture: FlowStage[] = [
  {
    stage: 'Save on the Device',
    parts: ['Native SwiftUI app', 'Full local copy of household records'],
    note: 'An edit does not wait for a network connection.',
  },
  {
    stage: 'Queue the Change',
    parts: ['Pending changes kept on the device', 'Retry after a connection failure'],
    note: 'The status line stays quiet while all is well. It appears when the device is offline, uploads are waiting, or a change could not be shared.',
  },
  {
    stage: 'Sync the Household',
    parts: ['Production backend on AWS', 'Signed-in household members', 'Lists, workouts, and imported health data'],
    note: 'Push pending changes, then pull the household change feed. The server checks membership on every request and merges field by field. Calendar events take a separate path through Google.',
  },
];
This is the diagram definition for this portfolio page, not the private app implementation.

Explore Next

Run a weekly delivery review in a sandbox that never leaves your browser.