Vai al contenuto principale

Changelog

What's shipped in MarginLock — features, improvements, and fixes.

April 2026

  • feature

    Marketing website launch

    The marketing site is live. Plans 4, 5, and 6 collapsed into a single shipping surface: the home page, four product-pillar pages, three solutions pages, pricing with localized currency conversion, and the company pages all render from the same compound library that the SaaS app reuses.

    Highlights:

    • Localized pricing — prices render in the visitor's currency using daily FX snapshots. No client-side fetch.
    • Compound componentsHero, FeatureGrid, MetricsBand, PricingTable, and friends are dual-use. The SaaS app borrows them for empty states.
    • A11y baseline — every interactive component ships with keyboard navigation and aria-* correctness, verified by axe in CI.

    See /product for the pillar overview and /pricing for the new pricing surface.

  • improvement

    Coverage thresholds and unified test layout across packages

    Every package and app now enforces explicit coverage thresholds in its Vitest config: 80% lines/branches/functions for frontend code, 90% for backend code, and a 50% per-file floor that prevents one well-tested module from masking a neglected one.

    We also moved every package onto the same test layout — co-located *.test.ts files under src/, with tests/ reserved for integration suites. The CI job now reports a single coverage summary per workspace instead of stitching results from four different shapes.

  • feature

    Marketing design system and compound library

    The marketing design system landed today. Beyond the existing UI primitives shared with the SaaS app, the marketing site adds a compound library:

    • Hero, FeatureGrid, FeatureSpotlight, MetricsBand
    • PricingTable, LogoStrip, Quote
    • FAQ, Steps, Compare, CTA
    • GradientPanel for product mock placeholders

    Every compound is theme-aware, dark-mode-correct, and uses the same tokens as the SaaS app, so any component we build for marketing can be reused as-is for in-product empty states or onboarding flows.

  • feature

    apps/web skeleton bootstrapped

    The marketing surface now has a home of its own. apps/web/ is a separate Next.js 15 app with the App Router, i18n routing baked in, the shared theme provider, the Geist font family, and a marketing-style nav and footer.

    It deploys to a Vercel preview on every PR and to production on every merge to main. The SaaS app at app.marginlock.io is unchanged; this is a separate deploy target so we can iterate on landing-page content without rebuilding the authenticated bundle.

  • feature

    Warehouse inventory page

    The warehouse pillar gained a new top-level surface today: the warehouse-inventory page. It pivots stock three ways:

    • By location — every active warehouse with current on-hand counts and reserved-for-shipment counts side by side.
    • By SKU — each SKU's distribution across all warehouses, with a single "where is it?" lookup.
    • By aging band — fresh, 30+, 60+, 90+, and stale buckets, so slow-moving inventory is visible at a glance.

    The page hangs off the existing warehouse navigation. Multi-warehouse plans get the cross-warehouse view; single-warehouse plans see the same layout collapsed to a single column.

  • feature

    Fee detector forecasting

    The fee engine just learned to look forward. After every settlement closes, MarginLock runs each detector against the last-cycle data and ranks them by expected hit rate on the next settlement.

    The forecast surfaces in two places:

    • The fee dashboard now shows a "next-cycle outlook" card with the top three detectors ordered by expected adjustments.
    • The alert center uses the same forecast to pre-stage the watch list, so ops teams know what to look for before the settlement lands.

    Forecasts are advisory, not auto-acting. The detectors still run for real on the next settlement and only the actual hits drive FeeAdjustment rows.

  • improvement

    Postgres LISTEN/NOTIFY for the worker job queue

    The worker fleet used to poll the Job table on a 5-second interval. As the SP-API integration grew, that poll started to dominate the database's read load — and the 5-second floor on job pickup time was visible in the UI.

    Workers now subscribe to a Postgres LISTEN channel that the API process NOTIFYs when a job is enqueued. Pickup latency dropped from ~5 seconds to sub-100 ms in steady state, and database CPU dropped about a third in production at idle.