Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

baybay

It is 3am. The baby is finally down, and you cannot remember which side the last feed was on, how much of the bottle went, or when the nap before it ended. That question is what baybay answers, and nearly all it does.

Open source feed and sleep tracking for the first year, built by a parent who got tired of apps that wanted an account, a subscription and a copy of the baby's data before they would show a bottle timer. Log a feed in two taps. Start a nap with one. See the pattern on a dashboard that fits on a phone at 3am. That is the whole product.

If someone runs it for you, all you ever touch is a web page. If you can paste five commands into a terminal, you can be that someone — Getting started is the whole install.

Using it

One screen does the daily work. Two big buttons log a feed or a sleep; an ongoing nap sits at the top with its running time until it ends. Under those, Recent lists the last couple of days, where the pencil edits an entry and the × removes it — a 3am mis-tap is a ten-second fix.

  • Feed opens a sheet with your usual amounts one tap away — the presets are yours to change in Settings — and room for a note when something is worth remembering.
  • Sleep is a stopwatch for naps: start it, come back whenever the baby is up. At bedtime, Night logs the whole stretch.
  • Dashboard answers what parents actually ask — how long since the last feed, when they last slept, what a typical day looks like — then charts the patterns over recent weeks and lays out the last seven days in detail.
  • Settings holds the household: children, the shareable code, bottle presets, the daily rhythm, signed-in devices, export, and the button that deletes everything for good.

Open your household's address on a phone and Add to Home Screen installs it like an app, icon and all. Lost the address? The front page emails it back to you.

Your data is a file

Everything one family logs lives in exactly one SQLite file:

storage/households/quiet-heron-4821.sqlite

Nothing about that family lives anywhere else. This is not a policy, it is the schema — which makes two promises cheap to keep and easy to verify:

  • Export hands you that file, as a consistent snapshot that opens in any SQLite browser, with CSV and JSON if you would rather have those.
  • Delete unlinks it. There are no rows scattered across a shared table to chase, and no soft-delete flag quietly retaining what you asked to remove.

Run it yourself and even that file never leaves your machine.

Requirements

  • PHP 8.2 or newer, with pdo_sqlite and openssl
  • A web server pointed at public/ — or none at all; PHP's built-in server is enough to try it

No Composer, no npm and no build step. Two third-party files are checked in rather than fetched:

  • public/assets/lib/chart.js — Chart.js 4.5.0, MIT, which draws the dashboard charts.
  • public/assets/fonts/JetBrainsMono-VariableFont_wght.ttf — JetBrains Mono, SIL Open Font License 1.1, whose terms are in OFL.txt beside it.

Nothing else is vendored, and nothing is loaded from a CDN — the Content-Security-Policy would refuse it.

Getting started

git clone https://github.com/webdevday/baybay.git
cd baybay
cp .env.example .env

Open .env and set the address the app will be served from. To try it on your own machine:

DOMAIN_APP=localhost:8000
URL_SCHEME=http

Then:

php bin/baybay key:generate
php bin/baybay migrate
php bin/baybay household:create --child="Wren"

That prints a URL, a household code and the path of the new data file. Serve it and open the URL:

php -S localhost:8000 -t public bin/dev-router.php

The router script only matters to PHP's built-in server — it serves real files and hands everything else to the app, which Apache and nginx do themselves. For Apache, point a vhost at public/; the .htaccess files shipped here do the rest. For nginx, start from deploy/nginx.example.conf.

A brand new household is empty, and an empty dashboard does not show much. To see what it looks like in use before trusting it with your own nights:

php bin/baybay household:seed <slug>

With no mail server configured, magic links are written to storage/logs/mail.log — follow them straight out of the log. That is the MAIL_DRIVER=log default, and the right setting until you deploy somewhere that can actually send mail.

Sharing access

Each household has its own permanent URL. Two ways in:

  • Magic link — the owner enters their email and clicks a link. No password to forget while holding a baby.
  • Household code — a short phrase like moss-lark-42 that a partner, grandparent or sitter types once. Rotate it from Settings and every session that joined with the old code is signed out.

The URL is the household's address, not its key. Both routes still require a session, so a link forwarded to the wrong person does not hand over the data.

The daily rhythm

Optional, and off until somebody asks for it. Set a schedule and the log screen gains one line — what is next and how long until it — that opens the right sheet when tapped, with Night already picked if the next thing is bedtime. Items tick themselves off as matching feeds and sleeps are logged; nothing is flagged as missed, because a skipped nap is a normal Tuesday.

Six age-based templates are built in, from a newborn's three-hourly day to a single midday nap. Applying one asks for the hour your baby actually wakes and moves the whole day to match, so a routine arrives in one tap rather than fourteen. Templates are copied in when chosen, so improving one in a later release never rewrites a schedule a parent has already adjusted. From there it is yours: rows are added, retimed, renamed and deleted in Settings, and a household can keep more than one rhythm and switch between them.

The command line tool

Administration happens through one script, run from the install directory. php bin/baybay help prints the same list with more detail.

Setup

php bin/baybay key:generate     Create APP_KEY and write it into .env
php bin/baybay migrate          Apply pending migrations to the control
                                database and every household
php bin/baybay migrate:status   Show what each database has applied

key:generate refuses to replace a key that is already set, because doing so signs every household out and makes every household code unreadable. Clearing the line by hand is the deliberate step it asks for first.

Households

