Developer-Dashboard

 view release on metacpan or  search on metacpan

doc/architecture.md  view on Meta::CPAN


- `Developer::Dashboard::SessionStore`
  Stores helper browser sessions as file-backed state.

- `Developer::Dashboard::Prompt`
  Renders `PS1` output from cached indicator state in compact or extended mode,
  with optional color and stale-state marking, so prompt redraws stay cheap and
  do not rerun expensive health checks.

- `dashboard`
  Canonical command-line entrypoint for runtime, page, collector, prompt, and user CLI extension operations.
  It is the only public executable the distribution installs into the global
  PATH, so generic helper names stay inside the dashboard runtime instead of
  leaking into the wider shell ecosystem.

- `dashboard of` / `dashboard open-file`
- open-file commands keep the interactive numbered chooser workflow for
  multi-match searches, support comma and range selections or blank-for-all,
  and fall back to `vim` when no editor is configured
  Resolve direct files, `file:line` references, Perl module names, Java class names, and recursive file-pattern matches below a resolved scope, then print or exec the configured editor.
  Scoped searches rank exact helper/script names ahead of broader substring matches, so `dashboard of . jq` prefers `jq` and `jq.js` before `jquery.js`.

- `dashboard jq` / `dashboard yq` / `dashboard tomq` / `dashboard propq` / `dashboard iniq` / `dashboard csvq` / `dashboard xmlq`
  Parse JSON, YAML, TOML, Java properties, INI, CSV, and XML input and optionally traverse a dotted path before printing a scalar or canonical JSON. File-path and query-path argument order is interchangeable, and `$d` selects the full parsed document...

- private `~/.developer-dashboard/cli/dd/jq` / `yq` / `tomq` / `propq` / `iniq` / `csvq` / `xmlq` / `of` / `open-file` / `ticket`
  Are staged into the dashboard runtime and used for private helper dispatch without installing generic command names into the system PATH.

- no public standalone `of`, `open-file`, or `ticket` executable
  The distribution keeps file-opening and ticket-session behaviour behind
  `dashboard` subcommands plus private runtime helpers instead of shipping more
  generic top-level binaries into the CPAN-installed PATH.

- `Developer::Dashboard::PageDocument`
  Canonical page model for saved, transient, and older bookmark pages.

- `Developer::Dashboard::PageStore`
  Persists saved pages and encodes/decodes transient page payloads.

- `Developer::Dashboard::PageResolver`
  Resolves saved pages and generated provider pages into one page-document model.

- `Developer::Dashboard::PageRuntime`
  Applies Template Toolkit rendering for `HTML`, then executes older `CODE*` sections inside one throwaway sandpit package per page run and captures their output for page rendering.

- `Developer::Dashboard::Web::App`
  Implements the browser service layer for page rendering, page actions, helper
  login/logout, and older compatibility flows behind the HTTP route table.

- `Developer::Dashboard::Web::DancerApp`
  Owns the explicit Dancer2 HTTP route table, normalizes requests, enforces
  protected-route authorization, and forwards work into the web-app service.

- `Developer::Dashboard::Web::Server`
  PSGI web server wrapper for the Dancer2 app, defaulting to bind `0.0.0.0:7890`.

- `Developer::Dashboard::UpdateManager`
  Runs ordered update scripts, stops running collectors, and restarts them afterward.

- `Developer::Dashboard::DockerCompose`
  Resolves compose base files plus explicit project, service, addon, and mode overlays, env injection, and the final `docker compose` command.
  It discovers isolated service folders from layered `config/docker` roots,
  including project-local `./.developer-dashboard/config/docker`, and exports `DDDC` for
  compose-time references to the runtime `config/docker` directory inside YAML.

## Runtime Model

The architecture follows a producer/consumer pattern:

- collectors prepare data in the background
- indicators and pages read cached state
- prompt rendering reads cached state only
- update scripts bootstrap runtime state and shell integration

Collector-backed indicator config has one extra split when `indicator.icon`
uses Template Toolkit syntax:

- the configured TT source is persisted as `icon_template`
- the live rendered indicator value is persisted separately as `icon`
- collector runs render `icon_template` against stdout JSON data
- later config-sync passes keep the rendered `icon` instead of rewriting raw
  `[% ... %]` text back into prompt and browser state

That connection matters to the product story:

- collectors prepare the answer once
- indicators summarize it in the browser and prompt
- pages and actions give the browser a working home instead of a static note page
- CLI helpers move the developer directly to files, paths, and container commands

