NirvanaLink

TL;DR
  • Built a serverless astrology, numerology, and feng shui app on AWS to test Lambda + CloudFormation after a coworker wouldn’t stop recommending it.
  • The standout feature: BaZi Travel — recommends vacation destinations based on your Kua compass lucky directions, so each city tells you what TYPE of luck it brings (prosperity, health, relationships, stability).
  • Includes cost-of-living data via the Apify API with DynamoDB caching so we don’t hammer the source on every request.
  • Full environment separation: dev.nirvanalink.com / beta.nirvanalink.com / nirvanalink.com, each with its own CloudFormation stack.
  • CI/CD pipeline: push to GitHub → GitHub Actions → CloudFormation deploy → Lambda code update → CloudFront invalidation.
10
API Endpoints
70+
Cities in Database
3
Environments
0
Manual Deploys

Why I Built This

This whole project started because of an old coworker who would not stop talking about Lambda and CloudFormation. Every standup, every lunch conversation — “you should try serverless,” “CloudFormation makes infra reproducible,” “you’ll never go back to managing servers.” I got tired of hearing it without having an informed opinion, so I decided to actually try it. But I wasn’t going to build another todo app. I wanted to build something I actually cared about.

I’ve always been into astrology, numerology, feng shui, and Chinese metaphysics. Not in a casual horoscope way — I mean the real systems. BaZi (八字), the Four Pillars of Destiny. Kua compass directions. Flying Star feng shui. The math behind these traditions is surprisingly precise, and I’ve always thought they deserved better than the clunky apps and spreadsheets people use to calculate them. So Nirvana Link became my playground: a place where I could combine a genuine passion for Chinese metaphysics with real cloud engineering and see how far I could push both.


How BaZi Directions Actually Work

If you’re not familiar with this system, here’s the quick version. In Chinese metaphysics, your Kua number (明卦) is a personal feng shui number derived from your birth year and gender. It places you in either the East Group or the West Group and assigns you four lucky compass directions and four unlucky ones. Each lucky direction carries a specific type of energy:

  • Sheng Chi (生氣) — your Prosperity direction. Best for career growth, wealth, and big opportunities.
  • Tien Yi (天醫) — your Health direction. Good for recovery, vitality, and physical well-being.
  • Nien Yen (延年) — your Relationships direction. Supports romance, family harmony, and meaningful connections.
  • Fu Wei (伏位) — your Stability direction. Brings personal growth, clarity, and inner peace.

One important detail: the year boundary in BaZi is not January 1st. It’s Li Chun (立春), the Start of Spring, which falls around February 4th each year. If you were born on January 20th, 1990, your BaZi year is actually 1989. Getting this wrong throws off every downstream calculation, so the app handles it correctly from the start.

Traditionally, people use Kua directions to orient furniture, pick bedrooms, and position desks. That’s useful, but I wanted to think bigger. What if you could apply these directions to the entire globe? What if the app could tell you that a particular city sits in your Sheng Chi direction — and that traveling or relocating there puts the wind at your back for prosperity?


The Travel Feature in Action

This is the heart of Nirvana Link and the feature I’m most proud of. BaZi Travel takes your Kua number and your current city, calculates the compass bearing from you to every city in the database, and maps that bearing to one of your eight directions. Then it tells you exactly what kind of luck each destination brings.

Let me walk through a real example. Say you’re a Kua 1 person living in Los Angeles. Your lucky directions are Southeast (Sheng Chi / Prosperity), East (Tien Yi / Health), South (Nien Yen / Relationships), and North (Fu Wei / Stability).

When the app calculates bearings from LA to every city in the database, some interesting results pop out. Vietnam and Taiwan fall in the Southeast — that’s your Nien Yen (延年) direction, relationships. If you’ve been wanting to deepen connections or meet someone meaningful, those destinations are energetically aligned for it. Georgia the country sits to your North — that’s Fu Wei (伏位), stability and personal growth. And Medellín, Colombia lands in the Southeast as well — Sheng Chi (生氣), prosperity.

The API response for a destination looks like this:

# BaZi Travel: Medellín result for Kua 1 from Los Angeles
{
  "city": "Medellín",
  "country": "Colombia",
  "bearing": 131.4,
  "compassDirection": "SE",
  "kuaDirection": "Sheng Chi",
  "kuaDirectionChinese": "生氣",
  "meaning": "Prosperity",
  "distanceKm": 4153,
  "costOfLiving": {
    "monthlyBudget": "$1,100 - $1,600",
    "vsOrigin": "-58% vs Los Angeles"
  }
}

Every city in the response carries that context. You’re not just getting a list of places — you’re getting a list of places annotated with what they mean for you specifically. Two people with different Kua numbers sitting in the same city will get completely different direction mappings for the same destination.


