---
title: "Today and calendar"
description: "Personal Day, Universal Day, moon illumination via astronomy-engine, local ?date=, pack /calendar, and n9life_council_log."
locale: "en"
---
# Today and calendar

N9Life's "today" for a signed-in member is the Cosmic Mirror. Pack `/today` still computes a public-ish day view (Universal Day, moon, system cards) and accepts **`?date=YYYY-MM-DD`** through `parseCivilDateParam`. On this clone that route **redirects to `/n9`**, so members see the panel instead. Pack `/calendar` remains the multi-day strip of labeled cards.

## Personal Day versus Universal Day

Pythagorean **Universal Day** is the civil date reduced without a birth date. **Personal Day** needs birth date plus the target civil date. Mirror mood is keyed (`dayThemeKey`, `moonMoodKey`) with an English `text` fallback from `dailyMood()`.

The today API takes the device local civil date as `?date=YYYY-MM-DD`. `buildTodayForUser` resolves that string (or the profile timezone's current date, then UTC) to a noon-UTC `Date` so the day does not flip with timezone offsets in the engine. Personal Day used to jump at 03:00 Kyiv when `new Date()` was used as UTC; the query param is the fix for the panel.

## Moon

`lib/numerology/celestial.ts` prefers Layer 1 `moonIllumination(utc)` from `lib/astro/ephemeris.ts` (`astronomy-engine` `Illumination(Body.Moon)`). Steps include `source: astronomy-engine` and the illumination fraction in `[0, 1]`. If that adapter throws, the function falls back to mean lunation from the J2000 new-moon epoch `2000-01-06T18:14:00Z` and labels the path `lunation-fallback`. Phase names are the eight keys under `evolvement.meanings.moon.*`.

## Calendar cards

`lib/evolvement/daily-calendar.ts` builds one card per ready system plus topic councils. Headlines are **keys** (`calendar.headlines.*`) with params (day number, hall id, arcana). It no longer concatenates English like `Life Path 7 / Day 3` as the only representation. Families come from `council-mappings.json`, not from undeclared constants in the TypeScript file.

Pack `/calendar` renders those cards through `SystemSummaryCard` and `keyedText`. Status `needs_input` maps to `status.needsInput`.

## Council log

`GET /api/n9life/numerology/today` upserts `n9life_council_log` (`user_id`, `date`, `topic`, `family`, `agreeing[]`, `differing[]`, optional `synthesis`). Primary key is `(user_id, date, topic)`. The panel can show a seven-day strip from that table once the migration is applied. `synthesis` stays empty while `aiSynthesis` is false.

> **Info**
> `chart_json.todaySample` stored at profile upsert is stale by design. Live Personal Day always comes from `buildTodayForUser` / `computeCharts` with an explicit target date.

  
- [n9life/cosmic-mirror](/docs/n9life/cosmic-mirror.md) — Same-workflow: panel fetches this API

  
- [n9life/numerology](/docs/n9life/numerology.md) — Deep-dive: Personal Day math

  
- [n9life/knowledge-council](/docs/n9life/knowledge-council.md) — Next-step: how today_practice is voted
