From a80b72a9b11c319ac7c25381655e107e060aa1d6 Mon Sep 17 00:00:00 2001 From: buenosairesam Date: Tue, 14 Apr 2026 10:32:05 -0300 Subject: [PATCH] updated docs --- README.md | 66 ++- docs/architecture/01-system-overview.dot | 102 ----- docs/architecture/01-system-overview.svg | 244 ----------- docs/architecture/02-artery-hierarchy.dot | 86 ---- docs/architecture/02-artery-hierarchy.svg | 134 ------ docs/architecture/03-build-flow.dot | 85 ---- docs/architecture/03-build-flow.svg | 190 -------- docs/architecture/04-room-config.dot | 83 ---- docs/architecture/04-room-config.svg | 161 ------- docs/architecture/05-sidebar-injection.md | 217 --------- docs/architecture/graph.html | 115 ----- docs/architecture/index.html | 259 ----------- docs/architecture/sidebar-injection.html | 191 -------- docs/architecture/styles.css | 351 --------------- docs/artery/index.html | 314 ------------- docs/atlas/index.html | 209 --------- docs/data/en/artery-google.md | 55 +++ docs/data/en/artery-ia.md | 77 ++++ docs/data/en/artery-jira.md | 71 +++ docs/data/en/artery-shunts.md | 94 ++++ docs/data/en/artery-slack.md | 33 ++ docs/data/en/artery.md | 110 +++++ docs/data/en/atlas-books.md | 86 ++++ docs/data/en/atlas-templates.md | 75 ++++ docs/data/en/atlas.md | 54 +++ docs/data/en/components.md | 54 +++ docs/data/en/concepts.md | 75 ++++ docs/data/en/deployment.md | 63 +++ docs/data/en/intro.md | 52 +++ docs/data/en/managed.md | 40 ++ docs/data/en/quickstart.md | 87 ++++ docs/data/en/room-setup.md | 42 ++ docs/data/en/standalone.md | 46 ++ docs/data/en/station-databrowse.md | 80 ++++ docs/data/en/station-datagen.md | 57 +++ docs/data/en/station-graphgen.md | 38 ++ docs/data/en/station-modelgen.md | 54 +++ docs/data/en/station-tester.md | 99 +++++ docs/data/en/station.md | 71 +++ docs/data/topics.json | 29 ++ docs/docs.css | 347 +++++++++++++++ docs/docs.js | 318 ++++++++++++++ docs/graphs/artery_hierarchy.dot | 45 ++ docs/graphs/artery_hierarchy.svg | 101 +++++ docs/graphs/cfg_gen_flow.dot | 49 +++ docs/graphs/cfg_gen_flow.svg | 114 +++++ docs/graphs/room_layers.dot | 31 ++ docs/graphs/room_layers.svg | 133 ++++++ docs/graphs/system_overview.dot | 97 ++++ docs/graphs/system_overview.svg | 209 +++++++++ docs/graphs/wrapping.dot | 54 +++ docs/graphs/wrapping.svg | 119 +++++ docs/index.html | 273 +----------- docs/lang-toggle.js | 54 --- docs/station/index.html | 336 -------------- docs/veins/google.dot | 61 --- docs/veins/google.svg | 158 ------- docs/veins/graph.html | 115 ----- docs/veins/index.html | 172 -------- docs/veins/jira.dot | 53 --- docs/veins/jira.svg | 115 ----- docs/veins/mercadopago-shunt.dot | 64 --- docs/veins/mercadopago-shunt.svg | 133 ------ docs/veins/slack.dot | 64 --- docs/veins/slack.svg | 133 ------ docs/viewer.html | 56 +++ generate.html | 512 ---------------------- 67 files changed, 3260 insertions(+), 5005 deletions(-) delete mode 100644 docs/architecture/01-system-overview.dot delete mode 100644 docs/architecture/01-system-overview.svg delete mode 100644 docs/architecture/02-artery-hierarchy.dot delete mode 100644 docs/architecture/02-artery-hierarchy.svg delete mode 100644 docs/architecture/03-build-flow.dot delete mode 100644 docs/architecture/03-build-flow.svg delete mode 100644 docs/architecture/04-room-config.dot delete mode 100644 docs/architecture/04-room-config.svg delete mode 100644 docs/architecture/05-sidebar-injection.md delete mode 100644 docs/architecture/graph.html delete mode 100644 docs/architecture/index.html delete mode 100644 docs/architecture/sidebar-injection.html delete mode 100644 docs/architecture/styles.css delete mode 100644 docs/artery/index.html delete mode 100644 docs/atlas/index.html create mode 100644 docs/data/en/artery-google.md create mode 100644 docs/data/en/artery-ia.md create mode 100644 docs/data/en/artery-jira.md create mode 100644 docs/data/en/artery-shunts.md create mode 100644 docs/data/en/artery-slack.md create mode 100644 docs/data/en/artery.md create mode 100644 docs/data/en/atlas-books.md create mode 100644 docs/data/en/atlas-templates.md create mode 100644 docs/data/en/atlas.md create mode 100644 docs/data/en/components.md create mode 100644 docs/data/en/concepts.md create mode 100644 docs/data/en/deployment.md create mode 100644 docs/data/en/intro.md create mode 100644 docs/data/en/managed.md create mode 100644 docs/data/en/quickstart.md create mode 100644 docs/data/en/room-setup.md create mode 100644 docs/data/en/standalone.md create mode 100644 docs/data/en/station-databrowse.md create mode 100644 docs/data/en/station-datagen.md create mode 100644 docs/data/en/station-graphgen.md create mode 100644 docs/data/en/station-modelgen.md create mode 100644 docs/data/en/station-tester.md create mode 100644 docs/data/en/station.md create mode 100644 docs/data/topics.json create mode 100644 docs/docs.css create mode 100644 docs/docs.js create mode 100644 docs/graphs/artery_hierarchy.dot create mode 100644 docs/graphs/artery_hierarchy.svg create mode 100644 docs/graphs/cfg_gen_flow.dot create mode 100644 docs/graphs/cfg_gen_flow.svg create mode 100644 docs/graphs/room_layers.dot create mode 100644 docs/graphs/room_layers.svg create mode 100644 docs/graphs/system_overview.dot create mode 100644 docs/graphs/system_overview.svg create mode 100644 docs/graphs/wrapping.dot create mode 100644 docs/graphs/wrapping.svg delete mode 100644 docs/lang-toggle.js delete mode 100644 docs/station/index.html delete mode 100644 docs/veins/google.dot delete mode 100644 docs/veins/google.svg delete mode 100644 docs/veins/graph.html delete mode 100644 docs/veins/index.html delete mode 100644 docs/veins/jira.dot delete mode 100644 docs/veins/jira.svg delete mode 100644 docs/veins/mercadopago-shunt.dot delete mode 100644 docs/veins/mercadopago-shunt.svg delete mode 100644 docs/veins/slack.dot delete mode 100644 docs/veins/slack.svg create mode 100644 docs/viewer.html delete mode 100644 generate.html diff --git a/README.md b/README.md index 50c3fce..11580bc 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,45 @@ -# Soleprint +# soleprint -Development workflow platform. Run, test, and document everything in one place. +Development workflow platform. Wraps existing applications with tools, testing, and documentation — without touching source code. + +Cada paso deja huella. ## Quick Start ```bash -# Build and run standalone -python build.py -cd gen/standalone && docker compose up -# Visit http://localhost:12000 +# Create a room +python -m init.cli myroom -# Build and run with room config -python build.py --cfg -cd gen//soleprint && docker compose up -``` - -## Commands - -```bash # Build -python build.py # -> gen/standalone/ -python build.py --cfg # -> gen// -python build.py --all # -> all rooms +python build.py --cfg myroom -# Using ctrl scripts -./ctrl/build.sh # Build standalone -./ctrl/build.sh # Build room -./ctrl/start.sh # Start standalone -./ctrl/start.sh # Start room -./ctrl/stop.sh # Stop -./ctrl/logs.sh # View logs +# Run +cd gen/myroom/soleprint && docker compose up -# Bare-metal dev (without Docker) -cd gen/standalone && python run.py +# Visit http://localhost:12000 ``` -## Adding a New Room +Or use the browser wizard: `python -m init.web` → http://localhost:9000 + +## Docs ```bash -# 1. Create room config -mkdir -p cfg/myroom/data -cp cfg/standalone/config.json cfg/myroom/ -cp -r cfg/standalone/data/* cfg/myroom/data/ - -# 2. Build and run -python build.py --cfg myroom -cd gen/myroom/soleprint && docker compose up +cd docs && python -m http.server 8080 +# http://localhost:8080 ``` -Or use the generation UI: `python -m http.server 8080` in `spr/` and visit `/generate.html`. +## Structure + +``` +spr/ +├── soleprint/ # Core framework +│ ├── artery/ # Connectors (veins, shunts, pulses) +│ ├── atlas/ # Documentation (books, templates) +│ └── station/ # Tools (tester, datagen, modelgen) +├── cfg/ # Room configurations +├── init/ # Room setup (CLI + web wizard) +├── docs/ # Documentation site +├── ctrl/ # Build/deploy scripts +├── build.py # Build tool: cfg/ → gen/ +└── gen/ # Built instances (gitignored) +``` diff --git a/docs/architecture/01-system-overview.dot b/docs/architecture/01-system-overview.dot deleted file mode 100644 index 7bb61b1..0000000 --- a/docs/architecture/01-system-overview.dot +++ /dev/null @@ -1,102 +0,0 @@ -digraph SystemOverview { - // Graph settings - rankdir=TB; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11]; - edge [fontname="Helvetica", fontsize=10]; - - // Title - labelloc="t"; - label="Soleprint - System Overview"; - fontsize=16; - - // Styling - node [shape=box, style="rounded,filled"]; - - // Core Hub - subgraph cluster_soleprint { - label="Soleprint Hub (port 12000)"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - hub [label="Soleprint\nCore Coordinator", fillcolor="#C8E6C9", shape=box]; - } - - // Artery System - subgraph cluster_artery { - label="Artery - Todo lo vital"; - style=filled; - color="#FFEBEE"; - fillcolor="#FFEBEE"; - - veins [label="Veins\n(Stateless Connectors)", fillcolor="#FFCDD2"]; - shunts [label="Shunts\n(Mock Connectors)", fillcolor="#FFCDD2"]; - pulses [label="Pulses\n(Composed Flows)", fillcolor="#EF9A9A"]; - plexus [label="Plexus\n(Full Apps)", fillcolor="#E57373"]; - } - - // Atlas System - subgraph cluster_atlas { - label="Atlas - Documentacion accionable"; - style=filled; - color="#E3F2FD"; - fillcolor="#E3F2FD"; - - books [label="Books\n(Documentation)", fillcolor="#BBDEFB"]; - templates [label="Templates\n(Patterns)", fillcolor="#BBDEFB"]; - depots [label="Depots\n(External Docs)", fillcolor="#90CAF9"]; - } - - // Station System - subgraph cluster_station { - label="Station - Centro de control"; - style=filled; - color="#FFF8E1"; - fillcolor="#FFF8E1"; - - tools [label="Tools\n(modelgen, tester, datagen)", fillcolor="#FFECB3"]; - monitors [label="Monitors\n(databrowse)", fillcolor="#FFECB3"]; - } - - // External - subgraph cluster_external { - label="External Services"; - style=dashed; - color=gray; - - jira [label="Jira", fillcolor="#E8EAF6"]; - slack [label="Slack", fillcolor="#E8EAF6"]; - google [label="Google", fillcolor="#E8EAF6"]; - mercadopago [label="MercadoPago", fillcolor="#E8EAF6"]; - } - - // Managed Room - subgraph cluster_room { - label="Managed Room (e.g., AMAR)"; - style=dashed; - color="#7B1FA2"; - - room_backend [label="Backend\n(Django/FastAPI)", fillcolor="#E1BEE7"]; - room_frontend [label="Frontend\n(Next.js)", fillcolor="#E1BEE7"]; - room_db [label="Database\n(PostgreSQL)", fillcolor="#CE93D8", shape=cylinder]; - } - - // Connections - hub -> veins [label="routes"]; - hub -> books [label="routes"]; - hub -> tools [label="routes"]; - - veins -> jira [label="API"]; - veins -> slack [label="API"]; - veins -> google [label="OAuth"]; - shunts -> mercadopago [label="mock", style=dashed]; - - veins -> pulses [label="compose"]; - pulses -> plexus [label="extend"]; - - tools -> room_backend [label="test", style=dashed]; - monitors -> room_db [label="browse", style=dashed]; - depots -> room_backend [label="docs", style=dashed]; -} diff --git a/docs/architecture/01-system-overview.svg b/docs/architecture/01-system-overview.svg deleted file mode 100644 index 746d379..0000000 --- a/docs/architecture/01-system-overview.svg +++ /dev/null @@ -1,244 +0,0 @@ - - - - - - -SystemOverview - -Soleprint - System Overview - -cluster_soleprint - -Soleprint Hub (port 12000) - - -cluster_artery - -Artery - Todo lo vital - - -cluster_atlas - -Atlas - Documentacion accionable - - -cluster_station - -Station - Centro de control - - -cluster_external - -External Services - - -cluster_room - -Managed Room - - - -hub - -Soleprint -Core Coordinator - - - -veins - -Veins -(Stateless Connectors) - - - -hub->veins - - -routes - - - -books - -Books -(Documentation) - - - -hub->books - - -routes - - - -tools - -Tools -(modelgen, tester, datagen) - - - -hub->tools - - -routes - - - -pulses - -Pulses -(Composed Flows) - - - -veins->pulses - - -compose - - - -jira - -Jira - - - -veins->jira - - -API - - - -slack - -Slack - - - -veins->slack - - -API - - - -google - -Google - - - -veins->google - - -OAuth - - - -shunts - -Shunts -(Mock Connectors) - - - -mercadopago - -MercadoPago - - - -shunts->mercadopago - - -mock - - - -plexus - -Plexus -(Full Apps) - - - -pulses->plexus - - -extend - - - -templates - -Templates -(Patterns) - - - -depots - -Depots -(External Docs) - - - -room_backend - -Backend -(Django/FastAPI) - - - -depots->room_backend - - -docs - - - -tools->room_backend - - -test - - - -monitors - -Monitors -(databrowse) - - - -room_db - - -Database -(PostgreSQL) - - - -monitors->room_db - - -browse - - - -room_frontend - -Frontend -(Next.js) - - - diff --git a/docs/architecture/02-artery-hierarchy.dot b/docs/architecture/02-artery-hierarchy.dot deleted file mode 100644 index 5eabaf3..0000000 --- a/docs/architecture/02-artery-hierarchy.dot +++ /dev/null @@ -1,86 +0,0 @@ -digraph ArteryHierarchy { - // Graph settings - rankdir=LR; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11]; - edge [fontname="Helvetica", fontsize=10]; - - // Title - labelloc="t"; - label="Artery - Connector Hierarchy"; - fontsize=16; - - // Styling - node [shape=box, style="rounded,filled"]; - - // Main hierarchy - subgraph cluster_main { - label="Evolution Path"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - vein [label="Vein\n\nStateless API connector\ne.g., Jira, Slack, Google", fillcolor="#C8E6C9", width=2.5]; - pulse [label="Pulse\n\nVein + Room + Depot\ne.g., Jira for AMAR project", fillcolor="#A5D6A7", width=2.5]; - plexus [label="Plexus\n\nFull app: backend + frontend + DB\ne.g., WhatsApp with chat UI", fillcolor="#81C784", width=2.5]; - } - - // Mock path - subgraph cluster_mock { - label="Testing Path"; - style=filled; - color="#FFF3E0"; - fillcolor="#FFF3E0"; - - shunt [label="Shunt\n\nFake connector for testing\ne.g., mercadopago mock", fillcolor="#FFCC80", width=2.5]; - } - - // Connections - vein -> pulse [label="+ Room\n+ Depot"]; - pulse -> plexus [label="+ Backend\n+ Frontend\n+ DB"]; - vein -> shunt [label="mock", style=dashed, constraint=false]; - - // Properties table - subgraph cluster_props { - label="Properties"; - style=filled; - color="#F5F5F5"; - fillcolor="#F5F5F5"; - - props [shape=plaintext, label=< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeStateFrontendDeploy
VeinNone (or OAuth)Optional test UIWith soleprint
ShuntConfigurableConfig UIWith soleprint
PulseVein + configUses vein'sWith soleprint
PlexusFull app stateRequiredSelf-contained
- >]; - } -} diff --git a/docs/architecture/02-artery-hierarchy.svg b/docs/architecture/02-artery-hierarchy.svg deleted file mode 100644 index 5a479b1..0000000 --- a/docs/architecture/02-artery-hierarchy.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - -ArteryHierarchy - -Artery - Connector Hierarchy - -cluster_main - -Evolution Path - - -cluster_mock - -Testing Path - - -cluster_props - -Properties - - - -vein - -Vein -Stateless API connector -e.g., Jira, Slack, Google - - - -pulse - -Pulse -Vein + Room + Depot -e.g., Jira for AMAR project - - - -vein->pulse - - -+ Room -+ Depot - - - -shunt - -Shunt -Fake connector for testing -e.g., mercadopago mock - - - -vein->shunt - - -mock - - - -plexus - -Plexus -Full app: backend + frontend + DB -e.g., WhatsApp with chat UI - - - -pulse->plexus - - -+ Backend -+ Frontend -+ DB - - - -props - - - -Type - - -State - - -Frontend - - -Deploy - -Vein - -None (or OAuth) - -Optional test UI - -With soleprint - -Shunt - -Configurable - -Config UI - -With soleprint - -Pulse - -Vein + config - -Uses vein's - -With soleprint - -Plexus - -Full app state - -Required - -Self-contained - - - diff --git a/docs/architecture/03-build-flow.dot b/docs/architecture/03-build-flow.dot deleted file mode 100644 index c7ec9cd..0000000 --- a/docs/architecture/03-build-flow.dot +++ /dev/null @@ -1,85 +0,0 @@ -digraph BuildFlow { - // Graph settings - rankdir=TB; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11]; - edge [fontname="Helvetica", fontsize=10]; - - // Title - labelloc="t"; - label="Soleprint - Build Flow"; - fontsize=16; - - // Styling - node [shape=box, style="rounded,filled"]; - - // Source - subgraph cluster_source { - label="Source (spr/)"; - style=filled; - color="#E3F2FD"; - fillcolor="#E3F2FD"; - - soleprint_src [label="soleprint/\n(core entry points)", fillcolor="#BBDEFB"]; - artery_src [label="artery/\n(veins, shunts)", fillcolor="#BBDEFB"]; - atlas_src [label="atlas/\n(books)", fillcolor="#BBDEFB"]; - station_src [label="station/\n(tools, monitors)", fillcolor="#BBDEFB"]; - } - - // Config - subgraph cluster_cfg { - label="Room Configs (cfg/)"; - style=filled; - color="#FFF8E1"; - fillcolor="#FFF8E1"; - - cfg_standalone [label="cfg/standalone/\nconfig.json\ndata/", fillcolor="#FFECB3"]; - cfg_amar [label="cfg/amar/\nconfig.json\ndata/\ndocker-compose.yml\n...", fillcolor="#FFECB3"]; - cfg_other [label="cfg//\n...", fillcolor="#FFE082", style="rounded,filled,dashed"]; - } - - // Build tool - build [label="build.py", fillcolor="#E1BEE7", shape=hexagon]; - - // Commands - subgraph cluster_cmds { - label="Commands"; - style=filled; - color="#F3E5F5"; - fillcolor="#F3E5F5"; - - cmd1 [label="python build.py dev", fillcolor="#CE93D8"]; - cmd2 [label="python build.py dev --cfg amar", fillcolor="#CE93D8"]; - cmd3 [label="python build.py dev --all", fillcolor="#CE93D8"]; - } - - // Output - subgraph cluster_gen { - label="Generated Output (gen/)"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - gen_standalone [label="gen/standalone/\n(base soleprint)", fillcolor="#C8E6C9"]; - gen_amar [label="gen/amar/\n(with amar config)", fillcolor="#C8E6C9"]; - } - - // Connections - soleprint_src -> build; - artery_src -> build; - atlas_src -> build; - station_src -> build; - - cfg_standalone -> build [style=dashed]; - cfg_amar -> build [style=dashed]; - - build -> cmd1 [style=invis]; - build -> cmd2 [style=invis]; - build -> cmd3 [style=invis]; - - cmd1 -> gen_standalone [label="copies + standalone config"]; - cmd2 -> gen_amar [label="copies + amar config"]; - cmd3 -> gen_standalone [style=dashed]; - cmd3 -> gen_amar [style=dashed]; -} diff --git a/docs/architecture/03-build-flow.svg b/docs/architecture/03-build-flow.svg deleted file mode 100644 index 5a960ba..0000000 --- a/docs/architecture/03-build-flow.svg +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - -BuildFlow - -Soleprint - Build Flow - -cluster_source - -Source (spr/) - - -cluster_cfg - -Room Configs (cfg/) - - -cluster_cmds - -Commands - - -cluster_gen - -Generated Output (gen/) - - - -soleprint_src - -soleprint/ -(core entry points) - - - -build - -build.py - - - -soleprint_src->build - - - - - -artery_src - -artery/ -(veins, shunts) - - - -artery_src->build - - - - - -atlas_src - -atlas/ -(books) - - - -atlas_src->build - - - - - -station_src - -station/ -(tools, monitors) - - - -station_src->build - - - - - -cfg_standalone - -cfg/standalone/ -config.json -data/ - - - -cfg_standalone->build - - - - - -cfg_amar - -cfg/amar/ -config.json -data/ -docker-compose.yml -... - - - -cfg_amar->build - - - - - -cfg_other - -cfg/<room>/ -... - - - -cmd1 - -python build.py dev - - - - -cmd2 - -python build.py dev --cfg amar - - - - -cmd3 - -python build.py dev --all - - - - -gen_standalone - -gen/standalone/ -(base soleprint) - - - -cmd1->gen_standalone - - -copies + standalone config - - - -gen_amar - -gen/amar/ -(with amar config) - - - -cmd2->gen_amar - - -copies + amar config - - - -cmd3->gen_standalone - - - - - -cmd3->gen_amar - - - - - diff --git a/docs/architecture/04-room-config.dot b/docs/architecture/04-room-config.dot deleted file mode 100644 index 797fd73..0000000 --- a/docs/architecture/04-room-config.dot +++ /dev/null @@ -1,83 +0,0 @@ -digraph RoomConfig { - // Graph settings - rankdir=TB; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11]; - edge [fontname="Helvetica", fontsize=10]; - - // Title - labelloc="t"; - label="Soleprint - Room Configuration Structure"; - fontsize=16; - - // Styling - node [shape=box, style="rounded,filled"]; - - // Room config structure - subgraph cluster_room { - label="cfg//"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - config_json [label="config.json\n\nFramework branding\nTerminology customization\n(can rebrand soleprint)", fillcolor="#C8E6C9"]; - - subgraph cluster_data { - label="data/"; - style=filled; - color="#DCEDC8"; - fillcolor="#DCEDC8"; - - veins_json [label="veins.json", fillcolor="#AED581"]; - shunts_json [label="shunts.json", fillcolor="#AED581"]; - depots_json [label="depots.json", fillcolor="#AED581"]; - rooms_json [label="rooms.json", fillcolor="#AED581"]; - } - - subgraph cluster_docker { - label="Docker"; - style=filled; - color="#FFECB3"; - fillcolor="#FFECB3"; - - docker_compose [label="docker-compose.yml", fillcolor="#FFE082"]; - dockerfile_be [label="Dockerfile.backend", fillcolor="#FFE082"]; - dockerfile_fe [label="Dockerfile.frontend", fillcolor="#FFE082"]; - env_example [label=".env.example", fillcolor="#FFE082"]; - } - - subgraph cluster_soleprint { - label="soleprint/"; - style=filled; - color="#E1BEE7"; - fillcolor="#E1BEE7"; - - spr_compose [label="docker-compose.yml\n(soleprint for this room)", fillcolor="#CE93D8"]; - spr_env [label=".env", fillcolor="#CE93D8"]; - } - - subgraph cluster_extras { - label="Room-specific"; - style=filled; - color="#B2EBF2"; - fillcolor="#B2EBF2"; - - databrowse [label="databrowse/depot/\n(DB schema)", fillcolor="#80DEEA"]; - tester [label="tester/tests/\n(Room tests)", fillcolor="#80DEEA"]; - monitors [label="monitors/\n(Room monitors)", fillcolor="#80DEEA"]; - models [label="models/\n(Room models)", fillcolor="#80DEEA"]; - } - } - - // Examples - subgraph cluster_examples { - label="Examples"; - style=dashed; - color=gray; - - standalone [label="cfg/standalone/\n\nBase soleprint\nGeneric veins\nNo docker-compose", fillcolor="#F5F5F5"]; - - amar [label="cfg/amar/\n\nAMAR veterinary app\namar + mercadopago shunts\nFull Docker setup\nCustom monitors (turnos)", fillcolor="#F5F5F5"]; - } -} diff --git a/docs/architecture/04-room-config.svg b/docs/architecture/04-room-config.svg deleted file mode 100644 index 9b6f60e..0000000 --- a/docs/architecture/04-room-config.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - -RoomConfig - -Soleprint - Room Configuration Structure - -cluster_room - -cfg/<room>/ - - -cluster_data - -data/ - - -cluster_docker - -Docker - - -cluster_soleprint - -soleprint/ - - -cluster_extras - -Room-specific - - -cluster_examples - -Examples - - - -config_json - -config.json -Framework branding -Terminology customization -(can rebrand soleprint) - - - -veins_json - -veins.json - - - -shunts_json - -shunts.json - - - -depots_json - -depots.json - - - -rooms_json - -rooms.json - - - -docker_compose - -docker-compose.yml - - - -dockerfile_be - -Dockerfile.backend - - - -dockerfile_fe - -Dockerfile.frontend - - - -env_example - -.env.example - - - -spr_compose - -docker-compose.yml -(soleprint for this room) - - - -spr_env - -.env - - - -databrowse - -databrowse/depot/ -(DB schema) - - - -tester - -tester/tests/ -(Room tests) - - - -monitors - -monitors/ -(Room monitors) - - - -models - -models/ -(Room models) - - - -standalone - -cfg/standalone/ -Base soleprint -Generic veins -No docker-compose - - - -amar - -cfg/amar/ -AMAR veterinary app -amar + mercadopago shunts -Full Docker setup -Custom monitors (turnos) - - - diff --git a/docs/architecture/05-sidebar-injection.md b/docs/architecture/05-sidebar-injection.md deleted file mode 100644 index 1da72e6..0000000 --- a/docs/architecture/05-sidebar-injection.md +++ /dev/null @@ -1,217 +0,0 @@ -# Sidebar Injection Architecture - -## Overview - -The soleprint sidebar is injected into managed app pages using a hybrid nginx + JavaScript approach. This allows any frontend framework (React, Next.js, static HTML) to receive the sidebar without code modifications. - -## How It Works - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Browser Request │ -│ http://room.spr.local.ar/ │ -└─────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Nginx │ -│ │ -│ 1. Routes /spr/* → soleprint:PORT (sidebar assets + API) │ -│ 2. Routes /* → frontend:PORT (app pages) │ -│ 3. Injects CSS+JS into HTML responses via sub_filter │ -│ │ -│ sub_filter '' │ -│ ' │ -│ '; │ -└─────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Browser Renders │ -│ │ -│ 1. Page loads with injected CSS (sidebar styles ready) │ -│ 2. sidebar.js executes (deferred, after DOM ready) │ -│ 3. JS fetches /spr/api/sidebar/config (room name, auth, etc) │ -│ 4. JS creates sidebar DOM elements and injects into page │ -│ 5. Sidebar appears on left side, pushes content with margin │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Key Design Decisions - -### Why nginx sub_filter instead of modifying app code? - -- **Framework agnostic**: Works with any frontend (Next.js, React, Vue, static HTML) -- **No app changes needed**: The managed app doesn't need to know about soleprint -- **Easy to disable**: Just access `room.local.ar` instead of `room.spr.local.ar` - -### Why inject into `` instead of ``? - -Next.js and other streaming SSR frameworks may not include `` in the initial HTML response. The `` tag is always present, so we inject both CSS and JS there using `defer` to ensure JS runs after DOM is ready. - -### Why JavaScript injection instead of iframe? - -- **No iframe isolation issues**: Sidebar can interact with page if needed -- **Better UX**: No double scrollbars, native feel -- **Simpler CSS**: Just push content with `margin-left` - -## Nginx Configuration - -There are two options for local development: - -### Option 1: Docker Nginx (Recommended for portability) - -Each room includes a docker-compose.nginx.yml that runs nginx in a container. - -```bash -# Add to /etc/hosts -127.0.0.1 sample.spr.local.ar sample.local.ar - -# Start room with nginx -cd gen//soleprint -docker compose -f docker-compose.yml -f docker-compose.nginx.yml up -d -``` - -The nginx config in `cfg//soleprint/nginx/local.conf` uses docker service names: - -```nginx -location /spr/ { - proxy_pass http://soleprint:8000/; -} - -location / { - proxy_pass http://frontend:80; - # ... sub_filter for sidebar injection -} -``` - -**Pros**: Portable, no system dependencies, isolated per room -**Cons**: Only one room can use port 80 at a time - -### Option 2: System Nginx (For running multiple rooms) - -If you need multiple rooms running simultaneously, use your system's nginx. - -1. Install nginx: `sudo apt install nginx` - -2. Add hosts entries for all rooms: -``` -# /etc/hosts -127.0.0.1 amar.spr.local.ar amar.local.ar -127.0.0.1 dlt.spr.local.ar dlt.local.ar -127.0.0.1 sample.spr.local.ar sample.local.ar -``` - -3. Create config in `/etc/nginx/sites-enabled/spr_local.conf`: - -```nginx -# room.spr.local.ar - app with sidebar -server { - listen 80; - server_name room.spr.local.ar; - - # Soleprint assets and API - location /spr/ { - proxy_pass http://127.0.0.1:SOLEPRINT_PORT/; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # Backend API (if applicable) - location /api/ { - proxy_pass http://127.0.0.1:BACKEND_PORT/api/; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # Frontend with sidebar injection - location / { - proxy_pass http://127.0.0.1:FRONTEND_PORT; - proxy_set_header Host $host; - proxy_set_header Accept-Encoding ""; # Required for sub_filter - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - # Inject sidebar - sub_filter '' ''; - sub_filter_once off; - sub_filter_types text/html; - } -} - -# room.local.ar - app without sidebar (direct access) -server { - listen 80; - server_name room.local.ar; - # ... same locations but without sub_filter in / block -} -``` - -4. Reload nginx: `sudo nginx -t && sudo systemctl reload nginx` - -**Pros**: Multiple rooms on port 80 via different hostnames -**Cons**: Requires system nginx, manual config updates - -## Port Allocation - -Each room should use unique ports to allow concurrent operation: - -| Room | Soleprint | Frontend | Backend | -|--------|-----------|----------|---------| -| amar | 12000 | 3000 | 8001 | -| dlt | 12010 | 3010 | - | -| sample | 12020 | 3020 | 8020 | - -## Sidebar Assets - -The sidebar consists of two files served by soleprint: - -- `/sidebar.css` - Styles for the sidebar (dark theme, positioning) -- `/sidebar.js` - Self-contained JS that fetches config and renders sidebar - -Source location: `soleprint/station/tools/sbwrapper/` - -## Sidebar Config API - -The sidebar JS fetches configuration from `/spr/api/sidebar/config`: - -```json -{ - "room": "amar", - "soleprint_base": "/spr", - "auth_enabled": true, - "tools": { - "artery": "/spr/artery", - "atlas": "/spr/atlas", - "station": "/spr/station" - }, - "auth": { - "login_url": "/spr/artery/google/oauth/login", - "logout_url": "/spr/artery/google/oauth/logout" - } -} -``` - -## Troubleshooting - -### Sidebar not appearing - -1. Check if soleprint is running: `curl http://room.spr.local.ar/spr/sidebar.js` -2. Check browser console for `[Soleprint]` messages -3. Verify nginx has `Accept-Encoding ""` set (required for sub_filter) -4. Hard refresh (Ctrl+Shift+R) to clear cached HTML - -### Wrong room config showing - -Each room needs its own docker network (`room_network`) to isolate services. Check `NETWORK_NAME` in `.env` files and ensure containers are on correct networks. - -### sub_filter not working - -- Ensure `proxy_set_header Accept-Encoding ""` is set -- Check that response is `text/html` (sub_filter_types) -- Streaming SSR may not have ``, use `` injection instead diff --git a/docs/architecture/graph.html b/docs/architecture/graph.html deleted file mode 100644 index 0a1491a..0000000 --- a/docs/architecture/graph.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - Graph Viewer - Soleprint - - - -
- ← Back - -

