Home Projects Roadmap Blog GitHub Contact
Active Mobile · Web · AWS serverless

Notle

A shared notes app for Android, iOS and web: notes live in "spaces" shared with the people you live or travel with, plus a private area only you can see. Expo/React Native client on a serverless AWS backend defined entirely as code.

Expo / React NativeTypeScriptAWS CDKCognitoLambdaRDS Postgres

Objective

Build a real, production-shaped shared-notes product end to end: a cross-platform mobile client, a serverless API with proper authentication and authorisation, relational storage for sharing permissions, and the release, compliance and branding work needed to put it in front of real users. Version 1 is deliberately turn-based sharing (no live co-editing cursors).

Current status

The full app design is implemented on Android and backed by a live AWS backend: real sign-up/sign-in, spaces and private notes, invite-by-join-code, inline editing, checklists, profile photos, offline support with conflict detection, and an unseen-activity indicator, all stored in Postgres via a Lambda API. App and infrastructure live in private GitHub repos. A branded self-service password-reset page and a public coming-soon marketing page are both live on the product's own domain.

Not yet release-ready. Production hardening of the infrastructure (data-retention and backup settings, removing debug tooling, tightening CORS, moving auth back to SRP-only) is tracked in a dedicated production-readiness runbook, and iOS is waiting on a cloud build pipeline.

Architecture

Expo app (Android / iOS / web) → Cognito (accounts, JWT) → HTTP API Gateway with JWT authoriser → Lambda (Node/TypeScript API) → RDS Postgres in isolated private subnets
ComponentRoleNotes
Amazon CognitoSign-up, email verification, sign-in, password resetValidated at the gateway, so the API never handles raw tokens
HTTP API Gateway + LambdaREST API for spaces, notes, checklists, members, activityChosen over REST API Gateway for cost and built-in JWT auth
RDS PostgresNotes, spaces, membership, activity logChosen over DynamoDB because sharing permissions are relational
S3 + CloudFrontProfile photos, password-reset pageDirect-to-S3 uploads via presigned URLs, with size and type enforced in the signature
VPC endpointPrivate access to Secrets ManagerNo NAT gateway, keeping fixed monthly cost low
AWS CDK (TypeScript)All of the above as infrastructure-as-codeChanges reviewed with cdk diff before deploy

Completed work

  • Designed the architecture up front and ported a complete UI prototype (home, shared/private lists, space detail with activity feed, note and checklist views, search, settings, account, share and delete flows) into the real Expo app.
  • Built the full serverless backend in CDK: Cognito, a Lambda API behind HTTP API Gateway, RDS Postgres in isolated subnets, and S3/CloudFront distributions, with schema migrations run as an idempotent Lambda.
  • Shipped real CRUD for spaces, notes and checklists, invite-to-space via join codes, inline touch-to-edit with save-on-blur, owner-only deletion enforced server-side (verified with real 403s, not just hidden buttons), member lists and drag-to-reorder spaces that follows the user across devices.
  • Added offline support: cached reads, a queued write log replayed on reconnect, and revision-based conflict detection so a clash with another device surfaces as a notice instead of a silent overwrite.
  • Added profile photos via presigned S3 uploads, then hardened them with a 5 MB ceiling and JPEG/PNG-only enforced in the signature itself, which also closed a gap where content type had never actually been enforced.
  • Shipped a branded self-service password-reset page on a custom subdomain (ACM certificate, CloudFront, DNS managed through Cloudflare) and a custom 404.
  • Diagnosed several non-obvious issues: Lambda-in-VPC timeouts caused by a missing Secrets Manager endpoint, duplicate rows from a fan-out SQL join, an auth flow incompatible with Expo Go, and an HTTPS handshake failure caused by a router port-forward mismatch behind Cloudflare.
  • Self-hosted a public coming-soon marketing page on the homelab with hardened nginx security headers and an atomic swap-in deploy script with rollback.
  • Produced supporting release material: a production-readiness runbook, privacy policy, terms, app-store data-safety and privacy declarations, a compliance checklist and a financial model.

Risks and open items

  • The infrastructure stack still uses development-stage retention settings; data-retention and backup policies must change before any real user data is stored.
  • A debug seed/cleanup action and a wide CORS policy are still present and need removing or tightening before release.
  • The latest batch of features passes type-checking and API-level verification but has not yet been tested on physical hardware.
  • iOS build, keyboard handling and Apple sign-in are untested until a cloud build workflow is in place.
  • The waitlist on the marketing page is intentionally disabled until privacy and data-protection registration work is complete.

Next actions

  1. Work through the production-readiness runbook: retention policies, backups, removing debug tooling, SRP-only auth.
  2. Test the latest feature batch on a real device.
  3. Finish remaining CRUD (per-note sharing, link sharing, removing members, editing checklist items) and wire up search and export.
  4. Live refresh when someone else edits a note, and a merge UI for checklist conflicts.
  5. Add social login (Google/Apple) and set up an EAS cloud build for iOS.