Cost of Living Integration

A travel recommendation isn’t very useful if you can’t afford the destination. I integrated cost-of-living data using the Apify API, which scrapes and normalizes living cost comparisons across cities worldwide. The app pulls monthly budget estimates, rent averages, and a percentage comparison against your origin city.

Since Apify calls aren’t free and the data doesn’t change daily, I cache the results in DynamoDB with a TTL. The first request for a city’s cost data hits Apify, stores the result, and every subsequent request for the next 30 days pulls from the cache. This keeps API costs low and response times fast — a DynamoDB read is single-digit milliseconds versus a few seconds for a fresh Apify call.

The result is that when you see Medellín in your travel recommendations with “Sheng Chi — Prosperity” next to it, you also see that your monthly budget there runs about 58% less than Los Angeles. The metaphysics tells you the direction is right; the cost data tells you the finances are right too.


The Serverless Stack

Here’s where my coworker’s evangelism finally paid off. The entire backend runs on serverless AWS services — no EC2 instances, no containers, no servers to patch at 2am.

  • AWS Lambda handles all the computation: BaZi calculations, Kua number derivation, compass bearing math, cost-of-living lookups. Each function is focused and independently deployable.
  • API Gateway exposes 10 REST endpoints, from /numerology to /bazitravel to /fengshui.
  • DynamoDB stores the travel city database (70+ cities with coordinates, element mappings, and cached cost-of-living data).
  • S3 hosts the static frontend — HTML, CSS, and JavaScript with no server-side rendering needed.
  • CloudFront sits in front of everything for CDN caching, HTTPS termination, and Origin Access Control so the S3 bucket stays fully private.

The whole thing is defined in a single CloudFormation template (main-stack.yaml). Every resource — every Lambda, every IAM role, every API route, the DynamoDB table, the CloudFront distribution — is codified. No clicking around in the AWS console. If I need to tear it all down and rebuild from scratch, it’s one command.

# Deploy the full stack to production
make cf-deploy ENV=prod

That single command validates the template, packages the Lambda code, creates or updates the CloudFormation stack, and waits for completion. My coworker was right — once you define infrastructure as code, going back to manual console work feels reckless.


Environment Separation and CI/CD

I run three fully isolated environments, each backed by its own CloudFormation stack:

  • dev.nirvanalink.com — where I break things freely
  • beta.nirvanalink.com — where I validate before going live
  • nirvanalink.com — production

Each environment has its own S3 bucket, its own API Gateway stage, its own Lambda functions (name-suffixed with the environment), its own CloudFront distribution, and its own DynamoDB table. A bad deploy to dev cannot touch production. This is not a shared staging situation — it is complete isolation.

Deploys are fully automated with GitHub Actions. The workflow maps branches to environments so there’s zero ambiguity about what goes where:

# .github/workflows/deploy.yml
on:
  push:
    branches:
      - develop    # → deploys to dev.nirvanalink.com
      - beta       # → deploys to beta.nirvanalink.com
      - main       # → deploys to nirvanalink.com (prod)

jobs:
  deploy:
    steps:
      - make cf-deploy ENV=${{ env.TARGET_ENV }}
      - make deploy-lambdas ENV=${{ env.TARGET_ENV }}
      - make cf-invalidate ENV=${{ env.TARGET_ENV }}

Push to develop and it deploys to dev. Push to beta and it deploys to beta. Merge to main and it deploys to production. Each job runs cf-deploy to update the CloudFormation stack, deploy-lambdas to push the latest function code, and cf-invalidate to bust the CloudFront cache so users see the changes immediately. Zero manual deploys. Zero “I forgot to update prod.”


What’s Next

I have a growing list. The city database is at 70+ right now, but I want to push it past 150 — more coverage in Africa, Central Asia, and Eastern Europe. I’m also working on a BaZi compatibility feature that compares two people’s Four Pillars to assess relationship compatibility, which would pair nicely with the Nien Yen travel recommendations. And I want to add annual forecast overlays — because your lucky directions remain constant, but the Flying Stars change every year, and some years a normally great direction gets afflicted by visiting stars.

The infrastructure side is in good shape. The CI/CD pipeline means I spend my time writing features instead of deploying them. CloudFormation means I can spin up a new environment in minutes if I ever need a fourth one for testing. And the serverless model means I pay essentially nothing when nobody is using the app and scale automatically when they are.

Mostly, though, I just enjoy working on this. It’s the rare project where the thing I’m building is also the thing I’d use as a consumer. When I’m planning my next trip, I actually check my own Kua directions first. That’s the best kind of side project — one where you’re your own first user.


Explore Nirvana Link

Astrology, numerology, feng shui, and BaZi travel recommendations — built on serverless AWS.

Explore Nirvana Link