Applications · entity catalog

cybele app

Authored subsystem deep-dive for cybele, layered on the code-linked entity catalog — what each system is, why it exists, and how it fits.

authored deep-dive
5entities1layers5deep-dives

On this page

The apps/cybele/ area: five self-contained Hono application modules that make up the Cybele real-estate / built-environment domain — a construction-projects API, a property portfolio dashboard, a listings marketplace, a prefab factory manager, and an API gateway that fronts them.

What this area is#

Cybele is Oshun's real-estate and physical-space domain (the counterpart to Freya's luxury-goods supply side, as noted on the Contracts area page). The apps/cybele/ directory holds its application tier: five Nx projects, each a projectType: "application" under scope:cybele, each built as a hono HTTP app. They are written for a Ghana market — money is denominated in Ghana Cedi (GHS) throughout, listings carry region/district, and the gateway's hand-written OpenAPI document advertises https://api.cybele.gh/v1 with a engineering@cybele.gh contact.

Each project follows an identical shape: src/index.ts constructs a new Hono() app, registers /health and /version endpoints (every app reports version: '0.2.0'), mounts a single feature router from src/routes/<name>.ts, and export defaults the app. The four domain apps mount their router under /api/v1/<name>; the gateway mounts its router at /gateway. The substance of each app lives in that one route file (527–893 lines apiece), where the domain types, Zod request schemas, in-memory stores, and handlers all sit together.

These are genuinely-implemented apps, not scaffolds — they carry real domain-specific logic (PMI earned-value formulas, sliding-window rate limiting, faceted property search, NOI / gross-yield computation, prefab pricing with option adders). Two honesty caveats apply across the area, though. First, persistence is in-process only: every store is a module-level new Map<...>() that starts empty and is populated through POST handlers, so all state is per-process and ephemeral — there is no database, cache, or contracts package wired in. Second, there is no server bootstrap: no serve(), no @hono/node-server, no main.ts, and no Dockerfile is tracked. The apps export Hono app objects that are exercised in-process (via app.request(...)) rather than bound to a listening port here.