php bin/baybay household:create   Create one, with its own data file
    --name="The Smiths"               household name
    --child="Wren"                    first child's name
    --tz=Europe/Lisbon                IANA timezone
php bin/baybay household:list     List every household
php bin/baybay household:code <slug>   Show the shareable code
php bin/baybay household:seed <slug>   Fill it with sample feeds and naps
php bin/baybay household:purge <slug>  Delete a household's data, for good

Maintenance

php bin/baybay prune            Remove expired demos, sessions and tokens —
                                the one cron should run
php bin/baybay prune <slug>     Remove one demo, by name
php bin/baybay prune --all      Remove every demo, expired or not
php bin/baybay test             Run the test suite

The tests build a disposable install under the system temp directory, so no run of the suite can touch a real household.

Configuration

Everything is in .env, and it is read on every request — a changed value takes effect on the next page load, with nothing to rebuild or restart. .env.example documents every key at length and is worth reading in full before changing one; this is the short version.

Key Default What it does
APP_ENV local local or production. Production tightens errors, cookies and analytics.
APP_DEBUG true Verbose errors in the browser. Must be false in production.
APP_KEY (empty) Signs sessions, magic links and household codes. Set once by key:generate, then guard it — see Backups.
APP_TIMEZONE America/Denver Only the default offered at signup; each household keeps its own.
DOMAIN_APP baybay.local Where households live, no scheme. This becomes part of every household's permanent URL, so pick it before inviting anyone.
URL_SCHEME https https in production, http on your own machine.
BASE_PATH (empty) Subdirectory prefix, only if the app is not at the web root.
DOMAIN_APP_ALIASES (empty) Extra hostnames to answer on in development — a LAN address, so a phone on the same Wi-Fi can open it. Empty in production.
DOMAIN_MARKETING (unset) Only if a separate site fronts this install. Left unset it equals DOMAIN_APP and every cross-site affordance hides itself — the right answer for self-hosting.
CONTACT_EMAIL (empty) Where a parent can reach whoever runs the install. Blank hides the affordances.
ANALYTICS_APP_ID (empty) Blank means no analytics and no third-party request at all — what a fork should keep. Every page it would measure is a named child's feed and sleep record; .env.example spells out what setting it means.
SESSION_LIFETIME_DAYS 90 How long a sign-in lasts. Deliberately long; refreshed on each visit.
MAGIC_LINK_TTL_MINUTES 30 How long an emailed link stays valid.
MAIL_DRIVER log log writes mail to storage/logs/mail.log, mail uses the server's sendmail, smtp talks to a relay using the MAIL_SMTP_* keys.
MAIL_FROM_ADDRESS / MAIL_FROM_NAME The sender on magic links and notices. Delivery depends on the domain's SPF, DKIM and DMARC records, not on baybay.

Backups

Each family's data is one file, so a lost file is a lost account with nothing to reconstruct it from. Do not copy those files with cp while the site is serving — a copy taken mid-write can be torn, and the -wal sibling beside each database holds committed data that has not been folded back in yet.

bin/backup.sh

Takes a consistent snapshot of the control database and every household, writes storage/backups/YYYY-MM-DD-HHMM.tar.gz, and deletes archives older than 30 days — set BAYBAY_BACKUP_KEEP_DAYS to change that. It resolves its own install root, so it needs no editing and works from cron:

41 3 * * * /path/to/baybay/bin/backup.sh >> /path/to/baybay/storage/logs/backup.log 2>&1

Restoring one family is copying their .sqlite back into storage/households/. There is nothing else to it — no rows scattered across shared tables.

Back up .env too, privately and separately from the data. It holds APP_KEY, and restoring households without their key leaves every household code unreadable and signs everyone out.

Upgrading

git pull
php bin/baybay migrate

Every database records which migrations it has applied, and any that are behind catch up on the next request. There is nothing to edit per household.

Layout

public/            Web root — the only directory a server should expose
app/               Application code (PSR-4 under Baybay\)
  Http/              Routing, requests, responses
  Controllers/       Request handlers
  Services/          Recent activity, daily totals, schedules, preferences, charts
  Domain/            Households, sessions, sign-in, sample data
  Database/          Connections and migrations
  Support/           Config, clock, crypto, mail, strings
resources/views/   Page templates and layouts
database/          Migrations, and the control database once created
storage/           Household data files, backups and logs
deploy/            Example nginx config
tests/             The suite behind `php bin/baybay test`
bin/baybay         Command line tool
bin/backup.sh      Consistent snapshot of every database
bin/dev-router.php Router for PHP's built-in server, development only

Two databases, deliberately. database/control.sqlite knows which households exist and who may sign in. It holds no logged baby data of any kind. Everything a parent actually records lives in that household's own file under storage/.

There is no billing in here

This repository is the application and nothing else. There is no payment code to leave switched off, no landing page, and no dependency on a payment provider — which is why the install above has no Composer step. Nothing is gated, metered or waiting to be unlocked: every feature baybay has is in this repository, running on your own server.

That goes for the schema too. There is no subscription table sitting empty, no invoice ledger and no customer id anywhere in database/migrations/ — the control database knows which households exist and who may sign in, and stops there. A deployment that does take money registers its own migrations at boot and keeps them in its own repository, so nothing about billing has to be carried by, or explained to, the people running this.

License

MIT. See LICENSE.

About

Open source, self-hosted baby tracker. Feeds and naps, logged in two taps

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages