Ghost Professional Publishing Platform

repository·main·Indexed 13 days ago

https://github.com/TryGhost/Ghost

An open-source, headless Node.js CMS for professional publishing. The platform features a React-based Admin interface transitioning from legacy Ember via an Ember Bridge, a lightweight Preact-based Admin Toolbar, and the Admin X Framework for shared micro-frontend functionality. It supports both hosted (Ghost(Pro)) and self-hosted deployments via the Ghost CLI.

Tokens
160.3K
Snippets
567
Records
768
Agent score
100%

What's inside Ghost

  1. Overview of Koenig (Ghost Editor)

    main

    Koenig is the post editor for Ghost. It consists of a React-based rich text editor UI and a suite of supporting TypeScript libraries that handle node definitions, rendering, and data conversion.

    Key architectural components include:

    • Editor UI: The visual interface used by Ghost Admin.
    • Lexical Node Libraries: The source of truth for how content (cards) is defined and rendered both in the browser and on the server.
    • Converters: Tools to bridge the gap between legacy Mobiledoc formats and the modern Lexical format.
  2. What is Shade?

    main
    Shade is the design system used to power the Ghost Admin UI. It provides a unified set of design tokens, layout primitives, generic UI components, and product-specific patterns to ensure consistency across Ghost Admin applications. It is organized into distinct layers to prevent reinventing existing UI elements.
  3. Overview of the Acceptance Tier for Admin Tests

    main

    The Acceptance tier provides full-app tests using the real Admin app (the same provider stack as src/main.tsx) booted in a real Chromium instance via Vitest Browser Mode. Instead of a real server, it uses a fake Ghost Admin API served in-browser via MSW.

    Key Characteristics:

    • Automatic Shell Boot: The shell's boot chrome (settings, config, site, me, sidebar members count, active theme, and changelog feed) is handled by default and does not need to be explicitly mentioned in specs.
    • One Render Per Test: Each renderAdminApp call gets a fresh QueryClient and the fake API resets between tests. There is no page reload.
    • Host Page Simulation: renderAdminApp mounts into a stand-in of the production host page (using the react-admin body class and #root), ensuring scroll-driven behaviors like virtualized lists and infinite paging work as they do in production.
    • Limitations: UI fed by the Ember state-bridge (window.EmberBridge events) is unreachable because there is no Ember app in this tier. If a component relies on ember-bridge hooks, the test must be moved to the e2e/ tier.
  4. What are Koenig Converters?

    main
    Koenig Converters is a utility package providing functions to convert content between two specific serialized formats: Lexical and Mobiledoc. This is useful for managing content migrations or interoperability between different editor formats used within the Ghost ecosystem.
  5. Understand the Portal membership widget

    main

    Portal is the visitor-facing membership widget embedded on a Ghost site. It is responsible for managing the following visitor journeys:

    • Member signup and sign-in
    • Checkout processes
    • Membership offers
    • Account management
    • Gift-subscription journeys (for both buyers and recipients)
  6. What is the Portal membership widget?

    main

    Portal is the visitor-facing membership widget that is embedded on a Ghost site. It serves as the primary interface for members and handles the following workflows:

    • Member signup and sign-in
    • Paid subscription checkout
    • Managing offers
    • Account management

    Detailed implementation context can be found in apps/portal/CONTEXT.md.

  7. How to handle the 418 loop (Unhandled Requests)

    main

    In this tier, any request not handled by a fake returns a 418 error. This is used to identify missing fakes in the app's network graph. If a test fails with a 418, you must either:

    1. Declare a resource fake for the Admin API path.
    2. Use a boot override via renderAdminApp.
    3. Use fakeEndpoint(method, url, response) for external origins.
    4. Use allowUnhandledRequests() for a single test if you want to opt-out (e.g., when navigating to a different app like Settings or ActivityPub that owns its own request graph).

    Important Rules:

    • No NQL in fakes: Fakes should never implement NQL (Natural Query Language). Instead, declare the response and assert against the outgoing filter string.
    • External Origins: Add new external origins to EXTERNAL_URL_BLOCKLIST in worker.ts to ensure forgotten fakes fail the test rather than hitting the real network in CI.
    • JSON Only: fakeEndpoint only serves JSON bodies. For image URLs, point them at a non-blocklisted host.
  8. Understand the Checkout Session Flow for New Subscriptions

    main

    When a member signs up for a paid plan, the following sequence occurs:

    1. Initiation: The Member interacts with the Portal to sign up.
    2. Session Creation: The Portal requests Ghost to create a checkout session. Ghost then calls Stripe to create the session and returns the session ID back to the Portal.
    3. Redirection: The Portal redirects the Member to Stripe's secure checkout page where payment details are entered.
    4. Completion: After payment, Stripe redirects the Member back to the success URL.
    5. Asynchronous Synchronization: Stripe sends multiple webhook events to Ghost (e.g., customer.subscription.created, checkout.session.completed, customer.subscription.updated, and invoice.payment_succeeded). Ghost uses these events to upsert member/subscription data and record payments.