forked from openedx/frontend-app-learning
-
Notifications
You must be signed in to change notification settings - Fork 3
feat: claude init #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
263d797
feat: add initial CLAUDE.md
nsprenkle 4daa613
docs: add note about forks & upgrades
nsprenkle eb904c3
feat: add validate command to run pre-PR validation
nsprenkle c8bd5bd
feat: add validate command and stub config to work regardless of loca…
nsprenkle 089425f
chore: add allowed npm run scripts
nsprenkle e773f13
chore: add more allowed scripts to settings.json
nsprenkle fe4492c
feat: add additional missing allow scripts
nsprenkle 846f621
fix: update to correct config location
nsprenkle 19589a0
fix: update path
nsprenkle 49110e9
fix: update validate command to correct release branch name
nsprenkle 1e7d0f8
fix: correct some validate command details
nsprenkle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| Run all pre-PR validation checks and report results. | ||
|
|
||
| > Note: The build step uses `npm run build:validate` (with a stub `env.config`) rather than `npm run build`, so the build succeeds without the private edX plugin packages required in production. All other checks match CI. | ||
|
|
||
| Execute the following checks **in order**, capturing output from each. Continue through all checks even if one fails — collect all failures before reporting. | ||
|
|
||
| ## Checks to run | ||
|
|
||
| ### 1. Commit messages | ||
| Run: `git log release-teak..HEAD --format="%H %s"` | ||
|
|
||
| > Note: `release-teak` is the current base branch for PRs in the `edx` fork. Update this (and the matching allow-list entry in `.claude/settings.json`) when the default branch changes. | ||
|
|
||
| For each commit, validate the subject line against the conventional commits format: | ||
| `<type>(<optional scope>): <description>` | ||
|
|
||
| Valid types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` | ||
|
|
||
| Flag any commit whose subject does not match this pattern. | ||
|
|
||
| ### 2. Lint | ||
| Run: `npm run lint -- --max-warnings 0` | ||
|
|
||
| ### 3. Type checking | ||
| Run: `npm run types` | ||
|
|
||
| ### 4. Tests | ||
| Run: `npm test -- --passWithNoTests` | ||
|
|
||
| ### 5. Build | ||
| Run: `npm run build:validate` | ||
|
|
||
| ### 6. Bundle size | ||
| Run: `npm run bundlewatch` | ||
|
|
||
| ## Report | ||
|
|
||
| After all checks complete, output a summary table: | ||
|
|
||
| | Check | Status | | ||
| |-------|--------| | ||
| | Commit messages | ✅ PASS / ❌ FAIL | | ||
| | Lint | ✅ PASS / ❌ FAIL | | ||
| | Types | ✅ PASS / ❌ FAIL | | ||
| | Tests | ✅ PASS / ❌ FAIL | | ||
| | Build | ✅ PASS / ❌ FAIL | | ||
| | Bundle size | ✅ PASS / ❌ FAIL | | ||
|
|
||
| For each failed check, show the specific errors and a brief suggested fix. | ||
| If all checks pass, confirm the branch is ready for a PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "permissions": { | ||
| "allow": [ | ||
| "Bash(npm run lint)", | ||
| "Bash(npm run lint -- --max-warnings 0)", | ||
| "Bash(npm run types)", | ||
| "Bash(npm test -- --passWithNoTests)", | ||
| "Bash(npm run build)", | ||
| "Bash(npm run build:validate)", | ||
| "Bash(git log -1 --pretty=%B)", | ||
|
nsprenkle marked this conversation as resolved.
|
||
| "Bash(git log release-teak..HEAD --format=\"%H %s\")", | ||
| "Bash(npm run bundlewatch)" | ||
| ] | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Commands | ||
|
|
||
| Run `/validate` to check all pre-PR requirements locally (lint, types, tests, build, bundle size, commit messages) and get a pass/fail summary with guidance on any failures. | ||
|
|
||
| ```bash | ||
| # Development | ||
| npm start # Start dev server (standard) | ||
| npm run dev # Start dev server with local OpenEdX config (host: apps.local.openedx.io) | ||
| npm run build # Production webpack build | ||
|
|
||
| # Testing | ||
| npm test # Run all tests with coverage | ||
| npm run test:watch # Watch mode | ||
| npm run snapshot # Update snapshots | ||
|
|
||
| # Run a single test file | ||
| NODE_ENV=test npx jest path/to/file.test.jsx | ||
|
|
||
| # Linting | ||
| npm run lint # Check | ||
| npm run lint:fix # Auto-fix | ||
|
|
||
| # Type checking | ||
| npm run types # tsc --noEmit (TypeScript only) | ||
|
|
||
| # i18n | ||
| npm run i18n_extract # Extract translation strings | ||
| ``` | ||
|
|
||
| ## Fork and Upgrade Strategy | ||
|
|
||
| This repo is a fork of [openedx/frontend-app-learning](https://github.com/openedx/frontend-app-learning) maintained in the `edx` GitHub org. Understanding this relationship is important when authoring changes. | ||
|
|
||
| ### Release cadence | ||
|
|
||
| The open source community authors changes on `openedx/master`. Every ~6 months, these are grouped into a named release branch, tested, and offered to forks. Because we run a large production instance, we pull in upstream changes only when named releases are available — not from `openedx/master` directly. | ||
|
|
||
| ### Authoring changes | ||
|
|
||
| We also author our own changes on this fork to ship features faster than the upstream review process allows. The guiding principle is: **every change should ideally be compatible with upstream and eventually contributed back.** | ||
|
|
||
| In practice this means: | ||
|
|
||
| - **Prefer plugin slots** — proprietary UI additions should use `@openedx/frontend-plugin-framework` plugin slots ([src/plugin-slots/](src/plugin-slots/)) so they can be injected without modifying core code. | ||
| - **Prefer feature toggles disabled by default** — any behavior that isn't appropriate for the broader open source community should be gated behind a config flag (via `getConfig()` from `@edx/frontend-platform`) that defaults to off, making the change safe to contribute upstream. | ||
| - **Avoid proprietary logic in core paths** — changes that can't be upstreamed should be isolated at the edges (plugin slots, config-gated branches) rather than embedded in shared data/API/redux code. | ||
|
|
||
| ## Architecture | ||
|
|
||
| This is an OpenEdX Micro-Frontend (MFE) built on `@edx/frontend-platform` and `@openedx/frontend-build`. It serves the learner-facing course experience. | ||
|
|
||
| ### Routing | ||
|
|
||
| Routes are defined in [src/constants.ts](src/constants.ts) as `DECODE_ROUTES` and `ROUTES`. The main route structure is: | ||
| - `/course/:courseId/home` — Course outline/home tab | ||
| - `/course/:courseId/dates` — Dates tab | ||
| - `/course/:courseId/progress` — Progress tab | ||
| - `/course/:courseId/discussion/...` — Discussion tab | ||
| - `/course/:courseId/:sequenceId/:unitId` — Courseware (unit content) | ||
| - `/course/:courseId/course-end` — Course exit | ||
|
|
||
| All routes under `DECODE_ROUTES` are wrapped in `<DecodePageRoute>` (URL decoding support). The app entry point is [src/index.jsx](src/index.jsx). | ||
|
|
||
| ### Redux Store Structure | ||
|
|
||
| The Redux store ([src/store.ts](src/store.ts)) has these slices: | ||
|
|
||
| | Key | Purpose | | ||
| |-----|---------| | ||
| | `models` | Normalized model store (courses, sequences, units by ID) | | ||
| | `courseware` | Current courseId, sequenceId, unit IDs and loading state | | ||
| | `courseHome` | Course home tab data | | ||
| | `specialExams` | Special exam state (external lib) | | ||
| | `learningAssistant` | AI chat assistant state (external lib) | | ||
| | `recommendations` | Course exit recommendations | | ||
| | `tours` | Product tour state | | ||
| | `plugins` | Plugin framework overrides | | ||
|
|
||
| **Model Store pattern**: API data is normalized and stored flat in `state.models.<type>[id]`. Slices store IDs, not full objects. Access via `state.models.courses[state.courseware.courseId]`. See [docs/decisions/0004-model-store.md](docs/decisions/0004-model-store.md). | ||
|
|
||
| ### Key Source Directories | ||
|
|
||
| - [src/courseware/](src/courseware/) — Unit content delivery: sequences, units, iframes, sidebar | ||
| - [src/courseware/data/](src/courseware/data/) — Redux slice, thunks, API, selectors for courseware | ||
| - [src/courseware/course/sequence/](src/courseware/course/sequence/) — Sequence navigation & unit rendering | ||
| - [src/courseware/course/new-sidebar/](src/courseware/course/new-sidebar/) — Sidebar (discussions, notifications) | ||
| - [src/course-home/](src/course-home/) — Outline, dates, progress, discussion tabs | ||
| - Each tab has its own `data/` subdirectory with slice, thunks, and API | ||
| - [src/generic/](src/generic/) — Domain-agnostic reusable code (model-store, hooks, notices, user-messages). Do not add app-specific logic here. | ||
| - [src/shared/](src/shared/) — App-specific shared code used across multiple top-level components | ||
| - [src/plugin-slots/](src/plugin-slots/) — `@openedx/frontend-plugin-framework` plugin slots for extensibility | ||
| - [src/tab-page/](src/tab-page/) — `TabContainer` wrapper that handles tab loading state | ||
| - [src/product-tours/](src/product-tours/) — Onboarding product tours | ||
|
|
||
| ### Naming Conventions | ||
|
|
||
| From [docs/decisions/0006-thunk-and-api-naming.md](docs/decisions/0006-thunk-and-api-naming.md): | ||
|
|
||
| - **API functions** use HTTP verb prefixes: `getCourseBlocks`, `postSequencePosition` | ||
| - **Redux thunks** use semantic prefixes: `fetchCourse`, `fetchSequence`, `saveSequencePosition`, `checkBlockCompletion` | ||
|
|
||
| ### Data Flow Pattern | ||
|
|
||
| Each major feature follows this pattern: | ||
| ``` | ||
| data/api.js — Raw API calls (HTTP verb naming) | ||
| data/thunks.js — Redux thunks that call APIs and dispatch to model-store (fetch/save naming) | ||
| data/slice.js — Redux slice (state shape + reducers) | ||
| data/selectors.js — Reselect selectors | ||
| data/__factories__/ — Rosie factories for test data | ||
| ``` | ||
|
|
||
| ### Loading State | ||
|
|
||
| Components own their own loading state (LOADING/LOADED/FAILED/DENIED constants from [src/constants.ts](src/constants.ts)). Components render spinners/skeletons themselves rather than relying on parents to gate rendering. See [docs/decisions/0005-components-own-their-loading-state.md](docs/decisions/0005-components-own-their-loading-state.md). | ||
|
|
||
| ### Plugin Slots | ||
|
|
||
| The app exposes many plugin slots via `@openedx/frontend-plugin-framework` in [src/plugin-slots/](src/plugin-slots/). Each slot has a README. Slots allow operators to inject/replace UI components without forking. | ||
|
|
||
| ### Testing Approach | ||
|
|
||
| From [docs/decisions/0007-testing.md](docs/decisions/0007-testing.md): | ||
|
|
||
| - Use **React Testing Library** — query by labels, text, roles; use `data-testid` as last resort | ||
| - Mock HTTP with **axios-mock-adapter**; build test data with **Rosie factories** in `data/__factories__/` | ||
| - Test non-obvious behavior (error states, interactions, corner cases) — not happy-path rendering | ||
| - **Avoid snapshots** for complex components; they're too brittle. Snapshots are acceptable for data/redux tests and tiny isolated components. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| const path = require('path'); | ||
| const { merge } = require('webpack-merge'); | ||
| const prodConfig = require('./webpack.prod.config'); | ||
|
|
||
|
nsprenkle marked this conversation as resolved.
|
||
| /** | ||
| * Webpack config used by `npm run build:validate`. | ||
| * | ||
| * Identical to the prod build except env.config is replaced with a stub so | ||
| * that the build succeeds without the private edX plugin packages that are | ||
| * only available in the local development monorepo. | ||
| */ | ||
| module.exports = merge(prodConfig, { | ||
| resolve: { | ||
| alias: { | ||
| 'env.config': path.resolve(__dirname, './env.config.validate.jsx'), | ||
| // TsconfigPathsPlugin doesn't hook correctly on the merged config, so | ||
| // replicate the tsconfig "@src/*" path mapping explicitly. | ||
| '@src': path.resolve(__dirname, 'src'), | ||
| }, | ||
| }, | ||
| }); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.