Overview
The architecture separates UI, computation, workspace management, and storage so multiple frontends can share the same backend behavior.
Repository Structure (top level)
- cache: temporary files for computation
- module: all the program logic
- scripts: generators for documentation
- tests: scenario and functionality testing
- venv: python environment with libraries
Core Layers
- UI layer: Streamlit, Kivy, or Tauri/Svelte call Python services directly.
- Services layer:
module.servicescomputes positions/aspects and builds charts. - Workspace layer:
module.workspaceloads/saves modular YAML workspaces. - Storage layer:
module.storagepersists positions to DuckDB and Parquet (positions-only).
Data Flow
- UI collects inputs and opens a workspace.
- Services compute positions (and aspects on demand).
- Storage writes positions to DuckDB and/or Parquet.
- UI renders charts from computed positions.
Storage Model
- Positions-only: aspects are computed on demand.
- Dual engines: Kerykeion (fast) and JPL/Skyfield (extended properties).
- Radix support:
radix_chart_id+is_radixfor transit comparisons. - Hybrid storage: DuckDB for active queries, Parquet for time series.
Storage (Backend)
Strategy (Python vs Rust)
Python storage (batch):
- Transit series and large time ranges
- Background jobs and data migrations
- Avoids JSON transfer overhead
Rust storage (interactive):
- Single chart computations
- User-driven queries
- Small datasets and quick updates
Both Python and Rust use the same DuckDB schema.
Schema (Positions-Only)
computed_positions stores:
chart_id,datetime,object_idlongitude,latitudedeclination,right_ascension,distancealtitude,azimuthapparent_magnitude,phase_angle,elongation,light_timespeed,retrogradeengine,ephemeris_fileradix_chart_id,is_radixhas_equatorial,has_topocentric,has_physical
Aspects are computed on demand from positions.
Current behavior
-
Dual engine support
- Default: Kerykeion (Swisseph)
- Optional: JPL (extended properties)
-
Radix-relative storage
radix_chart_idlinks transits to base chartsis_radixmarks base vs transit rows
-
Performance optimization
- Pre-initialized engine for batch series
- No aspect storage (computed on demand)
-
3D-ready fields
declinationanddistancestored for JPL
Storage paths
workspace/
├── workspace.yaml
└── data/
├── workspace.db
└── parquet/
└── chart_id_YYYY-MM-DD.parquet
Layers by responsibility
| 🔹 Category | 🌞 Horoscope | 📊 Chart | 🗂️ Workspace |
|---|---|---|---|
| 🧱 Key Objects |
|
|
|
| ⚙️ Core Functions |
|
|
|
| ✨ Features |
|
|
|
Key entry points
module.services.compute_positions(...)module.services.compute_positions_for_chart(...)module.services.compute_aspects_for_chart(...)module.services.build_chart_instance(...)module.workspace.load_workspace(...)module.workspace.save_workspace_modular(...)