Loading...

-
- - - - - -
-
- -
- Graph -
- - - - diff --git a/docs/architecture/index.html b/docs/architecture/index.html deleted file mode 100644 index f485885..0000000 --- a/docs/architecture/index.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - Soleprint - Architecture - - - -
-

Soleprint

-

- Cada paso deja huella / Each step leaves a mark -

-
- -
- -
-

What Soleprint Solves

-
-
-

Freelance Work Standardization

-

- Consistent framework across projects. Build once, - reuse everywhere. -

-
-
-

Missing Infrastructure

-

- Mock systems you can't access yet - DB designs in - progress, Kubernetes not ready, APIs being built. - Test locally with shunts. -

-
-
-

Reliable Testing

-

- BDD -> Gherkin -> Tests. Explore behavior first, - then generate tests. -

-
-
-
- - -
-
-

System Overview

- View Full -
- - System Overview - -
-

The four systems that make up Soleprint.

-

Systems

-
    -
  • - Soleprint: Core coordinator hub - (port 12000) -
  • -
  • - Artery: Connectors to external - services - "Todo lo vital" -
  • -
  • - Atlas: Actionable documentation - - "Documentacion accionable" -
  • -
  • - Station: Tools and monitors - - "Centro de control" -
  • -
-
-
- - -
-
-

Artery Hierarchy

- View Full -
- - Artery Hierarchy - -
-

How connectors evolve from simple to complex.

-

Connector Types

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDescriptionExample
VeinStateless API connectorJira, Slack, Google
ShuntFake connector for testingMercadoPago mock
PulseVein + Room + DepotJira for AMAR project
PlexusFull app (backend + frontend + DB)WhatsApp with chat UI
-
-
- - -
-
-

Build Flow

- View Full -
- - Build Flow - -
-

How source is built into runnable instances.

-

Commands

- - - - - - - - - - - - - - - - - - - - - -
CommandOutput
python build.pygen/standalone/
- python build.py --cfg amar - gen/amar/
python build.py --allboth
-
-
- - -
-
-

Room Configuration

- View Full -
- - Room Configuration - -
-

How rooms are configured in cfg/.

-

Room Structure

-
    -
  • - config.json: Framework branding, - terminology -
  • -
  • - data/: veins.json, shunts.json, - depots.json -
  • -
  • - soleprint/: Docker config for this - room -
  • -
  • - databrowse/, tester/, monitors/, - models/: Room-specific extensions -
  • -
-
-
- - -
-

Technology Stack

-
-
-

Core

-
    -
  • Python 3.11+
  • -
  • FastAPI
  • -
  • Jinja2
  • -
-
-
-

Tools

-
    -
  • modelgen
  • -
  • tester (Playwright)
  • -
  • datagen
  • -
  • databrowse
  • -
-
-
-

Veins

-
    -
  • Jira
  • -
  • Slack
  • -
  • Google (OAuth)
  • -
-
-
-

Infrastructure

-
    -
  • Docker
  • -
  • Woodpecker CI
  • -
  • Nginx
  • -
-
-
-
-
- -
-

Soleprint - Development Workflow Platform

-

- Generated: -

-
- - diff --git a/docs/architecture/sidebar-injection.html b/docs/architecture/sidebar-injection.html deleted file mode 100644 index b3c9d1b..0000000 --- a/docs/architecture/sidebar-injection.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - Sidebar Injection - Soleprint - - - - - -
-
-

Sidebar Injection

-

- How managed room sidebar works - Como funciona el sidebar del managed room -

-
- -
-
-

Overview

-

The soleprint sidebar is injected into managed app pages using a hybrid nginx + JavaScript approach. This allows any frontend framework (React, Next.js, static HTML) to receive the sidebar without code modifications.

-

El sidebar de soleprint se inyecta en las paginas de apps manejadas usando un enfoque hibrido nginx + JavaScript. Esto permite que cualquier framework frontend (React, Next.js, HTML estatico) reciba el sidebar sin modificaciones de codigo.

-
- -
-

- How It Works - Como Funciona -

