Skip to content

feat: Remote Instance Catalog Fetch - #514

Merged
volodymyr-chekyrta merged 5 commits into
openedx:developfrom
raccoongang:infra/04-remote-catalog-fetch
Oct 27, 2026
Merged

volodymyr-chekyrta merged 5 commits into
openedx:developfrom
raccoongang:infra/04-remote-catalog-fetch

Conversation

@IvanStepanok

Copy link
Copy Markdown
Contributor

Description

Adds fetching the instance catalog from a remote URL, with the bundled catalog as the offline fallback. Port of openedx-app-ios#676.

Stacked PR: builds on #513. Please review and merge in order.

This PR only adds the fetch, cache and parse machinery. Nothing calls InstanceConfigLoader at launch yet; until the launch-sequencing PR the app boots on its bundled config as before.

What's in this PR

Remote fetch, with an offline-safe merge policy

  • OkHttpInstanceApiService: a plain GET of INSTANCES_CATALOG_URL with an OkHttp client of its own, not the app's API client: no interceptors, no credentials, no HTTP cache, 10 second timeout. It is a fixed, anonymous endpoint.
  • InstanceConfigLoader.load(): the baseline is the last cached successful fetch, else the bundled catalog, else empty.
    • A response with at least one valid instance replaces the baseline and becomes the cache.
    • A failed, malformed or empty response leaves the baseline untouched; a reachable but empty catalog never wipes a good cache.
  • INSTANCES_CATALOG_URL is a new app-level key (empty in dev, stage and prod: bundled catalog only).

Remote schema

  • Accepts a bare array or an object wrapping it under instances / INSTANCES.
  • Remote snake_case keys are renamed at every nesting depth with the same map iOS uses; unmapped keys pass through unchanged. Palette field names are never renamed.

Not ported: YAML retirement

  • iOS #676 replaced config.yaml with config.json. Here the Gradle build already turns config.yaml into the bundled config.json the loader reads, so instances are written in YAML and arrive in the same JSON shape iOS ships. Changing the build-config format would be a separate decision for this repo.

Tests

  • InstanceConfigLoaderTest (17 cases) on a shared remote fixture: key normalization at every depth, untouched palette names, pass-through of unmapped keys, both payload shapes, rejected shapes, required fields; loader replace/cache/fallback semantics, including empty, malformed, offline and unparseable-cache cases and no request when no URL is set; the catalog request carries no Authorization or Cookie header and bypasses caches; non-2xx responses fail; the client has no interceptors and a 10 second timeout.

Out of scope

  • Calling the loader at launch.
  • Instance picker.

Testing

  • ./gradlew detektAll testProdDebugUnitTest :app:assembleProdDebug

Introduces Instance and InstancesConfig: what one Open edX platform is and how it is
parsed from the INSTANCES block of the bundled config. Nothing reads it yet.

Required fields are NAME, API_HOST_URL and OAUTH_CLIENT_ID; a malformed entry is dropped.
KEY falls back to a slug of NAME, INSTANCE_NAME is localized with an English fallback,
and PLATFORM_NAME defaults to the display name. The schema matches iOS (#672).
InstanceStore holds the instance catalog and the selected instance, persists the
selection by key and publishes it as a StateFlow. A single-instance catalog selects its
only instance automatically. Registered in Koin as InstanceStore and InstanceProvider;
nothing consumes it yet. Mirrors iOS #673.
InstanceTheme derives a palette from an instance's accent color and its optional
THEME.LIGHT/THEME.DARK overrides: only the fields an instance sets change, the rest keep
the compiled default, and a missing dark value falls back to the light one. Palette field
names are the ones iOS uses (#675), mapped onto AppColors.

OpenEdXTheme observes InstanceThemeManager, which holds the selected instance's theme.
Nothing applies a theme yet, so every screen still renders the default palette.
InstanceConfigLoader resolves the catalog the app runs with: the last cached remote
catalog, else the bundled INSTANCES list, else nothing. A live fetch with at least one
instance replaces that baseline and becomes the cache; a failed, malformed or empty
response leaves it untouched.

The catalog is fetched from INSTANCES_CATALOG_URL with a plain OkHttp client: no app
interceptors, no credentials, a 10 second timeout. Remote snake_case keys are normalized
with the same map iOS uses (#676). Nothing calls the loader at launch yet.

Unlike iOS, the YAML build configuration stays: the Gradle build already turns it into
the bundled config.json the loader reads.
@openedx-webhooks openedx-webhooks added open-source-contribution PR author is not from Axim or 2U core contributor PR author is a Core Contributor (who may or may not have write access to this repo). labels Oct 19, 2026
@openedx-webhooks

Copy link
Copy Markdown

Thanks for the pull request, @IvanStepanok!

This repository is currently maintained by @openedx/openedx-mobile-maintainers.

Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review.

🔘 Get product approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

Details
Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

RawanMatar89
RawanMatar89 previously approved these changes Oct 21, 2026
@mphilbrick211 mphilbrick211 moved this from Needs Triage to In Eng Review in Contributions Oct 22, 2026
@IvanStepanok

Copy link
Copy Markdown
Contributor Author

@RawanMatar89 I merged develop into this branch to clear the conflicts left by squashing #511–#513. Nothing in this PR's own changes moved; GitHub dropped your approval because of the new commit. The files tab shows only this PR's 11 files now. Could you re-approve when you have a minute?

@volodymyr-chekyrta
volodymyr-chekyrta merged commit 89c3603 into openedx:develop Oct 27, 2026
6 checks passed
@volodymyr-chekyrta
volodymyr-chekyrta deleted the infra/04-remote-catalog-fetch branch October 27, 2026 16:39
@github-project-automation github-project-automation Bot moved this from In Eng Review to Done in Contributions Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core contributor PR author is a Core Contributor (who may or may not have write access to this repo). open-source-contribution PR author is not from Axim or 2U

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants