Alam Sawame

Web app Developer

JP / EN / PT

Open for work

Have you ever felt this in everyday life?

Tracking each expense is tedious, it’s hard to grasp the total cost, and the more information you gather, the harder it becomes to decide—so nothing moves forward.

To solve that, I built Kaimono, a web app for shopping planning and budget management.


Project Overview

  • Project type: Personal SaaS / portfolio project
  • Role: Solo full-stack engineer
  • Stage: Active development
  • Users: No production users yet
  • Core focus: multi-tenant architecture, auth flows, i18n-aware routing
  • Stack snapshot: Next.js, TypeScript, Prisma, PostgreSQL, NextAuth/Auth.js, Zod

Proof (current build)

  • Subdomain multi-tenant routing with tenant isolation
  • RBAC enforced on server actions (OWNER/ADMIN/MEMBER)
  • 3 locales: EN / JA / PT-BR (i18n-aware routing)
  • Server-side validation on all mutations (Zod)
  • Prisma schema: 13 models / 4 enums (PostgreSQL)
  • Vercel deploy with preview environments + Prisma migrations

Key Features

Kaimono is built around three main features:

  1. Shopping management
    A simple to-do list for everyday necessities.
    It lets you track “things you need to buy” in the same place you manage spending—serving as the entry point for the app.

  2. Planned items management
    For items that are typically more expensive than essentials and require budgeting and intention before purchase.

  3. Project management (core feature)
    Groups planned items by purpose and visualizes the total budget per project.
    Example: redecorating a room (carpet, lighting, houseplants, etc.).
    You can also save links per item so you can quickly jump back to what you were considering.

On top of that, Kaimono uses a subdomain-based multi-tenant architecture to isolate user data so it isn’t visible to others.

team.p0r6iz89.cloud

  • team is the subdomain
  • p0r6iz89.cloud is the main domain.

If you want to collaborate, you can invite teammates from the Invitations page.


Tech Stack

My priority was to keep things as simple as possible while solving the core problem: making plans and budgets visible and easy to manage.

  • Next.js (full-stack)
  • Server Actions (server-side functions)
  • Prisma ORM + DB (e.g., PostgreSQL)
  • Zod (schema validation for server actions and form inputs)

In a previous project I used Django + React, but for smaller apps I felt the overhead of “building the frontend while constantly adjusting backend APIs” slowed development down.

So for Kaimono, I chose a structure where Server Actions talk to the database directly via Prisma, reducing friction between frontend and backend.

This helped me achieve both safe CRUD operations and consistent implementation.


Open Source

Kaimono is open source and can be run locally with npm + Docker:

npm install
docker compose up -d db
npx prisma migrate dev
npm run dev

Links:

Local URLs:

  • main app: http://localhost:3000/en
  • tenant app: http://team.localhost:3000/en

In this setup, Docker Compose starts only PostgreSQL (db service). The Next.js app runs locally with npm run dev.


How to Use

Live demo: https://p0r6iz89.cloud/home.

Kaimono is designed to make shopping decisions more intentional, collaborative, and easier to execute.


Challenges & What I Learned

At first, I started from the basics—writing clean code and satisfying TypeScript’s type system.

The first major challenge was: how to introduce multi-tenancy in a way that anyone can use.

There were faster options (e.g., adopting an auth service like Clerk and using its multi-tenant features), but I chose to implement it myself for learning and control: subdomains + middleware.

In middleware.ts, the request flow is:

  1. Locale handling: if the path is not localized, it goes through handleI18nRouting and gets normalized to locale-prefixed routes (/en, /ja, /pt-BR).
  2. Auth guard: middleware checks req.auth?.user and public paths.
    • no user + protected path => redirect to /{locale}/login
    • signed-in user on /login => redirect to /{locale}/
  3. Subdomain routing: middleware extracts tenant subdomain from hosts like team.localhost or team.example.com.
  4. Internal rewrite: if a subdomain request is missing the tenant prefix, middleware rewrites it to /{locale}/s/{subdomain}{rest}.

That rewrite keeps tenant routing invisible to users while maintaining a single App Router structure. I use Zod at the server boundary to validate input and return predictable error states.

middleware.ts Request Flow

Going forward, I’ll keep extending the app without breaking the architecture—especially to ensure that URL-based OAuth flows and i18n don’t interfere with the multi-tenant design.


Next: AI-Assisted Input

Right now, adding “Essentials” or “Planned items” requires manual input. Autocomplete could help, but I want to reduce friction further by exploring a feature that auto-fills item information from a photo—for example:

  • product name
  • category
  • estimated market price
  • URL
  • product details