Collector loops are managed explicitly:

- each loop writes a pid file plus `loop.json` metadata
- the process title is set to `dashboard collector: <name>`
- duplicate prevention requires both a live pid and a matching process title
- stale or foreign pid files are cleaned up instead of being trusted blindly

Web service lifecycle is managed the same way:

- `dashboard serve` backgrounds the web service by default
- `dashboard serve` starts the configured collector loops alongside the web service, so `serve`, `stop`, and `restart` all act on the same managed runtime set
- `dashboard stop` stops both the web service and collector loops
- `dashboard restart` stops both, restarts configured collectors, then starts the web service again
- the web process title is set to `dashboard web: <host>:<port>`
- shutdown prefers managed-process validation, then falls back to `pkill -f` style matching and explicit process scans

Browser access is managed explicitly:

- exact `127.0.0.1` with numeric host `127.0.0.1` is trusted as local admin
- `localhost`, other hosts, and other client IPs are helper-tier requests
- helper-tier requests must authenticate through file-backed user and session records
- helper usernames are validated, passwords require at least 8 characters, and user/session files are written with `0600` permissions
- helper sessions are bound to the originating remote address and expire after 12 hours
- helper page views show a Logout link in the top chrome, display the helper username in the top-right user marker, and logging out removes both the helper session and that helper account
- exact-loopback admin page views do not show a Logout link
- HTTP responses add CSP, frame-deny, nosniff, no-referrer, and no-store headers

Page source compatibility is explicit:

