‹ All projects

Khas Tracker - A Private, Encrypted Life Tracker

Try the demo: khas.tracker.muhammad-khas.com. Tap Try the demo on the sign-in screen. It runs on about 400 days of made-up data that never leaves your browser. Real accounts are invite-only.

Why I built it

I wanted one app for everything I try to keep up with: home and relationship check-ins, wellbeing, make-up (qadha) prayers and fasts, food, training, weight and blood pressure, and goals. Existing apps each cover a slice, and almost all of them keep your data in plain text on someone else's server. So I set three rules first:

  • Private by design. Not "we promise not to look." The server should be unable to look.
  • Cheap to run. Pay for what I use, with alarms if something misbehaves.
  • Editable by anyone. Every section optional; every list, color, and program changeable.

Up front: I'm not a developer. I built this by describing what I wanted to Claude Code, testing what came back, and pushing back until it was right. The decisions were mine; the typing mostly wasn't.

The security model

  • Everything is encrypted on the phone before it's sent anywhere, with AES-256-GCM and a random 256-bit data key. Each record is bound to its user and its own name, so records can't be swapped between accounts or slots.
  • The data key is wrapped twice: once by your passphrase (PBKDF2-SHA256, 600,000 iterations) and once by a recovery code. Lose both and the data is gone. Nobody can recover it, including me and AWS.
  • Keys in the browser are non-extractable, and the app auto-locks when idle.
  • Accounts are invite-only, an authenticator-app code (TOTP, no SMS) is mandatory, and there are no third-party scripts or trackers, enforced by a strict Content Security Policy.
  • The API takes your identity only from the verified sign-in token, never from the request. Automated tests check that before every deploy.

As the admin, I can see an account's email and when it signed in. I can't see anything inside it.

What runs on AWS

Everything is defined as code with the AWS CDK (TypeScript) in one stack:

PieceWhat it does
S3 + CloudFrontPrivate bucket for the app files, behind a CDN that also forwards /api/* and adds security headers.
Route 53 + ACMThe domain and its HTTPS certificate.
CognitoInvite-only sign-in with required authenticator codes.
API Gateway + LambdaA tiny four-route sync API with a JWT check, throttled low so abuse can't run up the bill.
DynamoDBHolds only encrypted blobs, with point-in-time recovery.
AWS BackupDaily backups for 35 days, plus a copy in a second region for 3 years.
BudgetsEmails me if spending heads past a small monthly limit.
IAM + GitHub OIDCGitHub deploys with short-lived tokens, so no AWS keys are stored in GitHub.

The front end is plain HTML, CSS, and JavaScript, works offline, and syncs when there's a connection. Every push to main tests and deploys in about five minutes.

How it got built

I wrote a spec and built it in small phases, each in its own fresh session, testing each piece in a local demo mode that fakes sign-in and the API. Two lessons: build small and test each piece, and read every "done" report skeptically. A few sessions said features were tested when they hadn't actually been clicked through, so I started checking every tab myself.

Hiccups worth sharing

  • GitHub couldn't sign in to AWS. My OIDC trust rule allowed owner/repo, but GitHub identified the repo with ID numbers added. Fixed by accepting both forms, still locked to one repo's main branch.
  • "Access denied" on Billing. I'd locked the account down properly (root MFA, admin user for daily work), but AWS hides billing from IAM users by default. One root sign-in to enable IAM billing access fixed it.
  • A surprise load balancer bill. Elastic Load Balancing was my biggest cost, on an app that doesn't use one. The likely cause was a leftover from an old tutorial. Lesson: delete tutorial resources, and set a budget alarm on day one.
  • A bug that ate my checkmarks. Default checklist items got new ids on every reload, so past ticks vanished. Defaults are now saved on first use.

What I'd do differently

  • Set up billing access and a budget before anything else.
  • Test on a real phone sooner.
  • Write the deploy guide as I go. It ended up being one of the most valuable parts of the project.