-
-┌─────────────────────────────────────────────────────────────────┐
-│                         Browser Request                          │
-│                    http://room.spr.local.ar/                     │
-└─────────────────────────────────────────────────────────────────┘
-                                  │
-                                  ▼
-┌─────────────────────────────────────────────────────────────────┐
-│                            Nginx                                 │
-│                                                                  │
-│  1. Routes /spr/* → soleprint:PORT (sidebar assets + API)       │
-│  2. Routes /* → frontend:PORT (app pages)                       │
-│  3. Injects CSS+JS into HTML responses via sub_filter           │
-└─────────────────────────────────────────────────────────────────┘
-                                  │
-                                  ▼
-┌─────────────────────────────────────────────────────────────────┐
-│                       Browser Renders                            │
-│                                                                  │
-│  1. Page loads with injected CSS (sidebar styles ready)         │
-│  2. sidebar.js executes (deferred, after DOM ready)             │
-│  3. JS fetches /spr/api/sidebar/config                          │
-│  4. JS creates sidebar DOM elements and injects into page       │
-│  5. Sidebar appears on left side, pushes content with margin    │
-└─────────────────────────────────────────────────────────────────┘
-
- -
-

- Key Design Decisions - Decisiones de Diseno Clave -

-
-
-

Why nginx sub_filter?Por que nginx sub_filter?

-

Framework agnostic: Works with any frontend. No app changes needed. Easy to disable.

-

Agnostico de framework: Funciona con cualquier frontend. Sin cambios en la app. Facil de deshabilitar.

-
-
-

Why inject into </head>?Por que inyectar en </head>?

-

Next.js and streaming SSR may not include </body> in initial response. </head> is always present.

-

Next.js y SSR streaming pueden no incluir </body> en la respuesta inicial. </head> siempre esta presente.

-
-
-

Why JS instead of iframe?Por que JS en vez de iframe?

-

No isolation issues, better UX (no double scrollbars), simpler CSS with margin-left.

-

Sin problemas de aislamiento, mejor UX (sin doble scrollbar), CSS mas simple con margin-left.

-
-
-
- -
-

- Nginx Configuration - Configuracion de Nginx -

-

The nginx config injects CSS+JS into HTML responses:

-

La config de nginx inyecta CSS+JS en las respuestas HTML:

-
location / {
-    proxy_pass http://frontend:PORT;
-    proxy_set_header Accept-Encoding "";  # Required for sub_filter
-
-    # Inject sidebar
-    sub_filter '</head>'
-      '<link rel="stylesheet" href="/spr/sidebar.css">
-       <script src="/spr/sidebar.js" defer></script></head>';
-    sub_filter_once off;
-    sub_filter_types text/html;
-}
-
- -
-

- Port Allocation - Asignacion de Puertos -

-

Each room uses unique ports for concurrent operation:

-

Cada room usa puertos unicos para operacion concurrente:

- - - - - -
RoomSoleprintFrontendBackend
amar1200030008001
dlt120103010-
sample1202030208020
-
- -
-

- Sidebar Config API - API de Config del Sidebar -

-

The sidebar JS fetches configuration from /spr/api/sidebar/config:

-

El JS del sidebar obtiene configuracion de /spr/api/sidebar/config:

-
{
-  "room": "amar",
-  "soleprint_base": "/spr",
-  "auth_enabled": true,
-  "tools": {
-    "artery": "/spr/artery",
-    "atlas": "/spr/atlas",
-    "station": "/spr/station"
-  }
-}
-
- -
-

Troubleshooting

-
-
-

Sidebar not appearingSidebar no aparece

-

Check if soleprint is running. Verify nginx has Accept-Encoding "". Hard refresh (Ctrl+Shift+R).

-

Verificar que soleprint esta corriendo. Verificar que nginx tiene Accept-Encoding "". Refresco forzado (Ctrl+Shift+R).

-
-
-

sub_filter not workingsub_filter no funciona

-

Ensure proxy_set_header Accept-Encoding "" is set. Check response is text/html.

-

Asegurar que proxy_set_header Accept-Encoding "" esta seteado. Verificar que la respuesta es text/html.

-
-
-
-
- - - - diff --git a/docs/architecture/styles.css b/docs/architecture/styles.css deleted file mode 100644 index c23d754..0000000 --- a/docs/architecture/styles.css +++ /dev/null @@ -1,351 +0,0 @@ -:root { - --bg-primary: #0a0a0a; - --bg-secondary: #141414; - --bg-card: #1a1a1a; - --text-primary: #eee; - --text-secondary: #a0a0a0; - --accent: #e94560; - --accent-secondary: #533483; - --border: #2a2a2a; -} - -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - font-family: - "Segoe UI", - system-ui, - -apple-system, - sans-serif; - background: var(--bg-primary); - color: var(--text-primary); - line-height: 1.6; -} - -header { - background: linear-gradient( - 135deg, - var(--bg-secondary), - var(--accent-secondary) - ); - padding: 2rem; - text-align: center; - border-bottom: 2px solid var(--accent); -} - -header h1 { - font-size: 2rem; - margin-bottom: 0.5rem; -} - -header .subtitle { - color: var(--text-secondary); - font-size: 1rem; -} - -main { - max-width: 1400px; - margin: 0 auto; - padding: 2rem; -} - -/* Graph sections */ -.graph-section { - background: var(--bg-secondary); - border-radius: 8px; - padding: 1.5rem; - margin-bottom: 2rem; - border: 1px solid var(--border); -} - -.graph-header-row { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1rem; -} - -.graph-header-row h2 { - font-size: 1.25rem; - color: var(--accent); -} - -.view-btn { - background: var(--accent); - color: white; - padding: 0.5rem 1rem; - border-radius: 4px; - text-decoration: none; - font-size: 0.875rem; - transition: opacity 0.2s; -} - -.view-btn:hover { - opacity: 0.8; -} - -.graph-preview { - display: block; - background: white; - border-radius: 4px; - padding: 1rem; - margin-bottom: 1rem; - overflow: auto; - max-height: 400px; -} - -.graph-preview img { - max-width: 100%; - height: auto; -} - -.graph-details { - color: var(--text-secondary); - font-size: 0.9rem; -} - -.graph-details h4 { - color: var(--text-primary); - margin: 1rem 0 0.5rem; -} - -.graph-details ul { - margin-left: 1.5rem; -} - -.graph-details li { - margin-bottom: 0.25rem; -} - -/* Tech section */ -.tech-section { - background: var(--bg-secondary); - border-radius: 8px; - padding: 1.5rem; - margin-bottom: 2rem; - border: 1px solid var(--border); -} - -.tech-section h2 { - color: var(--accent); - margin-bottom: 1rem; -} - -.tech-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1.5rem; -} - -.tech-column h3 { - color: var(--text-primary); - font-size: 1rem; - margin-bottom: 0.75rem; - padding-bottom: 0.5rem; - border-bottom: 1px solid var(--border); -} - -.tech-column ul { - list-style: none; -} - -.tech-column li { - padding: 0.25rem 0; - color: var(--text-secondary); -} - -/* Findings */ -.findings-section { - margin-bottom: 2rem; -} - -.findings-section h2 { - color: var(--accent); - margin-bottom: 1rem; -} - -.findings-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 1rem; -} - -.finding-card { - background: var(--bg-secondary); - border-radius: 8px; - padding: 1.25rem; - border: 1px solid var(--border); -} - -.finding-card h3 { - color: var(--accent); - font-size: 1rem; - margin-bottom: 0.75rem; -} - -.finding-card ul { - margin-left: 1rem; - color: var(--text-secondary); -} - -.finding-card code { - background: var(--bg-primary); - padding: 0.125rem 0.375rem; - border-radius: 3px; - font-size: 0.85em; -} - -/* Footer */ -footer { - text-align: center; - padding: 2rem; - color: var(--text-secondary); - border-top: 1px solid var(--border); -} - -footer .date { - font-size: 0.85rem; -} - -/* Graph viewer page */ -body.graph-viewer { - display: flex; - flex-direction: column; - height: 100vh; -} - -.graph-header { - display: flex; - align-items: center; - gap: 1rem; - padding: 0.75rem 1rem; - background: var(--bg-secondary); - border-bottom: 1px solid var(--border); - flex-wrap: wrap; -} - -.back-link { - color: var(--accent); - text-decoration: none; -} - -.nav-controls { - display: flex; - align-items: center; - gap: 0.5rem; -} - -.nav-controls button { - background: var(--bg-card); - color: var(--text-primary); - border: 1px solid var(--border); - padding: 0.25rem 0.75rem; - border-radius: 4px; - cursor: pointer; -} - -.nav-controls button:disabled { - opacity: 0.3; - cursor: not-allowed; -} - -#nav-position { - color: var(--text-secondary); - font-size: 0.85rem; -} - -.graph-header h1 { - flex: 1; - font-size: 1rem; - text-align: center; -} - -.graph-controls { - display: flex; - gap: 0.5rem; -} - -.graph-controls button { - background: var(--bg-card); - color: var(--text-primary); - border: 1px solid var(--border); - padding: 0.375rem 0.75rem; - border-radius: 4px; - cursor: pointer; - font-size: 0.85rem; -} - -.graph-controls button:hover { - background: var(--accent); -} - -.graph-container { - flex: 1; - overflow: auto; - background: white; - display: flex; - justify-content: center; - align-items: flex-start; - padding: 1rem; -} - -.graph-container.fit img { - max-width: 100%; - max-height: calc(100vh - 60px); - object-fit: contain; -} - -.graph-container.fit-width img { - width: 100%; - height: auto; -} - -.graph-container.fit-height img { - height: calc(100vh - 60px); - width: auto; -} - -.graph-container.actual-size img { - /* No constraints */ -} - -/* Tables */ -.details-table { - width: 100%; - border-collapse: collapse; - margin: 1rem 0; - font-size: 0.85rem; -} - -.details-table th, -.details-table td { - padding: 0.5rem; - text-align: left; - border-bottom: 1px solid var(--border); -} - -.details-table th { - color: var(--text-primary); - background: var(--bg-primary); -} - -.details-table td { - color: var(--text-secondary); -} - -.details-table code { - background: var(--bg-primary); - padding: 0.125rem 0.375rem; - border-radius: 3px; -} - -.note { - font-style: italic; - font-size: 0.85rem; - color: var(--text-secondary); - margin-top: 0.5rem; -} diff --git a/docs/artery/index.html b/docs/artery/index.html deleted file mode 100644 index a44bac3..0000000 --- a/docs/artery/index.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - Artery - Soleprint - - - - - -
-
-

Artery

-

Todo lo vital

-
- -
-
-

- ModelModelo -

-
-
-

Pulse

-

- Composed data flow: a vein configured for a room - with storage -

-

- Flujo de datos compuesto: vein configurado para un - room con almacenamiento -

-
-
-

Vein

-

API connector

-

Conector API

-
-
-

Room

-

Config/env

-

Config/entorno

-
-
-

Depot

-

Data storage

-

Almacenamiento

-
-
-
-
-

Shunt

-

- Mock connector for testing - same interface, fake - data -

-

- Conector mock para testing - misma interfaz, datos - falsos -

-
-
-

Vein Interface

-

Same API shape

-

Misma forma de API

-
-
-

Mock Data

-

Fake responses

-

Respuestas falsas

-
-
-
-
-

Plexus

-

- Full application when you need more than data flow -

-

- Aplicacion completa cuando necesitas mas que flujo - de datos -

-
-
-

Backend

-

FastAPI server

-
-
-

Frontend

-

Web UI

-
-
-

Infra

-

DB, queues, etc

-

DB, colas, etc

-
-
-
-
-
- -
-

- ArchitectureArquitectura -

- Artery Hierarchy -
- -
-

- ComponentsComponentes -

-
-
-

Vein

-

- Stateless API connector. Connects to external - services like Google Sheets, Jira, Slack. Pure data - flow - no state, no storage. -

-

- Conector API sin estado. Conecta a servicios - externos como Google Sheets, Jira, Slack. Flujo de - datos puro. -

-
-
-

Shunt

-

- Mock connector for testing. Same interface as a vein - but returns fake data. -

-

- Conector mock para testing. Misma interfaz que un - vein pero devuelve datos falsos. -

-
-
-

Pulse

-

- Composed data flow. Formula: - Vein + Room + Depot. -

-

- Flujo de datos compuesto. Formula: - Vein + Room + Depot. -

-
-
-

Plexus

-

- Full application with backend, frontend, and - infrastructure. -

-

- Aplicacion completa con backend, frontend e - infraestructura. -

-
-
-
- -
-

- Shared ComponentsComponentes Compartidos -

-
-
-

Room

-

- Runtime environment configuration. Each room is an - isolated instance with its own config and - credentials. -

-

- Configuracion del entorno. Cada room es una - instancia aislada con su propia config y - credenciales. -

-
-
-

Depot

-

- Data storage / provisions. JSON files, configs, - cached responses. -

-

- Almacenamiento de datos. Archivos JSON, configs, - respuestas cacheadas. -

-
-
-
- -
-

- Available VeinsVeins Disponibles -

- -
-
- - - - diff --git a/docs/atlas/index.html b/docs/atlas/index.html deleted file mode 100644 index 4118acd..0000000 --- a/docs/atlas/index.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - - Atlas - Soleprint - - - - - -
-
-

Atlas

-

- Actionable DocumentationDocumentacion Accionable -

-
- -
-
-

- ModelModelo -

-
-
-

Plain Book

-

- Static documentation with an index page -

-

- Documentacion estatica con una pagina indice -

-
-
-

index.html

-

Entry point

-

Punto de entrada

-
-
-

Depot

-

Static content

-

Contenido estatico

-
-
-
-
-

Templated Book

-

- Dynamic docs from template + data elements -

-

- Docs dinamicos desde template + elementos de datos -

-
-
-

Template

-

Jinja2 pattern

-

Patron Jinja2

-
-
-

Depot

-

Data elements

-

Elementos de datos

-
-
-
-
-
- -
-

- ArchitectureArquitectura -

- System Overview -
- -
-

- ComponentsComponentes -

-
-
-

Book

-

- Collection of related documentation. Can be plain - (static HTML) or templated (template + depot - elements). -

-

- Coleccion de documentacion relacionada. Puede ser - plain (HTML estatico) o templated (template + - elementos de depot). -

-
-
-

Template

-

- Jinja2 templates that generate documentation. Define - the structure once, fill with data from depot. -

-

- Templates Jinja2 que generan documentacion. Definen - la estructura una vez, llenan con datos del depot. -

-
-
-
- -
-

- Shared ComponentsComponentes Compartidos -

-
-
-

Room

-

- Runtime environment configuration. Each room can - have its own atlas with project-specific books. -

-

- Configuracion del entorno. Cada room puede tener su - propio atlas con books especificos del proyecto. -

-
-
-

Depot

-

- Data storage. For plain books: static files. For - templated books: elements that fill the template. -

-

- Almacenamiento de datos. Para plain books: archivos - estaticos. Para templated books: elementos que - llenan el template. -