The five apps are also self-contained: across all of apps/cybele/*/src the only imports are hono, @hono/zod-validator, and zod (plus vitest in the test file). They do not import @contracts/cybele or any other workspace library — each route file re-declares its own domain interfaces inline. So while the area maps conceptually onto the Cybele wire contracts, that coupling is not expressed as a code dependency today.

How it fits the wider system#

The intended topology is gateway-in-front: @cybele/app-api's service registry is seeded with exactly four built-in services — cybele-projects (:3001), cybele-portfolio (:3002), cybele-marketplace (:3003), and cybele-factory (:3004) — one per sibling app, and its OpenAPI document catalogs the same four surfaces. The gateway models cross-cutting concerns (token issuance, rate-limit policy, audit logging, health aggregation, webhook fan-out) for that fleet. In practice the gateway only registers and pings those services; it does not proxy traffic to them, and the four domain apps run independently of it.

The shared verification seam is apps/cybele/api/src/cybele-apps.test.ts — a single Vitest suite (69 it cases across 16 describe blocks) that imports all four domain routers plus the gateway router and exercises them through isolated Hono instances. Tellingly, only @cybele/app-api declares a test target in its project.json; the other four projects declare lint only, because their coverage lives inside that one cross-cutting suite.

Entity catalog (5)#

The 5 tracked Nx projects in cybele, each a code-linked entity node — package, type, source path, declared targets, and its internal dependency graph (depends-on / used-by, resolved from the package manifests, §6/§8), read from the project graph. Grouped by architectural layer; walk the dependency links to travel the system. 5 of these carry an authored deep-dive (what / why / how it fits); the rest are generated scaffolds awaiting one.

unclassified (5)#

app

@cybele/app-api

#

The Cybele API gateway (apps/cybele/api), whose logic is in src/routes/gateway.ts. It owns the platform-level concerns for the domain fleet: a service registry pre-seeded with the four sibling services, JWT token issue/revoke/inspect, a sliding-window rate-limiter (/rate-limits/check implements real per-minute/per-hour windowing and isBlocked accounting), API-version listing, an in-memory audit log, per-service health aggregation and ping, dynamic service registration, a hand-authored OpenAPI 3.1 document at /openapi.json, and webhook subscription CRUD with delivery records and history. Honest caveat on auth: token issuance is explicitly a simulation — the handler base64-encodes a payload (const fakeToken = Buffer.from(...)...) with a // Simulate JWT (in production would use jsonwebtoken) comment, so tokens are unsigned, not verifiable JWTs. This project is also the home of the area's shared test suite (src/cybele-apps.test.ts) and the only one with a test target.

testlint
scope: cybeleowner: @GreyChimp
app

@cybele/app-factory

#

The prefab / modular factory manager (apps/cybele/factory, src/routes/factory.ts). It models a production line for building modules: production orders, station-based scheduling, QC station results with computed pass-rate (computeQCPassRate), material inventory with reorder-level / low-stock detection, dispatch and logistics records, and a KPI dashboard (/kpis) that aggregates QA pass rate, factory-utilisation percentage, low-stock counts, and a summarizeDefects top-defects ranking. Its most domain-specific endpoint is /modules/:configId/quote, which prices a module configuration from a basePriceGHS plus per-option priceAdderGHS adders against selectedOptions, returns unit and total price, lead-time weeks, and a canFulfil check against minOrderQty. State is Map-backed and starts empty. Declares a lint target only.

lint
scope: cybeleowner: @GreyChimp
app

@cybele/app-marketplace

#

The property listings marketplace (apps/cybele/marketplace, src/routes/marketplace.ts) — the largest of the four domain route files' search surface. It provides listing CRUD plus a real faceted /search that filters on region, district, property/transaction type, price band, bedrooms, area, comma-separated required features, and free-text q (title/description/ address), then sorts (price_asc/price_desc/most_viewed/recency), paginates, and returns countBy facet histograms. Beyond search it has popularity-ranked recommendations (inquiryCount + viewCount), agent management, inquiry/lead capture, viewing appointments, listing comparison, market analytics, per-user favorites, and price alerts. All data lives in in-memory Maps seeded only through POST handlers. Declares a lint target only.

lint
scope: cybeleowner: @GreyChimp
app

@cybele/app-portfolio

#

The property portfolio / asset-management dashboard (apps/cybele/portfolio, src/routes/portfolio.ts). It manages owned properties and their leases, rent collection with arrears tracking, and maintenance tickets, and computes real property financials in /:propertyId/financials: gross rental income, maintenance cost, a property tax of 0.5% of current valuation, net operating income (NOI), gross yield, and unrealised gain over acquisition cost. It also handles valuations (recomputing yieldPct and updating the property's currentValuationGHS), a forward-looking lease-expiry calendar (/lease-calendar), and a /map endpoint that emits a GeoJSON FeatureCollection of property points with occupancy percentages. Map-backed, empty at start. Declares a lint target only.

lint
scope: cybeleowner: @GreyChimp
app

@cybele/app-projects

#

The construction project-management app (apps/cybele/projects, src/routes/projects.ts) — the largest route file (893 lines) and the most algorithmically rich. It covers projects and progress updates, a Gantt schedule, daily reports, RFIs (with responses), change orders (with approval), QC inspections, and safety incidents (with lost-time/fatality tallies). Its standout endpoint is /:projectId/earned-value, a full PMI earned-value- management calculator: from PV/EV/AC/BAC it derives SPI, CPI, schedule and cost variance, ETC, EAC, VAC, and TCPI, then assigns a green/amber/red health band by threshold. Documents support revision control (a new upload supersedes the prior current revision of the same title), and /:projectId/notifications/stream is a real Server-Sent-Events response (ReadableStream emitting a connected event then a 30-second heartbeat) — honestly a heartbeat stream rather than a wired event subscription, as its own comment notes. State is in-memory and ephemeral. Declares a lint target only.

lint
scope: cybeleowner: @GreyChimp