Skip to content

Latest commit

 

History

History
259 lines (172 loc) · 10.5 KB

File metadata and controls

259 lines (172 loc) · 10.5 KB

Architecture

This repository contains the MedRush Agents Hub frontend. The checked-in app is a lightweight Preact single page application under portable/, with a small custom Node/esbuild toolchain and root-level shell wrappers for local development and CI.

The project is currently frontend-only. There is no runtime backend service, database, or deployed API client in this checkout. Several folders such as src/api, src/contexts, src/registry, and src/transformers exist as extension points.

Repository Layout

.
+-- config.sh                 # Selects the active app directory for dev.sh
+-- dev.sh                    # Root command dispatcher: dev <command>
+-- scripts/                  # Local command wrappers and help docs
+-- ci/                       # GitHub/CI automation scripts
`-- portable/                 # Preact app, build pipeline, assets, styles
    +-- core/                 # Custom build/server/resolver scripts
    +-- public/               # HTML template, icons, fonts, preview image
    +-- assets/               # Static app assets copied to dist/assets
    +-- styles/               # Source CSS copied to dist/styles
    +-- src/                  # TypeScript/Preact source
    `-- dist/                 # Generated build output

config.sh sets DEV_APP="portable", so root commands operate on the portable/ app.

Runtime Architecture

The browser loads portable/public/index.html, after the build step has replaced metadata placeholders from portable/meta.json. The page loads:

  • styles/index.css for global and component styles.
  • app.js, the esbuild bundle generated from src/main.tsx.
  • Static images, fonts, and assets from public/ and assets/.

At runtime, src/main.tsx mounts a Preact app into #app and renders HomePage. HomePage uses the small router in src/utils/router.tsx with path segments from src/utils/path.ts. The current route table is empty, so unknown or root paths fall back to the home layout, which renders HomeView.

The current product UI path is:

src/main.tsx
`-- routes/home.tsx
    `-- components/view/home-view.tsx
        `-- components/block/about.tsx
            `-- components/kit/trip-info.tsx

About currently defines a hard-coded TripData[] and renders one delivery option through TripInfo.

Source Layers

Routes

portable/src/routes contains page-level routing entry points. home.tsx defines the HomePage route and a Layout component. Routing is intentionally simple:

  • useForwarded() splits window.location.pathname into path segments.
  • useRouter() picks the first segment and checks it against a route map.
  • If no route matches, the layout receives a dynamic value and can render fallback content.

The static server also falls back missing paths to index.html, so client-side routes can be loaded directly.

Views and Blocks

portable/src/components/view contains page-level view composition. HomeView wraps the home content in ScrollPop.

portable/src/components/block contains larger content blocks. About is the current primary block and owns the placeholder trip data displayed to agents.

Kit Components

portable/src/components/kit contains reusable product-level components:

  • TripInfo renders a delivery payout summary from TripData.
  • Infolet, Textlet, and Linklet are reusable display/link components.
  • Section and ScrollPop provide layout primitives for composed sections.

These components depend on lower-level UI primitives and generated class-name helpers.

UI Primitives

portable/src/components/ui contains small building blocks:

  • structure: Container, LimitWidth, Image, NodeBG.
  • text: Heading, Text, LineBreak.
  • interactive: Clickable, Link.

These primitives are intentionally thin wrappers around HTML elements and use CSS class names generated by the build pipeline.

Data and Utilities

portable/src/interfaces/trip-data.ts defines the current delivery data contract:

  • Location: name, latitude, longitude.
  • TripData: pickup locations, drop location, scale, payout, and time/distance stats.

portable/src/data/index.tsx defines a generic DataProvider/useData context with per-API subscriptions, but it is not currently mounted by main.tsx. It appears to be scaffolding for future shared data refresh behavior.

portable/src/utils/subscription.ts provides the subscription primitive used by the data context. portable/src/utils/generators.ts provides randomId().

Build Architecture

The app uses a custom build script in portable/core/build.mjs instead of a framework CLI.

Build Inputs

Primary inputs are:

  • portable/src/main.tsx
  • portable/public/
  • portable/styles/
  • portable/assets/
  • portable/meta.json
  • portable/src/components/

Build Outputs

Build output is written to portable/dist/:

  • app.js and app.js.map
  • copied and processed index.html
  • copied styles under dist/styles
  • copied assets under dist/assets
  • copied public files such as fonts, logo, and preview image

portable/dist is generated and should be treated as build output.

esbuild Bundle

core/build.mjs creates an esbuild context with:

  • entry point: src/main.tsx
  • output: dist/app.js
  • JSX runtime: Preact automatic JSX
  • target: es2020
  • aliases matching tsconfig.json paths, such as @components, @routes, @utils, @styles, and @assets
  • minification enabled for production builds and disabled for dev builds