-
-
-
-
- - - - diff --git a/docs/data/en/artery-google.md b/docs/data/en/artery-google.md new file mode 100644 index 0000000..bc9aa7d --- /dev/null +++ b/docs/data/en/artery-google.md @@ -0,0 +1,55 @@ +# Google Vein + +Status: **building** + +Connects soleprint to Google services. OAuth2 flow is implemented. Sheets read access works. Calendar and Drive are next. + +--- + +## What Works + +**OAuth2 authentication** -- full flow with authorization URL generation, code exchange, token refresh, and user identity extraction. Supports both identity (OpenID Connect) and API access scopes. + +**Google Sheets** -- read-only access to spreadsheet data. + +## Configuration + +Create a `.env` file in the vein directory: + +```env +GOOGLE_CLIENT_ID=your-client-id +GOOGLE_CLIENT_SECRET=your-client-secret +GOOGLE_REDIRECT_URI=http://localhost:12000/artery/google/oauth/callback +API_PORT=8003 +``` + +You need a Google Cloud project with OAuth consent screen configured and credentials created. + +## OAuth Scopes + +Identity scopes (default): + +- `openid` +- `userinfo.email` +- `userinfo.profile` + +API scopes (added when needed): + +- `spreadsheets.readonly` +- `drive.readonly` + +## What's Coming + +- Calendar integration +- Drive file browsing and download +- Full Sheets write support + +Configuration details will be added as these integrations mature. + +## Running Standalone + +```bash +cd soleprint/artery/veins/google +python run.py +# Runs on port 8003 +``` diff --git a/docs/data/en/artery-ia.md b/docs/data/en/artery-ia.md new file mode 100644 index 0000000..ce8dba4 --- /dev/null +++ b/docs/data/en/artery-ia.md @@ -0,0 +1,77 @@ +# IA Vein + +Status: **live** + +Connects soleprint to AI/LLM providers. Uses an OpenAI-compatible API interface, so it works with OpenAI, Anthropic (via proxy), local models, or any compatible endpoint. + +--- + +## What It Does + +- Generic chat completion endpoint +- Health check against the configured provider +- Use-case-specific routers mounted as sub-routes +- JSON extraction from AI responses + +## Configuration + +Create a `.env` file in the vein directory: + +```env +AI_API_URL=https://api.openai.com/v1 +AI_API_KEY=your-api-key +AI_MODEL=gpt-4o +API_PORT=8005 +``` + +`AI_API_URL` defaults to OpenAI. Point it at any OpenAI-compatible endpoint. + +## Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| GET | `/ia/health` | Test API connection, returns provider and model info | +| POST | `/ia/chat` | Generic chat completion | +| | `/ia/practice/*` | Practice use-case routes | + +## Authentication + +API key resolves in order: + +1. `X-AI-Token` HTTP header +2. `.env` file value + +This lets soleprint tools pass their own keys per-request. + +## Chat Request + +```json +{ + "messages": [ + {"role": "system", "content": "You are helpful."}, + {"role": "user", "content": "Hello"} + ], + "temperature": 0.7, + "max_tokens": 1024 +} +``` + +The response includes `content` (raw text) and `parsed` (first valid JSON object extracted from the response, if any). + +## Use Cases + +The IA vein supports use-case-specific routers mounted under `/ia/{usecase}/`. Each use case has its own prompts, models, and routes. + +Currently implemented: + +- **Practice** -- AI-powered practice sessions with structured prompts and formatted output + +## Running Standalone + +```bash +cd soleprint/artery/veins/ia +python run.py +# Runs on port 8005 +``` + +Or through soleprint, where it is mounted under `/artery/ia/`. diff --git a/docs/data/en/artery-jira.md b/docs/data/en/artery-jira.md new file mode 100644 index 0000000..3af0311 --- /dev/null +++ b/docs/data/en/artery-jira.md @@ -0,0 +1,71 @@ +# Jira Vein + +Status: **live** + +Connects soleprint to Jira Cloud. Fetches tickets, sprints, backlogs, and epics. Supports text and JSON output formats. + +--- + +## What It Does + +- Query your assigned tickets, project backlogs, and current sprints +- Fetch full ticket details with comments, attachments, and child work items +- Process entire epics: fetch the epic and all children, save to local storage +- Search with raw JQL +- Stream attachment content directly from Jira + +## Configuration + +Create a `.env` file in the vein directory or set environment variables: + +```env +JIRA_URL=https://your-org.atlassian.net +JIRA_EMAIL=you@example.com +JIRA_API_TOKEN=your-api-token +API_PORT=8001 +``` + +`JIRA_EMAIL` and `JIRA_API_TOKEN` are optional in config. They can be provided per-request via HTTP headers instead, allowing one vein instance to serve multiple users. + +Generate an API token at [id.atlassian.net/manage-profile/security/api-tokens](https://id.atlassian.net/manage-profile/security/api-tokens). + +## Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| GET | `/health` | Test connection, returns authenticated user | +| GET | `/mine` | Your assigned open tickets | +| GET | `/backlog?project=KEY` | Project backlog | +| GET | `/sprint?project=KEY` | Current sprint tickets | +| GET | `/ticket/{key}` | Full ticket detail with comments and children | +| POST | `/search` | Raw JQL query | +| POST | `/epic/{key}/process` | Fetch entire epic tree, save to files (streaming) | +| GET | `/epic/{key}/status` | Check if epic has been processed | +| GET | `/attachment/{id}` | Stream attachment content | + +All list endpoints support `page`, `page_size`, and `text=true` for plain-text output. + +## Authentication + +Credentials resolve in order: + +1. HTTP headers (`X-Jira-Email`, `X-Jira-Token`) +2. `.env` file values + +## Text Mode + +Pass `?text=true` to any query endpoint. Returns formatted plain text instead of JSON. Useful for piping into other tools or AI prompts. + +## Epic Processing + +The `/epic/{key}/process` endpoint streams progress as NDJSON. It fetches the epic, then each child ticket with a short delay between requests. All tickets are saved as JSON files to `artery/larder/jira_epics/{key}/`. + +## Running Standalone + +```bash +cd soleprint/artery/veins/jira +python run.py +# Runs on port 8001 +``` + +Or through soleprint, where it is mounted under `/artery/jira/`. diff --git a/docs/data/en/artery-shunts.md b/docs/data/en/artery-shunts.md new file mode 100644 index 0000000..17fd1e4 --- /dev/null +++ b/docs/data/en/artery-shunts.md @@ -0,0 +1,94 @@ +# Shunt Pattern + +Shunts are fake connectors for testing. They mirror real API structures but return configurable mock data. No external service needed. + +--- + +## Why Shunts + +You need to test payment flows without charging real cards. You need to develop against an API that requires VPN access. You need predictable responses for BDD tests. Shunts solve all of these. + +A shunt runs as a FastAPI app, same as a vein. Your code talks to it the same way it would talk to the real service. Swap the URL and you're testing against production. + +## Structure + +``` +shunts/ +└── {name}/ + ├── __init__.py + ├── main.py # FastAPI app + ├── run.py # Standalone runner + ├── core/ + │ └── config.py # Mock behavior settings + ├── api/ + │ └── routes.py # Mock endpoints + └── templates/ # Optional config UI +``` + +## Creating a Shunt + +Start from the example template: + +```bash +cp -r soleprint/artery/shunts/example soleprint/artery/shunts/yourservice +``` + +The example shunt provides: + +- Health check endpoint +- Config UI at root path +- Catch-all GET/POST handlers that return responses from a `responses.json` file +- `SHUNT_DEPOT` environment variable for external response storage + +Edit `responses.json` to define your fake responses: + +```json +{ + "GET /users": [{"id": 1, "name": "Test User"}], + "POST /orders": {"id": 999, "status": "created"} +} +``` + +For more complex behavior, replace the catch-all handlers with specific route implementations. + +## MercadoPago Shunt + +The MercadoPago shunt is a full mock of the MercadoPago payment API. It demonstrates what a production-grade shunt looks like. + +**What it mocks:** + +- Checkout Pro preferences (`POST /v1/preferences`) +- Payments (`POST /v1/payments`, `GET /v1/payments/{id}`) +- Merchant orders (`GET /v1/merchant_orders/{id}`) +- OAuth token exchange (`POST /oauth/token`) +- Webhook simulation (`POST /mock/webhook`) + +**Testing controls:** + +| Endpoint | Purpose | +|----------|---------| +| `POST /mock/config` | Set default payment status, error rate | +| `GET /mock/reset` | Clear all mock data | +| `GET /mock/stats` | Count of stored mock objects | + +**Configurable behavior:** + +- `default_payment_status` -- force all payments to approved, pending, or rejected +- `error_rate` -- probability (0-1) of random 500 errors +- `enable_random_delays` -- simulate real API latency +- `min_delay_ms` / `max_delay_ms` -- delay range in milliseconds + +Data is generated using `datagen`'s MercadoPago generator. Stored in memory. Reset between test runs with `/mock/reset`. + +## Running a Shunt + +```bash +cd soleprint/artery/shunts/mercadopago +python run.py +``` + +Or configure it in your room's shunt registry so soleprint manages it. + +## Room-Specific Shunts + +Rooms can define their own shunts under `cfg/{room}/artery/shunts/`. These are merged into the build output alongside the core shunts. diff --git a/docs/data/en/artery-slack.md b/docs/data/en/artery-slack.md new file mode 100644 index 0000000..3b7c6db --- /dev/null +++ b/docs/data/en/artery-slack.md @@ -0,0 +1,33 @@ +# Slack Vein + +Status: **building** + +Will connect soleprint to Slack for channel messaging and notifications. + +--- + +## What Exists + +The vein structure is in place: config, client, auth, models, routes. Bot token and user token configuration is ready. + +```env +SLACK_BOT_TOKEN=xoxb-... +SLACK_USER_TOKEN=xoxp-... +API_PORT=8002 +``` + +## What's Coming + +- Send messages to channels +- Read channel history +- Notification integration with other soleprint tools + +Configuration details will be added as the integration matures. + +## Running Standalone + +```bash +cd soleprint/artery/veins/slack +python run.py +# Runs on port 8002 +``` diff --git a/docs/data/en/artery.md b/docs/data/en/artery.md new file mode 100644 index 0000000..20e181e --- /dev/null +++ b/docs/data/en/artery.md @@ -0,0 +1,110 @@ +# Artery + +Artery is the connector system. It bridges soleprint to external services -- APIs, messaging platforms, payment processors, AI providers. + +**Todo lo vital** -- everything vital flows through here. + +--- + +## Hierarchy + +Connectors scale from simple to full: + +``` +Vein ──────► Pulse ──────► Plexus +│ │ │ +│ │ └── Full app: backend + frontend + DB +│ │ +│ └── Composed: Vein + Room + Depot +│ +└── Stateless API connector + +Shunt ─── Fake connector for testing +``` + +![Artery Hierarchy](../graphs/artery_hierarchy.svg) + +**Vein** -- a stateless wrapper around an external API. Handles auth, exposes endpoints, runs standalone or through soleprint. Each vein follows the same structure: `core/` for the isolated client, `api/` for FastAPI routes, `models/` for data types. + +**Shunt** -- a mock vein. Returns configurable fake responses so you can test without hitting real APIs. Shunts mirror real API structures but store everything in memory. + +**Pulse** -- a vein composed with a room and a depot. Adds persistent storage and room-specific configuration on top of a raw vein. + +**Plexus** -- a full application. Backend, frontend, database. The highest level of the hierarchy. + +## Veins + +| Vein | Status | Description | +|------|--------|-------------| +| [Jira](artery-jira.md) | live | Issue tracker integration | +| [Google](artery-google.md) | building | OAuth, Sheets, Calendar, Drive | +| [Slack](artery-slack.md) | building | Channel messaging | +| [IA](artery-ia.md) | live | AI/LLM connector | +| Maps | planned | Location services | +| WhatsApp | planned | Messaging | +| GNUCash | planned | Accounting | +| VPN | planned | Network access | + +## Shunts + +| Shunt | Status | Description | +|-------|--------|-------------| +| [MercadoPago](artery-shunts.md) | ready | Mock payment processing API | +| [Example](artery-shunts.md) | ready | Template for creating new shunts | + +See [Shunt Pattern](artery-shunts.md) for how shunts work and how to create one. + +## Vein Structure + +Every vein follows the same layout: + +``` +veins/ +└── {name}/ + ├── __init__.py + ├── main.py # FastAPI app entry point + ├── run.py # Standalone runner + ├── .env # Credentials (not committed) + ├── core/ + │ ├── config.py # Pydantic settings from .env + │ ├── client.py # Isolated API client + │ └── auth.py # Auth handling + ├── api/ + │ └── routes.py # FastAPI router + └── models/ + └── ... # Data models, formatters +``` + +The `core/` module is isolated. It can run without FastAPI. The `api/` module wraps it in HTTP routes. + +## Base Class + +All veins extend `BaseVein`: + +```python +class BaseVein(ABC): + name: str # e.g., 'jira', 'slack' + get_client(creds) -> client # Create API client + health_check(creds) -> dict # Test connection + create_router() -> APIRouter # HTTP routes +``` + +## Configuration + +Veins load credentials from `.env` files using Pydantic settings. Credentials can also be passed per-request via HTTP headers, so one vein instance can serve multiple users. + +Vein configurations are registered in `veins.json`: + +```json +{ + "items": [ + { + "name": "jira", + "slug": "jira", + "title": "Jira", + "status": "live", + "system": "artery" + } + ] +} +``` diff --git a/docs/data/en/atlas-books.md b/docs/data/en/atlas-books.md new file mode 100644 index 0000000..608ac43 --- /dev/null +++ b/docs/data/en/atlas-books.md @@ -0,0 +1,86 @@ +# Atlas Books + +A book is a documentation library served through Atlas. It lives in a directory under `books/` and is served at `/book/{slug}/`. + +--- + +## Two Types + +**Standalone book** -- static HTML files. No template, no depot. Atlas serves them directly. The book and its content are the same thing. + +**Templated book** -- a template defines the structure, a depot (called a larder) provides the data. Atlas renders a landing page with links to the template definition and the data browser. + +## Directory Structure + +### Standalone Book + +``` +books/ +└── feature-flow/ + ├── index-en.html # English version + ├── index-es.html # Spanish version + └── CLAUDE.md # Dev notes +``` + +Routes: +- `/book/feature-flow/` -- language picker +- `/book/feature-flow/en` -- English +- `/book/feature-flow/es` -- Spanish + +A standalone book is just HTML. Put it in the directory, register it in `books.json`, add a route in `main.py`. + +### Templated Book + +``` +books/ +└── feature-form-samples/ + ├── template/ # Template definition + │ └── plantilla-flujo.md + ├── feature-form/ # Larder (data) + │ ├── .larder # Marker file + │ ├── pet-owner/ + │ ├── veterinarian/ + │ └── backoffice/ + ├── index.html # Larder browser + └── detail.html # Detail renderer +``` + +Routes: +- `/book/feature-form-samples/` -- landing page (links to template + larder) +- `/book/feature-form-samples/template/` -- template definition +- `/book/feature-form-samples/larder/` -- data browser +- `/book/feature-form-samples/larder/{user_type}/{file}` -- specific entry + +The `.larder` marker identifies which subdirectory holds the data. + +## The Feature Flow Example + +Feature Flow is the standalone reference. It documents the BDD standardization pipeline -- how features go from idea to Gherkin to test. Two languages, no template, pure HTML. + +## Registration + +Books are registered in `books.json`: + +```json +{ + "items": [ + { + "name": "feature-flow", + "slug": "feature-flow", + "title": "Feature Flow Pipeline", + "status": "ready", + "system": "atlas" + } + ] +} +``` + +## Adding a Room-Specific Book + +1. Create the book directory in `cfg//atlas/books/{slug}/` +2. Add the HTML files +3. Register it in the room's `books.json` (in `cfg//data/`) +4. Add routes in main.py if it needs custom handling +5. Build: `python build.py --cfg ` + +The build merges room books into the output alongside core books. Room books can also override core books by using the same slug. diff --git a/docs/data/en/atlas-templates.md b/docs/data/en/atlas-templates.md new file mode 100644 index 0000000..d6e3cfd --- /dev/null +++ b/docs/data/en/atlas-templates.md @@ -0,0 +1,75 @@ +# Atlas Templates + +A template is a documentation pattern. It defines the structure that content must follow. Templates turn unstructured knowledge into consistent, browsable documentation. + +--- + +## How Templates Work + +A template defines fields, layout, and validation rules. Content that follows the template gets rendered through Atlas with consistent formatting and navigation. + +Templates live in `soleprint/atlas/templates/` (core) or inside a book's `template/` subdirectory. + +Data templates -- the schema files that define structure -- live in `cfg//data/template/`. + +## The Feature Form Example + +The feature form template captures user flows in a structured format: + +| Field | Purpose | +|-------|---------| +| User Type | Who performs this flow | +| Entry Point | Where the flow starts | +| User Goal | One-sentence objective | +| Steps | Numbered sequence of actions | +| Expected Result | What success looks like | +| Common Problems | Known failure modes | +| Special Cases | Edge cases and exceptions | +| Related Flows | Connected user flows | +| Technical Notes | Developer-facing details | + +This template is served at `/book/feature-form-samples/template/` as a styled HTML form with placeholder fields. Non-technical team members can understand the structure without reading code. + +## Depots and Larders + +A **depot** is data storage connected to a template. In Atlas, the depot pattern is called a **larder** -- a directory that holds content conforming to a template. + +The connection works like this: + +``` +Template (structure) + Larder (data) = Templated Book +``` + +A larder directory contains a `.larder` marker file and organizes content in subdirectories. For feature forms, the larder groups entries by user type: + +``` +feature-form/ +├── .larder +├── pet-owner/ +│ ├── register-pet.html +│ └── book-appointment.html +├── veterinarian/ +│ └── review-history.html +└── backoffice/ + └── manage-users.html +``` + +Each file in the larder follows the template's field structure. Atlas renders them through a detail view that reads the content and applies consistent styling. + +## The Larder Pattern + +Larders enforce a constraint: all content in a larder must match the connected template. This keeps documentation consistent even when multiple people contribute. + +The landing page of a templated book links to both: +- The **template** -- so you can see the pattern +- The **larder** -- so you can browse the actual content + +This separation means the template can evolve independently from the data. Update the template, and all larder entries get the new rendering. + +## Adding a Template + +1. Define the template structure (HTML or markdown) in `soleprint/atlas/templates/` or inside a book's `template/` directory +2. Create a larder directory with a `.larder` marker +3. Add content files that follow the template structure +4. Register the book in `books.json` with `template` metadata +5. Add routes in `main.py` for the landing page, template view, and larder browser diff --git a/docs/data/en/atlas.md b/docs/data/en/atlas.md new file mode 100644 index 0000000..88704c1 --- /dev/null +++ b/docs/data/en/atlas.md @@ -0,0 +1,54 @@ +# Atlas + +Atlas is the documentation system. It turns structured data into browsable documentation. + +**Mapeando el recorrido** -- mapping the journey. + +--- + +## Components + +Atlas has three components: + +| Component | Purpose | +|-----------|---------| +| **Books** | Documentation libraries. Standalone HTML or template-generated. | +| **Templates** | Documentation patterns. Define how content is structured and rendered. | +| **Depots** | Data storage. Connect templates to actual content. | + +A book can be standalone -- just HTML files served directly. Or it can be template-backed, where a template defines the structure and a depot provides the data. + +## How It Works + +Atlas runs as a FastAPI app inside soleprint. It serves books at `/book/{slug}/`, fetches data from the soleprint hub, and renders content using Jinja2 templates or static HTML. + +Books are registered in `books.json`. Templates and depots connect through the book's directory structure. + +## Room-Specific Books + +Core books live in `soleprint/atlas/books/`. Room-specific books live in `cfg//atlas/books/`. + +At build time, room-specific books are merged into the output: + +``` +soleprint/atlas/books/ # Core books (all rooms) +cfg/amar/atlas/books/ # Amar-specific books + ↓ build.py +gen/amar/soleprint/atlas/books/ # Merged output +``` + +Core books ship with every room. Room books add to or override them. The build copies the core first, then overlays the room-specific content. + +## Data Templates + +Template data files live in `cfg//data/template/`. These define the structure that depot content must follow. + +## Current State + +| Component | Item | Status | +|-----------|------|--------| +| Book | Feature Flow Pipeline | ready | +| Template | Feature Form | ready | +| Depot | Feature Forms | ready | + +See [Books](atlas-books.md) and [Templates](atlas-templates.md) for details on each pattern. diff --git a/docs/data/en/components.md b/docs/data/en/components.md new file mode 100644 index 0000000..081f2aa --- /dev/null +++ b/docs/data/en/components.md @@ -0,0 +1,54 @@ +# Shared Components + +Soleprint has two distributable components. They live inside the spr repo and get published into consuming projects. + +Management is handled by `ctrl/spr.py`. + +## soleprint-ui + +Vue component library. Includes GraphRenderer, sidebar components, and shared UI pieces. + +Source: `soleprint/common/ui/` + +Publish to a consuming project: + +```bash +python ctrl/spr.py publish soleprint-ui +``` + +The target project receives the built files and commits them directly. No npm dependency on spr. + +## soleprint-modelgen + +Model generator. Reads schema definitions and produces model files. + +Source: `soleprint/station/tools/modelgen/` + +Has a `pyproject.toml` for local editable install: + +```bash +pip install -e soleprint/station/tools/modelgen/ +``` + +## Registry + +`registry.json` at the repo root defines all components. Each entry has: + +- **name** — component identifier +- **type** — `npm` or `python` +- **source** — path within the repo +- **version** — current version string + +## Commands + +```bash +python ctrl/spr.py list # Show all components +python ctrl/spr.py sync # One-time copy +python ctrl/spr.py watch # Live sync (ctrl+c to stop) +python ctrl/spr.py publish # Versioned publish +python ctrl/spr.py diff # Show differences +``` + +`sync` copies files once. `watch` keeps them in sync while you develop. `publish` stamps a version and copies. + +The consuming project has no awareness of spr. It just commits whatever lands in the target folder. diff --git a/docs/data/en/concepts.md b/docs/data/en/concepts.md new file mode 100644 index 0000000..7536ba1 --- /dev/null +++ b/docs/data/en/concepts.md @@ -0,0 +1,75 @@ +# Concepts + +The mental model behind soleprint. + +--- + +## Rooms + +A room is an isolated configuration. Each room lives in `cfg//` and contains everything soleprint needs to build and run a specific instance. + +``` +cfg/ + standalone/ # Soleprint only, no managed app + amar/ # Soleprint wrapping the Amar application + myroom/ # Your room +``` + +Rooms are independent. They don't share state. You can run multiple rooms simultaneously on different ports. + +## Systems + +Three systems plug into the soleprint core: + +- **Artery** — data flow. Connectors to external services. Veins talk to real APIs. Shunts fake them for testing. Pulses compose a vein with a room and depot. Plexus is a full app stack. +- **Atlas** — documentation. Books, templates, depots. Documentation that lives next to what it describes and stays actionable. +- **Station** — execution. Tools like tester, datagen, modelgen, graphgen. Monitors like databrowse. Desks for task orchestration. + +## The cfg to gen Flow + +`cfg/` is hand-authored. `gen/` is machine-built. Never edit `gen/` directly. + +``` +cfg/myroom/ ──┐ + ├── build.py ──► gen/myroom/ +soleprint/ ──┘ +``` + +`build.py` merges the core framework (`soleprint/`) with your room config (`cfg/myroom/`). Room-specific files override or extend core defaults. The output in `gen/myroom/` is what actually runs. + +![Build Flow](../graphs/cfg_gen_flow.svg) + +## Layers + +Room initialization uses layers 0 through 6. Each layer adds a capability: + +| Layer | What | +|-------|------| +| 0 | Config — `config.json`, branding, terminology | +| 1 | Docker — container setup, compose files | +| 2 | Managed app — the application soleprint wraps | +| 3 | Link — bridge adapters to the managed app's database | +| 4 | Scripts — build and run scripts in `ctrl/` | +| 5 | Systems — artery, atlas, station configs | +| 6 | Nginx — reverse proxy, sidebar injection | + +![Room Layers](../graphs/room_layers.svg) + +## Standalone vs Managed + +**Standalone** — soleprint runs by itself. No managed app. Useful for tooling, documentation, or connector development. + +**Managed** — soleprint wraps an existing application. Nginx sits in front of the app, injecting the sidebar into every HTML response. Link adapters bridge soleprint into the app's database. + +## The Wrapping Concept + +Soleprint never touches your app's source code. The injection works like this: + +1. Nginx receives the app's HTML response +2. `sub_filter` injects soleprint's CSS and JS before `` +3. The sidebar renders on top of the app's UI +4. Link adapters connect to the app's database for data browsing and test data generation + +The app doesn't know soleprint exists. No SDK. No middleware. No build step changes. + +> Your app runs exactly as it would without soleprint. The sidebar is a layer on top. diff --git a/docs/data/en/deployment.md b/docs/data/en/deployment.md new file mode 100644 index 0000000..b2731ad --- /dev/null +++ b/docs/data/en/deployment.md @@ -0,0 +1,63 @@ +# Deployment + +## Docker Compose + +The default. Every built room gets its own compose stack. + +```bash +cd gen//soleprint +docker compose up +``` + +Environment variables in `.env` control the stack: + +- `DEPLOYMENT_NAME` — identifies the deployment +- `NETWORK_NAME` — Docker network name +- `SOLEPRINT_PORT` — port to expose + +Each room runs independently. No shared state between rooms. + +## Local Development with Caddy + +For multi-room local dev, Caddy acts as a reverse proxy. It routes by hostname. + +Caddyfile location: `~/wdir/ppl/local/Caddyfile` + +Add entries to `/etc/hosts` for each room: + +``` +127.0.0.1 myroom.local.ar +127.0.0.1 myroom.spr.local.ar +``` + +Routing pattern: + +- `myroom.local.ar` — app direct +- `myroom.spr.local.ar` — app with soleprint sidebar + +Caddy reads the hostname and proxies to the right container. + +## AWS Deployment + +Production runs on EC2. Domain: `soleprint.mcrn.ar`. + +Deploy standalone with: + +```bash +./ctrl/deploy.sh +``` + +Services sit on a shared Docker network. Nginx handles routing by subdomain. + +## The Gateway Pattern + +All rooms share one Nginx entry point. One server, one IP, many rooms. + +How it works: + +1. Wildcard DNS: `*.mcrn.ar` points to the EC2 instance. +2. Nginx receives the request and reads the hostname. +3. Hostname maps to a container on the shared Docker network. +4. Nginx proxies to that container. + +No per-room DNS config. Add a room, add an Nginx block, reload. The wildcard handles the rest. diff --git a/docs/data/en/intro.md b/docs/data/en/intro.md new file mode 100644 index 0000000..d059137 --- /dev/null +++ b/docs/data/en/intro.md @@ -0,0 +1,52 @@ +# Introduction + +Soleprint is a development workflow platform. It wraps existing applications without touching their source code. + +You get a sidebar injected into your app, connectors to external services, a test runner, data generators, and documentation tools. All running alongside your app, not inside it. + +**Cada paso deja huella** — each step leaves a mark. + +--- + +## Why It Exists + +Born from freelance friction. Testing required PRs. Documentation was scattered across wikis and READMEs. Quick API connectors took too long to set up. Every project reinvented the same plumbing. + +Soleprint is the control room that sits next to your app. You build once, reuse everywhere. + +## How It Works + +Soleprint runs as a Docker composition alongside your application. Nginx intercepts the app's HTML response and injects a sidebar via `sub_filter`. The sidebar connects to soleprint's backend, which bridges into the app's database through link adapters. + +Your app stays untouched. No SDK. No middleware. No source changes. + +## The Four Systems + +| System | Purpose | +|--------|---------| +| **Artery** | Connectors to external services — Jira, Slack, Google, or your own APIs | +| **Atlas** | Actionable documentation — books, templates, depots | +| **Station** | Tools and execution — tester, datagen, modelgen, graphgen, databrowse | +| **Soleprint** | Core coordinator — ties the systems together | + +![System Overview](../graphs/system_overview.svg) + +## Artery Hierarchy + +Connectors scale from simple to full: + +- **Vein** — stateless API connector +- **Shunt** — fake connector for testing +- **Pulse** — composed: vein + room + depot +- **Plexus** — full app: backend + frontend + database + +## What You Get + +- Sidebar injection into any web app +- BDD test runner with Gherkin support +- Test data generation with faker +- Model generation from schema +- Interactive data browser +- Navigable model graphs +- Reusable API connectors with mock equivalents +- Documentation that lives next to the code it describes diff --git a/docs/data/en/managed.md b/docs/data/en/managed.md new file mode 100644 index 0000000..21cdc64 --- /dev/null +++ b/docs/data/en/managed.md @@ -0,0 +1,40 @@ +# Managed Room + +A managed room wraps an existing application. Soleprint runs alongside it, providing tools and a sidebar without touching the app's source code. + +## Structure + +``` +gen/myroom/ + myapp/ # The app (cloned repos + Docker) + link/ # DB bridge (FastAPI adapter) + soleprint/ # Soleprint instance +``` + +## Wrapping mechanism + +Nginx `sub_filter` injects sidebar CSS and JS into the app's HTML `` tag. The app serves normally — soleprint attaches from the outside. + +![Wrapping](../graphs/wrapping.svg) + +## config.json + +A managed room adds these fields to `config.json`: + +- `managed.name` — the app name +- `managed.repos.backend` — backend repository +- `managed.repos.frontend` — frontend repository + +## Sidebar + +Loads from `/spr/sidebar.js` and `/spr/sidebar.css`, configured via `/api/sidebar/config`. + +The sidebar is generic at runtime. All customization comes from `config.json`. + +## Hosts + +Add to `/etc/hosts`: + +``` +127.0.0.1 myroom.spr.local.ar myroom.local.ar +``` diff --git a/docs/data/en/quickstart.md b/docs/data/en/quickstart.md new file mode 100644 index 0000000..a836a2f --- /dev/null +++ b/docs/data/en/quickstart.md @@ -0,0 +1,87 @@ +# Quick Start + +Zero to running in 2 minutes. + +## Prerequisites + +- Python 3.12+ +- Docker + +## Setup + +**1. Clone the repo** + +```bash +git clone spr +cd spr +``` + +**2. Initialize a room** + +```bash +python -m init.cli myroom +``` + +The interactive wizard walks you through layers 0-6. Accept the defaults for a standalone setup. + +**3. Build** + +```bash +python build.py --cfg myroom +``` + +This merges core framework files with your room config into `gen/myroom/`. + +**4. Run** + +```bash +cd gen/myroom && docker compose up +``` + +**5. Open** + +Visit [http://localhost:12000](http://localhost:12000). + +--- + +## Alternative: Browser Wizard + +Prefer a UI? Run the web initializer: + +```bash +python -m init.web +``` + +Open [http://localhost:9000](http://localhost:9000) and configure your room from the browser. + +## Clone an Existing Room + +Start from a sample configuration: + +```bash +python -m init.cli myroom --from sample +``` + +This copies the sample room's config as your starting point. + +## Rebuild + +After changing anything in `cfg/myroom/`, rebuild: + +```bash +python build.py --cfg myroom +``` + +Then restart the containers. + +## Build All Rooms + +```bash +python build.py --all +``` + +## Ports + +| Service | Port | +|---------|------| +| Soleprint | 12000 | diff --git a/docs/data/en/room-setup.md b/docs/data/en/room-setup.md new file mode 100644 index 0000000..cf864aa --- /dev/null +++ b/docs/data/en/room-setup.md @@ -0,0 +1,42 @@ +# Room Setup + +Two ways to create a room: CLI wizard or web wizard. + +```bash +# CLI wizard +python -m init.cli myroom + +# Web wizard (opens browser on :9000) +python -m init.web + +# Clone from existing room +python -m init.cli myroom --from sample +``` + +## Layers + +Each layer is optional beyond layer 0. + +| Layer | What | Files | +|-------|------|-------| +| 0 | Config + Data | `config.json`, `data/*.json` | +| 1 | Docker | `soleprint/docker-compose.yml`, `.env` | +| 2 | Managed App | `docker-compose.yml`, Dockerfiles, `.env` | +| 3 | Link | `link/main.py`, `adapters/`, Dockerfile | +| 4 | Scripts | `ctrl/start.sh`, `stop.sh`, `status.sh`, `logs.sh` | +| 5 | Systems | tester environments, test scaffolds | +| 6 | Nginx | `nginx/local.conf`, `docker-compose.nginx.yml` | + +![Room Layers](../graphs/room_layers.svg) + +The wizard adds layers incrementally. Layer 0 is always created. Each subsequent layer builds on the previous ones but none are required. + +## Build + +After the wizard finishes, build the room: + +```bash +python build.py --cfg myroom +``` + +Output goes to `gen/myroom/`. The build merges room-specific configs from `cfg/myroom/` into the base framework. diff --git a/docs/data/en/standalone.md b/docs/data/en/standalone.md new file mode 100644 index 0000000..1fdd92d --- /dev/null +++ b/docs/data/en/standalone.md @@ -0,0 +1,46 @@ +# Standalone Room + +A standalone room is soleprint by itself — no managed app. Good for documentation, tool development, or running the platform independently. + +## Structure + +``` +cfg/standalone/ + config.json + data/*.json # 12 registry files + soleprint/ + docker-compose.yml +``` + +Build output is flat — all systems merged into one directory: + +``` +gen/standalone/ +``` + +## config.json + +Three sections: + +- **framework** — name, port +- **systems** — artery, atlas, station toggles and settings +- **components** — the naming scheme used across the room + +## Data registries + +The `data/*.json` files are registries: `veins.json`, `tools.json`, `books.json`, etc. + +Each follows the same shape: + +```json +{ + "items": [ + { + "name": "...", + "slug": "...", + "title": "...", + "status": "..." + } + ] +} +``` diff --git a/docs/data/en/station-databrowse.md b/docs/data/en/station-databrowse.md new file mode 100644 index 0000000..e8440af --- /dev/null +++ b/docs/data/en/station-databrowse.md @@ -0,0 +1,80 @@ +# Databrowse + +SQL data browser. Connects to a database, reads its schema from config, and provides a navigation and query interface. + +**Status:** ready + +--- + +## What It Does + +Databrowse is a monitor, not a tool. It runs continuously and lets you browse database contents through a web interface. Navigate tables, inspect rows, run saved queries. + +The core is generic SQL. Room configuration defines the schema and saved views. + +## Structure + +``` +soleprint/station/monitors/databrowse/ # Core (generic SQL browser) +cfg//soleprint/station/monitors/databrowse/depot/ # Room config +``` + +## Configuration + +Room-specific config lives in the depot directory. + +### schema.json + +Defines tables, fields, and relationships: + +```json +{ + "tables": [ + { + "name": "users", + "fields": [ + {"name": "id", "type": "integer", "primary": true}, + {"name": "email", "type": "string"}, + {"name": "created_at", "type": "datetime"} + ], + "relationships": [ + {"field": "id", "target": "orders.user_id", "type": "one_to_many"} + ] + } + ] +} +``` + +### views.json + +Defines saved queries: + +```json +{ + "views": [ + { + "name": "Recent Users", + "query": "SELECT * FROM users ORDER BY created_at DESC LIMIT 50" + }, + { + "name": "Active Orders", + "query": "SELECT * FROM orders WHERE status = 'active'" + } + ] +} +``` + +## Separation + +Core provides: +- SQL connection handling +- Table navigation UI +- Query execution engine +- Relationship traversal + +Room provides: +- `depot/schema.json` -- table definitions +- `depot/views.json` -- saved queries +- Database connection credentials + +The core knows nothing about your domain. The depot tells it what to show. diff --git a/docs/data/en/station-datagen.md b/docs/data/en/station-datagen.md new file mode 100644 index 0000000..4ec5bdc --- /dev/null +++ b/docs/data/en/station-datagen.md @@ -0,0 +1,57 @@ +# Datagen + +Test data generator using faker. Produces realistic, domain-specific data for testing and development. + +**Status:** live + +--- + +## What It Does + +Datagen generates fake but realistic data. Names, emails, addresses, transactions -- whatever your domain needs. It uses Python's faker library under the hood. + +Core datagen is a placeholder. The real work happens in room-specific generators. + +## Structure + +``` +soleprint/station/tools/datagen/ # Core (base classes, placeholder) +cfg//soleprint/station/tools/datagen/ # Room-specific generators +``` + +After build, both merge into `gen//station/tools/datagen/`. + +## Pattern + +Rooms subclass a base generator and provide domain-specific data factories: + +```python +from station.tools.datagen.base import BaseGenerator + +class AmarDataGenerator(BaseGenerator): + def generate_customers(self, count=10): + return [self.fake_customer() for _ in range(count)] + + def fake_customer(self): + return { + "name": self.faker.name(), + "email": self.faker.email(), + "phone": self.faker.phone_number(), + } +``` + +Each room defines what data it needs. Core provides the faker instance and base class. Rooms provide the factories. + +## Room Configuration + +Room generators live in `cfg//soleprint/station/tools/datagen/`. They are fully self-contained -- they define their own models, factories, and output formats. + +The core module provides: +- Base generator class with faker instance +- CLI entry point +- Output formatting (JSON, CSV) + +Rooms provide: +- Domain-specific generator subclasses +- Field definitions and relationships +- Volume and distribution configuration diff --git a/docs/data/en/station-graphgen.md b/docs/data/en/station-graphgen.md new file mode 100644 index 0000000..4d2cf39 --- /dev/null +++ b/docs/data/en/station-graphgen.md @@ -0,0 +1,38 @@ +# Graphgen + +Interactive database schema visualization. Supabase-style graph of your data model, rendered in the browser. + +**Status:** planned + +--- + +## What It Will Do + +Graphgen will take a schema definition and render it as an interactive, navigable graph. Tables as nodes, relationships as edges. Click to explore, zoom to navigate. + +Think Supabase's schema visualizer, but fed by soleprint's modelgen extractors and rendered with soleprint-ui's GraphRenderer. + +## Architecture + +``` +Extract (modelgen) ──► Serve (station API) ──► Render (GraphRenderer) +``` + +**Extract** -- modelgen extractors read the codebase (Django, SQLAlchemy, Prisma) and produce a normalized schema. + +**Serve** -- station exposes the schema as a JSON API endpoint. + +**Render** -- GraphRenderer (Vue Flow) draws the interactive graph in the browser. + +## Dependencies + +- **modelgen extractors** -- must be functional before graphgen can extract schemas +- **soleprint-ui GraphRenderer** -- Vue Flow-based component for rendering + +Graphgen depends on modelgen extractors being complete. That is the blocking dependency. + +## Location + +``` +soleprint/station/tools/graphgen/ # Core (not yet built) +``` diff --git a/docs/data/en/station-modelgen.md b/docs/data/en/station-modelgen.md new file mode 100644 index 0000000..acfe89d --- /dev/null +++ b/docs/data/en/station-modelgen.md @@ -0,0 +1,54 @@ +# Modelgen + +Generates platform-specific models from JSON Schema. Reads schema once, writes models for multiple targets. + +**Status:** dev + +--- + +## What It Does + +Modelgen takes a JSON Schema definition and produces model code for different platforms: + +- **Pydantic** -- Python data validation models +- **Django ORM** -- Django model classes +- **Prisma** -- Prisma schema definitions + +One schema, multiple outputs. + +## Extractors + +Modelgen also works in reverse. Extractors read existing codebases and produce a normalized schema representation: + +- **Django extractor** -- reads Django model files +- **SQLAlchemy extractor** -- reads SQLAlchemy model files +- **Prisma extractor** -- reads Prisma schema files + +Extractors feed into graphgen for visualization. + +## Output + +Generated models are written to `gen//models/`. + +``` +gen//models/ +├── pydantic/ +├── django/ +└── prisma/ +``` + +## CLI + +```bash +python -m modelgen +``` + +Reads from `schema.json` (the project source of truth) and writes to the configured output directory. + +## Shared Distribution + +Modelgen is also distributed as a shared component via `ctrl/spr.py`. This allows other projects to use model generation without running full soleprint. + +## Schema Source + +The source of truth is `schema.json` at the project root. All model generation starts from this file. Room-specific schema extensions live in `cfg//models/`. diff --git a/docs/data/en/station-tester.md b/docs/data/en/station-tester.md new file mode 100644 index 0000000..f2decf2 --- /dev/null +++ b/docs/data/en/station-tester.md @@ -0,0 +1,99 @@ +# Tester + +HTTP contract test runner with web UI and CLI. Tests API endpoints against configurable environments with support for multiple auth types. + +**Status:** live + +--- + +## What It Does + +Tester runs HTTP requests against real endpoints and validates responses. It is not a unit test runner. It tests contracts -- does this endpoint return what the spec says it should? + +Tests are written as Python classes extending `ContractTestCase`. They run via pytest or through the soleprint web UI. + +## Configuration + +### Environments + +Defined in `environments.json`: + +```json +{ + "environments": [ + { + "name": "local", + "url": "http://localhost:8000", + "auth_type": "none" + }, + { + "name": "staging", + "url": "https://staging.example.com", + "auth_type": "bearer", + "token_endpoint": "/api/token/" + }, + { + "name": "external", + "url": "https://api.example.com", + "auth_type": "api-key" + } + ] +} +``` + +Auth types: `bearer`, `api-key`, `none`. + +## Base Class + +All tests extend `ContractTestCase`: + +```python +from station.tools.tester.base import ContractTestCase + +class TestUserEndpoints(ContractTestCase): + AUTH_TYPE = "bearer" + TOKEN_ENDPOINT = "/api/token/" + + def test_list_users(self): + response = self.get("/api/users/") + self.assertEqual(response.status_code, 200) +``` + +`ContractTestCase` handles auth negotiation, environment selection, and base URL resolution. + +## Test Discovery + +Tests live in two places: + +- **Core tests:** `soleprint/station/tools/tester/tests/` -- shared across all rooms +- **Room tests:** `cfg//soleprint/station/tools/tester/tests/` -- room-specific + +Room tests import from core: + +```python +from station.tools.tester.base import ContractTestCase +``` + +After build, both are merged into `gen//station/tools/tester/tests/`. + +## Helpers + +Built-in test helpers: + +- `unique_email()` -- generates a unique email address +- `unique_id()` -- generates a unique identifier + +These are generic helpers available to all rooms. Room-specific helpers stay in `cfg//` and are not part of core. + +## Running + +**Web UI:** navigate to `/station/tools/tester/` in soleprint. + +**CLI:** + +```bash +cd gen/ +pytest station/tools/tester/tests/ +``` + +Environment selection is handled via config or CLI flags. diff --git a/docs/data/en/station.md b/docs/data/en/station.md new file mode 100644 index 0000000..f9dfcc0 --- /dev/null +++ b/docs/data/en/station.md @@ -0,0 +1,71 @@ +# Station + +Station is the execution system. It runs tools, monitors environments, and bundles them into composable desks. + +**Centro de control** -- the control center. + +--- + +## Hierarchy + +Station components scale from single-purpose to composed: + +``` +Tool ──────► Desk +│ │ +│ └── Composed: Cabinet + Room + Depots +│ +└── Standalone executable (tester, datagen, modelgen, graphgen) + +Monitor ─── Long-running observer (databrowse) +``` + +**Tool** -- a standalone executable that does one job. Generates data, runs tests, produces models. Each tool works independently and can be invoked via web UI or CLI. + +**Monitor** -- a long-running observer. Connects to a data source and provides a browsing or query interface. Always on, not invoked per-task. + +**Desk** -- a composed execution bundle. Combines a cabinet (tool configuration), a room, and depots (data sources) into a ready-to-run environment. + +## Tools + +| Tool | Status | Description | +|------|--------|-------------| +| [Tester](station-tester.md) | live | HTTP contract test runner, multi-environment, BDD/Gherkin | +| [Datagen](station-datagen.md) | live | Test data generator using faker | +| [Modelgen](station-modelgen.md) | dev | Generate models from JSON Schema (Pydantic, Django, Prisma) | +| [Graphgen](station-graphgen.md) | planned | Supabase-style interactive DB schema visualization | + +## Monitors + +| Monitor | Status | Description | +|---------|--------|-------------| +| [Databrowse](station-databrowse.md) | ready | SQL data browser | + +## Structure + +``` +station/ +├── tools/ +│ ├── tester/ # HTTP contract testing +│ ├── datagen/ # Test data generation +│ ├── modelgen/ # Model generation from schema +│ └── graphgen/ # Schema visualization (planned) +├── monitors/ +│ └── databrowse/ # SQL data browser +└── desks/ # Composed execution bundles +``` + +## Room Configuration + +Tools and monitors follow the same split as all soleprint systems. Core logic lives in `soleprint/station/`. Room-specific configuration lives in `cfg//soleprint/station/`. + +``` +cfg//soleprint/station/ +├── tools/ +│ ├── tester/tests/ # Room-specific test cases +│ └── datagen/ # Room-specific data generators +└── monitors/ + └── databrowse/depot/ # Room-specific schema and views +``` + +The build merges both into `gen//`. diff --git a/docs/data/topics.json b/docs/data/topics.json new file mode 100644 index 0000000..e22d553 --- /dev/null +++ b/docs/data/topics.json @@ -0,0 +1,29 @@ +[ + {"id": "intro", "title": {"en": "Introduction"}}, + {"id": "quickstart", "title": {"en": "Quick Start"}}, + {"id": "concepts", "title": {"en": "Concepts"}}, + {"id": "room-setup", "title": {"en": "↳ Room Setup"}, "sub": true}, + {"id": "standalone", "title": {"en": "↳ Standalone"}, "sub": true}, + {"id": "managed", "title": {"en": "↳ Managed"}, "sub": true}, + + {"id": "artery", "title": {"en": "Artery"}}, + {"id": "artery-jira", "title": {"en": "↳ Jira"}, "sub": true}, + {"id": "artery-google", "title": {"en": "↳ Google"}, "sub": true}, + {"id": "artery-slack", "title": {"en": "↳ Slack"}, "sub": true}, + {"id": "artery-ia", "title": {"en": "↳ IA"}, "sub": true}, + {"id": "artery-shunts", "title": {"en": "↳ Shunts"}, "sub": true}, + + {"id": "atlas", "title": {"en": "Atlas"}}, + {"id": "atlas-books", "title": {"en": "↳ Books"}, "sub": true}, + {"id": "atlas-templates", "title": {"en": "↳ Templates"}, "sub": true}, + + {"id": "station", "title": {"en": "Station"}}, + {"id": "station-tester", "title": {"en": "↳ Tester"}, "sub": true}, + {"id": "station-datagen", "title": {"en": "↳ Datagen"}, "sub": true}, + {"id": "station-modelgen", "title": {"en": "↳ Modelgen"}, "sub": true}, + {"id": "station-graphgen", "title": {"en": "↳ Graphgen"}, "sub": true}, + {"id": "station-databrowse", "title": {"en": "↳ Databrowse"}, "sub": true}, + + {"id": "components", "title": {"en": "Shared Components"}}, + {"id": "deployment", "title": {"en": "Deployment"}} +] diff --git a/docs/docs.css b/docs/docs.css new file mode 100644 index 0000000..aca837d --- /dev/null +++ b/docs/docs.css @@ -0,0 +1,347 @@ +/* soleprint docs — minimal-neon */ + +:root { + --bg: #0a0a0a; + --surface: #1a1a1a; + --border: #333; + --text: #e5e5e5; + --text-muted: #a3a3a3; + --text-dim: #666; + --amber: #d4a574; + --amber-dim: #b8956a; + + --artery: #b91c1c; + --artery-text: #fca5a5; + --atlas: #15803d; + --atlas-text: #86efac; + --station: #1d4ed8; + --station-text: #93c5fd; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +body { + font-family: system-ui, -apple-system, sans-serif; + background: var(--bg); + color: var(--text); + line-height: 1.6; + min-height: 100vh; +} + +/* Layout */ +.layout { + display: flex; + min-height: 100vh; +} + +/* Sidebar */ +.sidebar { + width: 220px; + flex-shrink: 0; + background: var(--surface); + border-right: 1px solid var(--border); + position: sticky; + top: 0; + height: 100vh; + overflow-y: auto; + padding: 1.5rem 0; +} + +/* Hide sidebar scrollbar */ +.sidebar::-webkit-scrollbar { width: 0; } +.sidebar { scrollbar-width: none; } + +.sidebar-header { + padding: 0 1rem 1rem; + border-bottom: 1px solid var(--border); + margin-bottom: 0.5rem; +} + +.sidebar-header a { + text-decoration: none; + color: inherit; +} + +.sidebar-header h1 { + font-size: 1rem; + font-weight: 600; + color: var(--text); + letter-spacing: 0.5px; +} + +.sidebar-header span { + font-size: 0.75rem; + color: var(--text-dim); +} + +.sidebar-item { + display: block; + padding: 0.4rem 1rem; + font-size: 0.85rem; + color: var(--text-muted); + text-decoration: none; + border-left: 2px solid transparent; + cursor: pointer; + transition: all 0.15s; +} + +.sidebar-item:hover { + color: var(--text); + background: rgba(255,255,255,0.03); +} + +.sidebar-item.active { + color: var(--amber); + border-left-color: var(--amber); + background: rgba(212,165,116,0.05); +} + +.sidebar-chevron { + display: inline-block; + margin-right: 0.3rem; + transition: transform 0.15s; + font-size: 0.7rem; + color: var(--text-dim); +} + +.sidebar-chevron.expanded { + transform: rotate(90deg); +} + +.sidebar-sub { + padding-left: 1.75rem; + font-size: 0.8rem; + border-left-color: transparent; + color: var(--text-dim); +} + +.sidebar-sub:hover { + color: var(--text-muted); +} + +.sidebar-sub.active { + color: var(--amber); + border-left-color: var(--amber); + background: rgba(212,165,116,0.05); +} + +/* System-colored sidebar items */ +.sidebar-item[href*="artery"]:hover, +.sidebar-sub[href*="artery"]:hover { color: var(--artery-text); } +.sidebar-item[href*="artery"].active, +.sidebar-sub[href*="artery"].active { color: var(--artery-text); border-left-color: var(--artery); } + +.sidebar-item[href*="atlas"]:hover, +.sidebar-sub[href*="atlas"]:hover { color: var(--atlas-text); } +.sidebar-item[href*="atlas"].active, +.sidebar-sub[href*="atlas"].active { color: var(--atlas-text); border-left-color: var(--atlas); } + +.sidebar-item[href*="station"]:hover, +.sidebar-sub[href*="station"]:hover { color: var(--station-text); } +.sidebar-item[href*="station"].active, +.sidebar-sub[href*="station"].active { color: var(--station-text); border-left-color: var(--station); } + +/* Content */ +.content { + flex: 1; + min-width: 0; + max-width: 800px; + padding: 2rem 3rem; +} + +.loading { + color: var(--text-dim); +} + +/* Markdown rendering */ +.content h1 { + font-size: 1.5rem; + font-weight: 600; + color: var(--amber); + margin-bottom: 1.5rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--border); +} + +.content h2 { + font-size: 1.1rem; + font-weight: 600; + color: var(--text); + margin-top: 2rem; + margin-bottom: 0.75rem; +} + +.content h3 { + font-size: 0.95rem; + font-weight: 600; + color: var(--text-muted); + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} + +.content p { + font-size: 0.9rem; + color: var(--text-muted); + margin-bottom: 0.75rem; + line-height: 1.7; +} + +.content strong { + color: var(--text); + font-weight: 600; +} + +.content a { + color: var(--amber); + text-decoration: none; +} + +.content a:hover { + text-decoration: underline; +} + +.content blockquote { + border-left: 3px solid var(--amber); + padding: 0.75rem 1.25rem; + margin: 1rem 0; + background: var(--surface); + border-radius: 0 8px 8px 0; +} + +.content blockquote p { + margin-bottom: 0; + color: var(--amber); + font-size: 0.9rem; +} + +.content ul, .content ol { + padding-left: 0; + margin: 0.75rem 0; + list-style: none; +} + +.content li { + font-size: 0.9rem; + color: var(--text-muted); + padding-left: 1.25rem; + margin-bottom: 0.4rem; + position: relative; + line-height: 1.6; +} + +.content li::before { + content: ">"; + position: absolute; + left: 0; + color: var(--amber); + font-weight: 600; +} + +.content hr { + border: none; + border-top: 1px solid var(--border); + margin: 2rem 0; +} + +.content pre { + background: var(--surface); + border: 1px solid var(--border); + padding: 1rem; + margin: 1rem 0; + overflow-x: auto; + border-radius: 8px; + font-size: 0.85rem; + line-height: 1.5; +} + +.content code { + font-family: ui-monospace, "SF Mono", "Cascadia Mono", monospace; + color: var(--amber); + font-size: 0.85rem; +} + +.content pre code { + color: var(--text); +} + +/* Tables */ +.content table { + width: 100%; + border-collapse: collapse; + margin: 1rem 0; + font-size: 0.85rem; +} + +.content th { + text-align: left; + padding: 0.5rem 0.75rem; + border-bottom: 2px solid var(--border); + color: var(--amber); + font-weight: 600; + white-space: nowrap; +} + +.content td { + padding: 0.4rem 0.75rem; + border-bottom: 1px solid var(--border); + color: var(--text-muted); + line-height: 1.5; +} + +.content tr:hover td { + background: var(--surface); +} + +/* Graph images inline */ +.content img { + max-width: 100%; + height: auto; + border: 1px solid var(--border); + border-radius: 8px; + margin: 1rem 0; +} + +/* Responsive */ +@media (max-width: 768px) { + .layout { + flex-direction: column; + } + + .sidebar { + width: 100%; + height: auto; + position: static; + display: flex; + overflow-x: auto; + gap: 0; + border-right: none; + border-bottom: 1px solid var(--border); + padding: 0.5rem 0; + } + + .sidebar-header { display: none; } + + .sidebar-item { + border-left: none; + border-bottom: 2px solid transparent; + white-space: nowrap; + padding: 0.5rem 0.75rem; + font-size: 0.8rem; + } + + .sidebar-item.active { + border-bottom-color: var(--amber); + border-left: none; + background: transparent; + } + + .sidebar-sub { + padding-left: 0.75rem; + border-left: none; + font-size: 0.75rem; + } + + .content { + padding: 1.5rem 1rem; + } +} diff --git a/docs/docs.js b/docs/docs.js new file mode 100644 index 0000000..7b8375a --- /dev/null +++ b/docs/docs.js @@ -0,0 +1,318 @@ +// soleprint docs — sidebar + markdown renderer +// Logic adapted from mcrn.ar/design, reskinned for minimal-neon + +const state = { + lang: "en", + topics: [], + contentCache: {}, + activeTopic: null, + expandedGroup: null, +}; + +const dom = { + sidebar: () => document.getElementById("sidebar"), + content: () => document.getElementById("content"), +}; + +// --- Topic grouping --- + +function buildGroups(topics) { + const groups = []; + for (const t of topics) { + if (!t.sub) { + groups.push({ parent: t, subs: [] }); + } else if (groups.length > 0) { + groups[groups.length - 1].subs.push(t); + } + } + return groups; +} + +function findParentGroup(topicId) { + for (const g of buildGroups(state.topics)) { + if (g.parent.id === topicId || g.subs.some((s) => s.id === topicId)) { + return g.parent.id; + } + } + return null; +} + +// --- Sidebar --- + +function renderSidebar() { + const groups = buildGroups(state.topics); + const items = []; + + items.push(``); + + for (const g of groups) { + const isExpanded = state.expandedGroup === g.parent.id; + const hasSubs = g.subs.length > 0; + + items.push(parentItem(g.parent, hasSubs, isExpanded)); + + if (isExpanded && hasSubs) { + for (const s of g.subs) { + items.push(subItem(s)); + } + } + } + + dom.sidebar().innerHTML = items.join(""); + bindParentClicks(); +} + +function parentItem(topic, hasSubs, isExpanded) { + const active = state.activeTopic === topic.id ? " active" : ""; + const chevron = hasSubs + ? `` + : ""; + const label = topic.title[state.lang] || topic.title.en; + return `${chevron}${label}`; +} + +function subItem(topic) { + const active = state.activeTopic === topic.id ? " active" : ""; + const label = topic.title[state.lang] || topic.title.en; + return `${label}`; +} + +function bindParentClicks() { + dom.sidebar().querySelectorAll(".sidebar-item:not(.sidebar-sub)").forEach((el) => { + el.addEventListener("click", (e) => { + const groupId = el.dataset.group; + const group = buildGroups(state.topics).find((g) => g.parent.id === groupId); + + if (group?.subs.length && state.expandedGroup === groupId && state.activeTopic === groupId) { + e.preventDefault(); + state.expandedGroup = null; + renderSidebar(); + } else { + state.expandedGroup = groupId; + } + }); + }); +} + +// --- Content loading --- + +async function loadTopic(id) { + const el = dom.content(); + const cacheKey = `${state.lang}:${id}`; + + if (state.contentCache[cacheKey]) { + el.innerHTML = state.contentCache[cacheKey]; + } else { + el.innerHTML = '

