hd-prism-client/home/avalon/apps/hd-prism/apps/hdprism/cd /home/avalon/apps/hd-prism/apps/hdprism && npx next buildpm2 restart hd-prism-clienthd-prism-api/home/avalon/apps/hd-prism/apps/api/src/, compiled to dist//home/avalon/apps/hd-prism/apps/api/descriptions.sqlite because descriptionDb.ts resolves descriptions.sqlite from process.cwd() and the API runs from apps/apihdprism.apps.poofc.comreferences/environment-and-chart-storage.md — Environment calculation mapping, saved-chart/readings tables, and DB-path/storage notes/etc/nginx/sites-available/apps.poofc.com/api/ proxies to port 3005/_next/static/ must point at the live repo build output: /home/avalon/apps/hd-prism/apps/hdprism/.next/static//share/ proxies to port 3010 and remains publicly accessiblelocation / proxies to port 3010When adding any path that must be publicly accessible without auth (share links, webhooks, etc.), add a dedicated location block with auth_basic off BEFORE the catch-all location /. Example:
location /share/ {
auth_basic off;
proxy_pass http://127.0.0.1:3010;
# ... standard proxy headers
}
pm2 logs hd-prism-client or ss -tlnp._next/static from /home/avalon/apps/hd-prism/apps/hdprism/.next/static/. If it points at an old deploy directory, new builds will not actually reach users and PWA updates will appear stuck.auth_basic is enabled on location /, the installed app may open to a blank or broken screen. Keep nginx basic auth off for the main app and use app-level auth instead./share/ still needs a dedicated public location block or share pages will fail.?chart=<id> query param to track the current chart in the URL. The HdprismShell component syncs currentChartId to the URL and reads it on initial load (priority: URL param > localStorage > most recent chart).apps/hdprism/lib/ichingWheelData.js GATE_RING_ORDER identical to components/RaveMandala.tsx gate order/direction. A visually plausible reverse order is WRONG for this app.GATE_RING_ORDER, getRingFigure) are correct for the radial/library view but can be WRONG for a gate detail card. If a gate panel shows the right gate title/glyph but the wrong six-line stack, use a direct King Wen mapping keyed by gate/hexagram number for the figure and keep the mandala helpers only for the wheel visualization.activations.Design.SouthNode — Color selects the environment family and Tone < 4 determines left/right subtype. A common bug is using Design.Sun.Tone; that produces wrong environment variants. See references/environment-and-chart-storage.md.apps/api/src/strings/environments.jsonapps/api/src/strings/environmental-tones.jsonenvironment object from bodygraph.activations.Design.SouthNode
2. Attach it to the /api/bodygraph JSON response in the backend
3. Reuse that field in frontend result cards, saved-chart metadata, and PDF/report surfaces
4. For old saved charts, backfill on read from chart_json.activations.Design.SouthNode instead of forcing regenerationDesign.SouthNode.Tone; if the displayed variable and Environment orientation disagree, inspect that field first.Library button near Settings / Theme.Library opens a library home view; I Ching opens a custom SVG study view.apps/hdprism/components/LibraryView.tsxapps/hdprism/components/IChingMandalaDiagram.tsxapps/hdprism/lib/ichingWheelData.jsapps/hdprism/lib/ichingWheelData.test.mjsChartContext view modes include library and iching.node --test apps/hdprism/lib/ichingWheelData.test.mjscd apps/hdprism && npm run buildpm2 restart hd-prism-clientSidebar.tsx already had a local single/compare list toggle state; avoid naming collisions with app-wide viewMode from ChartContext (use a distinct local name like listViewMode).
5. Adding new app-level views: If you add a new top-level view (e.g. library, iching), update ChartContext.tsx in three places: the ViewMode union, scrollPositions, and visitedViews/resetScrollTracking. HdprismShell.tsx also needs explicit showXView flags so existing chart/reading/transit surfaces are hidden when the new view is active.
6. Sidebar naming collision: Sidebar.tsx already has its own local single-vs-compare list toggle state. Do NOT reuse the name viewMode for that local state once you consume app-level viewMode from ChartContext; rename the sidebar-local state to something like listViewMode to avoid Next/TypeScript compile failures from duplicate identifiers.When adding a library-style reference area to HD Prism:
components/LibraryView.tsx for the landing screen and any subviews.ChartContext.tsx (for example library and iching).Sidebar.tsx, add the new navigation button in the bottom row next to Settings / Theme and route it through switchViewMode(...).HdprismShell.tsx, render the new view components near the top-level return and guard existing chart/compare/reading/transit sections with !showLibraryView / !showIChingView so the new screens fully replace the main surfaces.node --test apps/hdprism/lib/<your-helper>.test.mjs for any pure helper logic
- npm run build in apps/hdprism (lint currently has many pre-existing unrelated failures, so build is the reliable gate)
- pm2 restart hd-prism-clientLoading..., treat that as a possible stale client/runtime state and also hard-refresh or reopen the PWA before assuming the new UI is missing.components/Sidebar.tsx already has a local view toggle for saved lists ("single" | "compare"). If you also pull viewMode from ChartContext to add app-level views (chart/reading/transits/library/etc.), DO NOT reuse the name viewMode for the local sidebar state or the Next build will fail with the name "viewMode" is defined multiple times. Rename the local state to something like listViewMode / setListViewMode.npm run lint currently reports many pre-existing repo-wide errors/warnings unrelated to most feature work. For targeted UI changes, use build as the primary gate (cd apps/hdprism && npm run build) after running any targeted tests you add, and only treat new errors in touched files as regressions you introduced.HdprismShell.tsx — Main app shell, chart loading/saving, URL sync, single-vs-compare mode, library/I Ching routing, and reading/transit coordination. For most UI/flow bugs, inspect this file first.ChartContext.tsx — Global chart state (currentChartId, viewMode, reading state)Sidebar.tsx — Chart list with search, pill-style sort toggle (New/A-Z), filter drawer, info button per row (opens ChartInfoModal), type-based emoji icons (⚡👁🔥🪞), no date sublinesDescriptionDrawer.tsx — Gate/line/color/tone/base info panel. If a gate panel needs extra I Ching context, this is where to add it.ShareChartShell.tsx — Shell for public share page (no auth required)app/share/c/[id]/page.tsx — Public share route (single chart)app/share/x/[id]/page.tsx — Public share route (comparison)apps/api/app.js — Live Express bootstrap that mounts the compiled dist/routes/* handlers plus health/log/socket routes. When debugging production routing, check this file, not just the TypeScript route sources.app/api/**/route.ts — Next.js proxy layer. Frontend components usually call same-origin /api/*; these route handlers forward to the backend via BACKEND_URL and pass cookies through.DescriptionDrawer.tsx, reuse the existing wheel data instead of hardcoding another mapping.apps/hdprism/lib/ichingWheelData.js:GATE_RING_ORDERgetRingFigure(6, wedgeIndex)HEXAGRAM_SYMBOLSactiveEntity
2. find its wedgeIndex with GATE_RING_ORDER.indexOf(gate)
3. call getRingFigure(6, wedgeIndex)/api/charts, /api/comparisons, /api/shared/..., /api/auth/..., or /api/bodygraph.apps/hdprism/app/api/**/route.ts and proxy to the Express backend using BACKEND_URL (default local dev fallback is http://localhost:3001).is_public column on saved_charts and saved_comparisons tables (INTEGER DEFAULT 0)GET /api/shared/charts/:id, GET /api/shared/comparisons/:idGET /api/shared/charts/:id returns the full saved chart JSON plus all persisted chart readings/sections for the chart fingerprint, so logged-out guests can read owner-generated readings without calling generation endpoints.isPublic in body to toggleInlineReadingView is read-only and hydrated from the share payload.BodygraphResult below it so guests see Profile, Authority, Definition, Environment, Variable, Incarnation Cross, centers, channels, gates, circuitry, and planet activations. Wire DescriptionDrawer from shared pages too, using a local selected-entity/open state and useChartReadingForContext={false} for read-only public context./share/c/[id] (chart), /share/x/[id] (comparison)ShareChartShell before conditional loading/error returns; putting a useCallback/hook after those returns causes production React error #310 (Rendered more hooks than during the previous render) once the share payload loads./api/shared/ routes may 404 through nginx — verify nginx proxies ALL /api/ subpaths to port 3005, not just specific routes. The Next.js app on 3010 may intercept first.apps/api/src/routes/readings.ts (POST /api/readings/generate).readings and reading_sections and emits SSE events; use it when Alex asks to actually “get the HD reading” for a chart.saved_charts, pass its stored chart_json as { bodygraph, regenerate: false } to http://127.0.0.1:3005/api/readings/generate rather than recalculating the chart.section_delta events can arrive before final section completion, the backend emits empty section placeholders first. Keep that placeholder behavior if refactoring, or the current frontend handlers may drop deltas for sections not yet present in state.cd apps/api && npx tsc, cd apps/hdprism && npm run build, restart pm2 restart hd-prism-api, then check /api/health and PM2 logs. A full live reading generation test may spend OpenRouter credits and can fail if credits are insufficient.POST /api/tenant/report with the full reading generator: tenant/report is deterministic/instant-ish and returns report/fact-pack structure only, with no LLM prose and no OpenRouter spend./api/charts, /api/charts/:id, /api/comparisons, /api/shared/charts/:id, /api/shared/comparisons/:idapps/api/app.js as /api/tenant, source apps/api/src/routes/tenantBodygraph.tshttps://hdprism.apps.poofc.com/api/tenantGET /api/tenant/healthPOST /api/tenant/bodygraph → { ok, service, input, resolved, summary, bodygraph }POST /api/tenant/fact-pack → reusable LLM-safe chart facts: centers, channels, gates, activation stack, variables, split/bridge candidates, hanging/electromagnetic gatesGET /api/tenant/reference/:entityType/:entityId → HD Prism description outputs for gates, centers, authorities, profiles, variables, channels, circuitry, etc.POST /api/tenant/reference/batch → same as above for up to 128 referencesPOST /api/tenant/chart-query → selected structured facts from a chart/bodygraph via include: [...]POST /api/tenant/report → deterministic assembled Reading V1 plan/snippet context from the fact pack; no LLM call or PDF generationbodygraph, fact-pack, chart-query, and report accept either birth data (birthDate, birthTime, timeZone/location) or an existing bodygraph object.timeZone/utc directly when supplied; otherwise resolves local birth date/time/location through transit-list-demo /api/time/resolve./api/bodygraph, which is still backed by the PDF-report route.cd apps/api && npx tsc && node --test test/tenantBodygraph.test.mjsreferences/tenant-api-astral-integration.md/api/ — these proxy or supplement the Express APIhd-prism-bulk-importUse the existing app internals to insert charts directly without triggering reading generation.
Key modules under apps/api/src/:
- models/bodygraph.ts → createBodygraph(name, dateUtc, location)
- descriptions/descriptionDb.ts → createSavedChart(...), listSavedChartsForUser(...)
- interpretation/chartFingerprint.ts → computeChartFingerprint(...)
Pattern:
1. parse source birth records
2. convert local civil time + timezone to UTC before calling createBodygraph
3. attach provenance like timezone/UTC to the bodygraph JSON if useful
4. compute chart fingerprint
5. dedupe against existing saved charts
6. persist with createSavedChart
Important lesson: readings are generated separately, so direct bodygraph/chart insertion is the safe path for bulk imports.
Library button next to Settings / Theme toggle.I Ching section.apps/hdprism/components/IChingMandalaDiagram.tsx.apps/hdprism/lib/ichingWheelData.js with tests in apps/hdprism/lib/ichingWheelData.test.mjs.ChartContext view modes were extended with library and iching; remember to update scroll bookkeeping when adding more custom views.The inner build rings must NOT repeat symbols at all 64 outer wedge positions.
Correct structure: - 2-line ring: exactly 4 visible figures - 3-line ring: exactly 8 visible figures - 4-line ring: exactly 16 visible figures - 5-line ring: exactly 32 visible figures - number ring: 64 positions - outer ring: 64 hexagrams
The right approach is:
- keep the outer 64-gate/hexagram wheel intact
- center each inner-ring figure in its parent sector using helper placements (see getDisplayRingPlacements())
- do NOT render 64 repeated parent-pattern stacks for the 2/3/4/5-line rings
Sidebar.tsx already had local list state named viewMode for single vs compare chart lists. When adding app-level viewMode from ChartContext, this caused a build-breaking duplicate identifier. Rename the sidebar-local state (for example listViewMode) instead of reusing viewMode.