Generated Style Module

Before bundling, matchComponentsCssFiles() scans src/components for .tsx and .jsx files. It ensures matching CSS files and index.css import files exist under styles/app.

Then buildStyles() scans CSS class names from portable/styles and writes portable/src/styles/styles.ts. The generated module exports:

  • ClassName
  • PossibleClassName
  • useClasses(...args)

Components import useClasses from @styles to avoid hand-typed class string assembly.

Generated Asset Module

buildAssets() scans portable/assets and writes portable/src/assets/assets.ts. The generated module maps asset names to public URLs under [[url]]/assets/..., using the root URL from meta.json.

Components can import useAsset from @assets when they need asset URLs.

Metadata Replacement

metaCopyDir() copies files from public/, styles/, and assets/ into dist/. For .html, .css, and .js files, it replaces [[key]] placeholders using values from meta.json.

The replacement loop runs twice so nested values such as "image": "[[url]]/preview.png" resolve after url is substituted.

Local Commands

Root-level development uses dev.sh:

source dev.sh
dev help
dev setup
dev run
dev build
dev start

The command dispatcher loads config.sh, finds a matching script in scripts/, and runs it against $DEV_APP.

Important commands:

  • dev setup: installs npm dependencies in portable/.
  • dev run: runs npm run dev, which starts watch mode and a dev server.
  • dev build: runs npm run build, which writes portable/dist.
  • dev start: builds and starts a static server for portable/dist.
  • dev install: forwards to npm install inside portable/.

The app-level npm scripts are:

{
  "dev": "node core/build.mjs dev",
  "start": "node core/build.mjs start",
  "build": "node core/build.mjs build"
}

The server defaults to port 3000 and can be overridden with PORT.

Static Server

portable/core/server.mjs implements a small Node HTTP server:

  • Serves files from dist/.
  • Maps / to index.html.
  • Falls back missing paths to index.html for SPA routing.
  • Sets MIME types for common static files.
  • Uses Cache-Control: no-cache in dev and public, max-age=600 in start mode.

Styling

portable/styles/index.css imports:

  • core/fonts.css
  • core/variables.css
  • core/base.css
  • app/index.css

styles/app/index.css imports component-layer style indexes. Component styles are organized to mirror src/components, and the build script can create missing component CSS files and index imports automatically.

CI and Automation

The ci/ directory contains shell automation intended for GitHub workflows:

  • ci/publish/main.sh: builds portable and force-publishes portable/dist to gh-pages.
  • ci/summary/main.sh: creates an AI-generated PR summary using an external $URL endpoint, $TOKEN, gh, jq, and PR environment variables.
  • ci/tagger/main.sh: suggests and applies labels through GitHub CLI using an external AI endpoint.
  • ci/leaks/checker/__main__.py: early scaffolding for import/module boundary checks.
  • ci/format/main.sh and ci/leaks/main.sh: currently empty placeholders.

These scripts assume a git repository and required CLI tools/environment variables. The current local workspace is not itself a git repository.

Dependency Summary

Runtime dependencies:

  • preact: UI rendering.
  • @attaditya/iconoir-preact: icon components. This package is not fully ready for broader use in this app; only direct icon components are currently considered usable. Provider-level APIs from the package should not be relied on yet.

Development dependencies:

  • esbuild: bundling and watch mode.
  • typescript: type checking and TypeScript support.

The app is configured as an ES module package through "type": "module".

Current Limitations and Extension Points

  • Trip data is hard-coded in components/block/about.tsx; there is no API integration yet.
  • DataProvider exists but is not mounted, so shared data subscription behavior is not active.
  • The router supports nested route forwarding, but no child routes are registered yet.
  • src/api, src/contexts, src/registry, and src/transformers are currently placeholders.
  • @attaditya/iconoir-preact should be treated as icons-only for now; package providers are not ready for use.
  • scripts/version.sh refers to an app directory, while this repository uses portable; that script likely needs alignment before use.
  • The top-level README describes GraphScript, while meta.json and UI content identify this app as MedRush Agents Hub.

Recommended Direction

For near-term product work, keep the existing layered structure:

  1. Add API clients under portable/src/api.
  2. Mount DataProvider in src/main.tsx once shared data refresh is needed.
  3. Move hard-coded trip data out of About into data/API modules.
  4. Expand TripInfo around the existing TripData interface instead of introducing parallel trip shapes.
  5. Register new pages through routes/home.tsx or split route maps into dedicated route modules when the app grows.