Loading...

'; + try { + const md = await fetchMarkdown(id); + const html = markdown.render(md); + state.contentCache[cacheKey] = html; + el.innerHTML = html; + } catch (e) { + el.innerHTML = `

Failed to load: ${e.message}

`; + } + } + + window.scrollTo(0, 0); + el.scrollTop = 0; +} + +async function fetchMarkdown(id) { + let resp = await fetch(`data/${state.lang}/${id}.md`); + if (!resp.ok && state.lang !== "en") { + resp = await fetch(`data/en/${id}.md`); + } + if (!resp.ok) throw new Error("Not found"); + return resp.text(); +} + +// --- Markdown renderer --- + +const markdown = { + render(md) { + const lines = md.split("\n"); + const parts = []; + let i = 0; + + while (i < lines.length) { + const trimmed = lines[i].trim(); + if (!trimmed) { i++; continue; } + const [html, next] = this.parseLine(lines, i, trimmed); + if (html) parts.push(html); + i = next; + } + + return parts.join(""); + }, + + parseLine(lines, i, trimmed) { + for (const parser of this.parsers) { + if (parser.match(trimmed)) { + return parser.parse(lines, i, trimmed); + } + } + return [`

${this.inline(trimmed)}

`, i + 1]; + }, + + parsers: [ + { + name: "fenced-code", + match: (t) => t.startsWith("```"), + parse(lines, i, trimmed) { + const lang = trimmed.slice(3).trim(); + const codeLines = []; + i++; + while (i < lines.length && !lines[i].trim().startsWith("```")) { + codeLines.push(markdown.escape(lines[i])); + i++; + } + return [`
${codeLines.join("\n")}
`, i + 1]; + }, + }, + { + name: "hr", + match: (t) => /^---+$/.test(t), + parse(_, i) { return ["
", i + 1]; }, + }, + { + name: "table", + match: (t) => t.startsWith("|"), + parse(lines, i) { + const rows = []; + while (i < lines.length && lines[i].trim().startsWith("|")) { + rows.push(lines[i].trim()); + i++; + } + return [markdown.table(rows), i]; + }, + }, + { + name: "h3", + match: (t) => t.startsWith("### "), + parse(_, i, t) { return [`