- bookmark files serialize back to the original `KEY: ...` plus divider-line syntax
- older `KEY: ...` documents separated by the original divider line are supported directly
- `HTML` is rendered through Template Toolkit with access to `stash`, `ENV`, and `SYSTEM`
- `TITLE` populates the document `<title>` and is exposed to Template Toolkit as `title`, but it is not injected into the page body automatically
- `CODE*` blocks run through the older page runtime, merge returned hashes into stash, dump returned hash and array values into the runtime output area, append printed `STDOUT` to the page, and show `STDERR` as red error output
- one generated sandpit package is reused across `CODE*` blocks for a single render, then destroyed so package globals do not leak into later requests
- `/` with no bookmark path opens the free-form instruction editor directly
- posting a root-editor document with `BOOKMARK: some-id` persists it as a saved bookmark so `/app/some-id` can load it on the next request
- `/apps` redirects to `/app/index`
- transient browser execution from `/?token=...`, `/action?atoken=...`, and older `/ajax?token=...` is disabled by default and only re-enabled when `DEVELOPER_DASHBOARD_ALLOW_TRANSIENT_URLS` is truthy
- saved bookmark `Ajax` helper calls can avoid transient tokens by supplying `file => 'name.json'`, which stores the code under `dashboards/ajax/...`, emits `/ajax/<name>?type=...`, and runs the stored file as a real process so live `stdout` and `std...
- edit and render views include shared top chrome with share/source links plus the original status-plus-alias indicator strip, refreshed from `/system/status`, alongside the local user, a machine IP link chosen from the active interfaces, and a brows...
- direct `nav/*.tt` saved bookmarks are treated as shared nav fragments, and raw TT/HTML fragment files under `nav/` are accepted too when they actually look like nav markup, so `/app/nav/foo.tt` remains editable like any other bookmark while non-nav...
- bookmark Template Toolkit rendering exposes `env.current_page` and `env.runtime_context.current_page`, so saved pages and nav fragments can branch on the active request path without losing the rest of the runtime context
- `DD-OOP-LAYERS` is the cross-runtime contract: starting at `~/.developer-dashboard` and walking down through every parent directory until the current working directory, every existing `.developer-dashboard/` layer participates as one inherited runt...
- under `DD-OOP-LAYERS`, the deepest discovered layer stays the write target and first lookup hit, while bookmarks, shared `nav/*.tt`, config, collectors, indicators, auth/session stores, runtime `local/lib/perl5`, static assets, and custom CLI hooks...
- DD-OOP-LAYERS ancestry and dedupe checks normalize canonical path identities, so macOS path aliases such as `/var/...` and `/private/var/...` still resolve to the same inherited layer chain
- dashboard-managed built-in helper extraction is the explicit home-only exception to that write rule: `dashboard init` and on-demand helper staging always seed built-in helpers only under `~/.developer-dashboard/cli/dd/`, while layered lookup still ...
- home-runtime helper staging is non-destructive: `dashboard init` may add or update dashboard-managed built-in helpers under `~/.developer-dashboard/cli/dd/`, but it must preserve the separate user command and hook space under `~/.developer-dashboar...
- dashboard-managed helper and starter-page refreshes are MD5-aware inside Perl, so `dashboard init` skips rewriting a dashboard-managed helper or shipped starter page when the existing file already matches the shipped content digest
- starter-page refreshes are safe across upgrades too: `dashboard init` records the md5 of the last dashboard-managed shipped starter-page copy under the active runtime config tree, refreshes only pages that still match that recorded or bridged histo...
- `dashboard init` seeds the current dashboard-managed starter pages as normal editable saved bookmarks, but rerunning it preserves an existing `~/.developer-dashboard/config/config.json` instead of overwriting user config; if the file is missing, in...
- the public `dashboard` entrypoint stays thin for all built-in commands: the shipped starter bookmark source plus helper script source live under `share/seeded-pages/` and `share/private-cli/`, dedicated helper bodies cover `jq`/`yq`/`of`/`open-file...
- `dashboard cpan <Module...>` installs optional runtime modules into `./.developer-dashboard/local` and appends them to `./.developer-dashboard/cpanfile`, while keeping that support in the `dashboard` entrypoint and having saved Ajax workers infer `...
- `dashboard serve logs` exposes the combined Dancer2 and Starman runtime log stored in the dashboard log file, with `-n N` tailing and `-f` follow mode
- `dashboard serve workers N` persists the default Starman worker count in config and auto-starts the web service when it is currently stopped; `--host HOST` and `--port PORT` steer that auto-start path, while `dashboard serve --workers N` and `dashb...
- the editor view auto-submits once focus leaves the whole editor form instead of relying on a visible update button
- the editor splits bookmark sections into separate visible blocks but still recomposes the canonical separator-based source into a hidden `instruction` field before save and play submits
- each visible editor block keeps a plain escaped source overlay with wrapping disabled so the visible text geometry stays identical to the real textarea during long bookmark edits

## Environment Overrides

The core supports compatibility-style environment overrides for project customization:

- `DEVELOPER_DASHBOARD_BOOKMARKS`
  Saved page/bookmark root.

- `DEVELOPER_DASHBOARD_CHECKERS`
  Filter for enabled collector/checker names using colon-separated values.

- `DEVELOPER_DASHBOARD_CONFIGS`
  Config root.

- `DEVELOPER_DASHBOARD_ALLOW_TRANSIENT_URLS`
  Opt-in flag for browser execution of transient `token=` and `atoken=` payloads.


The runtime also supports user CLI extensions:

- unknown top-level `dashboard` subcommands are resolved through the `DD-OOP-LAYERS` stack with the deepest matching `./.developer-dashboard/cli/<command>` winning over parent layers and finally `~/.developer-dashboard/cli`
- the matching executable receives the remaining argv unchanged
- stdin, stdout, and stderr are preserved through `exec`
- every top-level command also has optional hook directories at `./.developer-dashboard/cli/<command>` or `./.developer-dashboard/cli/<command>.d` in every inherited layer
- executable hook files run in sorted filename order within each layer, and the layers themselves execute from `~/.developer-dashboard` down to the deepest current layer
- non-executable files in the hook directory are skipped
- hook `stdout` and `stderr` stream live to the terminal while also being accumulated into `RESULT` JSON for later hooks and the final command
- after each hook exits, the updated `RESULT` JSON is written back into the environment before the next hook starts
- Perl hook scripts can use `Runtime::Result` to decode `RESULT` and inspect prior hook `stdout`, `stderr`, and exit codes
- there is no special built-in `update` path; `dashboard update` is just another user-provided command when `./.developer-dashboard/cli/update` or `./.developer-dashboard/cli/update/run` exists, with the same home fallback
- directory-backed custom commands can use `./.developer-dashboard/cli/<command>/run` as the final executable after hooks complete, with the same home fallback

## Packaging

- `dist.ini` controls Dist::Zilla packaging
- GitHub Actions builds with `dzil build`
- uploads to PAUSE use `PAUSE_USER` and `PAUSE_PASS`

## Quality Gates

- `prove -lr t` must pass
- library coverage is measured with Devel::Cover
- the coverage report should be reviewed before release, especially after adding new runtime modules



( run in 1.446 second using v1.01-cache-2.11-cpan-df04353d9ac )