Maaleto - Life Management Platform
A backend-first life-management platform — finance, tasks, habits and a Jalali calendar behind one API that the web app, an Android client and AI agents all consume unchanged
Overview
Maaleto is a backend-first life-management platform — finance, tasks, habits, a Jalali calendar, notes, reports and AI — sitting behind a single API. In this architecture the website is only "Client #1": an Android app, desktop, a Telegram bot, AI agents and MCP clients all have to consume the same backend without a single backend change.
The Problem
Most personal-management apps start with one client and put the business logic inside it. The second client then means rewriting half the product — and worse, maintaining two implementations of the same rule that quietly drift apart.
Balance calculation, habit streaks and kanban ordering give different answers per client the moment they live in the client.
A Persian calendar isn't a display concern. Recurrence, Iranian public holidays and reporting windows all have to be correct server-side.
Without enforced layer boundaries, importing the database "just this once" inside a UI component quietly becomes the permanent architecture.
The Solution
An npm-workspaces monorepo where the architectural boundaries are enforced mechanically rather than by convention:
packages/contracts — Zod schemas as the formal contract between the server and every client.
packages/core — the only place business logic exists, and the only place allowed to reach the database. Zero Next.js imports.
packages/db — Prisma schema and repository classes, each behind an interface so services stay testable.
apps/web — Next.js 16 App Router UI plus
/api/v1route handlers that are thin controllers only.apps/worker — BullMQ consumers and cron jobs.
mobile — a Flutter Android client consuming exactly the same API.
Those boundaries are declared with eslint-plugin-boundaries at the repo root, so importing @lifeos/db from a UI component fails lint — it isn't merely discouraged.
Modules
Auth: OTP login, short-lived JWT access tokens paired with opaque rotating refresh tokens, and session/device management.
Finance: wallets, categories, transactions and budgets, with a balance that is always derived and never stored, plus an idempotent create/update path via an
Idempotency-Keyheader.Tasks: tasks, subtasks, projects and labels, with server-owned manual kanban ordering.
Calendar: Jalali and Gregorian events with
rrulerecurrence, Iranian holiday lookup, an agenda view and a Saturday-start week grid.Habits: daily and weekly check-ins with a streak computed on read from check-in history rather than stored.
Reports & Notifications: in-app notifications, a budget-exceeded trigger fired from Finance, and a composed dashboard report endpoint.
The Outcome
All six modules ship real UI — Tailwind v4, shadcn/ui and TanStack Query, Farsi and RTL throughout.
The Flutter Android client builds for release and consumes the same API with no backend changes.
The full production stack (Docker Compose, migrations, standalone app) was smoke-deployed against a real Ubuntu 26.04 VM: all five migrations applied to a genuinely empty Postgres and a complete request-OTP → verify-OTP round trip succeeded.
Decisions that would be expensive to reverse are recorded as ADRs in
docs/decisions/, including the alternatives that were rejected and why.
Current status: the deployment pipeline is verified end to end, but no internet-facing server is provisioned yet, so there is no public live demo. The source is available at github.com/Nikosonz/lifeos.
Tech Stack
Language & contracts: TypeScript, Zod
Backend: Next.js 16 (App Router), Prisma, PostgreSQL, Redis, BullMQ
Frontend: React, Tailwind CSS v4, shadcn/ui, TanStack Query
Mobile: Flutter (Android)
Infrastructure: Docker, Docker Compose, GitHub Actions