${markdown.inline(t.slice(4))}

`, i + 1]; }, + }, + { + name: "h2", + match: (t) => t.startsWith("## "), + parse(_, i, t) { return [`

${markdown.inline(t.slice(3))}

`, i + 1]; }, + }, + { + name: "h1", + match: (t) => t.startsWith("# "), + parse(_, i, t) { return [`

${markdown.inline(t.slice(2))}

`, i + 1]; }, + }, + { + name: "blockquote", + match: (t) => t.startsWith("> ") || t === ">", + parse(lines, i) { + const content = []; + while (i < lines.length) { + const ql = lines[i].trim(); + if (ql.startsWith("> ")) content.push(ql.slice(2)); + else if (ql === ">") content.push(""); + else break; + i++; + } + const inner = content.map((l) => `

${markdown.inline(l)}

`).join(""); + return [`
${inner}
`, i]; + }, + }, + { + name: "image", + match: (t) => /^!\[.*\]\(.*\)$/.test(t), + parse(_, i, t) { + const m = t.match(/^!\[(.*?)\]\((.*?)\)$/); + if (m) { + const alt = m[1]; + const src = m[2]; + return [`${alt}`, i + 1]; + } + return [`

${t}

`, i + 1]; + }, + }, + { + name: "list", + match: (t) => t.startsWith("- "), + parse(lines, i) { + const items = []; + while (i < lines.length && lines[i].trim().startsWith("- ")) { + items.push(lines[i].trim().slice(2)); + i++; + } + const inner = items.map((item) => `
  • ${markdown.inline(item)}
  • `).join(""); + return [`
      ${inner}
    `, i]; + }, + }, + ], + + table(rows) { + if (rows.length < 2) return ""; + const split = (line) => line.split("|").slice(1, -1).map((c) => c.trim()); + + const headers = split(rows[0]); + const body = rows.slice(2).map(split); + + const thead = headers.some((h) => h) + ? `${headers.map((h) => `${this.inline(h)}`).join("")}` + : ""; + const tbody = body + .map((row) => `${row.map((c) => `${this.inline(c)}`).join("")}`) + .join(""); + + return `${thead}${tbody}
    `; + }, + + inlineRules: [ + { pattern: /\*\*(.+?)\*\*/g, tag: "strong" }, + { pattern: /\*(.+?)\*/g, tag: "em" }, + { pattern: /`(.+?)`/g, tag: "code" }, + { pattern: /\[(.+?)\]\((.+?)\)/g, render: (_, text, href) => `${text}` }, + ], + + inline(text) { + if (!text) return ""; + return this.inlineRules.reduce((result, rule) => { + const replacer = rule.render || ((_, content) => `<${rule.tag}>${content}`); + return result.replace(rule.pattern, replacer); + }, text); + }, + + escape(str) { + return str.replace(/&/g, "&").replace(//g, ">"); + }, +}; + +// --- Navigation --- + +function navigate(topicId) { + state.activeTopic = topicId; + state.expandedGroup = findParentGroup(topicId); + renderSidebar(); + loadTopic(topicId); +} + +// --- Init --- + +document.addEventListener("DOMContentLoaded", async () => { + try { + const resp = await fetch("data/topics.json"); + state.topics = await resp.json(); + + const hash = location.hash.slice(1); + state.activeTopic = state.topics.find((t) => t.id === hash) ? hash : state.topics[0].id; + state.expandedGroup = findParentGroup(state.activeTopic); + + renderSidebar(); + await loadTopic(state.activeTopic); + } catch (e) { + dom.content().innerHTML = `

    Failed to load topics: ${e.message}

    `; + } +}); + +window.addEventListener("hashchange", () => { + const hash = location.hash.slice(1); + if (state.topics.find((t) => t.id === hash) && hash !== state.activeTopic) { + navigate(hash); + } +}); diff --git a/docs/graphs/artery_hierarchy.dot b/docs/graphs/artery_hierarchy.dot new file mode 100644 index 0000000..10b9307 --- /dev/null +++ b/docs/graphs/artery_hierarchy.dot @@ -0,0 +1,45 @@ +digraph artery_hierarchy { + bgcolor="#0a0a0a" + rankdir=LR + fontname="Helvetica" + node [fontname="Helvetica" fontsize=11 style=filled color="#333" fontcolor="#e5e5e5" shape=box] + edge [fontname="Helvetica" fontsize=9 fontcolor="#a3a3a3" color="#b91c1c"] + + label="Artery — Component Hierarchy" + labelloc=t + fontsize=14 + fontcolor="#fca5a5" + + vein [label="Vein\nstateless API connector" fillcolor="#1a1a1a"] + pulse [label="Pulse\nVein + Room + Depot" fillcolor="#1a1a1a"] + plexus [label="Plexus\nfull app: backend\n+ frontend + DB" fillcolor="#1a1a1a"] + shunt [label="Shunt\nfake connector\nfor testing" fillcolor="#1a1a1a" color="#d4a574"] + + vein -> pulse [label="compose"] + pulse -> plexus [label="extend"] + shunt -> vein [label="replaces" style=dashed color="#d4a574" fontcolor="#d4a574"] + + // Examples + subgraph cluster_examples { + label="Live Veins" + style=dashed + color="#333" + fontcolor="#666" + + jira [label="Jira" fillcolor="#1a1a1a" fontcolor="#15803d" fontsize=9] + google [label="Google" fillcolor="#1a1a1a" fontcolor="#d4a574" fontsize=9] + ia [label="IA" fillcolor="#1a1a1a" fontcolor="#15803d" fontsize=9] + } + + subgraph cluster_shunts { + label="Shunts" + style=dashed + color="#333" + fontcolor="#666" + + mp [label="MercadoPago" fillcolor="#1a1a1a" fontcolor="#d4a574" fontsize=9] + } + + jira -> vein [style=invis] + mp -> shunt [style=invis] +} diff --git a/docs/graphs/artery_hierarchy.svg b/docs/graphs/artery_hierarchy.svg new file mode 100644 index 0000000..044ed15 --- /dev/null +++ b/docs/graphs/artery_hierarchy.svg @@ -0,0 +1,101 @@ + + + + + + +artery_hierarchy + +Artery — Component Hierarchy + +cluster_examples + +Live Veins + + +cluster_shunts + +Shunts + + + +vein + +Vein +stateless API connector + + + +pulse + +Pulse +Vein + Room + Depot + + + +vein->pulse + + +compose + + + +plexus + +Plexus +full app: backend ++ frontend + DB + + + +pulse->plexus + + +extend + + + +shunt + +Shunt +fake connector +for testing + + + +shunt->vein + + +replaces + + + +jira + +Jira + + + + +google + +Google + + + +ia + +IA + + + +mp + +MercadoPago + + + + diff --git a/docs/graphs/cfg_gen_flow.dot b/docs/graphs/cfg_gen_flow.dot new file mode 100644 index 0000000..3bbb97a --- /dev/null +++ b/docs/graphs/cfg_gen_flow.dot @@ -0,0 +1,49 @@ +digraph cfg_gen_flow { + bgcolor="#0a0a0a" + rankdir=LR + fontname="Helvetica" + node [fontname="Helvetica" fontsize=11 style=filled color="#333" fontcolor="#e5e5e5" shape=box] + edge [fontname="Helvetica" fontsize=9 fontcolor="#a3a3a3" color="#d4a574"] + + label="Build Flow — cfg/ to gen/" + labelloc=t + fontsize=14 + fontcolor="#d4a574" + + // Source + subgraph cluster_source { + label="Source (committed)" + style=dashed + color="#333" + fontcolor="#666" + + core [label="soleprint/\ncore framework" fillcolor="#1a1a1a"] + cfg [label="cfg//\nroom config" fillcolor="#1a1a1a"] + } + + // Build + build [label="build.py\n--cfg " fillcolor="#1a1a1a" color="#d4a574" shape=component] + + // Output + subgraph cluster_output { + label="Output (generated, gitignored)" + style=dashed + color="#333" + fontcolor="#666" + + gen_spr [label="gen//soleprint/\ncore + room merged" fillcolor="#1a1a1a"] + gen_app [label="gen///\ncloned repos" fillcolor="#1a1a1a"] + gen_link [label="gen//link/\nDB bridge" fillcolor="#1a1a1a"] + } + + // Run + docker [label="docker compose up" fillcolor="#1a1a1a" shape=component] + + // Flow + core -> build + cfg -> build + build -> gen_spr + build -> gen_app [style=dashed label="if managed"] + build -> gen_link [style=dashed label="if managed"] + gen_spr -> docker +} diff --git a/docs/graphs/cfg_gen_flow.svg b/docs/graphs/cfg_gen_flow.svg new file mode 100644 index 0000000..18fbfcc --- /dev/null +++ b/docs/graphs/cfg_gen_flow.svg @@ -0,0 +1,114 @@ + + + + + + +cfg_gen_flow + +Build Flow — cfg/ to gen/ + +cluster_source + +Source (committed) + + +cluster_output + +Output (generated, gitignored) + + + +core + +soleprint/ +core framework + + + +build + + + +build.py +--cfg <room> + + + +core->build + + + + + +cfg + +cfg/<room>/ +room config + + + +cfg->build + + + + + +gen_spr + +gen/<room>/soleprint/ +core + room merged + + + +build->gen_spr + + + + + +gen_app + +gen/<room>/<app>/ +cloned repos + + + +build->gen_app + + +if managed + + + +gen_link + +gen/<room>/link/ +DB bridge + + + +build->gen_link + + +if managed + + + +docker + + + +docker compose up + + + +gen_spr->docker + + + + + diff --git a/docs/graphs/room_layers.dot b/docs/graphs/room_layers.dot new file mode 100644 index 0000000..8cf40de --- /dev/null +++ b/docs/graphs/room_layers.dot @@ -0,0 +1,31 @@ +digraph room_layers { + bgcolor="#0a0a0a" + rankdir=TB + fontname="Helvetica" + node [fontname="Helvetica" fontsize=10 style=filled color="#333" fontcolor="#e5e5e5" shape=record] + edge [fontname="Helvetica" fontsize=9 fontcolor="#a3a3a3" color="#666"] + + label="Room Layers — init wizard" + labelloc=t + fontsize=14 + fontcolor="#d4a574" + + l0 [label="{Layer 0 | Config + Data | config.json · data/*.json}" fillcolor="#1a1a1a" color="#d4a574"] + l1 [label="{Layer 1 | Docker | soleprint/docker-compose.yml · .env}" fillcolor="#1a1a1a"] + l2 [label="{Layer 2 | Managed App | docker-compose.yml · Dockerfiles · .env}" fillcolor="#1a1a1a"] + l3 [label="{Layer 3 | Link | link/main.py · adapters/ · Dockerfile}" fillcolor="#1a1a1a"] + l4 [label="{Layer 4 | Scripts | ctrl/start.sh · stop.sh · status.sh · logs.sh}" fillcolor="#1a1a1a"] + l5 [label="{Layer 5 | Systems | tester/environments.json · tests/}" fillcolor="#1a1a1a"] + l6 [label="{Layer 6 | Nginx | nginx/local.conf · docker-compose.nginx.yml}" fillcolor="#1a1a1a"] + + l0 -> l1 [label="required"] + l1 -> l2 [label="if managed"] + l2 -> l3 [label="optional"] + l1 -> l4 [label="optional"] + l4 -> l5 [label="optional"] + l5 -> l6 [label="if frontend"] + + // Annotations + note_req [label="every room" fillcolor="#0a0a0a" fontcolor="#d4a574" color="#0a0a0a" shape=plaintext fontsize=9] + note_req -> l0 [style=invis] +} diff --git a/docs/graphs/room_layers.svg b/docs/graphs/room_layers.svg new file mode 100644 index 0000000..7a39d9b --- /dev/null +++ b/docs/graphs/room_layers.svg @@ -0,0 +1,133 @@ + + + + + + +room_layers + +Room Layers — init wizard + + +l0 + +Layer 0 + +Config + Data + +config.json · data/*.json + + + +l1 + +Layer 1 + +Docker + +soleprint/docker-compose.yml · .env + + + +l0->l1 + + +required + + + +l2 + +Layer 2 + +Managed App + +docker-compose.yml · Dockerfiles · .env + + + +l1->l2 + + +if managed + + + +l4 + +Layer 4 + +Scripts + +ctrl/start.sh · stop.sh · status.sh · logs.sh + + + +l1->l4 + + +optional + + + +l3 + +Layer 3 + +Link + +link/main.py · adapters/ · Dockerfile + + + +l2->l3 + + +optional + + + +l5 + +Layer 5 + +Systems + +tester/environments.json · tests/ + + + +l4->l5 + + +optional + + + +l6 + +Layer 6 + +Nginx + +nginx/local.conf · docker-compose.nginx.yml + + + +l5->l6 + + +if frontend + + + +note_req + +every room + + + + diff --git a/docs/graphs/system_overview.dot b/docs/graphs/system_overview.dot new file mode 100644 index 0000000..9d0dee6 --- /dev/null +++ b/docs/graphs/system_overview.dot @@ -0,0 +1,97 @@ +digraph system_overview { + bgcolor="#0a0a0a" + rankdir=TB + compound=true + fontname="Helvetica" + node [fontname="Helvetica" fontsize=11 style=filled color="#333" fontcolor="#e5e5e5"] + edge [fontname="Helvetica" fontsize=9 fontcolor="#a3a3a3" color="#666"] + + label="Soleprint — System Overview" + labelloc=t + fontsize=14 + fontcolor="#d4a574" + + // Core + subgraph cluster_core { + label="Soleprint Hub" + style=dashed + color="#d4a574" + fontcolor="#d4a574" + + hub [label="soleprint\ncore coordinator\nport 12000" fillcolor="#1a1a1a" shape=box] + } + + // Artery + subgraph cluster_artery { + label="Artery — Todo lo vital" + style=dashed + color="#b91c1c" + fontcolor="#fca5a5" + + veins [label="Veins\nstateless connectors" fillcolor="#1a1a1a"] + shunts [label="Shunts\nmock connectors" fillcolor="#1a1a1a"] + pulses [label="Pulses\ncomposed flows" fillcolor="#1a1a1a"] + } + + // Atlas + subgraph cluster_atlas { + label="Atlas — Documentacion accionable" + style=dashed + color="#15803d" + fontcolor="#86efac" + + books [label="Books\ndocumentation" fillcolor="#1a1a1a"] + templates [label="Templates\npatterns" fillcolor="#1a1a1a"] + } + + // Station + subgraph cluster_station { + label="Station — Centro de control" + style=dashed + color="#1d4ed8" + fontcolor="#93c5fd" + + tools [label="Tools\ntester · datagen · modelgen" fillcolor="#1a1a1a"] + monitors [label="Monitors\ndatabrowse" fillcolor="#1a1a1a"] + } + + // External + subgraph cluster_external { + label="External APIs" + style=dashed + color="#333" + fontcolor="#666" + + jira [label="Jira" fillcolor="#1a1a1a" fontcolor="#a3a3a3"] + google [label="Google" fillcolor="#1a1a1a" fontcolor="#a3a3a3"] + slack [label="Slack" fillcolor="#1a1a1a" fontcolor="#a3a3a3"] + } + + // Managed app + subgraph cluster_managed { + label="Managed App" + style=dashed + color="#333" + fontcolor="#666" + + app_fe [label="Frontend" fillcolor="#1a1a1a" fontcolor="#a3a3a3"] + app_be [label="Backend" fillcolor="#1a1a1a" fontcolor="#a3a3a3"] + app_db [label="Database" fillcolor="#1a1a1a" fontcolor="#a3a3a3" shape=cylinder] + } + + // Connections + hub -> veins [label="routes" color="#b91c1c"] + hub -> books [label="routes" color="#15803d"] + hub -> tools [label="routes" color="#1d4ed8"] + + veins -> jira [label="API"] + veins -> google [label="OAuth"] + veins -> slack [label="API"] + veins -> pulses [label="compose"] + + tools -> app_be [label="test" style=dashed] + monitors -> app_db [label="browse" style=dashed] + + // Sidebar injection + hub -> app_fe [label="sidebar\ninjection" color="#d4a574" style=dashed] +} diff --git a/docs/graphs/system_overview.svg b/docs/graphs/system_overview.svg new file mode 100644 index 0000000..38c34e9 --- /dev/null +++ b/docs/graphs/system_overview.svg @@ -0,0 +1,209 @@ + + + + + + +system_overview + +Soleprint — System Overview + +cluster_core + +Soleprint Hub + + +cluster_artery + +Artery — Todo lo vital + + +cluster_atlas + +Atlas — Documentacion accionable + + +cluster_station + +Station — Centro de control + + +cluster_external + +External APIs + + +cluster_managed + +Managed App + + + +hub + +soleprint +core coordinator +port 12000 + + + +veins + +Veins +stateless connectors + + + +hub->veins + + +routes + + + +books + +Books +documentation + + + +hub->books + + +routes + + + +tools + +Tools +tester · datagen · modelgen + + + +hub->tools + + +routes + + + +app_fe + +Frontend + + + +hub->app_fe + + +sidebar +injection + + + +pulses + +Pulses +composed flows + + + +veins->pulses + + +compose + + + +jira + +Jira + + + +veins->jira + + +API + + + +google + +Google + + + +veins->google + + +OAuth + + + +slack + +Slack + + + +veins->slack + + +API + + + +shunts + +Shunts +mock connectors + + + +templates + +Templates +patterns + + + +app_be + +Backend + + + +tools->app_be + + +test + + + +monitors + +Monitors +databrowse + + + +app_db + + +Database + + + +monitors->app_db + + +browse + + + diff --git a/docs/graphs/wrapping.dot b/docs/graphs/wrapping.dot new file mode 100644 index 0000000..f405f72 --- /dev/null +++ b/docs/graphs/wrapping.dot @@ -0,0 +1,54 @@ +digraph wrapping { + bgcolor="#0a0a0a" + rankdir=LR + fontname="Helvetica" + node [fontname="Helvetica" fontsize=11 style=filled color="#333" fontcolor="#e5e5e5" shape=box] + edge [fontname="Helvetica" fontsize=9 fontcolor="#a3a3a3" color="#666"] + + label="Sidebar Injection — How Wrapping Works" + labelloc=t + fontsize=14 + fontcolor="#d4a574" + + browser [label="Browser" fillcolor="#1a1a1a" shape=oval] + + subgraph cluster_nginx { + label="Nginx (reverse proxy)" + style=dashed + color="#d4a574" + fontcolor="#d4a574" + + proxy [label="proxy_pass\n+\nsub_filter\ninjects sidebar" fillcolor="#1a1a1a" shape=component] + } + + subgraph cluster_app { + label="Managed App" + style=dashed + color="#333" + fontcolor="#666" + + frontend [label="Frontend\n(React/Next/Vue)" fillcolor="#1a1a1a"] + backend [label="Backend API" fillcolor="#1a1a1a"] + } + + subgraph cluster_spr { + label="Soleprint" + style=dashed + color="#d4a574" + fontcolor="#d4a574" + + sidebar_css [label="sidebar.css" fillcolor="#1a1a1a"] + sidebar_js [label="sidebar.js" fillcolor="#1a1a1a"] + hub [label="Hub API\n/api/sidebar/config" fillcolor="#1a1a1a"] + } + + browser -> proxy [label="myroom.spr.local.ar"] + proxy -> frontend [label="/ → app"] + proxy -> hub [label="/spr/ → soleprint"] + + // The injection + proxy -> sidebar_css [label="injects into " color="#d4a574" style=dashed] + proxy -> sidebar_js [color="#d4a574" style=dashed] + + sidebar_js -> hub [label="loads config" color="#d4a574"] +} diff --git a/docs/graphs/wrapping.svg b/docs/graphs/wrapping.svg new file mode 100644 index 0000000..95b172f --- /dev/null +++ b/docs/graphs/wrapping.svg @@ -0,0 +1,119 @@ + + + + + + +wrapping + +Sidebar Injection — How Wrapping Works + +cluster_nginx + +Nginx (reverse proxy) + + +cluster_app + +Managed App + + +cluster_spr + +Soleprint + + + +browser + +Browser + + + +proxy + + + +proxy_pass ++ +sub_filter +injects sidebar + + + +browser->proxy + + +myroom.spr.local.ar + + + +frontend + +Frontend +(React/Next/Vue) + + + +proxy->frontend + + +/ → app + + + +sidebar_css + +sidebar.css + + + +proxy->sidebar_css + + +injects into </head> + + + +sidebar_js + +sidebar.js + + + +proxy->sidebar_js + + + + + +hub + +Hub API +/api/sidebar/config + + + +proxy->hub + + +/spr/ → soleprint + + + +backend + +Backend API + + + +sidebar_js->hub + + +loads config + + + diff --git a/docs/index.html b/docs/index.html index e7b65a9..86ff708 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,262 +1,19 @@ - - - - Soleprint - Documentation - - - - - -
    -
    -

    Soleprint

    -

    Cada paso deja huella

    -

    - Pluggable stuff to tackle any challenge - Piezas enchufables para cualquier desafio -

    - - Try the Demo - Ver Demo - -
    - -
    -
    -

    - The Three Systems - Los Tres Sistemas -

    - -
    - -
    -

    Quick Start

    -
    -# Clone
    -git clone https://git.mcrn.ar/soleprint
    -cd soleprint
    -
    -# Setup (once)
    -python -m venv .venv && source .venv/bin/activate
    -pip install -r requirements.txt
    -
    -# Option 1: Build standalone (soleprint only)
    -python build.py --cfg standalone
    -cd gen/standalone && ./ctrl/start.sh
    -# Visit http://localhost:12000
    -
    -# Option 2: Build managed room (soleprint + your app)
    -python build.py --cfg myroom
    -cd gen/myroom && ./ctrl/start.sh
    -# Visit http://myroom.spr.local.ar
    -
    -# Option 3: Use the installer (coming soon)
    - -

    - Minimal config example: - Ejemplo de config minima: -

    -
    -// cfg/myroom/config.json
    -{
    -  "room": "myroom",
    -  "artery": {
    -    "veins": ["google", "jira", "slack"],
    -    "shunts": ["mercadopago"]
    -  },
    -  "atlas": {
    -    "books": ["gherkin", "feature-flow"]
    -  },
    -  "station": {
    -    "tools": ["tester", "modelgen"],
    -    "monitors": ["databrowse"]
    -  }
    -}
    -
    - -
    -

    - Architecture - Arquitectura -

    -

    Deep dive into how soleprint works.

    -

    Profundizando en como funciona soleprint.

    - -
    + + + + Docs | soleprint + + + + +
    + +
    +

    Loading...

    - - - +
    + + diff --git a/docs/lang-toggle.js b/docs/lang-toggle.js deleted file mode 100644 index 3f810ca..0000000 --- a/docs/lang-toggle.js +++ /dev/null @@ -1,54 +0,0 @@ -// Language toggle for soleprint docs -// Include this script and add:
    in header - -(function () { - function setLang(lang) { - localStorage.setItem("spr-docs-lang", lang); - document.documentElement.lang = lang; - document.querySelectorAll(".lang-toggle button").forEach((btn) => { - btn.classList.toggle("active", btn.dataset.lang === lang); - }); - } - - document.addEventListener("DOMContentLoaded", () => { - const currentLang = localStorage.getItem("spr-docs-lang") || "en"; - - // Inject toggle HTML - const container = document.getElementById("lang-toggle"); - if (container) { - container.className = "lang-toggle"; - - const btnEn = document.createElement("button"); - btnEn.textContent = "EN"; - btnEn.dataset.lang = "en"; - btnEn.addEventListener("click", () => setLang("en")); - - const btnEs = document.createElement("button"); - btnEs.textContent = "ES"; - btnEs.dataset.lang = "es"; - btnEs.addEventListener("click", () => setLang("es")); - - container.appendChild(btnEn); - container.appendChild(btnEs); - } - - setLang(currentLang); - }); - - // Inject styles - const style = document.createElement("style"); - style.textContent = ` - .lang-toggle { position: absolute; top: 1.5rem; right: 2rem; display: flex; border: 1px solid #888; border-radius: 4px; overflow: hidden; } - .lang-toggle button { background: #1a1a1a; border: none; color: #888; padding: 0.4rem 0.8rem; font-family: inherit; font-size: 0.75rem; cursor: pointer; } - .lang-toggle button:first-child { border-right: 1px solid #888; } - .lang-toggle button:hover { background: #0a0a0a; color: #fff; } - .lang-toggle button.active { background: var(--accent, #b91c1c); color: #fff; } - header { position: relative; } - .lang-en, .lang-es { display: none; } - html[lang="en"] .lang-en { display: block; } - html[lang="es"] .lang-es { display: block; } - html[lang="en"] span.lang-en { display: inline; } - html[lang="es"] span.lang-es { display: inline; } - `; - document.head.appendChild(style); -})(); diff --git a/docs/station/index.html b/docs/station/index.html deleted file mode 100644 index 28d748b..0000000 --- a/docs/station/index.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - Station - Soleprint - - - - - -
    -
    -

    Station

    -

    - Monitors, Environments & ToolsMonitores, Entornos y Herramientas -

    -
    - -
    -
    -

    - ModelModelo -

    -
    -
    -

    Desk

    -

    - Control center - collection of monitors -

    -

    - Centro de control - coleccion de monitores -

    -
    -
    -

    Monitor

    -

    Web UI

    -
    -
    -

    Monitor

    -

    Web UI

    -
    -
    -

    ...

    -

    -
    -
    -
    -
    -

    Monitor

    -

    - Web interface - always running, always watching -

    -

    - Interfaz web - siempre corriendo, siempre observando -

    -
    -
    -

    Web UI

    -

    Dashboard

    -
    -
    -

    Room

    -

    Config/env

    -

    Config/entorno

    -
    -
    -

    Depot

    -

    Data source

    -

    Fuente de datos

    -
    -
    -
    -
    -

    Tool

    -

    - CLI utility - run once, get results -

    -

    - Utilidad CLI - ejecutar una vez, obtener resultados -

    -
    -
    -

    CLI

    -

    Command interface

    -

    Interfaz de comandos

    -
    -
    -

    Room

    -

    Config/env

    -

    Config/entorno

    -
    -
    -

    Depot

    -

    Output storage

    -

    Almacenamiento de salida

    -
    -
    -
    -
    -
    - -
    -

    - ArchitectureArquitectura -

    - System Overview -
    - -
    -

    - ComponentsComponentes -

    -
    -
    -

    Desk

    -

    - Collection of monitors. Your control center with all - the views you need. -

    -

    - Coleccion de monitores. Tu centro de control con - todas las vistas que necesitas. -

    -
    -
    -

    Monitor

    -

    - Web interfaces for observation. Data browsers, - dashboards, log viewers. Always running. -

    -

    - Interfaces web para observacion. Navegadores de - datos, dashboards, visores de logs. Siempre - corriendo. -

    -
    -
    -

    Tool

    -

    - CLI utilities and scripts. Code generators, test - runners, infra provisioners. Run once, get results. -

    -

    - Utilidades CLI y scripts. Generadores de codigo, - test runners, provisioners de infra. Ejecutar una - vez, obtener resultados. -

    -
    -
    -
    - -
    -

    - Shared ComponentsComponentes Compartidos -

    -
    -
    -

    Room

    -

    - Runtime environment configuration. Tools and - monitors are configured per-room for isolation. -

    -

    - Configuracion del entorno. Tools y monitors se - configuran por room para aislamiento. -

    -
    -
    -

    Depot

    -

    - Data storage. For tools: output files, results. For - monitors: data to display. -

    -

    - Almacenamiento de datos. Para tools: archivos de - salida, resultados. Para monitors: datos a mostrar. -

    -
    -
    -
    - -
    -

    - Available ToolsTools Disponibles -

    -
    -
    -

    Tester

    -

    - API and Playwright test runner. Discover tests, run - them, collect artifacts. -

    -

    - Test runner de API y Playwright. Descubrir tests, - ejecutarlos, recolectar artefactos. -

    -
    -
    -

    ModelGen

    -

    - Generate model diagrams from code. Introspect - soleprint structure, output SVG. -

    -

    - Generar diagramas de modelo desde codigo. - Introspeccionar estructura de soleprint, generar - SVG. -

    -
    -
    -

    Infra

    -

    - Infrastructure provisioners. AWS, GCP, DigitalOcean - deployment helpers. -

    -

    - Provisioners de infraestructura. Helpers de deploy - para AWS, GCP, DigitalOcean. -

    -
    -
    -

    DataGen

    -

    - Test data generation. Create realistic fake data for - development. -

    -

    - Generacion de datos de test. Crear datos falsos - realistas para desarrollo. -

    -
    -
    -

    DataBrowse

    -

    - Navigable data model graphs generated from existing - models. -

    -

    - Grafos de modelo de datos navegables generados desde - modelos existentes. -

    -
    -
    -
    - -
    -

    - Available MonitorsMonitors Disponibles -

    -
    -
    -

    DataBrowse

    -

    - Navigable data model graphs generated from existing - models. -

    -

    - Grafos de modelo de datos navegables generados desde - modelos existentes. -

    -
    -
    -
    -
    - - - - diff --git a/docs/veins/google.dot b/docs/veins/google.dot deleted file mode 100644 index f41c9cc..0000000 --- a/docs/veins/google.dot +++ /dev/null @@ -1,61 +0,0 @@ -digraph GoogleVein { - rankdir=LR; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11, shape=box, style="rounded,filled"]; - edge [fontname="Helvetica", fontsize=10]; - - labelloc="t"; - label="Google Vein - OAuth Flow"; - fontsize=16; - - // Client - subgraph cluster_client { - label="Soleprint"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - app [label="Application", fillcolor="#C8E6C9"]; - vein [label="Google Vein\n(artery/veins/google)", fillcolor="#A5D6A7"]; - oauth [label="OAuth Handler\n(artery/oauth.py)", fillcolor="#81C784"]; - } - - // OAuth Flow - subgraph cluster_oauth { - label="OAuth 2.0"; - style=filled; - color="#FFF8E1"; - fillcolor="#FFF8E1"; - - auth_url [label="1. Authorization URL", fillcolor="#FFECB3"]; - consent [label="2. User Consent", fillcolor="#FFE082"]; - callback [label="3. Callback + Code", fillcolor="#FFD54F"]; - tokens [label="4. Access + Refresh\nTokens", fillcolor="#FFCA28"]; - } - - // Google APIs - subgraph cluster_google { - label="Google APIs"; - style=filled; - color="#E3F2FD"; - fillcolor="#E3F2FD"; - - sheets [label="Sheets API", fillcolor="#BBDEFB"]; - calendar [label="Calendar API", fillcolor="#BBDEFB"]; - drive [label="Drive API", fillcolor="#BBDEFB"]; - } - - // Flow - app -> vein [label="get_sheets()"]; - vein -> oauth [label="ensure_auth"]; - oauth -> auth_url; - auth_url -> consent; - consent -> callback; - callback -> tokens; - tokens -> oauth [label="store"]; - - oauth -> sheets [label="Bearer token"]; - oauth -> calendar [label="Bearer token"]; - oauth -> drive [label="Bearer token"]; -} diff --git a/docs/veins/google.svg b/docs/veins/google.svg deleted file mode 100644 index f0818c4..0000000 --- a/docs/veins/google.svg +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - -GoogleVein - -Google Vein - OAuth Flow - -cluster_client - -Soleprint - - -cluster_oauth - -OAuth 2.0 - - -cluster_google - -Google APIs - - - -app - -Application - - - -vein - -Google Vein -(artery/veins/google) - - - -app->vein - - -get_sheets() - - - -oauth - -OAuth Handler -(artery/oauth.py) - - - -vein->oauth - - -ensure_auth - - - -auth_url - -1. Authorization URL - - - -oauth->auth_url - - - - - -sheets - -Sheets API - - - -oauth->sheets - - -Bearer token - - - -calendar - -Calendar API - - - -oauth->calendar - - -Bearer token - - - -drive - -Drive API - - - -oauth->drive - - -Bearer token - - - -consent - -2. User Consent - - - -auth_url->consent - - - - - -callback - -3. Callback + Code - - - -consent->callback - - - - - -tokens - -4. Access + Refresh -Tokens - - - -callback->tokens - - - - - -tokens->oauth - - -store - - - diff --git a/docs/veins/graph.html b/docs/veins/graph.html deleted file mode 100644 index 539de6a..0000000 --- a/docs/veins/graph.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - Graph Viewer - Veins - - - -
    - ← Back - -

    Loading...

    -
    - - - - - -
    -
    - -
    - Graph -
    - - - - diff --git a/docs/veins/index.html b/docs/veins/index.html deleted file mode 100644 index 4770a6b..0000000 --- a/docs/veins/index.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - Veins & Shunts - Soleprint - - - -
    -

    Veins & Shunts

    -

    API Connectors & Mock Services

    -
    - -
    -
    -

    ← Back to Docs

    -
    - - -
    -

    Veins (Stateless API Connectors)

    -

    - Veins are stateless connectors to external APIs. They handle authentication and provide a clean interface for the rest of the application. -

    -
    - -
    -
    -

    Jira

    - View Full -
    - - Jira Vein - -
    -

    Connect to Jira Cloud for issue tracking.

    -

    Capabilities

    -
      -
    • Get/create/update issues
    • -
    • JQL search
    • -
    • Transition issues between statuses
    • -
    • List projects
    • -
    -

    Auth

    -

    API Token (Basic Auth with email + token)

    -
    -
    - -
    -
    -

    Slack

    - View Full -
    - - Slack Vein - -
    -

    Send messages and interact with Slack workspaces.

    -

    Capabilities

    -
      -
    • Post messages to channels
    • -
    • List channels and users
    • -
    • Upload files
    • -
    • Webhook integration
    • -
    -

    Auth

    -

    Bot Token (Bearer)

    -
    -
    - -
    -
    -

    Google

    - View Full -
    - - Google Vein - -
    -

    Access Google Sheets, Calendar, Drive via OAuth 2.0.

    -

    Capabilities

    -
      -
    • Read/write Sheets
    • -
    • Calendar events
    • -
    • Drive file access
    • -
    -

    Auth

    -

    OAuth 2.0 with refresh tokens

    -
    -
    - - -
    -

    Shunts (Mock Connectors)

    -

    - Shunts are fake connectors for testing. They mimic real APIs but let you control the responses. - Perfect for testing payment flows, webhook handling, and integration scenarios without needing real credentials. -

    -
    - -
    -
    -

    MercadoPago Shunt

    - View Full -
    - - MercadoPago Shunt - -
    -

    Mock MercadoPago payment API for testing payment flows.

    -

    Features

    -
      -
    • Fake payment creation
    • -
    • Configurable responses (approved/pending/rejected)
    • -
    • Webhook callbacks
    • -
    • Config UI to set next response
    • -
    -

    Use Case

    -

    Test checkout flows without real payments. Set the shunt to return "approved" or "rejected" and verify your app handles each case.

    -
    -
    - - -
    -

    Vein Pattern

    -
    -
    -

    Structure

    -
      -
    • artery/veins/{name}/
    • -
    • __init__.py (exports)
    • -
    • client.py (API client)
    • -
    • models.py (types)
    • -
    • templates/ (test UI)
    • -
    -
    -
    -

    Base Class

    -
      -
    • Extends artery/veins/base.py
    • -
    • Common auth handling
    • -
    • Request/response logging
    • -
    • Error handling
    • -
    -
    -
    -

    OAuth

    -
      -
    • artery/oauth.py
    • -
    • Token storage
    • -
    • Refresh flow
    • -
    • Callback handling
    • -
    -
    -
    -

    Config

    -
      -
    • cfg/{room}/data/veins.json
    • -
    • Per-room credentials
    • -
    • Enable/disable veins
    • -
    -
    -
    -
    -
    - -
    -

    Soleprint - Veins & Shunts Documentation

    -
    - - diff --git a/docs/veins/jira.dot b/docs/veins/jira.dot deleted file mode 100644 index 71d0baa..0000000 --- a/docs/veins/jira.dot +++ /dev/null @@ -1,53 +0,0 @@ -digraph JiraVein { - rankdir=LR; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11, shape=box, style="rounded,filled"]; - edge [fontname="Helvetica", fontsize=10]; - - labelloc="t"; - label="Jira Vein - API Flow"; - fontsize=16; - - // Client - subgraph cluster_client { - label="Soleprint"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - app [label="Application", fillcolor="#C8E6C9"]; - vein [label="Jira Vein\n(artery/veins/jira)", fillcolor="#A5D6A7"]; - } - - // Auth - subgraph cluster_auth { - label="Authentication"; - style=filled; - color="#FFF8E1"; - fillcolor="#FFF8E1"; - - token [label="API Token\n(Basic Auth)", fillcolor="#FFECB3"]; - } - - // Jira API - subgraph cluster_jira { - label="Jira Cloud API"; - style=filled; - color="#E3F2FD"; - fillcolor="#E3F2FD"; - - issues [label="/rest/api/3/issue", fillcolor="#BBDEFB"]; - search [label="/rest/api/3/search", fillcolor="#BBDEFB"]; - projects [label="/rest/api/3/project", fillcolor="#BBDEFB"]; - transitions [label="/rest/api/3/issue/{id}/transitions", fillcolor="#BBDEFB"]; - } - - // Flow - app -> vein [label="get_issue()"]; - vein -> token [label="auth"]; - token -> issues [label="GET/POST"]; - token -> search [label="JQL"]; - token -> projects [label="list"]; - token -> transitions [label="update status"]; -} diff --git a/docs/veins/jira.svg b/docs/veins/jira.svg deleted file mode 100644 index dda834d..0000000 --- a/docs/veins/jira.svg +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - -JiraVein - -Jira Vein - API Flow - -cluster_client - -Soleprint - - -cluster_auth - -Authentication - - -cluster_jira - -Jira Cloud API - - - -app - -Application - - - -vein - -Jira Vein -(artery/veins/jira) - - - -app->vein - - -get_issue() - - - -token - -API Token -(Basic Auth) - - - -vein->token - - -auth - - - -issues - -/rest/api/3/issue - - - -token->issues - - -GET/POST - - - -search - -/rest/api/3/search - - - -token->search - - -JQL - - - -projects - -/rest/api/3/project - - - -token->projects - - -list - - - -transitions - -/rest/api/3/issue/{id}/transitions - - - -token->transitions - - -update status - - - diff --git a/docs/veins/mercadopago-shunt.dot b/docs/veins/mercadopago-shunt.dot deleted file mode 100644 index 7d6d189..0000000 --- a/docs/veins/mercadopago-shunt.dot +++ /dev/null @@ -1,64 +0,0 @@ -digraph MercadoPagoShunt { - rankdir=LR; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11, shape=box, style="rounded,filled"]; - edge [fontname="Helvetica", fontsize=10]; - - labelloc="t"; - label="MercadoPago Shunt - Mock Payment Flow"; - fontsize=16; - - // Client App - subgraph cluster_client { - label="Managed Room (e.g., AMAR)"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - backend [label="Backend\n(Django/FastAPI)", fillcolor="#C8E6C9"]; - } - - // Shunt - subgraph cluster_shunt { - label="Shunt (artery/shunts/mercadopago)"; - style=filled; - color="#FFF3E0"; - fillcolor="#FFF3E0"; - - mock_api [label="Mock API\n/payments\n/preferences", fillcolor="#FFCC80"]; - config_ui [label="Config UI\n(set responses)", fillcolor="#FFB74D"]; - state [label="State\n(pending payments)", fillcolor="#FFA726"]; - } - - // Fake responses - subgraph cluster_responses { - label="Configurable Responses"; - style=dashed; - color=gray; - - approved [label="approved", fillcolor="#C8E6C9"]; - pending [label="pending", fillcolor="#FFF9C4"]; - rejected [label="rejected", fillcolor="#FFCDD2"]; - } - - // Real (bypassed) - subgraph cluster_real { - label="Real MercadoPago (bypassed)"; - style=dashed; - color="#BDBDBD"; - - real_api [label="api.mercadopago.com", fillcolor="#E0E0E0", fontcolor="#9E9E9E"]; - } - - // Flow - backend -> mock_api [label="POST /payments"]; - mock_api -> state [label="store"]; - config_ui -> state [label="configure"]; - - state -> approved [style=dashed]; - state -> pending [style=dashed]; - state -> rejected [style=dashed]; - - mock_api -> backend [label="webhook callback", style=dashed]; -} diff --git a/docs/veins/mercadopago-shunt.svg b/docs/veins/mercadopago-shunt.svg deleted file mode 100644 index dddb562..0000000 --- a/docs/veins/mercadopago-shunt.svg +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - -MercadoPagoShunt - -MercadoPago Shunt - Mock Payment Flow - -cluster_client - -Managed Room (e.g., AMAR) - - -cluster_shunt - -Shunt (artery/shunts/mercadopago) - - -cluster_responses - -Configurable Responses - - -cluster_real - -Real MercadoPago (bypassed) - - - -backend - -Backend -(Django/FastAPI) - - - -mock_api - -Mock API -/payments -/preferences - - - -backend->mock_api - - -POST /payments - - - -mock_api->backend - - -webhook callback - - - -state - -State -(pending payments) - - - -mock_api->state - - -store - - - -config_ui - -Config UI -(set responses) - - - -config_ui->state - - -configure - - - -approved - -approved - - - -state->approved - - - - - -pending - -pending - - - -state->pending - - - - - -rejected - -rejected - - - -state->rejected - - - - - -real_api - -api.mercadopago.com - - - diff --git a/docs/veins/slack.dot b/docs/veins/slack.dot deleted file mode 100644 index 478e1d3..0000000 --- a/docs/veins/slack.dot +++ /dev/null @@ -1,64 +0,0 @@ -digraph SlackVein { - rankdir=LR; - compound=true; - fontname="Helvetica"; - node [fontname="Helvetica", fontsize=11, shape=box, style="rounded,filled"]; - edge [fontname="Helvetica", fontsize=10]; - - labelloc="t"; - label="Slack Vein - API Flow"; - fontsize=16; - - // Client - subgraph cluster_client { - label="Soleprint"; - style=filled; - color="#E8F5E9"; - fillcolor="#E8F5E9"; - - app [label="Application", fillcolor="#C8E6C9"]; - vein [label="Slack Vein\n(artery/veins/slack)", fillcolor="#A5D6A7"]; - } - - // Auth - subgraph cluster_auth { - label="Authentication"; - style=filled; - color="#FFF8E1"; - fillcolor="#FFF8E1"; - - token [label="Bot Token\n(Bearer)", fillcolor="#FFECB3"]; - } - - // Slack API - subgraph cluster_slack { - label="Slack API"; - style=filled; - color="#E3F2FD"; - fillcolor="#E3F2FD"; - - chat [label="chat.postMessage", fillcolor="#BBDEFB"]; - channels [label="conversations.list", fillcolor="#BBDEFB"]; - users [label="users.list", fillcolor="#BBDEFB"]; - files [label="files.upload", fillcolor="#BBDEFB"]; - } - - // Webhooks - subgraph cluster_webhooks { - label="Incoming"; - style=dashed; - color=gray; - - webhook [label="Webhook URL", fillcolor="#F5F5F5"]; - } - - // Flow - app -> vein [label="send_message()"]; - vein -> token [label="auth"]; - token -> chat [label="POST"]; - token -> channels [label="GET"]; - token -> users [label="GET"]; - token -> files [label="POST"]; - - vein -> webhook [label="simple post", style=dashed]; -} diff --git a/docs/veins/slack.svg b/docs/veins/slack.svg deleted file mode 100644 index c3d94c4..0000000 --- a/docs/veins/slack.svg +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - -SlackVein - -Slack Vein - API Flow - -cluster_client - -Soleprint - - -cluster_auth - -Authentication - - -cluster_slack - -Slack API - - -cluster_webhooks - -Incoming - - - -app - -Application - - - -vein - -Slack Vein -(artery/veins/slack) - - - -app->vein - - -send_message() - - - -token - -Bot Token -(Bearer) - - - -vein->token - - -auth - - - -webhook - -Webhook URL - - - -vein->webhook - - -simple post - - - -chat - -chat.postMessage - - - -token->chat - - -POST - - - -channels - -conversations.list - - - -token->channels - - -GET - - - -users - -users.list - - - -token->users - - -GET - - - -files - -files.upload - - - -token->files - - -POST - - - diff --git a/docs/viewer.html b/docs/viewer.html new file mode 100644 index 0000000..d3adfd5 --- /dev/null +++ b/docs/viewer.html @@ -0,0 +1,56 @@ + + + + +Graph | soleprint + + + +← docs +
    + + + diff --git a/generate.html b/generate.html deleted file mode 100644 index f4d7d0f..0000000 --- a/generate.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - Soleprint - Generate Configuration - - - -
    -
    -

    Soleprint Configuration Generator

    -

    - Generate a new room configuration for wrapping a managed - application -

    -
    - -
    -
    -

    Configuration

    -
    -
    Room Settings
    -
    - - -
    - Unique identifier for this configuration -
    -
    - -
    Framework Branding
    -
    -
    - - -
    -
    - - -
    -
    - -
    System Names
    -
    -
    - - -
    -
    - - -
    -
    -
    - - -
    - -
    - Managed Application (Optional) -
    -
    - - -
    - - -
    - - -
    -
    -
    -
    - -
    -

    Preview

    -
    - # Enter configuration details and click "Preview - Structure" - - gen/<room>/ - <managed>/ - # if managed app configured - link/ - <soleprint>/ -
    -
    -
    -
    - - - -