A private, self-hosted web app to track your baby's daily moments, milestones, reminders, and growth.
babybook/
├── backend/
│ ├── app.py # Flask entry point
│ ├── db.py # SQLite init & schema
│ ├── utils.py # Photo upload helper
│ ├── requirements.txt
│ ├── Dockerfile
│ └── routes/
│ ├── baby.py # GET/POST baby profile
│ ├── daily.py # Daily entries CRUD
│ ├── moments.py # Milestones CRUD
│ └── reminders.py # Reminders CRUD + toggle
│
├── frontend/
│ ├── index.html
│ ├── vite.config.js
│ ├── nginx.conf
│ ├── Dockerfile
│ └── src/
│ ├── main.js
│ ├── App.vue # Root layout + sidebar
│ ├── router.js
│ ├── api.js # All API calls (axios)
│ ├── assets/style.css # Global design system
│ ├── stores/
│ │ └── baby.js # Pinia store (days old, etc.)
│ └── views/
│ ├── Dashboard.vue
│ ├── Daily.vue
│ ├── Moments.vue
│ ├── Reminders.vue
│ └── Profile.vue
│
└── docker-compose.yml
Method
Endpoint
Description
GET
/api/baby/
Get baby profile
POST
/api/baby/
Create or update profile (FormData)
Method
Endpoint
Description
GET
/api/daily/
List entries
POST
/api/daily/
Create entry
PUT
/api/daily/:id
Update entry
DELETE
/api/daily/:id
Delete entry
GET
/api/daily/weight-history
All weight records
Method
Endpoint
Description
GET
/api/moments/
List moments
POST
/api/moments/
Create moment
PUT
/api/moments/:id
Update moment
DELETE
/api/moments/:id
Delete moment
Method
Endpoint
Description
GET
/api/reminders/
All reminders
GET
/api/reminders/upcoming
Next 5 due
POST
/api/reminders/
Create reminder
PUT
/api/reminders/:id
Update reminder
PATCH
/api/reminders/:id/toggle
Toggle done status
DELETE
/api/reminders/:id
Delete reminder
-- Single-row baby profile
CREATE TABLE baby (
id INTEGER PRIMARY KEY , -- always 1
name TEXT NOT NULL ,
birth_date TEXT NOT NULL , -- ISO 8601: YYYY-MM-DD
gender TEXT ,
blood_type TEXT ,
birth_weight REAL , -- kg
birth_height REAL , -- cm
notes TEXT ,
photo TEXT , -- stored filename
updated_at TEXT DEFAULT (datetime(' now' ))
);
CREATE TABLE daily_entries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL ,
photo TEXT ,
weight REAL ,
notes TEXT ,
created_at TEXT DEFAULT (datetime(' now' ))
);
CREATE TABLE moments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL ,
description TEXT ,
date TEXT NOT NULL ,
photo TEXT ,
emoji TEXT DEFAULT ' ⭐' ,
created_at TEXT DEFAULT (datetime(' now' ))
);
CREATE TABLE reminders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL ,
description TEXT ,
date TEXT NOT NULL ,
type TEXT DEFAULT ' general' , -- general | vaccination | doctor
is_done INTEGER DEFAULT 0 ,
created_at TEXT DEFAULT (datetime(' now' ))
);
Running Locally (Development)
cd backend
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
python app.py
# → http://localhost:5000
cd frontend
npm install
npm run dev
# → http://localhost:3000 (proxies /api → :5000)
Docker / Production (AWS Lightsail)
# Build and run everything
docker-compose up -d --build
# App is available on port 80
# Data is persisted in:
# ./backend/babybook.db (SQLite)
# ./backend/uploads/ (photos)
Deploying to AWS Lightsail
Create a Lightsail instance (Linux/Ubuntu, $5–$10/month is plenty)
SSH in and install Docker:
curl -fsSL https://get.docker.com | sh
sudo apt install docker-compose-plugin -y
Copy your project (scp or git clone)
Run docker compose up -d --build
Open port 80 in Lightsail's firewall rules
Optional: HTTPS with Certbot
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com
No authentication — this is a private LAN/VPN app
Photos are stored as files in backend/uploads/, mounted as a Docker volume so they persist across rebuilds
SQLite WAL mode is enabled for better concurrent read performance
The frontend uses a warm, editorial aesthetic — Playfair Display serif + DM Sans
All API calls go through /api/ — nginx proxies them to Flask in production