diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json
index 752ae8d..5926b79 100644
--- a/.claude-plugin/marketplace.json
+++ b/.claude-plugin/marketplace.json
@@ -8,8 +8,8 @@
{
"name": "bcquality",
"source": "./",
- "description": "Business Central AL quality knowledge base and review skills, packaged as an installable plugin. Exposes an AL review adapter while preserving BCQuality's internal Entry and action-skill protocols.",
- "version": "0.2.0",
+ "description": "Business Central AL quality knowledge base and skills, packaged as an installable plugin. Exposes development and review adapters while preserving BCQuality's internal Entry and action-skill protocols.",
+ "version": "0.3.0",
"skills": [
"./skills/"
]
diff --git a/.github/scripts/validate_frontmatter.py b/.github/scripts/validate_frontmatter.py
index b0076cc..ada7505 100644
--- a/.github/scripts/validate_frontmatter.py
+++ b/.github/scripts/validate_frontmatter.py
@@ -39,6 +39,7 @@ ACTION_SKILL_REQUIRED_KEYS = {
}
ACTION_SKILL_OPTIONAL_KEYS = {
"bc-version", "technologies", "countries", "application-area", "sub-skills",
+ "quality-skill", "guidance-skill",
}
META_SKILL_REQUIRED_KEYS = {"kind", "id", "version", "title"}
ENTRY_SKILL_REQUIRED_KEYS = {"kind", "id", "version", "title"}
@@ -46,8 +47,11 @@ HOST_SKILL_REQUIRED_KEYS = {"name", "description"}
STANDARD_INPUTS = {
"pr-diff", "object-list", "file-path", "repository", "telemetry-query",
+ "development-request", "development-plan",
+}
+ALLOWED_OUTPUTS = {
+ "findings-report", "implementation-report", "development-guidance-report",
}
-ALLOWED_OUTPUTS = {"findings-report"}
VALID_SAMPLE_KINDS = {"good", "bad"}
ACTION_SKILL_SECTIONS = ["Source", "Relevance", "Worklist", "Action", "Output"]
@@ -340,9 +344,11 @@ def validate_action_skill(path: Path, parsed: Parsed, report: Report) -> None:
if not is_non_empty_list_of_str(out):
report.error(path, "R18", "outputs must be a non-empty list of strings", 1)
else:
+ if len(out) != 1:
+ report.error(path, "R18", "outputs must contain exactly one output kind", 1)
bad = [x for x in out if x not in ALLOWED_OUTPUTS]
if bad:
- report.error(path, "R18", f"outputs contains non-allowed values {bad}; currently only {sorted(ALLOWED_OUTPUTS)} is defined", 1)
+ report.error(path, "R18", f"outputs contains non-allowed values {bad}; allowed values are {sorted(ALLOWED_OUTPUTS)}", 1)
# R19 optional filter dimensions, if present
if "bc-version" in fm:
@@ -382,6 +388,20 @@ def validate_action_skill(path: Path, parsed: Parsed, report: Report) -> None:
if bad:
report.error(path, "R20", f"sub-skills entries must end in '.md': {bad}", 1)
+ if "quality-skill" in fm:
+ quality_skill = fm["quality-skill"]
+ if not isinstance(quality_skill, str) or not quality_skill.endswith(".md"):
+ report.error(path, "R31", "quality-skill must be one repo-relative .md path", 1)
+ if fm.get("outputs") != ["implementation-report"]:
+ report.error(path, "R31", "quality-skill is valid only with outputs: [implementation-report]", 1)
+
+ if "guidance-skill" in fm:
+ guidance_skill = fm["guidance-skill"]
+ if not isinstance(guidance_skill, str) or not guidance_skill.endswith(".md"):
+ report.error(path, "R32", "guidance-skill must be one repo-relative .md path", 1)
+ if fm.get("outputs") != ["implementation-report"]:
+ report.error(path, "R32", "guidance-skill is valid only with outputs: [implementation-report]", 1)
+
# R21 five required sections, in order, each exactly once
heads = [h for h, _ in headings_in_order(parsed.body)]
indices: list[int] = []
@@ -603,6 +623,58 @@ def validate_sub_skills_registry(path: Path, fm: dict[str, Any], root: Path, rep
report.error(path, "R26", f"leaf not registered in sub-skills: {leaf}", 1)
+def validate_quality_skill(path: Path, fm: dict[str, Any], root: Path, report: Report) -> None:
+ """R30: implementation quality-skill paths resolve to a findings producer."""
+ quality_skill = fm.get("quality-skill")
+ if not isinstance(quality_skill, str) or not quality_skill.endswith(".md"):
+ return
+
+ normalized = quality_skill.lstrip("./")
+ target = root / normalized
+ if not target.is_file():
+ report.error(path, "R30", f"quality-skill does not exist on disk: {normalized}", 1)
+ return
+ if target.resolve() == path.resolve():
+ report.error(path, "R30", "quality-skill must not reference the implementation skill itself", 1)
+ return
+
+ try:
+ target_parsed = parse_markdown(target.read_text(encoding="utf-8"))
+ except UnicodeDecodeError as e:
+ report.error(path, "R30", f"quality-skill is not valid UTF-8: {e}", 1)
+ return
+ target_outputs = (target_parsed.frontmatter or {}).get("outputs")
+ if target_outputs != ["findings-report"]:
+ report.error(path, "R30", f"quality-skill must emit findings-report: {normalized}", 1)
+
+
+def validate_guidance_skill(path: Path, fm: dict[str, Any], root: Path, report: Report) -> None:
+ """R33: implementation guidance-skill paths resolve to a read-only planner."""
+ guidance_skill = fm.get("guidance-skill")
+ if not isinstance(guidance_skill, str) or not guidance_skill.endswith(".md"):
+ return
+
+ normalized = guidance_skill.lstrip("./")
+ target = root / normalized
+ if not target.is_file():
+ report.error(path, "R33", f"guidance-skill does not exist on disk: {normalized}", 1)
+ return
+ if target.resolve() == path.resolve():
+ report.error(path, "R33", "guidance-skill must not reference the implementation skill itself", 1)
+ return
+
+ try:
+ target_parsed = parse_markdown(target.read_text(encoding="utf-8"))
+ except UnicodeDecodeError as e:
+ report.error(path, "R33", f"guidance-skill is not valid UTF-8: {e}", 1)
+ return
+ target_fm = target_parsed.frontmatter or {}
+ if target_fm.get("outputs") != ["development-guidance-report"]:
+ report.error(path, "R33", f"guidance-skill must emit development-guidance-report: {normalized}", 1)
+ if "development-plan" not in (target_fm.get("inputs") or []):
+ report.error(path, "R33", f"guidance-skill must accept development-plan: {normalized}", 1)
+
+
def run(root: Path) -> Report:
report = Report()
skill_records: list[SkillRecord] = []
@@ -670,9 +742,11 @@ def run(root: Path) -> Report:
others = [q.relative_to(root).as_posix() for q in paths if q != p]
report.error(p, "R24", f"skill id '{sid}' ({kind}) is not unique; also defined in: {others}")
- # Fourth pass: R26 sub-skills registry matches leaf files on disk
+ # Fourth pass: cross-skill references
for path, fm in action_skill_fms:
validate_sub_skills_registry(path, fm, root, report)
+ validate_quality_skill(path, fm, root, report)
+ validate_guidance_skill(path, fm, root, report)
return report
diff --git a/.github/workflows/development-coverage.yml b/.github/workflows/development-coverage.yml
new file mode 100644
index 0000000..73383a1
--- /dev/null
+++ b/.github/workflows/development-coverage.yml
@@ -0,0 +1,26 @@
+name: Validate development coverage
+
+on:
+ pull_request:
+ branches: [main]
+ push:
+ branches: [main]
+
+jobs:
+ validate-development-coverage:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Validate Microsoft Learn coverage ledger
+ shell: pwsh
+ run: ./tools/Test-LearnCoverage.ps1 -Root .
+
+ - name: Validate and prepare development fixtures
+ shell: pwsh
+ run: ./tools/Test-DevelopmentFixtures.ps1 -Root . -PrepareDirectory "$env:RUNNER_TEMP/bcquality-development-fixtures"
+
+ - name: Validate and prepare development-guidance fixtures
+ shell: pwsh
+ run: ./tools/Test-DevelopmentGuidanceFixtures.ps1 -Root . -PrepareDirectory "$env:RUNNER_TEMP/bcquality-development-guidance-fixtures"
diff --git a/README.md b/README.md
index 43032d4..8a97d21 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ Skills define how agents consume knowledge. They come in three flavors:
READ and DO are read on demand — typically when the first dispatched action skill runs. They are not prerequisites for invoking Entry. WRITE is only used when scaffolding new content.
-- **Action skills** — concrete skills that follow the Action Skill template to do real work (review code, audit telemetry, etc.). Action skills live inside the layers that own them (`/microsoft/skills/`, `/community/skills/`, `/custom/skills/`). An action skill is either a **leaf** that evaluates knowledge files directly, or a **super-skill** that composes other action skills (declared via `sub-skills` in frontmatter). The canonical reference is [`microsoft/skills/review/al-code-review.md`](microsoft/skills/review/al-code-review.md) (super-skill), which composes the AL review leaf skills under [`microsoft/skills/review/`](microsoft/skills/review/) — one per knowledge domain.
+- **Action skills** — concrete skills that follow the Action Skill template to do real work. Review skills emit findings reports; read-only planning skills emit development-guidance reports; implementation skills emit implementation reports. Action skills live inside the layers that own them (`/microsoft/skills/`, `/community/skills/`, `/custom/skills/`). [`microsoft/skills/development/al-development-plan.md`](microsoft/skills/development/al-development-plan.md) turns an existing plan into knowledge constraints, [`microsoft/skills/development/al-development.md`](microsoft/skills/development/al-development.md) consumes those constraints while implementing features, bugs, refactors, upgrades, and maintenance, and [`microsoft/skills/review/al-code-review.md`](microsoft/skills/review/al-code-review.md) provides the final quality gate.
### Agent bootstrapping
@@ -64,10 +64,10 @@ An orchestrator (such as AL-Go) points the agent at BCQuality's URL and provides
### Standalone plugin installation
-BCQuality can also be installed directly as a plugin. The plugin registers one
-host-native skill,
-[`al-code-review`](skills/al-code-review/SKILL.md), which adapts the caller's
-request to the same Entry protocol used by orchestrators.
+BCQuality can also be installed directly as a plugin. The plugin registers
+host-native adapters for [`al-code-review`](skills/al-code-review/SKILL.md) and
+[`al-development`](skills/al-development/SKILL.md). Both adapt
+the caller's request to the same Entry protocol used by orchestrators.
For GitHub Copilot CLI:
@@ -81,32 +81,37 @@ must be updated. The name remains distinct from BC-ALAgents' public
`al-review` skill because current hosts may load plugin skill names into one
shared inventory.
-The adapter is intentionally not a second review implementation:
+Plugin version `0.3.0` adds `al-development`, the knowledge-backed
+implementation adapter for features, bugs, refactors, upgrades, and maintenance.
+
+The adapters are intentionally not second implementations:
```text
standalone host skill: skills/al-code-review/SKILL.md
-> routing contract: skills/entry.md
-> review coordinator: microsoft/skills/review/al-code-review.md
-> domain review leaves
+
+standalone host skill: skills/al-development/SKILL.md
+ -> routing contract: skills/entry.md
+ -> implementation skill: microsoft/skills/development/al-development.md
+ -> knowledge-guided implementation + AL review quality gate
```
-Only the first file follows the host's `SKILL.md` packaging format. The
-remaining files are BCQuality's internal protocol and layered action skills.
-Entry remains the single owner of routing and index preparation;
-`al-code-review.md` remains the single owner of broad-review composition. This
-separation keeps standalone installation available without duplicating those
-policies in the plugin adapter.
+Only the files under `skills/*/SKILL.md` follow the host's packaging format.
+The remaining files are BCQuality's internal protocol and layered action
+skills. Entry remains the single owner of routing and index preparation. This
+separation keeps standalone installation available without duplicating policy
+in either adapter.
Note that a plugin install ships the entire tree, so `BCQUALITY_ENABLED_LAYERS`
narrows discovery without removing any files. Layer selection is a filter here,
not a deny mechanism — see [the adapter](skills/al-code-review/SKILL.md) for the
difference from the pruned-clone model.
-The host adapter and internal action skill intentionally share the
-`al-code-review` name: they expose the same operation in two different skill
-formats. Their paths make the boundary explicit. The adapter lives under
-`skills/al-code-review/SKILL.md`; the internal Microsoft-layer coordinator
-lives at `microsoft/skills/review/al-code-review.md`.
+Each host adapter and internal action skill intentionally share a name: they
+expose the same operation in two different skill formats. Their paths make the
+boundary explicit.
## Knowledge file format
@@ -138,10 +143,29 @@ Code examples belong in separate files, not in the knowledge file itself. Knowle
## Scope
-The current curated corpus is focused on **technical AL code review**: Agents, AppSource and compatibility, data modeling, error handling, events, interfaces, performance, privacy, Query objects, security, style, telemetry, testing, UI, upgrade, and web services. These are the domains backed by knowledge files and registered review leaves today.
+The current curated corpus covers technical AL concerns across Agents, AppSource and compatibility, data modeling, error handling, events, interfaces, performance, privacy, Query objects, security, style, telemetry, testing, UI, upgrade, and web services. Review skills evaluate existing changes against those domains. The `al-development` skill applies them before and during implementation, then runs the review coordinator as a final gate.
+
+Repository-specific orchestrators do not need to delegate implementation to
+`al-development`. They can invoke `al-development-plan` with their existing
+plan, feed its read-only guidance report into their own phases, and retain their
+specialized environment, test, propagation, and delivery gates.
Business Central functional domains (Finance, Supply Chain Management, Manufacturing, Jobs, Warehousing, Service), PowerShell, pipelines, and Power Platform remain valid future repository scope, but they are **not current coverage claims** until corresponding knowledge and action skills exist. Consumers should derive supported review scope from the live knowledge index and dispatched skills, not from roadmap breadth.
+## Tracking developer coverage
+
+BCQuality tracks source ingestion and implementation capability separately:
+
+- [`coverage/microsoft-learn-developer-catalog.json`](coverage/microsoft-learn-developer-catalog.json) is the generated inventory of Business Central developer training.
+- [`coverage/learn-coverage.json`](coverage/learn-coverage.json) records editorial progress and the disposition of each extracted concern.
+- [`coverage/development-capabilities.json`](coverage/development-capabilities.json) tracks representative development capabilities and their evaluation fixtures.
+
+Run `pwsh ./tools/Test-LearnCoverage.ps1` for current source progress and
+`pwsh ./tools/Test-DevelopmentFixtures.ps1` for capability coverage. Article
+count alone is not a completion metric: a capability becomes `validated` only
+after its generated implementation passes compilation, tests, and the review
+quality gate.
+
## How agents consume BCQuality
Action skills follow a four-step pattern:
@@ -151,7 +175,7 @@ Action skills follow a four-step pattern:
3. **Worklist** — narrow from N candidates to the M that apply to the current task
4. **Action** — apply the relevant knowledge and produce structured output
-Every action skill produces output in a common format that orchestrators can consume without skill-specific parsing. The format is JSON and includes an `outcome` (so a clean run, a not-applicable skill, and a partial failure are all distinguishable), `findings` (what the skill observed), structured `references` back to the knowledge files that informed each finding, per-finding `confidence`, and a `suppressed` list recording any knowledge files overridden by layer precedence. This contract is defined in the Action Skill meta-skill so that orchestrators and action skills remain independently evolvable.
+Every action skill declares one structured JSON output. Review skills emit a `findings-report`; planning skills emit a read-only `development-guidance-report`; implementation skills emit an `implementation-report` containing the plan, knowledge used, changed files, real validation results, and post-implementation review. All contracts are defined in the Action Skill meta-skill so orchestrators and action skills remain independently evolvable.
BCQuality is an **additive** knowledge layer: it augments the agent's review judgement, it does not replace it. Super-skills (such as `al-code-review`) run a self-review pass alongside their sub-skills and surface concerns the agent identified on its own, marked with `from-sub-skill: "agent"` and an empty `references: []` so consumers can render them distinctly from knowledge-backed findings. See [agent-consumption.md](agent-consumption.md) and [`skills/do.md`](skills/do.md) for the full contract.
@@ -163,7 +187,8 @@ For the end-to-end flow — from orchestrator trigger through to how output reac
```
├── /skills/ # Global: entry-point skill + meta-skill contracts (READ, DO, WRITE)
-├── /evaluation/ # Neutral good/bad review fixtures and scoring contract
+├── /coverage/ # Source-ingestion ledger and development capability matrix
+├── /evaluation/ # Review and development evaluation fixtures
├── /.github/ # Actions and workflows
├── /microsoft/ # Microsoft-endorsed layer
│ ├── /knowledge/ # Knowledge files by domain
diff --git a/agent-consumption.md b/agent-consumption.md
index 37a7a10..d703aa2 100644
--- a/agent-consumption.md
+++ b/agent-consumption.md
@@ -13,8 +13,10 @@ For the high-level framing and repo structure, start with the [README](README.md
- **Layer content** in `/microsoft/`, `/community/`, and `/custom/` — knowledge files and action skills grouped by authority.
When BCQuality is installed as a standalone plugin, it additionally exposes
-`skills/al-code-review/SKILL.md`. This is a host-format adapter, not another
-action skill: it creates the task context and enters the same flow at Entry.
+`skills/al-code-review/SKILL.md` and
+`skills/al-development/SKILL.md`. These are host-format adapters, not
+additional action skills: each creates the task context and enters the same
+flow at Entry.
## The flow
@@ -25,7 +27,7 @@ flowchart LR
E -->|3 dispatch record| A
A -->|4 invoke dispatched skill| S[Action skill
e.g. al-code-review]
S -->|5 execute| P[Source → Relevance
→ Worklist → Action
reading READ · DO on demand]
- P -->|6 emit| R[Findings · Domain labels
· References · Confidence]
+ P -->|6 emit| R[Findings report
or implementation report]
R -->|7 integrate| O
```
@@ -35,11 +37,11 @@ The orchestrator has a URL setting that points at BCQuality (default: `github.co
### 2. Agent invokes Entry
The agent reads `/skills/entry.md` and runs it against the task context. Entry applies its Source → Relevance → Worklist → Action steps over the action skills under `*/skills/**/*.md` and returns a **dispatch record**: the set of action skills to invoke, plus a list of candidates it skipped (with reasons). Routing is a skill, not orchestrator logic.
-For a standalone plugin installation, the host activates the
-`skills/al-code-review/SKILL.md` adapter first. That adapter preserves the
-caller's actual goal, constructs the task context, and invokes Entry. It does
-not select the internal `microsoft/skills/review/al-code-review.md` action skill
-itself or duplicate Entry's preparation, routing, and failure semantics.
+For a standalone plugin installation, the host activates the matching adapter
+first. The adapter preserves the caller's actual goal, constructs the task
+context, and invokes Entry. It does not select the internal review or
+development action skill itself or duplicate Entry's preparation, routing, and
+failure semantics.
### 3. Agent consumes the dispatch record
The dispatch record names one or more action skills and the subset of inputs each should receive. If the outcome is `no-match` or `failed`, the agent returns the record to the orchestrator unchanged.
@@ -71,19 +73,44 @@ The index is **owned and produced by BCQuality**, not by each consumer: its gene
The index changes only *how candidates are discovered*, never *which are selected*. The Worklist predicate is unchanged — `keywords` still drive selection — and the agent still opens each worklisted article **in full** to read its `## Best Practice` / `## Anti Pattern` rule bodies; the index is discovery metadata only and never substitutes for the article body. When no index is present, skills fall back to path-based discovery (collect by domain folder), so review still works.
### 6. Agent emits structured output
-The output contract is defined in the DO meta-skill so that every action skill — today's and next year's — produces the same shape:
+The output contracts are defined in the DO meta-skill:
-- **Outcome** — `completed`, `not-applicable`, `no-knowledge`, `partial`, or `failed`. An orchestrator can distinguish a clean run from a no-op from a failure without guessing.
-- **Findings** — what the skill observed (severity, message, optional location).
-- **Domain** — the producer-owned, human-readable display label on each review finding.
-- **References** — structured objects (`path` plus optional commit `sha`) pointing to the knowledge files that informed each finding.
-- **Confidence** — per-finding evidence strength.
-- **Suppressed** — knowledge files that were discarded by layer precedence or configuration, so reviewers can see what was overridden.
+- A **findings report** carries review findings, domain labels, references, confidence, and suppressions.
+- A **development guidance report** carries read-only knowledge constraints and validation considerations for an existing plan.
+- An **implementation report** carries the development plan, classified mode, knowledge applied, changed files, validation results, final review, and remaining work.
The orchestrator parses this **without skill-specific logic**. This is the point of the contract: orchestrators and action skills evolve independently.
+For development, the action happens before the report: the skill
+first invokes the read-only planning skill to select applicable knowledge, then
+changes the target repository, runs its native validation, and invokes the
+configured review quality-skill over the resulting diff. A specialized
+repository orchestrator may invoke only the planning skill and feed its
+guidance report into its own implementation phases. The implementation report
+is a machine-readable record of persisted work, not a code proposal for the
+orchestrator to apply later.
+
### 7. Orchestrator integrates
-The orchestrator turns findings into PR comments, build gates, or IDE diagnostics, and links the references back to the knowledge files so the PR author — human or agent — can read the guidance.
+The orchestrator turns findings into PR comments, build gates, or IDE diagnostics. For implementation it presents the changed files and validation state, while the agent has already persisted the requested change in the target repository.
+
+## Repository-specific development orchestrators
+
+A repository-specific workflow can keep ownership of implementation and consume
+BCQuality only for planning and review:
+
+1. Produce its normal development plan after repository investigation.
+2. Invoke Entry with `inputs-available: [development-plan, repository]` plus
+ the resolved applicability dimensions.
+3. Execute the dispatched `al-development-plan` skill and preserve its
+ `development-guidance-report`.
+4. Pass the selected article references, constraints, samples, and validation
+ considerations into its own test, implementation, and critique phases.
+5. Run its existing BCQuality-backed review gate over the completed diff.
+
+This is the integration model for specialized bug-fix or release workflows.
+They keep environment provisioning, retries, state, commits, propagation, and
+pull-request delivery; BCQuality supplies shared product knowledge before and
+after the code change.
## Knowledge-backed and agent findings
diff --git a/coverage/README.md b/coverage/README.md
new file mode 100644
index 0000000..3b2bb18
--- /dev/null
+++ b/coverage/README.md
@@ -0,0 +1,44 @@
+# Developer knowledge coverage
+
+This directory separates **source coverage** from the knowledge corpus itself.
+Microsoft Learn units are inputs to editorial work, not articles to import
+one-for-one.
+
+## Files
+
+- `microsoft-learn-developer-catalog.json` is generated source metadata for all
+ Microsoft Learn modules tagged with both `dynamics-business-central` and
+ `developer`.
+- `learn-coverage.json` is the maintained editorial ledger. Units absent from
+ this file are unreviewed.
+- `development-capabilities.json` tracks whether representative Business
+ Central development capabilities have implementation fixtures.
+
+Each tracked unit has a `reviewStatus`:
+
+- `in-progress` — at least one concern has been identified, but editorial
+ triage of the unit is not complete.
+- `complete` — every relevant concern in the unit has a recorded outcome. A
+ complete unit may have no outcomes when it contains no remedial knowledge.
+
+Each concern has one disposition:
+
+- `candidate` — worth authoring or reconciling with existing knowledge.
+- `authored` — produced one or more new knowledge articles.
+- `covered-existing` — already represented by the linked article.
+- `rejected` — fails BCQuality's remedial admission test.
+- `deferred` — valid but intentionally postponed, with a rationale.
+
+An authored article does not make its source unit complete automatically. One
+unit can contain several independent concerns.
+
+## Update and report
+
+```powershell
+pwsh ./tools/Update-LearnCatalog.ps1
+pwsh ./tools/Test-LearnCoverage.ps1
+```
+
+The catalog updater also accepts `-CatalogPath` for an exported Microsoft Learn
+Platform API response. CI validates the committed snapshot and editorial ledger
+without network access.
diff --git a/coverage/development-capabilities.json b/coverage/development-capabilities.json
new file mode 100644
index 0000000..493316a
--- /dev/null
+++ b/coverage/development-capabilities.json
@@ -0,0 +1,129 @@
+{
+ "version": 1,
+ "capabilities": [
+ {
+ "id": "setup-and-master-data",
+ "title": "Setup and master data",
+ "status": "fixture",
+ "domains": [
+ "data-modeling",
+ "security",
+ "testing",
+ "ui"
+ ],
+ "fixtureIds": [
+ "setup-backed-master-data"
+ ]
+ },
+ {
+ "id": "document-workflows",
+ "title": "Document header and lines workflows",
+ "status": "fixture",
+ "domains": [
+ "data-modeling",
+ "events",
+ "performance",
+ "testing",
+ "ui"
+ ],
+ "fixtureIds": [
+ "document-header-and-lines"
+ ]
+ },
+ {
+ "id": "api-integrations",
+ "title": "Versioned API integrations",
+ "status": "fixture",
+ "domains": [
+ "security",
+ "testing",
+ "web-services"
+ ],
+ "fixtureIds": [
+ "versioned-master-data-api"
+ ]
+ },
+ {
+ "id": "bug-diagnosis-and-fix",
+ "title": "Bug diagnosis and surgical repair",
+ "status": "fixture",
+ "domains": [
+ "performance",
+ "testing"
+ ],
+ "fixtureIds": [
+ "fix-filtered-batch-processing"
+ ]
+ },
+ {
+ "id": "journals-and-posting",
+ "title": "Journals and posting routines",
+ "status": "planned",
+ "domains": [
+ "data-modeling",
+ "error-handling",
+ "events",
+ "performance",
+ "testing"
+ ],
+ "fixtureIds": []
+ },
+ {
+ "id": "reports-and-documents",
+ "title": "Reports and document layouts",
+ "status": "planned",
+ "domains": [
+ "performance",
+ "testing",
+ "ui"
+ ],
+ "fixtureIds": []
+ },
+ {
+ "id": "install-and-upgrade",
+ "title": "Installation and data upgrade",
+ "status": "planned",
+ "domains": [
+ "breaking-changes",
+ "testing",
+ "upgrade"
+ ],
+ "fixtureIds": []
+ },
+ {
+ "id": "external-services",
+ "title": "Outbound services and authentication",
+ "status": "planned",
+ "domains": [
+ "error-handling",
+ "privacy",
+ "security",
+ "telemetry"
+ ],
+ "fixtureIds": []
+ },
+ {
+ "id": "role-centers-and-onboarding",
+ "title": "Role Centers, setup, and onboarding",
+ "status": "planned",
+ "domains": [
+ "security",
+ "testing",
+ "ui"
+ ],
+ "fixtureIds": []
+ },
+ {
+ "id": "appsource-lifecycle",
+ "title": "AppSource packaging and lifecycle",
+ "status": "planned",
+ "domains": [
+ "appsource",
+ "breaking-changes",
+ "testing",
+ "upgrade"
+ ],
+ "fixtureIds": []
+ }
+ ]
+}
diff --git a/coverage/learn-coverage.json b/coverage/learn-coverage.json
new file mode 100644
index 0000000..53934d6
--- /dev/null
+++ b/coverage/learn-coverage.json
@@ -0,0 +1,456 @@
+{
+ "version": 1,
+ "catalog": "coverage/microsoft-learn-developer-catalog.json",
+ "units": [
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.4a-use-round-function",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "round-direction-symbols-use-magnitude",
+ "title": "Round direction symbols use magnitude rather than mathematical ordering",
+ "disposition": "authored",
+ "domain": "data-modeling",
+ "articlePaths": [
+ "microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.md"
+ ]
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.3-use-initrecord-function",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "initialize-document-defaults-in-initrecord",
+ "title": "Initialize document defaults in InitRecord after assigning the number",
+ "disposition": "authored",
+ "domain": "data-modeling",
+ "articlePaths": [
+ "microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.md"
+ ]
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.type-testing",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "guard-interface-casts-with-is",
+ "title": "Guard optional interface casts with is",
+ "disposition": "authored",
+ "domain": "interfaces",
+ "articlePaths": [
+ "microsoft/knowledge/interfaces/guard-interface-casts-with-is.md"
+ ]
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.add-field-group",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "dropdown-fieldgroup-respects-lookup-page-visibility",
+ "title": "DropDown fields remain hidden when their lookup-page controls are hidden",
+ "disposition": "authored",
+ "domain": "ui",
+ "articlePaths": [
+ "microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.md"
+ ]
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.8-controls",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "updatepropagation-both-refreshes-main-page",
+ "title": "UpdatePropagation Both refreshes the main page after line edits",
+ "disposition": "authored",
+ "domain": "ui",
+ "articlePaths": [
+ "microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.md"
+ ]
+ },
+ {
+ "id": "applicationarea-parent-inheritance",
+ "title": "Page-level ApplicationArea inheritance excludes extension controls",
+ "disposition": "covered-existing",
+ "domain": "style",
+ "articlePaths": [
+ "microsoft/knowledge/style/applicationarea-required-on-page-controls.md"
+ ]
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.3-installation-upgrade-codeunits",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "install-and-upgrade-codeunits-have-no-order",
+ "title": "Separate install or upgrade codeunits have no execution order",
+ "disposition": "authored",
+ "domain": "upgrade",
+ "articlePaths": [
+ "microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.md"
+ ]
+ },
+ {
+ "id": "appversion-meaning-depends-on-execution-context",
+ "title": "ModuleInfo AppVersion changes meaning with execution context",
+ "disposition": "authored",
+ "domain": "upgrade",
+ "articlePaths": [
+ "microsoft/knowledge/upgrade/appversion-meaning-depends-on-execution-context.md"
+ ]
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.text-search",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "optimize-for-text-search-requires-double-ampersand-filter",
+ "title": "Optimized full-text search requires the double-ampersand filter operator",
+ "disposition": "candidate",
+ "domain": "query"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.define-extension-objects",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "same-app-extension-references-follow-object-id-order",
+ "title": "Same-app extension objects can only reference lower-ID extension objects",
+ "disposition": "candidate",
+ "domain": "data-modeling"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.resource-policy-settings",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "resource-exposure-policy-is-not-nondebuggable",
+ "title": "Resource exposure policy and NonDebuggable protect different surfaces",
+ "disposition": "candidate",
+ "domain": "security"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.3-create-entitlements-permission-sets",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "entitlement-objects-reference-same-app-permission-sets",
+ "title": "Entitlement objects are online-only and reference same-app permission sets",
+ "disposition": "candidate",
+ "domain": "security"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.override-entitlements",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "inherent-permissions-cannot-elevate-other-extensions",
+ "title": "Inherent permissions cannot elevate access to another extension",
+ "disposition": "candidate",
+ "domain": "security"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.3a-snapshot",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "snapshot-debugging-captures-only-snappoints-and-exceptions",
+ "title": "Snapshot debugging captures state only at snappoints and exceptions",
+ "disposition": "candidate",
+ "domain": "testing"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.recovery-failures",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "publish-recovery-cannot-restore-every-extension-state",
+ "title": "Publish recovery cannot restore every upgrade or app-move failure",
+ "disposition": "candidate",
+ "domain": "upgrade"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.database-wait-statistics",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "database-wait-statistics-are-exposed-as-a-virtual-table",
+ "title": "Database wait statistics are exposed as a Business Central virtual table",
+ "disposition": "candidate",
+ "domain": "performance"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.use-rich-text-editor",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "rich-text-controls-use-html-backed-blob-fields",
+ "title": "Rich text controls use HTML-backed Blob fields and isolated layout groups",
+ "disposition": "candidate",
+ "domain": "ui"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.scan-barcodes",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "barcode-integration-scenarios-have-different-platform-support",
+ "title": "Barcode field, camera action, and hardware-scanner scenarios have different platform support",
+ "disposition": "candidate",
+ "domain": "ui"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.9-search",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "card-pages-should-not-be-directly-searchable",
+ "title": "Card pages should be opened through their list rather than Tell Me",
+ "disposition": "candidate",
+ "domain": "ui"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.hidden-fields",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "allowincustomizations-controls-the-add-field-pane",
+ "title": "AllowInCustomizations controls exposure through the Add field pane",
+ "disposition": "candidate",
+ "domain": "privacy"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.differentiate-apps",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "application-modules-depend-only-on-same-or-lower-layers",
+ "title": "Application modules depend only on the same or lower architectural layers",
+ "disposition": "candidate",
+ "domain": "data-modeling"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.2-retrieve-data",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "legacy-find-directions-do-not-use-top-one",
+ "title": "Legacy Find direction calls do not have FindFirst or FindLast query behavior",
+ "disposition": "candidate",
+ "domain": "performance"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.2-upgrade-responsibilities",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "uninstall-preserves-extension-data",
+ "title": "Uninstall preserves extension data for reinstall or upgrade",
+ "disposition": "candidate",
+ "domain": "upgrade"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.consider-update-lifecycle",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "incompatible-cloud-extensions-have-a-remediation-window",
+ "title": "Incompatible cloud extensions have a fixed remediation window",
+ "disposition": "candidate",
+ "domain": "upgrade"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.6-answers-about-updates",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "minor-and-major-releases-update-apps-differently",
+ "title": "Minor and major Business Central releases update AppSource apps differently",
+ "disposition": "candidate",
+ "domain": "upgrade"
+ },
+ {
+ "id": "dependency-version-is-a-minimum",
+ "title": "An app.json dependency version is a minimum rather than an exact pin",
+ "disposition": "candidate",
+ "domain": "upgrade"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.3-library-dependency-applications",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "library-apps-install-through-the-dependency-chain",
+ "title": "Library apps install and update through the dependency chain",
+ "disposition": "candidate",
+ "domain": "appsource"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.extending-interfaces",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "interfaces-can-compose-multiple-base-interfaces",
+ "title": "Interfaces can compose multiple base interfaces",
+ "disposition": "candidate",
+ "domain": "interfaces"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.page-scripting-tool",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "page-scripting-cannot-drive-non-al-ui",
+ "title": "Page scripting cannot drive control add-ins or other non-AL UI",
+ "disposition": "candidate",
+ "domain": "testing"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.2-test-automation-responsibilities",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "appsource-validation-must-use-the-current-build",
+ "title": "AppSource validation must use the current validation build",
+ "disposition": "candidate",
+ "domain": "appsource"
+ },
+ {
+ "id": "permission-testing-also-protects-the-essential-experience",
+ "title": "Permission testing must also protect the unextended Essential experience",
+ "disposition": "candidate",
+ "domain": "testing"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.4-answers-about-testing",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "appsource-tests-run-for-every-supported-country",
+ "title": "AppSource tests must run separately for every supported country",
+ "disposition": "candidate",
+ "domain": "appsource"
+ },
+ {
+ "id": "upgrade-tests-cover-nonadjacent-versions",
+ "title": "Upgrade tests cover nonadjacent historical versions",
+ "disposition": "candidate",
+ "domain": "testing"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource.4-technical-validation",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "appsource-submissions-cannot-use-runtime-packages",
+ "title": "AppSource submissions cannot use runtime packages",
+ "disposition": "candidate",
+ "domain": "appsource"
+ },
+ {
+ "id": "per-tenant-and-marketplace-apps-need-distinct-identities",
+ "title": "Per-tenant and Marketplace variants need distinct app identities",
+ "disposition": "candidate",
+ "domain": "appsource"
+ },
+ {
+ "id": "profiles-are-declared-with-profile-objects",
+ "title": "Profiles are shipped with AL profile objects rather than table inserts",
+ "disposition": "candidate",
+ "domain": "appsource"
+ },
+ {
+ "id": "extension-layout-uses-relative-placement",
+ "title": "Extension layout uses named relative placement anchors",
+ "disposition": "candidate",
+ "domain": "breaking-changes"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.3-documentation-examples",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "tests-use-reproducible-random-data",
+ "title": "Tests use reproducible randomized data instead of shared literals",
+ "disposition": "candidate",
+ "domain": "testing"
+ },
+ {
+ "id": "al-tests-run-through-vscode-test-explorer",
+ "title": "AL tests can run and debug through Visual Studio Code Test Explorer",
+ "disposition": "candidate",
+ "domain": "testing"
+ }
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.4-manage-apps",
+ "reviewStatus": "in-progress",
+ "outcomes": [
+ {
+ "id": "manage-apps-separates-install-and-update-requirements",
+ "title": "Manage Apps separates missing dependencies from dependency updates",
+ "disposition": "candidate",
+ "domain": "upgrade"
+ }
+ ]
+ }
+ ]
+}
diff --git a/coverage/microsoft-learn-developer-catalog.json b/coverage/microsoft-learn-developer-catalog.json
new file mode 100644
index 0000000..68fe859
--- /dev/null
+++ b/coverage/microsoft-learn-developer-catalog.json
@@ -0,0 +1,8282 @@
+{
+ "version": 1,
+ "source": {
+ "provider": "Microsoft Learn",
+ "catalogUri": "https://learn.microsoft.com/api/catalog/?locale=en-us",
+ "locale": "en-us",
+ "filters": {
+ "product": "dynamics-business-central",
+ "role": "developer"
+ },
+ "catalogLastModified": "2026-09-03T23:14:00Z"
+ },
+ "counts": {
+ "learningPaths": 12,
+ "modules": 74,
+ "units": 623
+ },
+ "learningPaths": [
+ {
+ "uid": "learn-dynamics.application-foundation-al-language",
+ "title": "Learn the application foundation with the AL programming language for Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/application-foundation-al-language",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 573,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions",
+ "learn-dynamics.al-statements",
+ "learn-dynamics.create-custom-functions",
+ "learn-dynamics.events-triggers",
+ "learn-dynamics.handle-errors",
+ "learn-dynamics.interfaces",
+ "learn-dynamics.intro-basics-al-programming",
+ "learn-dynamics.manage-multilanguage-development",
+ "learn-dynamics.manipulate-data-via-code",
+ "learn-dynamics.work-with-codeunits"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-reports",
+ "title": "Build reports for Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/build-reports",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 482,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report",
+ "learn-dynamics.add-reports-tell-me",
+ "learn-dynamics.complete-report-request-page",
+ "learn-dynamics.design-data-model-report",
+ "learn-dynamics.implement-multilanguage-reports",
+ "learn-dynamics.introduction-report-components",
+ "learn-dynamics.report-extensibility",
+ "learn-dynamics.understand-report-design-process",
+ "learn-dynamics.understand-report-triggers-functions",
+ "learn-dynamics.work-with-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.continuous-integration",
+ "title": "Continuous integration with Azure DevOps for Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/continuous-integration",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 439,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation",
+ "learn-dynamics.use-application-lifecycle",
+ "learn-dynamics.use-azure-pipelines",
+ "learn-dynamics.use-branch-merge-git",
+ "learn-dynamics.use-docker-business-central",
+ "learn-dynamics.work-azure-boards",
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.data-management-foundation-business-central",
+ "title": "Learn about the data management foundation in Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/data-management-foundation-business-central",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 205,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management",
+ "learn-dynamics.work-with-queries",
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.development-get-started-business-central",
+ "title": "Get started with development in Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/development-get-started-business-central",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 262,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects",
+ "learn-dynamics.assisted-setup-tooltips",
+ "learn-dynamics.extend-functionality-using-events",
+ "learn-dynamics.extend-tables-page-objects",
+ "learn-dynamics.initialize-data-extension-installation",
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.essential-development-standards",
+ "title": "Work with essential development standards for Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/essential-development-standards",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 223,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types",
+ "learn-dynamics.implement-data-process-model-business-central",
+ "learn-dynamics.use-document-standards-business-central",
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.foundation-customize-business-central",
+ "title": "Discover the foundation of customizing Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/foundation-customize-business-central",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 608,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension",
+ "learn-dynamics.extend-modify-existing-pages",
+ "learn-dynamics.extend-modify-existing-table",
+ "learn-dynamics.intro-development-environment",
+ "learn-dynamics.work-entitlements-permission-sets",
+ "learn-dynamics.work-with-pages",
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.interface-with-business-central",
+ "title": "Interface with Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/interface-with-business-central",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 283,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services",
+ "learn-dynamics.build-control-add-ins",
+ "learn-dynamics.use-al-controlled-barcode-scanning",
+ "learn-dynamics.use-azure-functions",
+ "learn-dynamics.work-with-api",
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.power-apps-power-automate-business-central",
+ "title": "Develop using Power Apps and Power Automate for Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/power-apps-power-automate-business-central",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 396,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app",
+ "learn-dynamics.create-custom-connector-power-platform",
+ "learn-dynamics.introduction-power-platform-business-central",
+ "learn-dynamics.use-model-driven-apps-common-data-service",
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.tailor-roles-design-ui",
+ "title": "Tailor roles and design the UI for Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/tailor-roles-design-ui",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 256,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup",
+ "learn-dynamics.customize-ui-experience",
+ "learn-dynamics.develop-role-center",
+ "learn-dynamics.send-notifications",
+ "learn-dynamics.set-up-onboarding-experiences"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-development-business-central",
+ "title": "Use application development best practices in Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/use-application-development-business-central",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 377,
+ "moduleUids": [
+ "learn-dynamics.application-monetization",
+ "learn-dynamics.application-performance-monitor",
+ "learn-dynamics.application-types",
+ "learn-dynamics.bring-app-appsource",
+ "learn-dynamics.easy-application-upgrade",
+ "learn-dynamics.implement-saas-techniques",
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-bi",
+ "title": "Use Power BI in Microsoft Dynamics 365 Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/paths/use-power-bi",
+ "lastModified": "2025-03-24T22:55:00Z",
+ "durationInMinutes": 233,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report",
+ "learn-dynamics.create-data-set",
+ "learn-dynamics.work-power-bi"
+ ]
+ }
+ ],
+ "modules": [
+ {
+ "uid": "learn-dynamics.access-rest-services",
+ "title": "Access REST services from within Dynamics 365 Business Central",
+ "summary": "Learn how to use HTTP data types, connect to external REST services, and handle JSON data in Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 62,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "cross-development"
+ ],
+ "learningPathUids": "learn-dynamics.interface-with-business-central",
+ "unitUids": [
+ "learn-dynamics.access-rest-services.1-introduction",
+ "learn-dynamics.access-rest-services.2-http-classes",
+ "learn-dynamics.access-rest-services.3-get-send-data",
+ "learn-dynamics.access-rest-services.4-use-read-json",
+ "learn-dynamics.access-rest-services.5-get-json-data",
+ "learn-dynamics.access-rest-services.6-exercise",
+ "learn-dynamics.access-rest-services.7-check",
+ "learn-dynamics.access-rest-services.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report",
+ "title": "Add a layout to a report in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to add a layout to a report in Microsoft Dynamics 365 Business Central? In this module, you'll learn about the client report definition (RDLC) layout and Word layout formats and how to create them.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 70,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.add-layout-report.1-introduction",
+ "learn-dynamics.add-layout-report.2-add-report-definition",
+ "learn-dynamics.add-layout-report.3-add-word-layout",
+ "learn-dynamics.add-layout-report.word-add-in",
+ "learn-dynamics.add-layout-report.add-excel-layout",
+ "learn-dynamics.add-layout-report.4-exercise",
+ "learn-dynamics.add-layout-report.5-check",
+ "learn-dynamics.add-layout-report.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects",
+ "title": "Add new objects to Dynamics 365 Business Central",
+ "summary": "Do you want to know how to add objects, like tables and pages, to Microsoft Dynamics 365 Business Central? If so, this module is for you. In this module, you'll learn how to create tables and pages for an extension.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 57,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.development-get-started-business-central",
+ "unitUids": [
+ "learn-dynamics.add-new-objects.1-introduction",
+ "learn-dynamics.add-new-objects.2-reward",
+ "learn-dynamics.add-new-objects.3-activation-code",
+ "learn-dynamics.add-new-objects.4-customer-rewards",
+ "learn-dynamics.add-new-objects.5-reward-list",
+ "learn-dynamics.add-new-objects.6-exercise",
+ "learn-dynamics.add-new-objects.7-exercise",
+ "learn-dynamics.add-new-objects.8-exercise",
+ "learn-dynamics.add-new-objects.9-check",
+ "learn-dynamics.add-new-objects.10-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-reports-tell-me",
+ "title": "Add reports to Tell Me and substitute a report in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to add reports to Tell Me and substitute a report in Microsoft Dynamics 365 Business Central? In this module, you'll learn how to add reports to Tell Me and how to substitute a report.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-reports-tell-me",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 27,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "finance-accounting"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.add-reports-tell-me.1-introduction",
+ "learn-dynamics.add-reports-tell-me.2-add-reports-tell-me",
+ "learn-dynamics.add-reports-tell-me.3-substitute-report",
+ "learn-dynamics.add-reports-tell-me.4-check",
+ "learn-dynamics.add-reports-tell-me.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions",
+ "title": "Work with AL built-in functions in Dynamics 365 Business Central",
+ "summary": "Do you want to know more about the built-in programming functions of Business Central? This module will discuss the different available functions that you can use when developing for Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 86,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.al-built-in-functions.1-introduction",
+ "learn-dynamics.al-built-in-functions.2-interaction-functions",
+ "learn-dynamics.al-built-in-functions.3-string-functions",
+ "learn-dynamics.al-built-in-functions.4-date-functions",
+ "learn-dynamics.al-built-in-functions.5-numeric-functions",
+ "learn-dynamics.al-built-in-functions.6-array-functions",
+ "learn-dynamics.al-built-in-functions.7-list-functions",
+ "learn-dynamics.al-built-in-functions.8-system-functions",
+ "learn-dynamics.al-built-in-functions.9-variable-functions",
+ "learn-dynamics.al-built-in-functions.10-exercise",
+ "learn-dynamics.al-built-in-functions.11-check",
+ "learn-dynamics.al-built-in-functions.12-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements",
+ "title": "Learn the AL statements in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to use basic AL statements? This module shows you how to use conditional statements, compound statements, and comments when developing for Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 67,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.al-statements.1-introduction",
+ "learn-dynamics.al-statements.2-compound",
+ "learn-dynamics.al-statements.3-conditional",
+ "learn-dynamics.al-statements.4-repetitive",
+ "learn-dynamics.al-statements.5-exercise",
+ "learn-dynamics.al-statements.6-check",
+ "learn-dynamics.al-statements.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-monetization",
+ "title": "Consider application monetization responsibilities in Business Central",
+ "summary": "Do you want to understand your application monetization responsibilities? In this module, you'll learn about monetization responsibilities, and where to find useful guides and documentation.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-monetization",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 23,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "marketing-sales"
+ ],
+ "learningPathUids": "learn-dynamics.use-application-development-business-central",
+ "unitUids": [
+ "learn-dynamics.application-monetization.1-introduction",
+ "learn-dynamics.application-monetization.2-responsibilities",
+ "learn-dynamics.application-monetization.3-documentation-examples",
+ "learn-dynamics.application-monetization.4-check",
+ "learn-dynamics.application-monetization.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-performance-monitor",
+ "title": "Learn about application performance and monitoring in Business Central",
+ "summary": "Do you want to learn about application performance and monitoring? Learn what is required to write performant code, understand how you can monitor application performance, and get required insights.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-performance-monitor",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 33,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.use-application-development-business-central",
+ "unitUids": [
+ "learn-dynamics.application-performance-monitor.1-introduction",
+ "learn-dynamics.application-performance-monitor.2-prepare-application",
+ "learn-dynamics.application-performance-monitor.3-get-insights",
+ "learn-dynamics.application-performance-monitor.4-check",
+ "learn-dynamics.application-performance-monitor.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types",
+ "title": "Introduction to application types in Business Central",
+ "summary": "Explore the differences between connect and addon applications, understand library and dependency apps, and learn app development resources in Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 66,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.use-application-development-business-central",
+ "unitUids": [
+ "learn-dynamics.application-types.1-introduction",
+ "learn-dynamics.application-types.2-connect-vs-add-on",
+ "learn-dynamics.application-types.3-library-dependency-applications",
+ "learn-dynamics.application-types.4-find-development-resources",
+ "learn-dynamics.application-types.5-set-up-code-cop-tools",
+ "learn-dynamics.application-types.6-check",
+ "learn-dynamics.application-types.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips",
+ "title": "Introduction to assisted setup and tooltips in Dynamics 365 Business Central",
+ "summary": "Do you want to know an effective way to let a user perform the installation steps of your extension by using an efficient and accessible wizard in Microsoft Dynamics 365 Business Central? If so, this module is for you. In this module, you'll learn how to add a wizard page by using a navigate page object.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 47,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.development-get-started-business-central",
+ "unitUids": [
+ "learn-dynamics.assisted-setup-tooltips.1-introduction",
+ "learn-dynamics.assisted-setup-tooltips.2-rewards-wizard",
+ "learn-dynamics.assisted-setup-tooltips.3-assisted-setup",
+ "learn-dynamics.assisted-setup-tooltips.4-tooltips",
+ "learn-dynamics.assisted-setup-tooltips.5-exercise",
+ "learn-dynamics.assisted-setup-tooltips.6-exercise",
+ "learn-dynamics.assisted-setup-tooltips.7-check",
+ "learn-dynamics.assisted-setup-tooltips.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource",
+ "title": "Understand the process of bringing an app to AppSource in Business Central",
+ "summary": "Do you want to know about technical and marketing AppSource validation procedures? In this module, you'll learn what is required from a technical and marketing point of view for your application to be validated for AppSource.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/bring-app-appsource",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 45,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.use-application-development-business-central",
+ "unitUids": [
+ "learn-dynamics.bring-app-appsource.1-introduction",
+ "learn-dynamics.bring-app-appsource.2-get-accounts",
+ "learn-dynamics.bring-app-appsource.3-marketing-validation",
+ "learn-dynamics.bring-app-appsource.4-technical-validation",
+ "learn-dynamics.bring-app-appsource.5-check",
+ "learn-dynamics.bring-app-appsource.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup",
+ "title": "Build an Assisted Setup in Dynamics 365 Business Central",
+ "summary": "Assisted Setup guides you in configuring Business Central. Do you want to learn how you can integrate with the Assisted Setup feature and create your own wizard pages? If so, this module explains that process.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 54,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.tailor-roles-design-ui",
+ "unitUids": [
+ "learn-dynamics.build-assisted-setup.1-introduction",
+ "learn-dynamics.build-assisted-setup.2-assisted-setup",
+ "learn-dynamics.build-assisted-setup.3-wizard-pages",
+ "learn-dynamics.build-assisted-setup.4-extensions",
+ "learn-dynamics.build-assisted-setup.5-exercise",
+ "learn-dynamics.build-assisted-setup.6-check",
+ "learn-dynamics.build-assisted-setup.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins",
+ "title": "Build control add-in objects in Dynamics 365 Business Central",
+ "summary": "Do you need to build control add-ins? This module discusses how to build and integrate control add-ins with JavaScript in AL.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 51,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.interface-with-business-central",
+ "unitUids": [
+ "learn-dynamics.build-control-add-ins.1-introduction",
+ "learn-dynamics.build-control-add-ins.2-apply-look-feel",
+ "learn-dynamics.build-control-add-ins.3-create",
+ "learn-dynamics.build-control-add-ins.4-asynchronous-considerations",
+ "learn-dynamics.build-control-add-ins.5-connect",
+ "learn-dynamics.build-control-add-ins.6-exercise",
+ "learn-dynamics.build-control-add-ins.7-check",
+ "learn-dynamics.build-control-add-ins.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report",
+ "title": "Build a Power BI report with Business Central data",
+ "summary": "Do you want to build a Business Central report using Power BI Desktop? This module will guide you through the steps required to create a Power BI report.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 74,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "cloud-computing",
+ "data-visualization"
+ ],
+ "learningPathUids": "learn-dynamics.use-power-bi",
+ "unitUids": [
+ "learn-dynamics.build-power-bi-report.1-introduction",
+ "learn-dynamics.build-power-bi-report.2-build-data-model",
+ "learn-dynamics.build-power-bi-report.3-add-data-dimension",
+ "learn-dynamics.build-power-bi-report.4-introduction-dax",
+ "learn-dynamics.build-power-bi-report.5-create-report",
+ "learn-dynamics.build-power-bi-report.6-build-dashboard",
+ "learn-dynamics.build-power-bi-report.7-exercise",
+ "learn-dynamics.build-power-bi-report.8-exercise",
+ "learn-dynamics.build-power-bi-report.9-check",
+ "learn-dynamics.build-power-bi-report.10-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration",
+ "title": "Integrate Dynamics 365 Business Central with Teams",
+ "summary": "Learn to integrate Dynamics 365 Business Central with Microsoft Teams.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 48,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": null,
+ "unitUids": [
+ "learn-dynamics.business-central-teams-integration.introduction",
+ "learn-dynamics.business-central-teams-integration.manage-install-use",
+ "learn-dynamics.business-central-teams-integration.extend-teams-cards",
+ "learn-dynamics.business-central-teams-integration.create-tabs",
+ "learn-dynamics.business-central-teams-integration.get-session-details",
+ "learn-dynamics.business-central-teams-integration.check",
+ "learn-dynamics.business-central-teams-integration.summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.complete-report-request-page",
+ "title": "Complete the report request page in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to complete the report request page for a report in Business Central? In this module, you'll learn about the report request page and how to create it.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/complete-report-request-page",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 36,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.complete-report-request-page.1-introduction",
+ "learn-dynamics.complete-report-request-page.2-design-request-page",
+ "learn-dynamics.complete-report-request-page.3-design-request-options",
+ "learn-dynamics.complete-report-request-page.4-check",
+ "learn-dynamics.complete-report-request-page.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app",
+ "title": "Create a canvas app based on Business Central data",
+ "summary": "Do you want to create a canvas app using Business Central data? This module focuses on how to create canvas app using Business Central data and how to customize the created app.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 73,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "cross-development"
+ ],
+ "learningPathUids": "learn-dynamics.power-apps-power-automate-business-central",
+ "unitUids": [
+ "learn-dynamics.create-canvas-app.1-introduction",
+ "learn-dynamics.create-canvas-app.2-data-app",
+ "learn-dynamics.create-canvas-app.3-blank-app",
+ "learn-dynamics.create-canvas-app.4-customizations",
+ "learn-dynamics.create-canvas-app.5-save-publish-share",
+ "learn-dynamics.create-canvas-app.6-embed",
+ "learn-dynamics.create-canvas-app.7-exercise",
+ "learn-dynamics.create-canvas-app.8-check",
+ "learn-dynamics.create-canvas-app.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform",
+ "title": "Create a custom connector to extend Microsoft Power Platform functionalities with Business Central",
+ "summary": "Do you need to create custom connectors for Business Central? Use this module to find out the details of creating custom connectors.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 59,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "cross-development"
+ ],
+ "learningPathUids": "learn-dynamics.power-apps-power-automate-business-central",
+ "unitUids": [
+ "learn-dynamics.create-custom-connector-power-platform.1-introduction",
+ "learn-dynamics.create-custom-connector-power-platform.2-custom-connector",
+ "learn-dynamics.create-custom-connector-power-platform.3-power-apps",
+ "learn-dynamics.create-custom-connector-power-platform.4-power-automate",
+ "learn-dynamics.create-custom-connector-power-platform.5-share-custom-connectors",
+ "learn-dynamics.create-custom-connector-power-platform.6-exercise",
+ "learn-dynamics.create-custom-connector-power-platform.7-check",
+ "learn-dynamics.create-custom-connector-power-platform.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions",
+ "title": "Create custom procedures in Dynamics 365 Business Central",
+ "summary": "Do you want to create custom procedures in AL? This module focuses on explaining how you can create new procedures. Additionally, it describes the difference between local and global procedures, the difference between local and global variables, and how you can pass variables to a procedure.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 37,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.create-custom-functions.1-introduction",
+ "learn-dynamics.create-custom-functions.2-custom-function",
+ "learn-dynamics.create-custom-functions.3-local-global-function",
+ "learn-dynamics.create-custom-functions.4-local-global-variable",
+ "learn-dynamics.create-custom-functions.5-pass",
+ "learn-dynamics.create-custom-functions.6-parameter",
+ "learn-dynamics.create-custom-functions.7-check",
+ "learn-dynamics.create-custom-functions.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set",
+ "title": "Create a dataset for a Power BI report in Dynamics 365 Business Central",
+ "summary": "Learn how to create a dataset for a Power BI report in Business Central using assisted reporting setup and custom data sets.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 94,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "data-analytics"
+ ],
+ "learningPathUids": "learn-dynamics.use-power-bi",
+ "unitUids": [
+ "learn-dynamics.create-data-set.1-introduction",
+ "learn-dynamics.create-data-set.2-install",
+ "learn-dynamics.create-data-set.3-use-data-source",
+ "learn-dynamics.create-data-set.5-develop-query-page-objects",
+ "learn-dynamics.create-data-set.develop-api-query",
+ "learn-dynamics.create-data-set.use-dedicated-apis",
+ "learn-dynamics.create-data-set.6-mind-performance-impact",
+ "learn-dynamics.create-data-set.create-power-bi-dataflow",
+ "learn-dynamics.create-data-set.7-exercise",
+ "learn-dynamics.create-data-set.9-exercise",
+ "learn-dynamics.create-data-set.10-exercise",
+ "learn-dynamics.create-data-set.11-check",
+ "learn-dynamics.create-data-set.12-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience",
+ "title": "Customize the UI experience in Dynamics 365 Business Central",
+ "summary": "Do you want to further customize the UI experience for a user? Do you want to be able to add your pages and reports to the search functionality? In this module, you'll learn how to create page customizations for specific user profiles and extend the application areas.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 50,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.tailor-roles-design-ui",
+ "unitUids": [
+ "learn-dynamics.customize-ui-experience.1-introduction",
+ "learn-dynamics.customize-ui-experience.2-objects",
+ "learn-dynamics.customize-ui-experience.3-customizations",
+ "learn-dynamics.customize-ui-experience.4-profiles",
+ "learn-dynamics.customize-ui-experience.extend-customize",
+ "learn-dynamics.customize-ui-experience.5-views",
+ "learn-dynamics.customize-ui-experience.6-application-areas",
+ "learn-dynamics.customize-ui-experience.7-check",
+ "learn-dynamics.customize-ui-experience.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension",
+ "title": "Debug and deploy your extension in Dynamics 365 Business Central",
+ "summary": "Discover how to debug with Visual Studio Code and deploy your extension using RAD feature in Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 134,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.foundation-customize-business-central",
+ "unitUids": [
+ "learn-dynamics.debug-deploy-extension.1-introduction",
+ "learn-dynamics.debug-deploy-extension.2-debug",
+ "learn-dynamics.debug-deploy-extension.recovery-failures",
+ "learn-dynamics.debug-deploy-extension.3-attach",
+ "learn-dynamics.debug-deploy-extension.3a-snapshot",
+ "learn-dynamics.debug-deploy-extension.4-rapid-application-development",
+ "learn-dynamics.debug-deploy-extension.5-publish",
+ "learn-dynamics.debug-deploy-extension.resource-policy-settings",
+ "learn-dynamics.debug-deploy-extension.protect-sensitive-values",
+ "learn-dynamics.debug-deploy-extension.projects-workspaces",
+ "learn-dynamics.debug-deploy-extension.code-actions",
+ "learn-dynamics.debug-deploy-extension.generate-help",
+ "learn-dynamics.debug-deploy-extension.5a-performance-toolkit",
+ "learn-dynamics.debug-deploy-extension.database-wait-statistics",
+ "learn-dynamics.debug-deploy-extension.6-exercise",
+ "learn-dynamics.debug-deploy-extension.7-exercise",
+ "learn-dynamics.debug-deploy-extension.8-check",
+ "learn-dynamics.debug-deploy-extension.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report",
+ "title": "Design the data model of a report in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to build the data model for a report in Microsoft Dynamics 365 Business Central? This module will discuss the different components of a report data model.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 48,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "data-modeling"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.design-data-model-report.1-introduction",
+ "learn-dynamics.design-data-model-report.2-create-report-data-items",
+ "learn-dynamics.design-data-model-report.3-add-columns-report-dataset",
+ "learn-dynamics.design-data-model-report.4-link-order-indent-data-items",
+ "learn-dynamics.design-data-model-report.use-query",
+ "learn-dynamics.design-data-model-report.5-check",
+ "learn-dynamics.design-data-model-report.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center",
+ "title": "Develop a Role Center in Dynamics 365 Business Central",
+ "summary": "Create a Role Center page for Microsoft Dynamics 365 Business Central and learn how it's constructed.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 60,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "finance-accounting"
+ ],
+ "learningPathUids": "learn-dynamics.tailor-roles-design-ui",
+ "unitUids": [
+ "learn-dynamics.develop-role-center.1-introduction",
+ "learn-dynamics.develop-role-center.2-create-page",
+ "learn-dynamics.develop-role-center.3-activity-parts",
+ "learn-dynamics.develop-role-center.4-cue-setup",
+ "learn-dynamics.develop-role-center.5-role-center-lists",
+ "learn-dynamics.develop-role-center.6-headline-parts",
+ "learn-dynamics.develop-role-center.7-exercise",
+ "learn-dynamics.develop-role-center.8-check",
+ "learn-dynamics.develop-role-center.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade",
+ "title": "Prepare for an easy application upgrade experience in Business Central",
+ "summary": "Do you want to learn about how to build efficient installation and upgrade procedures? There are essential techniques you should learn to build good and user-friendly applications.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 88,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications",
+ "data-management"
+ ],
+ "learningPathUids": "learn-dynamics.use-application-development-business-central",
+ "unitUids": [
+ "learn-dynamics.easy-application-upgrade.1-introduction",
+ "learn-dynamics.easy-application-upgrade.2-upgrade-responsibilities",
+ "learn-dynamics.easy-application-upgrade.consider-update-lifecycle",
+ "learn-dynamics.easy-application-upgrade.3-installation-upgrade-codeunits",
+ "learn-dynamics.easy-application-upgrade.transfer-data",
+ "learn-dynamics.easy-application-upgrade.4-manage-apps",
+ "learn-dynamics.easy-application-upgrade.5-detect-breaking-changes",
+ "learn-dynamics.easy-application-upgrade.6-answers-about-updates",
+ "learn-dynamics.easy-application-upgrade.7-check",
+ "learn-dynamics.easy-application-upgrade.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers",
+ "title": "Use events and triggers in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to access different table and page triggers? Do you also want to learn how to develop by using event-based architecture? If so, this module will explain how to use events and triggers in Microsoft Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 60,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "architecture",
+ "data-visualization"
+ ],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.events-triggers.1-introduction",
+ "learn-dynamics.events-triggers.2-table-field-triggers",
+ "learn-dynamics.events-triggers.3-page-control-action-triggers",
+ "learn-dynamics.events-triggers.4-event-based",
+ "learn-dynamics.events-triggers.5-publish-subscribe",
+ "learn-dynamics.events-triggers.6-exercise",
+ "learn-dynamics.events-triggers.7-check",
+ "learn-dynamics.events-triggers.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-functionality-using-events",
+ "title": "Extend functionality by using events in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to add your business logic to existing functionality in Microsoft Dynamics 365 Business Central? In this module, you'll learn how to add code and work with events.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-functionality-using-events",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 44,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.development-get-started-business-central",
+ "unitUids": [
+ "learn-dynamics.extend-functionality-using-events.1-introduction",
+ "learn-dynamics.extend-functionality-using-events.2-programming-basics",
+ "learn-dynamics.extend-functionality-using-events.3-customer-rewards",
+ "learn-dynamics.extend-functionality-using-events.4-exercise",
+ "learn-dynamics.extend-functionality-using-events.5-check",
+ "learn-dynamics.extend-functionality-using-events.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-pages",
+ "title": "Extend and modify an existing page in Dynamics 365 Business Central",
+ "summary": "Do you want to add extra fields or remove fields from an existing page? If so, this module will help you discover how to modify an existing page by using page extensions.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-pages",
+ "lastModified": "2026-09-01T17:24:00Z",
+ "durationInMinutes": 45,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.foundation-customize-business-central",
+ "unitUids": [
+ "learn-dynamics.extend-modify-existing-pages.1-introduction",
+ "learn-dynamics.extend-modify-existing-pages.2-get-started",
+ "learn-dynamics.extend-modify-existing-pages.3-properties",
+ "learn-dynamics.extend-modify-existing-pages.4-layout",
+ "learn-dynamics.extend-modify-existing-pages.5-check",
+ "learn-dynamics.extend-modify-existing-pages.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table",
+ "title": "Extend and modify an existing table in Dynamics 365 Business Central",
+ "summary": "Do you want to add extra fields to an existing table? This module discusses how you can modify an existing table by using table extensions.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 33,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.foundation-customize-business-central",
+ "unitUids": [
+ "learn-dynamics.extend-modify-existing-table.1-introduction",
+ "learn-dynamics.extend-modify-existing-table.2-get-started",
+ "learn-dynamics.extend-modify-existing-table.3-properties",
+ "learn-dynamics.extend-modify-existing-table.add-field-group",
+ "learn-dynamics.extend-modify-existing-table.define-extension-objects",
+ "learn-dynamics.extend-modify-existing-table.4-check",
+ "learn-dynamics.extend-modify-existing-table.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects",
+ "title": "Extend existing table and page objects in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to modify existing tables and pages for Microsoft Dynamics 365 Business Central? In this module, you'll learn ways to create and customize table and page objects.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 42,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [
+ "data-modeling"
+ ],
+ "learningPathUids": "learn-dynamics.development-get-started-business-central",
+ "unitUids": [
+ "learn-dynamics.extend-tables-page-objects.1-introduction",
+ "learn-dynamics.extend-tables-page-objects.2-customer-table",
+ "learn-dynamics.extend-tables-page-objects.3-customer-card",
+ "learn-dynamics.extend-tables-page-objects.4-customer-list",
+ "learn-dynamics.extend-tables-page-objects.5-exercise",
+ "learn-dynamics.extend-tables-page-objects.6-exercise",
+ "learn-dynamics.extend-tables-page-objects.7-exercise",
+ "learn-dynamics.extend-tables-page-objects.8-check",
+ "learn-dynamics.extend-tables-page-objects.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.handle-errors",
+ "title": "Handle errors by using application language in Dynamics 365 Business Central",
+ "summary": "Learn how to handle errors in Dynamics 365 Business Central by using application language (AL).",
+ "url": "https://learn.microsoft.com/en-us/training/modules/handle-errors",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 35,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.handle-errors.introduction",
+ "learn-dynamics.handle-errors.handle-errors",
+ "learn-dynamics.handle-errors.collect-errors",
+ "learn-dynamics.handle-errors.progress-windows",
+ "learn-dynamics.handle-errors.check",
+ "learn-dynamics.handle-errors.summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types",
+ "title": "Identify functional table types and characteristics in Dynamics 365 Business Central",
+ "summary": "Do you want to learn about table types in Business Central? In this module, you'll learn about the different functional table types and their specific characteristics, such as special fields, properties, and linked pages.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 68,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.essential-development-standards",
+ "unitUids": [
+ "learn-dynamics.identify-table-types.1-introduction",
+ "learn-dynamics.identify-table-types.2-define-table-types",
+ "learn-dynamics.identify-table-types.3-create-master-tables",
+ "learn-dynamics.identify-table-types.4-create-supplemental-tables",
+ "learn-dynamics.identify-table-types.5-create-subsidiary-tables",
+ "learn-dynamics.identify-table-types.6-create-ledger-tables",
+ "learn-dynamics.identify-table-types.7-create-register-tables",
+ "learn-dynamics.identify-table-types.8-create-journal-tables",
+ "learn-dynamics.identify-table-types.9-create-document-tables",
+ "learn-dynamics.identify-table-types.10-create-setup-tables",
+ "learn-dynamics.identify-table-types.11-check",
+ "learn-dynamics.identify-table-types.12-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-data-process-model-business-central",
+ "title": "Implement the data process model in Dynamics 365 Business Central",
+ "summary": "Do you want to understand how data flows in Business Central? This module provides an overview of how data flows within the application so you can develop solutions efficiently.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-data-process-model-business-central",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 37,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "data-modeling",
+ "process-workflow"
+ ],
+ "learningPathUids": "learn-dynamics.essential-development-standards",
+ "unitUids": [
+ "learn-dynamics.implement-data-process-model-business-central.1-introduction",
+ "learn-dynamics.implement-data-process-model-business-central.2-standard-data-model",
+ "learn-dynamics.implement-data-process-model-business-central.3-typical-data-triggers",
+ "learn-dynamics.implement-data-process-model-business-central.4-standard-data-flow",
+ "learn-dynamics.implement-data-process-model-business-central.5-check",
+ "learn-dynamics.implement-data-process-model-business-central.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-multilanguage-reports",
+ "title": "Implement multilingual reports in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to make your reports multilingual in Microsoft Dynamics 365 Business Central? In this module, you'll learn how to generate a report in the language of the user or the recipient.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-multilanguage-reports",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 36,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.implement-multilanguage-reports.1-introduction",
+ "learn-dynamics.implement-multilanguage-reports.2-create-report-user-language",
+ "learn-dynamics.implement-multilanguage-reports.3-create-report-recipient-language",
+ "learn-dynamics.implement-multilanguage-reports.define-regional-settings",
+ "learn-dynamics.implement-multilanguage-reports.4-check",
+ "learn-dynamics.implement-multilanguage-reports.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-saas-techniques",
+ "title": "Implement SaaSification techniques in Business Central",
+ "summary": "Do you want to learn about how to build your user interface using SaaSification techniques? Learn about properly building a good user interface and first trial experience for the users of your application.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-saas-techniques",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 31,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "custom-app-development"
+ ],
+ "learningPathUids": "learn-dynamics.use-application-development-business-central",
+ "unitUids": [
+ "learn-dynamics.implement-saas-techniques.1-introduction",
+ "learn-dynamics.implement-saas-techniques.2-build-trial",
+ "learn-dynamics.implement-saas-techniques.3-implement-saasification",
+ "learn-dynamics.implement-saas-techniques.4-check",
+ "learn-dynamics.implement-saas-techniques.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.initialize-data-extension-installation",
+ "title": "Initialize data during extension installation in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to initialize data during extension installation for Microsoft Dynamics 365 Business Central? Initializing data when you're installing an extension automate many steps that you must otherwise perform manually. By automating this process, you can quickly set up an extension and it becomes more user-friendly.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/initialize-data-extension-installation",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 32,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [
+ "data-engineering"
+ ],
+ "learningPathUids": "learn-dynamics.development-get-started-business-central",
+ "unitUids": [
+ "learn-dynamics.initialize-data-extension-installation.1-introduction",
+ "learn-dynamics.initialize-data-extension-installation.2-install-logic",
+ "learn-dynamics.initialize-data-extension-installation.3-exercise",
+ "learn-dynamics.initialize-data-extension-installation.4-check",
+ "learn-dynamics.initialize-data-extension-installation.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.interfaces",
+ "title": "Implement interfaces in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to implement interfaces in AL? If so, this module will explain how to implement interfaces in AL for use with Microsoft Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 54,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "process-workflow"
+ ],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.business-central-interfaces.1-introduction",
+ "learn-dynamics.business-central-interfaces.2-snippet-support",
+ "learn-dynamics.business-central-interfaces.type-testing",
+ "learn-dynamics.business-central-interfaces.3-why-interfaces",
+ "learn-dynamics.business-central-interfaces.extending-interfaces",
+ "learn-dynamics.business-central-interfaces.4-exercise",
+ "learn-dynamics.business-central-interfaces.5-check",
+ "learn-dynamics.business-central-interfaces.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming",
+ "title": "Introduction to the basics of AL programming in Dynamics 365 Business Central",
+ "summary": "Explore the basics of Application Language (AL) programming, including variables, data types, options, and enums.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 88,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.intro-basics-al-programming.1-intro",
+ "learn-dynamics.intro-basics-al-programming.2-get-started",
+ "learn-dynamics.intro-basics-al-programming.3-variables",
+ "learn-dynamics.intro-basics-al-programming.4-data-types",
+ "learn-dynamics.intro-basics-al-programming.5-options-enums",
+ "learn-dynamics.intro-basics-al-programming.6-collections",
+ "learn-dynamics.intro-basics-al-programming.7-assignments",
+ "learn-dynamics.intro-basics-al-programming.8-expressions",
+ "learn-dynamics.intro-basics-al-programming.9-exercise",
+ "learn-dynamics.intro-basics-al-programming.10-exercise",
+ "learn-dynamics.intro-basics-al-programming.11-check",
+ "learn-dynamics.intro-basics-al-programming.12-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment",
+ "title": "Introduction to the development environment for Dynamics 365 Business Central",
+ "summary": "Do you want to start developing for Microsoft Dynamics 365 Business Central? If so, this module is for you. Learn about the development environment that is used for Business Central development and how to configure that environment. You will also learn about the different objects in Microsoft Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 95,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [
+ "devops"
+ ],
+ "learningPathUids": "learn-dynamics.foundation-customize-business-central",
+ "unitUids": [
+ "learn-dynamics.intro-development-environment.1-intro",
+ "learn-dynamics.intro-development-environment.2-get-started",
+ "learn-dynamics.intro-development-environment.3-install",
+ "learn-dynamics.intro-development-environment.4-logical-database",
+ "learn-dynamics.intro-development-environment.differentiate-apps",
+ "learn-dynamics.intro-development-environment.5-extension",
+ "learn-dynamics.intro-development-environment.6-json",
+ "learn-dynamics.intro-development-environment.7-al-language",
+ "learn-dynamics.intro-development-environment.8-multiple",
+ "learn-dynamics.intro-development-environment.segment-code-reduce-conflicts",
+ "learn-dynamics.intro-development-environment.open-visual-studio-code-web-client",
+ "learn-dynamics.intro-development-environment.9-exercise",
+ "learn-dynamics.intro-development-environment.10-check",
+ "learn-dynamics.intro-development-environment.11-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management",
+ "title": "Introduction to the basics of file management in Dynamics 365 Business Central",
+ "summary": "Explore the file data type, File Management codeunit, Temp Blob codeunit, and stream functions for file manipulation in Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 61,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications",
+ "data-management"
+ ],
+ "learningPathUids": "learn-dynamics.data-management-foundation-business-central",
+ "unitUids": [
+ "learn-dynamics.introduction-basics-file-management.1-introduction",
+ "learn-dynamics.introduction-basics-file-management.2-file-object",
+ "learn-dynamics.introduction-basics-file-management.3-temp-blob-object",
+ "learn-dynamics.introduction-basics-file-management.4-read-write-stream",
+ "learn-dynamics.introduction-basics-file-management.uploads-drop-zones",
+ "learn-dynamics.introduction-basics-file-management.5-exercise",
+ "learn-dynamics.introduction-basics-file-management.6-check",
+ "learn-dynamics.introduction-basics-file-management.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process",
+ "title": "Introduction to the development process in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to start creating an extension for Microsoft Dynamics 365 Business Central? If so, this module is for you. In this module, you'll learn about the different components that make up a typical extension. Then, the module will provide a brief description of the development environment and explain the different steps that are involved in getting started with an extension.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 40,
+ "levels": [
+ "beginner"
+ ],
+ "subjects": [
+ "process-workflow"
+ ],
+ "learningPathUids": "learn-dynamics.development-get-started-business-central",
+ "unitUids": [
+ "learn-dynamics.introduction-development-process.1-introduction",
+ "learn-dynamics.introduction-development-process.2-process",
+ "learn-dynamics.introduction-development-process.3-setup",
+ "learn-dynamics.introduction-development-process.4-rewards",
+ "learn-dynamics.introduction-development-process.5-exercise",
+ "learn-dynamics.introduction-development-process.6-exercise",
+ "learn-dynamics.introduction-development-process.7-check",
+ "learn-dynamics.introduction-development-process.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central",
+ "title": "Introduction to Microsoft Power Platform and Business Central",
+ "summary": "Do you want to use Microsoft Power Platform with Business Central? This module focuses on the business value and product capabilities of Microsoft Power Platform when you use it with Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 53,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.power-apps-power-automate-business-central",
+ "unitUids": [
+ "learn-dynamics.introduction-power-platform-business-central.1-introduction",
+ "learn-dynamics.introduction-power-platform-business-central.2-data-connectors",
+ "learn-dynamics.introduction-power-platform-business-central.3-business-central-connectors",
+ "learn-dynamics.introduction-power-platform-business-central.4-power-apps",
+ "learn-dynamics.introduction-power-platform-business-central.5-power-automate",
+ "learn-dynamics.introduction-power-platform-business-central.use-cases",
+ "learn-dynamics.introduction-power-platform-business-central.6-embed-power-platform",
+ "learn-dynamics.introduction-power-platform-business-central.7-check",
+ "learn-dynamics.introduction-power-platform-business-central.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components",
+ "title": "Introduction to report components in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to start creating reports for Business Central? If so, this module will explain the different components that a typical report consists of.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 37,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "data-management"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.introduction-report-components.1-introduction",
+ "learn-dynamics.introduction-report-components.2-learn-overview-report-description",
+ "learn-dynamics.introduction-report-components.3-report-properties-triggers",
+ "learn-dynamics.introduction-report-components.4-data-items-columns",
+ "learn-dynamics.introduction-report-components.5-request-page",
+ "learn-dynamics.introduction-report-components.6-work-report-labels",
+ "learn-dynamics.introduction-report-components.7-report-layouts",
+ "learn-dynamics.introduction-report-components.8-check",
+ "learn-dynamics.introduction-report-components.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation",
+ "title": "Introduction to test automation in Business Central",
+ "summary": "Discover how to write test code in AL using Test Codeunits and run standard Business Central tests.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 58,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.continuous-integration",
+ "unitUids": [
+ "learn-dynamics.introduction-test-automation.1-introduction",
+ "learn-dynamics.introduction-test-automation.2-test-applications",
+ "learn-dynamics.introduction-test-automation.3-install-run-test-toolkit",
+ "learn-dynamics.introduction-test-automation.4-run-standard-tests",
+ "learn-dynamics.introduction-test-automation.5-create-test-code-units",
+ "learn-dynamics.introduction-test-automation.6-check",
+ "learn-dynamics.introduction-test-automation.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manage-multilanguage-development",
+ "title": "Manage multilanguage development in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to manage multiple languages in an AL extension? If so, this module explains how to create and use translation files.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manage-multilanguage-development",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 43,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "devops"
+ ],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.manage-multilanguage-development.1-introduction",
+ "learn-dynamics.manage-multilanguage-development.2-translation-files",
+ "learn-dynamics.manage-multilanguage-development.3-automate",
+ "learn-dynamics.manage-multilanguage-development.4-exercise",
+ "learn-dynamics.manage-multilanguage-development.5-check",
+ "learn-dynamics.manage-multilanguage-development.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code",
+ "title": "Manipulate data by using code in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to retrieve data from the database and manipulate that data or add new data? In this module, you learn about the different AL data manipulation statements.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 77,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "data-engineering",
+ "data-management"
+ ],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.manipulate-data-via-code.1-introduction",
+ "learn-dynamics.manipulate-data-via-code.2-retrieve-data",
+ "learn-dynamics.manipulate-data-via-code.3-sort-filter",
+ "learn-dynamics.manipulate-data-via-code.4-add-modify-delete",
+ "learn-dynamics.manipulate-data-via-code.5-field-functions",
+ "learn-dynamics.manipulate-data-via-code.control-database-locking-behavior",
+ "learn-dynamics.manipulate-data-via-code.6-exercise",
+ "learn-dynamics.manipulate-data-via-code.7-exercise",
+ "learn-dynamics.manipulate-data-via-code.8-check",
+ "learn-dynamics.manipulate-data-via-code.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.report-extensibility",
+ "title": "Extend reports in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to extend reports in Microsoft Dynamics 365 Business Central? In this module, you'll learn how to extend reports.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/report-extensibility",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 53,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "finance-accounting"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.report-extensibility.1-introduction",
+ "learn-dynamics.report-extensibility.2-anatomy",
+ "learn-dynamics.report-extensibility.3-report-extension-example",
+ "learn-dynamics.report-extensibility.4-check",
+ "learn-dynamics.report-extensibility.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.send-notifications",
+ "title": "Send notifications in Dynamics 365 Business Central",
+ "summary": "Discover how to create, send, and enhance user interactions through notifications in this comprehensive guide in Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/send-notifications",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 36,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "collaboration",
+ "communication"
+ ],
+ "learningPathUids": "learn-dynamics.tailor-roles-design-ui",
+ "unitUids": [
+ "learn-dynamics.send-notifications.1-introduction",
+ "learn-dynamics.send-notifications.2-notifications",
+ "learn-dynamics.send-notifications.3-create-send",
+ "learn-dynamics.send-notifications.4-exercise",
+ "learn-dynamics.send-notifications.5-check",
+ "learn-dynamics.send-notifications.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.set-up-onboarding-experiences",
+ "title": "Set up onboarding experiences in Dynamics 365 Business Central",
+ "summary": "Learn how to set up onboarding experiences in Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/set-up-onboarding-experiences",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 56,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.tailor-roles-design-ui",
+ "unitUids": [
+ "learn-dynamics.set-up-onboarding-experiences.introduction",
+ "learn-dynamics.set-up-onboarding-experiences.onboard-new-users",
+ "learn-dynamics.set-up-onboarding-experiences.get-users-started-checklist",
+ "learn-dynamics.set-up-onboarding-experiences.implement-tips-tour",
+ "learn-dynamics.set-up-onboarding-experiences.check",
+ "learn-dynamics.set-up-onboarding-experiences.summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation",
+ "title": "Implement test automation techniques in Business Central",
+ "summary": "Do you want to implement test automation techniques? In this module, you learn about implementing test automation techniques and where to find useful guides and documentation.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 91,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "process-workflow"
+ ],
+ "learningPathUids": "learn-dynamics.use-application-development-business-central",
+ "unitUids": [
+ "learn-dynamics.test-automation.1-introduction",
+ "learn-dynamics.test-automation.2-test-automation-responsibilities",
+ "learn-dynamics.test-automation.3-documentation-examples",
+ "learn-dynamics.test-automation.page-scripting-tool",
+ "learn-dynamics.test-automation.4-answers-about-testing",
+ "learn-dynamics.test-automation.5-check",
+ "learn-dynamics.test-automation.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-design-process",
+ "title": "Use the report design process in Dynamics 365 Business Central",
+ "summary": "Do you want to learn about the report design process for Microsoft Dynamics 365 Business Central? If so, this module will explain the different steps that are involved in creating a report.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-design-process",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 24,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.understand-report-design-process.1-introduction",
+ "learn-dynamics.understand-report-design-process.2-report-design-process",
+ "learn-dynamics.understand-report-design-process.3-use-snippet-create-report",
+ "learn-dynamics.understand-report-design-process.4-check",
+ "learn-dynamics.understand-report-design-process.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions",
+ "title": "Use report triggers, functions, and processing-only reports in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to work with report triggers and functions in Microsoft Dynamics 365 Business Central? In this module, you'll learn how to create processing-only reports and how to use the report triggers and functions.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 56,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.understand-report-triggers-functions.1-introduction",
+ "learn-dynamics.understand-report-triggers-functions.2-understand-report-trigger-execution",
+ "learn-dynamics.understand-report-triggers-functions.3-use-report-functions",
+ "learn-dynamics.understand-report-triggers-functions.4-create-processing-only-report",
+ "learn-dynamics.understand-report-triggers-functions.4a-adding-barcodes",
+ "learn-dynamics.understand-report-triggers-functions.5-exercise",
+ "learn-dynamics.understand-report-triggers-functions.6-check",
+ "learn-dynamics.understand-report-triggers-functions.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning",
+ "title": "Use AL-controlled barcode scanning in Dynamics 365 Business Central",
+ "summary": "Learn how Business Central provides barcode scanning capabilities in the mobile application and AL language.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 35,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.interface-with-business-central",
+ "unitUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning.introduction",
+ "learn-dynamics.use-al-controlled-barcode-scanning.scenarios-barcodes",
+ "learn-dynamics.use-al-controlled-barcode-scanning.add-button",
+ "learn-dynamics.use-al-controlled-barcode-scanning.invoke-scanning",
+ "learn-dynamics.use-al-controlled-barcode-scanning.integrate-scanners",
+ "learn-dynamics.use-al-controlled-barcode-scanning.check",
+ "learn-dynamics.use-al-controlled-barcode-scanning.summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle",
+ "title": "Use Application Lifecycle Management for Business Central",
+ "summary": "Do you want to know how to start implementing a version control system to manage your Business Central applications source code? With Azure DevOps you can do that, and much more. You'll learn about the features of the application lifecycle management tool Azure DevOps.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 47,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "devops"
+ ],
+ "learningPathUids": "learn-dynamics.continuous-integration",
+ "unitUids": [
+ "learn-dynamics.use-application-lifecycle.1-introduction",
+ "learn-dynamics.use-application-lifecycle.2-create-azure-devops",
+ "learn-dynamics.use-application-lifecycle.3-manage-azure-devops",
+ "learn-dynamics.use-application-lifecycle.4-introduction-devops-services",
+ "learn-dynamics.use-application-lifecycle.5-connect-devops-tokens",
+ "learn-dynamics.use-application-lifecycle.6-introduction-github",
+ "learn-dynamics.use-application-lifecycle.7-exercise",
+ "learn-dynamics.use-application-lifecycle.8-check",
+ "learn-dynamics.use-application-lifecycle.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-functions",
+ "title": "Use Azure Functions with Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to use Azure Functions with Business Central? This module will explain what an Azure function is and how to create one. You'll also learn how to integrate them with Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-functions",
+ "lastModified": "2026-08-17T18:23:00Z",
+ "durationInMinutes": 25,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.interface-with-business-central",
+ "unitUids": [
+ "learn-dynamics.use-azure-functions.1-introduction",
+ "learn-dynamics.use-azure-functions.2-create-basic",
+ "learn-dynamics.use-azure-functions.3-create-existing",
+ "learn-dynamics.use-azure-functions.4-use",
+ "learn-dynamics.use-azure-functions.6-check",
+ "learn-dynamics.use-azure-functions.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines",
+ "title": "Use Azure Pipelines for CI/CD with Business Central",
+ "summary": "Learn how to configure and set up an automated build process, create pipelines using YAML files, and set up a release process in Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 46,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "process-workflow"
+ ],
+ "learningPathUids": "learn-dynamics.continuous-integration",
+ "unitUids": [
+ "learn-dynamics.use-azure-pipelines.1-introduction",
+ "learn-dynamics.use-azure-pipelines.2-what-continuous-integration",
+ "learn-dynamics.use-azure-pipelines.3-configure-build-agents",
+ "learn-dynamics.use-azure-pipelines.4-create-build-pipeline",
+ "learn-dynamics.use-azure-pipelines.5-work-yaml-files",
+ "learn-dynamics.use-azure-pipelines.6-create-release-pipeline",
+ "learn-dynamics.use-azure-pipelines.7-exercise",
+ "learn-dynamics.use-azure-pipelines.8-check",
+ "learn-dynamics.use-azure-pipelines.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git",
+ "title": "Use branching and merging with Git for Business Central",
+ "summary": "Do you want to work with different branches in Git to separate your development code from the code in production? In this module we'll discuss how you can work with branches in Git and merge your modifications.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 64,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "devops"
+ ],
+ "learningPathUids": "learn-dynamics.continuous-integration",
+ "unitUids": [
+ "learn-dynamics.use-branch-merge-git.1-introduction",
+ "learn-dynamics.use-branch-merge-git.2-branch-commands",
+ "learn-dynamics.use-branch-merge-git.3-use-rebase",
+ "learn-dynamics.use-branch-merge-git.4-set-branch-policies",
+ "learn-dynamics.use-branch-merge-git.5-use-pull-requests",
+ "learn-dynamics.use-branch-merge-git.6-work-branch-strategies",
+ "learn-dynamics.use-branch-merge-git.7-exercise",
+ "learn-dynamics.use-branch-merge-git.8-check",
+ "learn-dynamics.use-branch-merge-git.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central",
+ "title": "Use Docker in your Business Central development process",
+ "summary": "Do you want to know how you can benefit from working with Docker and Microsoft Dynamics 365 Business Central? Docker offers images for every released version of Business Central in every available country or region.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 68,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.continuous-integration",
+ "unitUids": [
+ "learn-dynamics.use-docker-business-central.1-introduction",
+ "learn-dynamics.use-docker-business-central.2-docker-images-containers",
+ "learn-dynamics.use-docker-business-central.3-install-docker-windows",
+ "learn-dynamics.use-docker-business-central.4-process-isolation-hyper-v",
+ "learn-dynamics.use-docker-business-central.5-basic-docker-commands",
+ "learn-dynamics.use-docker-business-central.6-use-bc-container-helper",
+ "learn-dynamics.use-docker-business-central.7-exercise",
+ "learn-dynamics.use-docker-business-central.8-check",
+ "learn-dynamics.use-docker-business-central.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central",
+ "title": "Use document standards in Dynamics 365 Business Central",
+ "summary": "Do you plan to develop solutions involving documents? In this module, you learn how to work with document data and about document standards in Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 57,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.essential-development-standards",
+ "unitUids": [
+ "learn-dynamics.use-document-standards-business-central.1-introduction",
+ "learn-dynamics.use-document-standards-business-central.2-create-document-page",
+ "learn-dynamics.use-document-standards-business-central.3-use-initrecord-function",
+ "learn-dynamics.use-document-standards-business-central.4-use-testfield-function",
+ "learn-dynamics.use-document-standards-business-central.4a-use-round-function",
+ "learn-dynamics.use-document-standards-business-central.4b-exercise",
+ "learn-dynamics.use-document-standards-business-central.5-check",
+ "learn-dynamics.use-document-standards-business-central.6-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service",
+ "title": "Use model-driven apps and Dataverse with Business Central",
+ "summary": "This module focuses on the building blocks of Dataverse and model-driven apps as well as using them together with Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 83,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.power-apps-power-automate-business-central",
+ "unitUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service.1-introduction",
+ "learn-dynamics.use-model-driven-apps-common-data-service.2-entities-fields-common-data-service",
+ "learn-dynamics.use-model-driven-apps-common-data-service.3-create-entity-import-data",
+ "learn-dynamics.use-model-driven-apps-common-data-service.4-model-driven-apps",
+ "learn-dynamics.use-model-driven-apps-common-data-service.5-user-interface-logic",
+ "learn-dynamics.use-model-driven-apps-common-data-service.6-create-model-driven-app",
+ "learn-dynamics.use-model-driven-apps-common-data-service.7-exercise",
+ "learn-dynamics.use-model-driven-apps-common-data-service.8-check",
+ "learn-dynamics.use-model-driven-apps-common-data-service.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate",
+ "title": "Use Power Automate with Business Central",
+ "summary": "Discover the power of Power Automate in Business Central and explore the available actions and triggers.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 128,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.power-apps-power-automate-business-central",
+ "unitUids": [
+ "learn-dynamics.use-power-automate.1-introduction",
+ "learn-dynamics.use-power-automate.2-triggers",
+ "learn-dynamics.use-power-automate.3-create-power-automate",
+ "learn-dynamics.use-power-automate.4-item-approvals",
+ "learn-dynamics.use-power-automate.5-general-journal-approvals",
+ "learn-dynamics.use-power-automate.6-document-approvals",
+ "learn-dynamics.use-power-automate.7-business-scenarios",
+ "learn-dynamics.use-power-automate.8-create-button",
+ "learn-dynamics.use-power-automate.9-schedule",
+ "learn-dynamics.use-power-automate.10-troubleshoot",
+ "learn-dynamics.use-power-automate.11-exercise",
+ "learn-dynamics.use-power-automate.12-check",
+ "learn-dynamics.use-power-automate.13-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards",
+ "title": "Work with Azure Boards for project management in Business Central",
+ "summary": "Learn to manage development tasks, track project progress, assign work items and integrate Microsoft Teams with Azure DevOps in Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 62,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.continuous-integration",
+ "unitUids": [
+ "learn-dynamics.work-azure-boards.1-introduction",
+ "learn-dynamics.work-azure-boards.2-work-process-templates",
+ "learn-dynamics.work-azure-boards.3-configure-iterations",
+ "learn-dynamics.work-azure-boards.4-create-work-items",
+ "learn-dynamics.work-azure-boards.5-project-dashboards-wikis",
+ "learn-dynamics.work-azure-boards.6-teams-integrate-devops",
+ "learn-dynamics.work-azure-boards.7-exercise",
+ "learn-dynamics.work-azure-boards.8-check",
+ "learn-dynamics.work-azure-boards.9-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets",
+ "title": "Work with entitlements and permission sets in Dynamics 365 Business Central",
+ "summary": "Learn about entitlements and permission sets and how to extend them in Microsoft Dynamics 365 Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-entitlements-permission-sets",
+ "lastModified": "2026-09-03T23:14:00Z",
+ "durationInMinutes": 43,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "identity-access"
+ ],
+ "learningPathUids": "learn-dynamics.foundation-customize-business-central",
+ "unitUids": [
+ "learn-dynamics.work-entitlements-permission-sets.1-introduction",
+ "learn-dynamics.work-entitlements-permission-sets.2-get-started",
+ "learn-dynamics.work-entitlements-permission-sets.3-create-entitlements-permission-sets",
+ "learn-dynamics.work-entitlements-permission-sets.override-entitlements",
+ "learn-dynamics.work-entitlements-permission-sets.4-check",
+ "learn-dynamics.work-entitlements-permission-sets.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi",
+ "title": "Work with Power BI in Business Central",
+ "summary": "Do you want to know how to work with Microsoft Power BI in Dynamics 365 Business Central? If so, this module is for you. You'll learn how to deploy Business Central dashboards in Power BI and how to set up Power BI inside Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 65,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "business-applications"
+ ],
+ "learningPathUids": "learn-dynamics.use-power-bi",
+ "unitUids": [
+ "learn-dynamics.work-power-bi.1-introduction",
+ "learn-dynamics.work-power-bi.2-deploy-dashboards",
+ "learn-dynamics.work-power-bi.3-set-up-power-bi",
+ "learn-dynamics.work-power-bi.4-view-list-data",
+ "learn-dynamics.work-power-bi.add-report-parts",
+ "learn-dynamics.work-power-bi.5-exercise",
+ "learn-dynamics.work-power-bi.6-check",
+ "learn-dynamics.work-power-bi.7-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git",
+ "title": "Work with source control using Git in Visual Studio Code for Business Central",
+ "summary": "Explore how to work with local and remote Git repositories, including configuring Git and creating new repositories in Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 94,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "process-workflow"
+ ],
+ "learningPathUids": "learn-dynamics.continuous-integration",
+ "unitUids": [
+ "learn-dynamics.work-source-control-git.1-introduction",
+ "learn-dynamics.work-source-control-git.2-configure-git",
+ "learn-dynamics.work-source-control-git.3-local-remote-repositories",
+ "learn-dynamics.work-source-control-git.4-create-local-git",
+ "learn-dynamics.work-source-control-git.5-use-git-ignore",
+ "learn-dynamics.work-source-control-git.6-add-remove-files",
+ "learn-dynamics.work-source-control-git.7-get-status-repository",
+ "learn-dynamics.work-source-control-git.8-use-remote-git",
+ "learn-dynamics.work-source-control-git.9-clone-remote-git",
+ "learn-dynamics.work-source-control-git.10-work-remote-git",
+ "learn-dynamics.work-source-control-git.11-exercise",
+ "learn-dynamics.work-source-control-git.12-check",
+ "learn-dynamics.work-source-control-git.13-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api",
+ "title": "Work with the API in Dynamics 365 Business Central",
+ "summary": "Learn how to work with the API in Dynamics Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 43,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.interface-with-business-central",
+ "unitUids": [
+ "learn-dynamics.work-with-api.1-introduction",
+ "learn-dynamics.work-with-api.2-access",
+ "learn-dynamics.work-with-api.3-tips",
+ "learn-dynamics.work-with-api.4-limits",
+ "learn-dynamics.work-with-api.5-create-new",
+ "learn-dynamics.work-with-api.6-read",
+ "learn-dynamics.work-with-api.7-bound-actions",
+ "learn-dynamics.work-with-api.9-check",
+ "learn-dynamics.work-with-api.10-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-codeunits",
+ "title": "Work with codeunits in Dynamics 365 Business Central",
+ "summary": "Do you want to create your own codeunit and learn how to access the functions within that codeunit? If so, this module is the ideal place to start.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-codeunits",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 26,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.application-foundation-al-language",
+ "unitUids": [
+ "learn-dynamics.work-with-codeunits.1-introduction",
+ "learn-dynamics.work-with-codeunits.2-create-codeunit",
+ "learn-dynamics.work-with-codeunits.keyword",
+ "learn-dynamics.work-with-codeunits.3-check",
+ "learn-dynamics.work-with-codeunits.4-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central",
+ "title": "Work with master data in Dynamics 365 Business Central",
+ "summary": "Learn to enter or import master data into Dynamics 365 Business Central, including creating tables, implementing design patterns, and formatting fields.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 61,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "data-engineering",
+ "data-management"
+ ],
+ "learningPathUids": "learn-dynamics.essential-development-standards",
+ "unitUids": [
+ "learn-dynamics.work-with-master-data-business-central.1-introduction",
+ "learn-dynamics.work-with-master-data-business-central.2-setup-table-signature-design",
+ "learn-dynamics.work-with-master-data-business-central.3-master-table-page-standards",
+ "learn-dynamics.work-with-master-data-business-central.4-implement-series-pattern",
+ "learn-dynamics.work-with-master-data-business-central.5-use-blocked-field",
+ "learn-dynamics.work-with-master-data-business-central.6-frequently-used-table-properties",
+ "learn-dynamics.work-with-master-data-business-central.6a-exercise",
+ "learn-dynamics.work-with-master-data-business-central.7-check",
+ "learn-dynamics.work-with-master-data-business-central.8-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages",
+ "title": "Work with pages in Dynamics 365 Business Central",
+ "summary": "Do you want to create new pages in Business Central that have the same appearance as existing pages? This module focuses on how to create new pages. It will also show you how to enable users to search for specific pages.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 113,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.foundation-customize-business-central",
+ "unitUids": [
+ "learn-dynamics.work-with-pages.1-introduction",
+ "learn-dynamics.work-with-pages.2-get-started",
+ "learn-dynamics.work-with-pages.3-types",
+ "learn-dynamics.work-with-pages.4-properties",
+ "learn-dynamics.work-with-pages.5-layout",
+ "learn-dynamics.work-with-pages.6-link",
+ "learn-dynamics.work-with-pages.7-snippets",
+ "learn-dynamics.work-with-pages.8-controls",
+ "learn-dynamics.work-with-pages.use-rich-text-editor",
+ "learn-dynamics.work-with-pages.scan-barcodes",
+ "learn-dynamics.work-with-pages.9-search",
+ "learn-dynamics.work-with-pages.10-actions",
+ "learn-dynamics.work-with-pages.hidden-fields",
+ "learn-dynamics.work-with-pages.11-exercise",
+ "learn-dynamics.work-with-pages.12-exercise",
+ "learn-dynamics.work-with-pages.13-check",
+ "learn-dynamics.work-with-pages.14-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries",
+ "title": "Work with queries in Dynamics 365 Business Central",
+ "summary": "Learn how to work with the Query object in Dynamics 365 Business Central to join, filter, and aggregate data.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 79,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [
+ "data-analytics"
+ ],
+ "learningPathUids": "learn-dynamics.data-management-foundation-business-central",
+ "unitUids": [
+ "learn-dynamics.work-with-queries.1-introduction",
+ "learn-dynamics.work-with-queries.2-get-started",
+ "learn-dynamics.work-with-queries.3-create",
+ "learn-dynamics.work-with-queries.4-join-data",
+ "learn-dynamics.work-with-queries.5-filter-data",
+ "learn-dynamics.work-with-queries.6-aggregate-data",
+ "learn-dynamics.work-with-queries.7-al-function",
+ "learn-dynamics.work-with-queries.8-advanced-concepts",
+ "learn-dynamics.work-with-queries.optimize-performance",
+ "learn-dynamics.work-with-queries.9-check",
+ "learn-dynamics.work-with-queries.10-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-reports",
+ "title": "Work with reports in Dynamics 365 Business Central",
+ "summary": "Do you want to learn how to work with reports in Microsoft Dynamics 365 Business Central? In this module, you'll learn how to work with reports and the difference between preview, run, email, and print.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-reports",
+ "lastModified": "2026-08-20T17:11:00Z",
+ "durationInMinutes": 59,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.build-reports",
+ "unitUids": [
+ "learn-dynamics.work-with-reports.1-introduction",
+ "learn-dynamics.work-with-reports.2-preview-run",
+ "learn-dynamics.work-with-reports.set-layout",
+ "learn-dynamics.work-with-reports.3-printers",
+ "learn-dynamics.work-with-reports.4-check",
+ "learn-dynamics.work-with-reports.5-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables",
+ "title": "Work with tables in Dynamics 365 Business Central",
+ "summary": "Do you want to know how to create new tables in Business Central? If so, this module is for you. This module focuses on the different table types in Business Central and show you how to create new tables. Additionally, you learn how to use Visual Studio Code snippets to create a table, fields, and keys.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 99,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.foundation-customize-business-central",
+ "unitUids": [
+ "learn-dynamics.work-with-tables.1-introduction",
+ "learn-dynamics.work-with-tables.2-get-started",
+ "learn-dynamics.work-with-tables.3-types",
+ "learn-dynamics.work-with-tables.4-properties",
+ "learn-dynamics.work-with-tables.5-fields",
+ "learn-dynamics.work-with-tables.6-linking",
+ "learn-dynamics.work-with-tables.7-keys",
+ "learn-dynamics.work-with-tables.8-dropdown",
+ "learn-dynamics.work-with-tables.text-search",
+ "learn-dynamics.work-with-tables.9-calculated",
+ "learn-dynamics.work-with-tables.10-snippets",
+ "learn-dynamics.work-with-tables.11-exercise",
+ "learn-dynamics.work-with-tables.12-check",
+ "learn-dynamics.work-with-tables.13-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services",
+ "title": "Work with web services in Dynamics 365 Business Central",
+ "summary": "Use SOAP and OData to read and update records, and handle UI interaction in Business Central.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 67,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.interface-with-business-central",
+ "unitUids": [
+ "learn-dynamics.work-with-web-services.1-introduction",
+ "learn-dynamics.work-with-web-services.2-differences",
+ "learn-dynamics.work-with-web-services.3-authentication",
+ "learn-dynamics.work-with-web-services.4-enable-access",
+ "learn-dynamics.work-with-web-services.5-return-documents",
+ "learn-dynamics.work-with-web-services.6-request-records-odata",
+ "learn-dynamics.work-with-web-services.7-query-options",
+ "learn-dynamics.work-with-web-services.8-new-records",
+ "learn-dynamics.work-with-web-services.9-update-records",
+ "learn-dynamics.work-with-web-services.10-use-soap",
+ "learn-dynamics.work-with-web-services.11-request-records-soap",
+ "learn-dynamics.work-with-web-services.12-ui-interaction",
+ "learn-dynamics.work-with-web-services.14-check",
+ "learn-dynamics.work-with-web-services.15-summary"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports",
+ "title": "Work with XMLports in Dynamics 365 Business Central",
+ "summary": "Learn how to define and use XMLports in AL, understand different nodes and properties, and apply them in AL code.",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 65,
+ "levels": [
+ "intermediate"
+ ],
+ "subjects": [],
+ "learningPathUids": "learn-dynamics.data-management-foundation-business-central",
+ "unitUids": [
+ "learn-dynamics.work-with-xmlports.1-introduction",
+ "learn-dynamics.work-with-xmlports.2-get-started",
+ "learn-dynamics.work-with-xmlports.3-configure",
+ "learn-dynamics.work-with-xmlports.4-define-nodes",
+ "learn-dynamics.work-with-xmlports.5-design",
+ "learn-dynamics.work-with-xmlports.6-create",
+ "learn-dynamics.work-with-xmlports.7-al-functions",
+ "learn-dynamics.work-with-xmlports.8-exercise",
+ "learn-dynamics.work-with-xmlports.9-check",
+ "learn-dynamics.work-with-xmlports.10-summary"
+ ]
+ }
+ ],
+ "units": [
+ {
+ "uid": "learn-dynamics.access-rest-services.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.access-rest-services.2-http-classes",
+ "title": "Use the different HTTP classes and their functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/2-http-classes",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.access-rest-services.3-get-send-data",
+ "title": "Get data from and send data to an external REST service",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/3-get-send-data",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.access-rest-services.4-use-read-json",
+ "title": "Use and read JSON in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/4-use-read-json",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.access-rest-services.5-get-json-data",
+ "title": "Get JSON data from external REST services",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/5-get-json-data",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.access-rest-services.6-exercise",
+ "title": "Exercise - Connect to external REST services",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/6-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.access-rest-services.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/7-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.access-rest-services.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/access-rest-services/8-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.access-rest-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.2-add-report-definition",
+ "title": "Add an RDLC layout to a report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/2-add-report-definition",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.3-add-word-layout",
+ "title": "Add a Word layout to a report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/3-add-word-layout",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.4-exercise",
+ "title": "Exercise - Create a basic report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/4-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/5-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/6-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.add-excel-layout",
+ "title": "Add an Excel layout to a report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/add-excel-layout",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-layout-report.word-add-in",
+ "title": "Use the Word add-in for report layouts",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-layout-report/word-add-in",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.add-layout-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.10-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/10-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.2-reward",
+ "title": "Create the reward level table object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/2-reward",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.3-activation-code",
+ "title": "Create the activation code information table object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/3-activation-code",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.4-customer-rewards",
+ "title": "Create the Customer Rewards Management Setup table object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/4-customer-rewards",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.5-reward-list",
+ "title": "Create the Rewards Level List page object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/5-reward-list",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.6-exercise",
+ "title": "Exercise - Create the Activation Code Information table object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/6-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.7-exercise",
+ "title": "Exercise - Create the Customer Rewards Mgt Setup table object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/7-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.8-exercise",
+ "title": "Exercise - Create the Rewards Level List page object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/8-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-new-objects.9-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-new-objects/9-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.add-new-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-reports-tell-me.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-reports-tell-me/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.add-reports-tell-me"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-reports-tell-me.2-add-reports-tell-me",
+ "title": "Add reports to Tell Me",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-reports-tell-me/2-add-reports-tell-me",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.add-reports-tell-me"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-reports-tell-me.3-substitute-report",
+ "title": "Substitute a report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-reports-tell-me/3-substitute-report",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.add-reports-tell-me"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-reports-tell-me.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-reports-tell-me/4-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.add-reports-tell-me"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.add-reports-tell-me.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/add-reports-tell-me/5-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.add-reports-tell-me"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.10-exercise",
+ "title": "Exercise - Use built-in functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/10-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.11-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/11-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.12-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/12-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.2-interaction-functions",
+ "title": "Interaction methods",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/2-interaction-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.3-string-functions",
+ "title": "String functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/3-string-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.4-date-functions",
+ "title": "Date functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/4-date-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.5-numeric-functions",
+ "title": "Numeric functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/5-numeric-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.6-array-functions",
+ "title": "Array functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/6-array-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.7-list-functions",
+ "title": "List functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/7-list-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.8-system-functions",
+ "title": "System functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/8-system-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-built-in-functions.9-variable-functions",
+ "title": "Variable functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-built-in-functions/9-variable-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.al-built-in-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.al-statements"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements.2-compound",
+ "title": "Work with comment and compound statements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements/2-compound",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.al-statements"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements.3-conditional",
+ "title": "Work with conditional statements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements/3-conditional",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.al-statements"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements.4-repetitive",
+ "title": "Use repetitive statements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements/4-repetitive",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.al-statements"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements.5-exercise",
+ "title": "Exercise - Use conditional and compound statements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements/5-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.al-statements"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements.6-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements/6-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.al-statements"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.al-statements.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/al-statements/7-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.al-statements"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-monetization.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-monetization/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.application-monetization"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-monetization.2-responsibilities",
+ "title": "Understand application monetization responsibilities",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-monetization/2-responsibilities",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.application-monetization"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-monetization.3-documentation-examples",
+ "title": "Find application monetization documentation and examples",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-monetization/3-documentation-examples",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.application-monetization"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-monetization.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-monetization/4-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.application-monetization"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-monetization.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-monetization/5-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.application-monetization"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-performance-monitor.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-performance-monitor/1-introduction",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.application-performance-monitor"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-performance-monitor.2-prepare-application",
+ "title": "Prepare your application for optimal performance",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-performance-monitor/2-prepare-application",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.application-performance-monitor"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-performance-monitor.3-get-insights",
+ "title": "Get essential Application Insights",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-performance-monitor/3-get-insights",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 20,
+ "moduleUids": [
+ "learn-dynamics.application-performance-monitor"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-performance-monitor.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-performance-monitor/4-check",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.application-performance-monitor"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-performance-monitor.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-performance-monitor/5-summary",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.application-performance-monitor"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types/1-introduction",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.application-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.2-connect-vs-add-on",
+ "title": "Understand the difference between connect and add-on applications",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types/2-connect-vs-add-on",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.application-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.3-library-dependency-applications",
+ "title": "Understand library and dependency applications",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types/3-library-dependency-applications",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.application-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.4-find-development-resources",
+ "title": "Find development resources for building applications",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types/4-find-development-resources",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 11,
+ "moduleUids": [
+ "learn-dynamics.application-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.5-set-up-code-cop-tools",
+ "title": "Learn how to properly set up code cop tools for app validation",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types/5-set-up-code-cop-tools",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 20,
+ "moduleUids": [
+ "learn-dynamics.application-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.6-check",
+ "title": "Module assessment",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types/6-check",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.application-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.application-types.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/application-types/7-summary",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.application-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.2-rewards-wizard",
+ "title": "Create the Customer Rewards Wizard page object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/2-rewards-wizard",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.3-assisted-setup",
+ "title": "Add the Customer Rewards Wizard page to the assisted setup",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/3-assisted-setup",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.4-tooltips",
+ "title": "Add tooltips to your extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/4-tooltips",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.5-exercise",
+ "title": "Exercise - Create the Customer Rewards Wizard page object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/5-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.6-exercise",
+ "title": "Exercise - Add the Customer Rewards Wizard page to the assisted setup",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/6-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/7-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.assisted-setup-tooltips.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/assisted-setup-tooltips/8-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.assisted-setup-tooltips"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/bring-app-appsource/1-introduction",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.bring-app-appsource"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource.2-get-accounts",
+ "title": "Get your accounts in place",
+ "url": "https://learn.microsoft.com/en-us/training/modules/bring-app-appsource/2-get-accounts",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.bring-app-appsource"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource.3-marketing-validation",
+ "title": "Understand the marketing validation requirements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/bring-app-appsource/3-marketing-validation",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.bring-app-appsource"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource.4-technical-validation",
+ "title": "Understand the technical validation requirements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/bring-app-appsource/4-technical-validation",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.bring-app-appsource"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/bring-app-appsource/5-check",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.bring-app-appsource"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.bring-app-appsource.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/bring-app-appsource/6-summary",
+ "lastModified": "2026-08-26T23:12:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.bring-app-appsource"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup.2-assisted-setup",
+ "title": "Use Assisted Setup",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup/2-assisted-setup",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup.3-wizard-pages",
+ "title": "Create a wizard page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup/3-wizard-pages",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup.4-extensions",
+ "title": "Integrate with Assisted Setup in your extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup/4-extensions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup.5-exercise",
+ "title": "Exercise - Build a wizard page with Assisted Setup",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup/5-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup.6-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup/6-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-assisted-setup.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-assisted-setup/7-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.build-assisted-setup"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.2-apply-look-feel",
+ "title": "Apply the Business Central look and feel",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/2-apply-look-feel",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.3-create",
+ "title": "Build a control add-in for Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/3-create",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.4-asynchronous-considerations",
+ "title": "Asynchronous considerations for control add-ins",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/4-asynchronous-considerations",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.5-connect",
+ "title": "Connect control add-ins with Azure Functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/5-connect",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.6-exercise",
+ "title": "Exercise - Build a control add-in object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/6-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/7-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-control-add-ins.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-control-add-ins/8-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.build-control-add-ins"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.10-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/10-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.2-build-data-model",
+ "title": "Build the data model for Power BI",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/2-build-data-model",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.3-add-data-dimension",
+ "title": "Add a date dimension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/3-add-data-dimension",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.4-introduction-dax",
+ "title": "Introduction to DAX",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/4-introduction-dax",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.5-create-report",
+ "title": "Create a report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/5-create-report",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.6-build-dashboard",
+ "title": "Build a dashboard",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/6-build-dashboard",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.7-exercise",
+ "title": "Exercise - Add a calculated column and measure in Power BI Desktop using DAX",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/7-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.8-exercise",
+ "title": "Exercise - Visualize your data in Power BI Desktop",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/8-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.build-power-bi-report.9-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/build-power-bi-report/9-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.build-power-bi-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.2-snippet-support",
+ "title": "Snippet support",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/2-snippet-support",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.3-why-interfaces",
+ "title": "Importance of interfaces",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/3-why-interfaces",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.4-exercise",
+ "title": "Exercise - Create an interface",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/4-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/5-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/6-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.extending-interfaces",
+ "title": "Extending interfaces in AL",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/extending-interfaces",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-interfaces.type-testing",
+ "title": "Understand type testing and casting operators for interfaces",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/type-testing",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.interfaces"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration.check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration/check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.business-central-teams-integration"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration.create-tabs",
+ "title": "Create Business Central tabs for Teams",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration/create-tabs",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.business-central-teams-integration"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration.extend-teams-cards",
+ "title": "Extend Teams cards",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration/extend-teams-cards",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.business-central-teams-integration"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration.get-session-details",
+ "title": "Get relevant session and environment details for Teams integration",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration/get-session-details",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.business-central-teams-integration"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration.introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration/introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.business-central-teams-integration"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration.manage-install-use",
+ "title": "Manage, install, and use the Business Central App for Teams",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration/manage-install-use",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.business-central-teams-integration"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.business-central-teams-integration.summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/business-central-teams-integration/summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.business-central-teams-integration"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.complete-report-request-page.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/complete-report-request-page/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.complete-report-request-page"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.complete-report-request-page.2-design-request-page",
+ "title": "Design the request page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/complete-report-request-page/2-design-request-page",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.complete-report-request-page"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.complete-report-request-page.3-design-request-options",
+ "title": "Design the request options page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/complete-report-request-page/3-design-request-options",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.complete-report-request-page"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.complete-report-request-page.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/complete-report-request-page/4-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.complete-report-request-page"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.complete-report-request-page.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/complete-report-request-page/5-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.complete-report-request-page"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/1-introduction",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.2-data-app",
+ "title": "Build an app using data",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/2-data-app",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.3-blank-app",
+ "title": "Build an app from blank",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/3-blank-app",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.4-customizations",
+ "title": "Make basic customizations in an app",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/4-customizations",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 14,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.5-save-publish-share",
+ "title": "Save, publish, and share an app",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/5-save-publish-share",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.6-embed",
+ "title": "Embed an app",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/6-embed",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.7-exercise",
+ "title": "Exercise - Create the customer financial details app in Power Apps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/7-exercise",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/8-check",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-canvas-app.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-canvas-app/9-summary",
+ "lastModified": "2026-08-03T17:47:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.create-canvas-app"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/1-introduction",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.2-custom-connector",
+ "title": "Create a custom connector for Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/2-custom-connector",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 25,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.3-power-apps",
+ "title": "Use Business Central custom connector from Power Apps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/3-power-apps",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.4-power-automate",
+ "title": "Use a Business Central custom connector in Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/4-power-automate",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.5-share-custom-connectors",
+ "title": "Share Business Central custom connector across the organization",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/5-share-custom-connectors",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.6-exercise",
+ "title": "Exercise - Create a testing process",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/6-exercise",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/7-check",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-connector-power-platform.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-connector-power-platform/8-summary",
+ "lastModified": "2026-08-05T23:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.create-custom-connector-power-platform"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.2-custom-function",
+ "title": "Custom procedures",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/2-custom-function",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.3-local-global-function",
+ "title": "Identify differences between local and global procedures",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/3-local-global-function",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.4-local-global-variable",
+ "title": "Identify differences between local and global variables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/4-local-global-variable",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.5-pass",
+ "title": "Pass into a procedure",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/5-pass",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.6-parameter",
+ "title": "Identify differences between a parameter by value and by reference",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/6-parameter",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/7-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-custom-functions.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-custom-functions/8-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.create-custom-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/1-introduction",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.10-exercise",
+ "title": "Exercise - Import data into Power BI Desktop",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/10-exercise",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.11-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/11-check",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.12-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/12-summary",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.2-install",
+ "title": "Install Power BI Desktop",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/2-install",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.3-use-data-source",
+ "title": "Use Business Central as a data source in Power BI",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/3-use-data-source",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.5-develop-query-page-objects",
+ "title": "Develop query and page objects for Power BI",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/5-develop-query-page-objects",
+ "lastModified": "2025-08-20T23:10:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.6-mind-performance-impact",
+ "title": "Weigh the performance impact",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/6-mind-performance-impact",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.7-exercise",
+ "title": "Exercise - Create a dataset for a Power BI report in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/7-exercise",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.9-exercise",
+ "title": "Exercise - Publish and install the extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/9-exercise",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.create-power-bi-dataflow",
+ "title": "Create a Power BI dataflow with Business Central data",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/create-power-bi-dataflow",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.develop-api-query",
+ "title": "Develop API query and API page objects for Power BI",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/develop-api-query",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.create-data-set.use-dedicated-apis",
+ "title": "Use new dedicated APIs for financial reporting",
+ "url": "https://learn.microsoft.com/en-us/training/modules/create-data-set/use-dedicated-apis",
+ "lastModified": "2025-06-05T17:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.create-data-set"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.2-objects",
+ "title": "Add objects to search",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/2-objects",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.3-customizations",
+ "title": "Create page customizations",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/3-customizations",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.4-profiles",
+ "title": "Create profiles in application language",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/4-profiles",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.5-views",
+ "title": "Use and create views in application language",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/5-views",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.6-application-areas",
+ "title": "Extend application areas",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/6-application-areas",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/7-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/8-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.customize-ui-experience.extend-customize",
+ "title": "Extend and customize profiles",
+ "url": "https://learn.microsoft.com/en-us/training/modules/customize-ui-experience/extend-customize",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.customize-ui-experience"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.2-debug",
+ "title": "Debug your extension with Visual Studio Code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/2-debug",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.3-attach",
+ "title": "Use attach and debug with attach configurations",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/3-attach",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.3a-snapshot",
+ "title": "Implement snapshot debugging",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/3a-snapshot",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.4-rapid-application-development",
+ "title": "Work with Rapid Application Development",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/4-rapid-application-development",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.5-publish",
+ "title": "Publish and install an extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/5-publish",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.5a-performance-toolkit",
+ "title": "Work with the Business Central Performance Toolkit",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/5a-performance-toolkit",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.6-exercise",
+ "title": "Exercise - Create a table extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/6-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.7-exercise",
+ "title": "Exercise - Create a page extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/7-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/8-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/9-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.code-actions",
+ "title": "Use AL code actions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/code-actions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.database-wait-statistics",
+ "title": "Use Database Wait Statistics",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/database-wait-statistics",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.generate-help",
+ "title": "Generate help with the ALDoc tool",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/generate-help",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.projects-workspaces",
+ "title": "Configure projects and workspaces",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/projects-workspaces",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.protect-sensitive-values",
+ "title": "Protect sensitive values",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/protect-sensitive-values",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.recovery-failures",
+ "title": "Recovery from publishing failures",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/recovery-failures",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.debug-deploy-extension.resource-policy-settings",
+ "title": "Set Resource Exposure Policy settings",
+ "url": "https://learn.microsoft.com/en-us/training/modules/debug-deploy-extension/resource-policy-settings",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.debug-deploy-extension"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.design-data-model-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report.2-create-report-data-items",
+ "title": "Create report data items and their properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report/2-create-report-data-items",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.design-data-model-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report.3-add-columns-report-dataset",
+ "title": "Add columns to a report dataset",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report/3-add-columns-report-dataset",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.design-data-model-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report.4-link-order-indent-data-items",
+ "title": "Link, order, and indent data items",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report/4-link-order-indent-data-items",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.design-data-model-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report/5-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.design-data-model-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report/6-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.design-data-model-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.design-data-model-report.use-query",
+ "title": "Use a query to create a report dataset",
+ "url": "https://learn.microsoft.com/en-us/training/modules/design-data-model-report/use-query",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.design-data-model-report"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.2-create-page",
+ "title": "Create a Role Center page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/2-create-page",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.3-activity-parts",
+ "title": "Create activity page parts",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/3-activity-parts",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.4-cue-setup",
+ "title": "Integrate with the Cue Setup",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/4-cue-setup",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.5-role-center-lists",
+ "title": "Create Role Center lists",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/5-role-center-lists",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.6-headline-parts",
+ "title": "Implement headline parts",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/6-headline-parts",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.7-exercise",
+ "title": "Exercise - Create a Role Center page with an Activity page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/7-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/8-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.develop-role-center.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/develop-role-center/9-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.develop-role-center"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.2-upgrade-responsibilities",
+ "title": "Understand upgrade responsibilities and best practices",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/2-upgrade-responsibilities",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.3-installation-upgrade-codeunits",
+ "title": "Create proper installation and upgrade codeunits",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/3-installation-upgrade-codeunits",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 25,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.4-manage-apps",
+ "title": "Manage apps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/4-manage-apps",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.5-detect-breaking-changes",
+ "title": "Detect and avoid breaking changes",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/5-detect-breaking-changes",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.6-answers-about-updates",
+ "title": "Frequently asked questions about updating your Business Central App",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/6-answers-about-updates",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/7-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/8-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.consider-update-lifecycle",
+ "title": "Consider the update lifecycle",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/consider-update-lifecycle",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.easy-application-upgrade.transfer-data",
+ "title": "Transfer data between tables using DataTransfer",
+ "url": "https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/transfer-data",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.easy-application-upgrade"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.2-table-field-triggers",
+ "title": "Identify different table and field triggers",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/2-table-field-triggers",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.3-page-control-action-triggers",
+ "title": "Identify different page, control, and action triggers",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/3-page-control-action-triggers",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.4-event-based",
+ "title": "Event-based architecture",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/4-event-based",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.5-publish-subscribe",
+ "title": "Publish and subscribe to events",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/5-publish-subscribe",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.6-exercise",
+ "title": "Exercise - Events and triggers",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/6-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/7-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.events-triggers.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/events-triggers/8-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.events-triggers"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-functionality-using-events.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-functionality-using-events/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-functionality-using-events"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-functionality-using-events.2-programming-basics",
+ "title": "Learn the basics of AL programming language",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-functionality-using-events/2-programming-basics",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.extend-functionality-using-events"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-functionality-using-events.3-customer-rewards",
+ "title": "Create the Customer Rewards Extension Management codeunit object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-functionality-using-events/3-customer-rewards",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.extend-functionality-using-events"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-functionality-using-events.4-exercise",
+ "title": "Exercise - Create the Customer Rewards Extension Management codeunit object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-functionality-using-events/4-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.extend-functionality-using-events"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-functionality-using-events.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-functionality-using-events/5-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.extend-functionality-using-events"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-functionality-using-events.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-functionality-using-events/6-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.extend-functionality-using-events"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-pages.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-pages/1-introduction",
+ "lastModified": "2026-09-01T17:24:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-pages.2-get-started",
+ "title": "Get started with page extensions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-pages/2-get-started",
+ "lastModified": "2026-09-01T17:24:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-pages.3-properties",
+ "title": "Compare page extension properties with page properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-pages/3-properties",
+ "lastModified": "2026-09-01T17:24:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-pages.4-layout",
+ "title": "Personalize pages",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-pages/4-layout",
+ "lastModified": "2026-09-01T17:24:00Z",
+ "durationInMinutes": 20,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-pages.5-check",
+ "title": "Module assessment",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-pages/5-check",
+ "lastModified": "2026-09-01T17:24:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-pages.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-pages/6-summary",
+ "lastModified": "2026-09-01T17:24:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/1-introduction",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-table"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.2-get-started",
+ "title": "Get started with table extensions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/2-get-started",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-table"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.3-properties",
+ "title": "Compare table extension properties with table properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/3-properties",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-table"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/4-check",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-table"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/5-summary",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-table"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.add-field-group",
+ "title": "Add a new FieldGroup to an existing table",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/add-field-group",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-table"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-modify-existing-table.define-extension-objects",
+ "title": "Define extension objects in same app as their base object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/define-extension-objects",
+ "lastModified": "2026-08-17T23:09:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-modify-existing-table"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.2-customer-table",
+ "title": "Create the customer table extension object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/2-customer-table",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.3-customer-card",
+ "title": "Create the customer card page extension object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/3-customer-card",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.4-customer-list",
+ "title": "Create the customer list page extension object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/4-customer-list",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.5-exercise",
+ "title": "Exercise - Create the Customer table extension object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/5-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.6-exercise",
+ "title": "Exercise - Create the Customer Card page extension object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/6-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.7-exercise",
+ "title": "Exercise - Create the Customer List page extension object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/7-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/8-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.extend-tables-page-objects.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/extend-tables-page-objects/9-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.extend-tables-page-objects"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.handle-errors.check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/handle-errors/check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.handle-errors"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.handle-errors.collect-errors",
+ "title": "Collect errors",
+ "url": "https://learn.microsoft.com/en-us/training/modules/handle-errors/collect-errors",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.handle-errors"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.handle-errors.handle-errors",
+ "title": "Handle errors by using try methods",
+ "url": "https://learn.microsoft.com/en-us/training/modules/handle-errors/handle-errors",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.handle-errors"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.handle-errors.introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/handle-errors/introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.handle-errors"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.handle-errors.progress-windows",
+ "title": "Progress windows and the message, error, and confirm methods",
+ "url": "https://learn.microsoft.com/en-us/training/modules/handle-errors/progress-windows",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.handle-errors"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.handle-errors.summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/handle-errors/summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 1,
+ "moduleUids": [
+ "learn-dynamics.handle-errors"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.10-create-setup-tables",
+ "title": "Create setup tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/10-create-setup-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.11-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/11-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.12-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/12-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.2-define-table-types",
+ "title": "Define the different functional table types and characteristics",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/2-define-table-types",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.3-create-master-tables",
+ "title": "Create master tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/3-create-master-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.4-create-supplemental-tables",
+ "title": "Create supplemental tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/4-create-supplemental-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.5-create-subsidiary-tables",
+ "title": "Create subsidiary tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/5-create-subsidiary-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.6-create-ledger-tables",
+ "title": "Create ledger tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/6-create-ledger-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.7-create-register-tables",
+ "title": "Create register tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/7-create-register-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.8-create-journal-tables",
+ "title": "Create journal tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/8-create-journal-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.identify-table-types.9-create-document-tables",
+ "title": "Create document tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/identify-table-types/9-create-document-tables",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.identify-table-types"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-data-process-model-business-central.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-data-process-model-business-central/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.implement-data-process-model-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-data-process-model-business-central.2-standard-data-model",
+ "title": "Work with the standard data model",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-data-process-model-business-central/2-standard-data-model",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.implement-data-process-model-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-data-process-model-business-central.3-typical-data-triggers",
+ "title": "Use typical data triggers",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-data-process-model-business-central/3-typical-data-triggers",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.implement-data-process-model-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-data-process-model-business-central.4-standard-data-flow",
+ "title": "Adopt the standard data flow",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-data-process-model-business-central/4-standard-data-flow",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.implement-data-process-model-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-data-process-model-business-central.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-data-process-model-business-central/5-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.implement-data-process-model-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-data-process-model-business-central.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-data-process-model-business-central/6-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.implement-data-process-model-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-multilanguage-reports.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-multilanguage-reports/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.implement-multilanguage-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-multilanguage-reports.2-create-report-user-language",
+ "title": "Create a report in the language of the user",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-multilanguage-reports/2-create-report-user-language",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 11,
+ "moduleUids": [
+ "learn-dynamics.implement-multilanguage-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-multilanguage-reports.3-create-report-recipient-language",
+ "title": "Create a report in the language of the recipient",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-multilanguage-reports/3-create-report-recipient-language",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.implement-multilanguage-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-multilanguage-reports.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-multilanguage-reports/4-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.implement-multilanguage-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-multilanguage-reports.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-multilanguage-reports/5-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.implement-multilanguage-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-multilanguage-reports.define-regional-settings",
+ "title": "Define regional settings in reports",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-multilanguage-reports/define-regional-settings",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.implement-multilanguage-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-saas-techniques.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-saas-techniques/1-introduction",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.implement-saas-techniques"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-saas-techniques.2-build-trial",
+ "title": "Build a first trial experience",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-saas-techniques/2-build-trial",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 11,
+ "moduleUids": [
+ "learn-dynamics.implement-saas-techniques"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-saas-techniques.3-implement-saasification",
+ "title": "Implement SaaSification techniques when building your user interface",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-saas-techniques/3-implement-saasification",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.implement-saas-techniques"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-saas-techniques.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-saas-techniques/4-check",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.implement-saas-techniques"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.implement-saas-techniques.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/implement-saas-techniques/5-summary",
+ "lastModified": "2026-08-27T17:36:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.implement-saas-techniques"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.initialize-data-extension-installation.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/initialize-data-extension-installation/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.initialize-data-extension-installation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.initialize-data-extension-installation.2-install-logic",
+ "title": "Create the Customer Rewards Install Logic codeunit object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/initialize-data-extension-installation/2-install-logic",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.initialize-data-extension-installation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.initialize-data-extension-installation.3-exercise",
+ "title": "Exercise - Create the Customer Rewards Install Logic codeunit object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/initialize-data-extension-installation/3-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.initialize-data-extension-installation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.initialize-data-extension-installation.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/initialize-data-extension-installation/4-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.initialize-data-extension-installation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.initialize-data-extension-installation.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/initialize-data-extension-installation/5-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.initialize-data-extension-installation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.1-intro",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/1-intro",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.10-exercise",
+ "title": "Exercise - Use logical and relational expressions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/10-exercise",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.11-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/11-check",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.12-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/12-summary",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.2-get-started",
+ "title": "Get started with application language",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/2-get-started",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.3-variables",
+ "title": "Work with identifiers, syntax, and variables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/3-variables",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.4-data-types",
+ "title": "Discover intrinsic data types",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/4-data-types",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.5-options-enums",
+ "title": "Options and enums",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/5-options-enums",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.6-collections",
+ "title": "Work with collections",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/6-collections",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.7-assignments",
+ "title": "Use assignments and type conversions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/7-assignments",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.8-expressions",
+ "title": "Define different expression types",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/8-expressions",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-basics-al-programming.9-exercise",
+ "title": "Exercise - Discover the intrinsic data types",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-basics-al-programming/9-exercise",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.intro-basics-al-programming"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.1-intro",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/1-intro",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.10-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/10-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.11-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/11-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.2-get-started",
+ "title": "Get started with Visual Studio Code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/2-get-started",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.3-install",
+ "title": "Install the AL language extension in Visual Studio Code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/3-install",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.4-logical-database",
+ "title": "Discover the logical database and its objects",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/4-logical-database",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.5-extension",
+ "title": "Create a new Business Central extension in Visual Studio Code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/5-extension",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.6-json",
+ "title": "Work with JSON configuration files",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/6-json",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.7-al-language",
+ "title": "Configure the AL language extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/7-al-language",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.8-multiple",
+ "title": "Manage multiple AL extensions in one workspace",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/8-multiple",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.9-exercise",
+ "title": "Exercise - Create and run an AL extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/9-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.differentiate-apps",
+ "title": "Differentiate the base app and the system app",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/differentiate-apps",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.open-visual-studio-code-web-client",
+ "title": "Open Visual Studio Code from the web client",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/open-visual-studio-code-web-client",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.intro-development-environment.segment-code-reduce-conflicts",
+ "title": "Segment AL code and reduce naming conflicts with namespaces",
+ "url": "https://learn.microsoft.com/en-us/training/modules/intro-development-environment/segment-code-reduce-conflicts",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.intro-development-environment"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/1-introduction",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.2-file-object",
+ "title": "Work with the File object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/2-file-object",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.3-temp-blob-object",
+ "title": "Work with the Temp Blob object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/3-temp-blob-object",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.4-read-write-stream",
+ "title": "Read and write files by using streaming in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/4-read-write-stream",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.5-exercise",
+ "title": "Exercise - Read and write files",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/5-exercise",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.6-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/6-check",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/7-summary",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-basics-file-management.uploads-drop-zones",
+ "title": "Handle multiple file uploads and file drop zones",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-basics-file-management/uploads-drop-zones",
+ "lastModified": "2026-08-18T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.introduction-basics-file-management"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.2-process",
+ "title": "Introduction to the development process",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/2-process",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.3-setup",
+ "title": "Set up the development environment",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/3-setup",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.4-rewards",
+ "title": "Build a customer rewards extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/4-rewards",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.5-exercise",
+ "title": "Exercise - Set up the development environment",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/5-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.6-exercise",
+ "title": "Exercise - Create the reward level table object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/6-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/7-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-development-process.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-development-process/8-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.introduction-development-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.2-data-connectors",
+ "title": "Explore data connectors",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/2-data-connectors",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.3-business-central-connectors",
+ "title": "Explore Business Central connectors",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/3-business-central-connectors",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.4-power-apps",
+ "title": "Get started with Power Apps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/4-power-apps",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.5-power-automate",
+ "title": "Get started with Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/5-power-automate",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.6-embed-power-platform",
+ "title": "Embed Microsoft Power Platform in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/6-embed-power-platform",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/7-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/8-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-power-platform-business-central.use-cases",
+ "title": "Power Platform integration use cases",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-power-platform-business-central/use-cases",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.introduction-power-platform-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.2-learn-overview-report-description",
+ "title": "Report descriptions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/2-learn-overview-report-description",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.3-report-properties-triggers",
+ "title": "Report properties and triggers",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/3-report-properties-triggers",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.4-data-items-columns",
+ "title": "Data items and columns",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/4-data-items-columns",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.5-request-page",
+ "title": "Request page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/5-request-page",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.6-work-report-labels",
+ "title": "Work with report labels",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/6-work-report-labels",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.7-report-layouts",
+ "title": "Report layouts",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/7-report-layouts",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/8-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-report-components.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-report-components/9-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.introduction-report-components"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation/1-introduction",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation.2-test-applications",
+ "title": "Test applications in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation/2-test-applications",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation.3-install-run-test-toolkit",
+ "title": "Install and run the Test Toolkit",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation/3-install-run-test-toolkit",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation.4-run-standard-tests",
+ "title": "Run the standard tests",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation/4-run-standard-tests",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation.5-create-test-code-units",
+ "title": "Create your own test codeunits with a test app",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation/5-create-test-code-units",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation.6-check",
+ "title": "Module assessment",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation/6-check",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.introduction-test-automation.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/introduction-test-automation/7-summary",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.introduction-test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manage-multilanguage-development.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manage-multilanguage-development/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.manage-multilanguage-development"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manage-multilanguage-development.2-translation-files",
+ "title": "Create and use translation files",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manage-multilanguage-development/2-translation-files",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.manage-multilanguage-development"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manage-multilanguage-development.3-automate",
+ "title": "Use Azure Translator Text to automate translation",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manage-multilanguage-development/3-automate",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.manage-multilanguage-development"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manage-multilanguage-development.4-exercise",
+ "title": "Exercise - Multilanguage development",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manage-multilanguage-development/4-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.manage-multilanguage-development"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manage-multilanguage-development.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manage-multilanguage-development/5-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.manage-multilanguage-development"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manage-multilanguage-development.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manage-multilanguage-development/6-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.manage-multilanguage-development"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.2-retrieve-data",
+ "title": "Retrieve data from the database with AL statements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/2-retrieve-data",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.3-sort-filter",
+ "title": "Sort and filter data in code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/3-sort-filter",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.4-add-modify-delete",
+ "title": "Add, modify, or delete data with AL",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/4-add-modify-delete",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.5-field-functions",
+ "title": "Use different field functions in AL",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/5-field-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.6-exercise",
+ "title": "Exercise - Use data manipulation statements",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/6-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.7-exercise",
+ "title": "Exercise - Custom functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/7-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/8-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/9-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.manipulate-data-via-code.control-database-locking-behavior",
+ "title": "Control database locking behavior",
+ "url": "https://learn.microsoft.com/en-us/training/modules/manipulate-data-via-code/control-database-locking-behavior",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.manipulate-data-via-code"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.report-extensibility.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/report-extensibility/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.report-extensibility"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.report-extensibility.2-anatomy",
+ "title": "Anatomy of a report extension",
+ "url": "https://learn.microsoft.com/en-us/training/modules/report-extensibility/2-anatomy",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 20,
+ "moduleUids": [
+ "learn-dynamics.report-extensibility"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.report-extensibility.3-report-extension-example",
+ "title": "Examples of report extensions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/report-extensibility/3-report-extension-example",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 24,
+ "moduleUids": [
+ "learn-dynamics.report-extensibility"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.report-extensibility.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/report-extensibility/4-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.report-extensibility"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.report-extensibility.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/report-extensibility/5-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.report-extensibility"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.send-notifications.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/send-notifications/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.send-notifications"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.send-notifications.2-notifications",
+ "title": "Work with notifications",
+ "url": "https://learn.microsoft.com/en-us/training/modules/send-notifications/2-notifications",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.send-notifications"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.send-notifications.3-create-send",
+ "title": "Create and send notifications",
+ "url": "https://learn.microsoft.com/en-us/training/modules/send-notifications/3-create-send",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.send-notifications"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.send-notifications.4-exercise",
+ "title": "Exercise - Create a notification",
+ "url": "https://learn.microsoft.com/en-us/training/modules/send-notifications/4-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.send-notifications"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.send-notifications.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/send-notifications/5-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.send-notifications"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.send-notifications.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/send-notifications/6-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.send-notifications"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.set-up-onboarding-experiences.check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/set-up-onboarding-experiences/check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.set-up-onboarding-experiences"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.set-up-onboarding-experiences.get-users-started-checklist",
+ "title": "Get users started with the checklist",
+ "url": "https://learn.microsoft.com/en-us/training/modules/set-up-onboarding-experiences/get-users-started-checklist",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.set-up-onboarding-experiences"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.set-up-onboarding-experiences.implement-tips-tour",
+ "title": "Implement teaching tips and in-app tours",
+ "url": "https://learn.microsoft.com/en-us/training/modules/set-up-onboarding-experiences/implement-tips-tour",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 20,
+ "moduleUids": [
+ "learn-dynamics.set-up-onboarding-experiences"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.set-up-onboarding-experiences.introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/set-up-onboarding-experiences/introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.set-up-onboarding-experiences"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.set-up-onboarding-experiences.onboard-new-users",
+ "title": "Greet new users with the welcome banner",
+ "url": "https://learn.microsoft.com/en-us/training/modules/set-up-onboarding-experiences/onboard-new-users",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.set-up-onboarding-experiences"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.set-up-onboarding-experiences.summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/set-up-onboarding-experiences/summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.set-up-onboarding-experiences"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation/1-introduction",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.2-test-automation-responsibilities",
+ "title": "Understand test automation responsibilities",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation/2-test-automation-responsibilities",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.3-documentation-examples",
+ "title": "Find test automation documentation and examples",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation/3-documentation-examples",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.4-answers-about-testing",
+ "title": "Frequently asked questions about testing your Business Central App",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation/4-answers-about-testing",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation/5-check",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation/6-summary",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.test-automation.page-scripting-tool",
+ "title": "Use the in-client page scripting tool for acceptance testing",
+ "url": "https://learn.microsoft.com/en-us/training/modules/test-automation/page-scripting-tool",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 50,
+ "moduleUids": [
+ "learn-dynamics.test-automation"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-design-process.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-design-process/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.understand-report-design-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-design-process.2-report-design-process",
+ "title": "Report design process",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-design-process/2-report-design-process",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.understand-report-design-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-design-process.3-use-snippet-create-report",
+ "title": "Use a snippet to create a report object",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-design-process/3-use-snippet-create-report",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.understand-report-design-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-design-process.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-design-process/4-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.understand-report-design-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-design-process.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-design-process/5-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.understand-report-design-process"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/1-introduction",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.2-understand-report-trigger-execution",
+ "title": "Report trigger implementation flow",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/2-understand-report-trigger-execution",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.3-use-report-functions",
+ "title": "Use report functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/3-use-report-functions",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.4-create-processing-only-report",
+ "title": "Create a processing-only report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/4-create-processing-only-report",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.4a-adding-barcodes",
+ "title": "Adding barcodes to a report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/4a-adding-barcodes",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.5-exercise",
+ "title": "Exercise - Create a processing-only report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/5-exercise",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.6-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/6-check",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.understand-report-triggers-functions.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/understand-report-triggers-functions/7-summary",
+ "lastModified": "2026-08-27T23:37:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.understand-report-triggers-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning.add-button",
+ "title": "Add a barcode-scanning UI button on a field",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning/add-button",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning.check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning/check",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning.integrate-scanners",
+ "title": "Integrate dedicated barcode scanners",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning/integrate-scanners",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning.introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning/introduction",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 1,
+ "moduleUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning.invoke-scanning",
+ "title": "Invoke barcode scanning programmatically from AL",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning/invoke-scanning",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning.scenarios-barcodes",
+ "title": "Supported scenarios and barcodes",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning/scenarios-barcodes",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-al-controlled-barcode-scanning.summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-al-controlled-barcode-scanning/summary",
+ "lastModified": "2026-08-20T23:07:00Z",
+ "durationInMinutes": 1,
+ "moduleUids": [
+ "learn-dynamics.use-al-controlled-barcode-scanning"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/1-introduction",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.2-create-azure-devops",
+ "title": "Create an Azure DevOps organization",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/2-create-azure-devops",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.3-manage-azure-devops",
+ "title": "Manage Azure DevOps Projects",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/3-manage-azure-devops",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.4-introduction-devops-services",
+ "title": "Introduction to Azure DevOps Services",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/4-introduction-devops-services",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.5-connect-devops-tokens",
+ "title": "Connect to Azure DevOps via Personal Access Tokens",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/5-connect-devops-tokens",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.6-introduction-github",
+ "title": "Introduction to GitHub",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/6-introduction-github",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.7-exercise",
+ "title": "Exercise - Create an Azure DevOps organization and project",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/7-exercise",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/8-check",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-application-lifecycle.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-application-lifecycle/9-summary",
+ "lastModified": "2026-08-28T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-application-lifecycle"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-functions.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-functions/1-introduction",
+ "lastModified": "2026-08-17T18:23:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-azure-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-functions.2-create-basic",
+ "title": "Create basic Azure functions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-functions/2-create-basic",
+ "lastModified": "2026-08-17T18:23:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-azure-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-functions.3-create-existing",
+ "title": "Create an Azure function",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-functions/3-create-existing",
+ "lastModified": "2026-08-17T18:23:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-azure-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-functions.4-use",
+ "title": "Use an Azure function in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-functions/4-use",
+ "lastModified": "2026-08-17T18:23:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-azure-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-functions.6-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-functions/6-check",
+ "lastModified": "2026-08-17T18:23:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.use-azure-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-functions.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-functions/7-summary",
+ "lastModified": "2026-08-17T18:23:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-azure-functions"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/1-introduction",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.2-what-continuous-integration",
+ "title": "What is CI/CD?",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/2-what-continuous-integration",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.3-configure-build-agents",
+ "title": "Configure build agents",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/3-configure-build-agents",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.4-create-build-pipeline",
+ "title": "Create a build pipeline",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/4-create-build-pipeline",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.5-work-yaml-files",
+ "title": "Work with YAML files",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/5-work-yaml-files",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.6-create-release-pipeline",
+ "title": "Create a release pipeline",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/6-create-release-pipeline",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.7-exercise",
+ "title": "Exercise - Use Azure Pipelines for CI/CD with Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/7-exercise",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/8-check",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-azure-pipelines.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-azure-pipelines/9-summary",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-azure-pipelines"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/1-introduction",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.2-branch-commands",
+ "title": "Branch commands in Git",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/2-branch-commands",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.3-use-rebase",
+ "title": "Use Rebase in Git",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/3-use-rebase",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.4-set-branch-policies",
+ "title": "Set branch policies in Azure DevOps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/4-set-branch-policies",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 14,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.5-use-pull-requests",
+ "title": "Use pull requests in Git with Azure DevOps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/5-use-pull-requests",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.6-work-branch-strategies",
+ "title": "Work with different branching strategies",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/6-work-branch-strategies",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.7-exercise",
+ "title": "Exercise - Use branching and merging with Git",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/7-exercise",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/8-check",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-branch-merge-git.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-branch-merge-git/9-summary",
+ "lastModified": "2026-08-28T17:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.use-branch-merge-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/1-introduction",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.2-docker-images-containers",
+ "title": "Work with Docker images and containers",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/2-docker-images-containers",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.3-install-docker-windows",
+ "title": "Install Docker on Windows",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/3-install-docker-windows",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.4-process-isolation-hyper-v",
+ "title": "Process Isolation vs. Hyper-V Isolation",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/4-process-isolation-hyper-v",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.5-basic-docker-commands",
+ "title": "Basic Docker commands",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/5-basic-docker-commands",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.6-use-bc-container-helper",
+ "title": "Use the BcContainerHelper",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/6-use-bc-container-helper",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.7-exercise",
+ "title": "Exercise - Use Docker to test the latest Business Central version",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/7-exercise",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/8-check",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-docker-business-central.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-docker-business-central/9-summary",
+ "lastModified": "2026-08-13T17:20:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-docker-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.2-create-document-page",
+ "title": "Create a document page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/2-create-document-page",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.3-use-initrecord-function",
+ "title": "Use the InitRecord function",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/3-use-initrecord-function",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.4-use-testfield-function",
+ "title": "Use the TestField function",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/4-use-testfield-function",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.4a-use-round-function",
+ "title": "Use the Round function",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/4a-use-round-function",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.4b-exercise",
+ "title": "Exercise - Create example documents",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/4b-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.5-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/5-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-document-standards-business-central.6-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/6-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-document-standards-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/1-introduction",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.2-entities-fields-common-data-service",
+ "title": "Identify tables and columns in Microsoft Dataverse",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/2-entities-fields-common-data-service",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.3-create-entity-import-data",
+ "title": "Create a table and connection to import data from Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/3-create-entity-import-data",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 25,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.4-model-driven-apps",
+ "title": "Get started with model-driven apps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/4-model-driven-apps",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.5-user-interface-logic",
+ "title": "Explore the user interface and logic in model-driven apps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/5-user-interface-logic",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.6-create-model-driven-app",
+ "title": "Create a model-driven app based on Business Central data",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/6-create-model-driven-app",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 17,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.7-exercise",
+ "title": "Exercise - Create a table in Microsoft Dataverse",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/7-exercise",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/8-check",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-model-driven-apps-common-data-service.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-model-driven-apps-common-data-service/9-summary",
+ "lastModified": "2026-08-14T23:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-model-driven-apps-common-data-service"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/1-introduction",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.10-troubleshoot",
+ "title": "Troubleshoot and monitor flows",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/10-troubleshoot",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.11-exercise",
+ "title": "Exercise - Create a flow for sending emails when a new item is created in Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/11-exercise",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.12-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/12-check",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.13-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/13-summary",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.2-triggers",
+ "title": "Explore Business Central triggers in Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/2-triggers",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.3-create-power-automate",
+ "title": "Create a Power Automate flow from scratch",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/3-create-power-automate",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.4-item-approvals",
+ "title": "Create customer, vendor, and item approvals in Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/4-item-approvals",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 20,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.5-general-journal-approvals",
+ "title": "Create approvals in a general journal with Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/5-general-journal-approvals",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.6-document-approvals",
+ "title": "Create documents approvals with Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/6-document-approvals",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 9,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.7-business-scenarios",
+ "title": "Create Power Automate flows for different business scenarios",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/7-business-scenarios",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 22,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.8-create-button",
+ "title": "Create a button or instant flow in Power Automate",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/8-create-button",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.use-power-automate.9-schedule",
+ "title": "Run a Power Automate flow on a schedule",
+ "url": "https://learn.microsoft.com/en-us/training/modules/use-power-automate/9-schedule",
+ "lastModified": "2026-08-10T18:36:00Z",
+ "durationInMinutes": 9,
+ "moduleUids": [
+ "learn-dynamics.use-power-automate"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/1-introduction",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.2-work-process-templates",
+ "title": "Work with the process templates",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/2-work-process-templates",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.3-configure-iterations",
+ "title": "Configure iterations in Azure Boards",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/3-configure-iterations",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 13,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.4-create-work-items",
+ "title": "Create work items and link to code changes",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/4-create-work-items",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.5-project-dashboards-wikis",
+ "title": "Work with project dashboards and wikis",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/5-project-dashboards-wikis",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.6-teams-integrate-devops",
+ "title": "Use Microsoft Teams to integrate with Azure DevOps",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/6-teams-integrate-devops",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.7-exercise",
+ "title": "Exercise - Work with Azure Boards",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/7-exercise",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.8-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/8-check",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-azure-boards.9-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-azure-boards/9-summary",
+ "lastModified": "2026-08-11T23:09:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-azure-boards"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-entitlements-permission-sets/1-introduction",
+ "lastModified": "2026-09-03T23:14:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-entitlements-permission-sets"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.2-get-started",
+ "title": "Get started with entitlements and permissions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-entitlements-permission-sets/2-get-started",
+ "lastModified": "2026-09-03T23:14:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-entitlements-permission-sets"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.3-create-entitlements-permission-sets",
+ "title": "Create entitlements and permission sets",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-entitlements-permission-sets/3-create-entitlements-permission-sets",
+ "lastModified": "2026-09-03T23:14:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.work-entitlements-permission-sets"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.4-check",
+ "title": "Module assessment",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-entitlements-permission-sets/4-check",
+ "lastModified": "2026-09-03T23:14:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-entitlements-permission-sets"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-entitlements-permission-sets/5-summary",
+ "lastModified": "2026-09-03T23:14:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-entitlements-permission-sets"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-entitlements-permission-sets.override-entitlements",
+ "title": "Override entitlements with inherent permissions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-entitlements-permission-sets/override-entitlements",
+ "lastModified": "2026-09-03T23:14:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-entitlements-permission-sets"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/1-introduction",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.2-deploy-dashboards",
+ "title": "Deploy Business Central dashboards in Power BI",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/2-deploy-dashboards",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.3-set-up-power-bi",
+ "title": "Set up Power BI in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/3-set-up-power-bi",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.4-view-list-data",
+ "title": "View list data in Power BI reports in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/4-view-list-data",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.5-exercise",
+ "title": "Exercise - Embed your report in Business Central",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/5-exercise",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.6-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/6-check",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.7-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/7-summary",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-power-bi.add-report-parts",
+ "title": "Adding Power BI Report Parts to pages",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-power-bi/add-report-parts",
+ "lastModified": "2026-09-02T17:07:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.work-power-bi"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/1-introduction",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.10-work-remote-git",
+ "title": "Work with a remote Git Repository",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/10-work-remote-git",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.11-exercise",
+ "title": "Exercise - Source control with Git",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/11-exercise",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.12-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/12-check",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.13-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/13-summary",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.2-configure-git",
+ "title": "Configure Git",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/2-configure-git",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.3-local-remote-repositories",
+ "title": "Compare and contrast local and remote repositories",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/3-local-remote-repositories",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.4-create-local-git",
+ "title": "Create a local Git repository",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/4-create-local-git",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.5-use-git-ignore",
+ "title": "Use the .gitignore file",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/5-use-git-ignore",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.6-add-remove-files",
+ "title": "Add and remove files in Git",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/6-add-remove-files",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.7-get-status-repository",
+ "title": "Get the status of your Git repository",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/7-get-status-repository",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.8-use-remote-git",
+ "title": "Use a remote Git repository",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/8-use-remote-git",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-source-control-git.9-clone-remote-git",
+ "title": "Clone a remote Git repository",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-source-control-git/9-clone-remote-git",
+ "lastModified": "2026-08-24T17:14:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-source-control-git"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.10-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/10-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.2-access",
+ "title": "Access Business Central API",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/2-access",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.3-tips",
+ "title": "Tips for working with APIs",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/3-tips",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.4-limits",
+ "title": "Work with API limits",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/4-limits",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.5-create-new",
+ "title": "Create new APIs",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/5-create-new",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.6-read",
+ "title": "Read, create, and update by using API",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/6-read",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.7-bound-actions",
+ "title": "API and OData bound actions",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/7-bound-actions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-api.9-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-api/9-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-api"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-codeunits.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-codeunits/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-codeunits"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-codeunits.2-create-codeunit",
+ "title": "Create and access a codeunit",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-codeunits/2-create-codeunit",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-with-codeunits"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-codeunits.3-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-codeunits/3-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-codeunits"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-codeunits.4-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-codeunits/4-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-codeunits"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-codeunits.keyword",
+ "title": "Use keywords for codeunit self-reference",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-codeunits/keyword",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-codeunits"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/1-introduction",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.2-setup-table-signature-design",
+ "title": "Use the setup table and Singleton Design Pattern",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/2-setup-table-signature-design",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.3-master-table-page-standards",
+ "title": "Use master table and page standards",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/3-master-table-page-standards",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.4-implement-series-pattern",
+ "title": "Implement the number series pattern",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/4-implement-series-pattern",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.5-use-blocked-field",
+ "title": "Use the Blocked field and the Blocked Entity Design Pattern",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/5-use-blocked-field",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.6-frequently-used-table-properties",
+ "title": "Implement frequently used table properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/6-frequently-used-table-properties",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.6a-exercise",
+ "title": "Exercise - Add tables and pages for master data",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/6a-exercise",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.7-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/7-check",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-master-data-business-central.8-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-master-data-business-central/8-summary",
+ "lastModified": "2026-08-18T23:35:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-master-data-business-central"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.10-actions",
+ "title": "Define actions on a page and its properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/10-actions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 18,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.11-exercise",
+ "title": "Exercise - Create a Card page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/11-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.12-exercise",
+ "title": "Exercise - Create a List page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/12-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.13-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/13-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.14-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/14-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.2-get-started",
+ "title": "Get started with pages",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/2-get-started",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.3-types",
+ "title": "Identify different page types",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/3-types",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.4-properties",
+ "title": "Configure the different page properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/4-properties",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.5-layout",
+ "title": "Build a page layout by using controls",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/5-layout",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.6-link",
+ "title": "Link pages with page parts",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/6-link",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.7-snippets",
+ "title": "Use snippets in Visual Studio Code to create pages",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/7-snippets",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.8-controls",
+ "title": "Set different control properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/8-controls",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.9-search",
+ "title": "Enable users to search for a page",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/9-search",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.hidden-fields",
+ "title": "Add existing hidden fields to pages",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/hidden-fields",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.scan-barcodes",
+ "title": "Scan barcodes in the mobile app",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/scan-barcodes",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-pages.use-rich-text-editor",
+ "title": "Use the built-in rich text editor to enter data",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-pages/use-rich-text-editor",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-pages"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.10-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/10-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.2-get-started",
+ "title": "Get started with queries",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/2-get-started",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.3-create",
+ "title": "Create a query in Visual Studio Code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/3-create",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.4-join-data",
+ "title": "Join data in queries",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/4-join-data",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.5-filter-data",
+ "title": "Filter data in queries",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/5-filter-data",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.6-aggregate-data",
+ "title": "Aggregate and sort data in a query",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/6-aggregate-data",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.7-al-function",
+ "title": "Access queries from AL",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/7-al-function",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.8-advanced-concepts",
+ "title": "Advanced query concepts",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/8-advanced-concepts",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.9-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/9-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-queries.optimize-performance",
+ "title": "Optimize performance in Query objects",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-queries/optimize-performance",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-queries"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-reports.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-reports/1-introduction",
+ "lastModified": "2026-08-20T17:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-reports.2-preview-run",
+ "title": "Preview and run reports",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-reports/2-preview-run",
+ "lastModified": "2026-08-20T17:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.work-with-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-reports.3-printers",
+ "title": "Set up printers",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-reports/3-printers",
+ "lastModified": "2026-08-20T17:11:00Z",
+ "durationInMinutes": 16,
+ "moduleUids": [
+ "learn-dynamics.work-with-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-reports.4-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-reports/4-check",
+ "lastModified": "2026-08-20T17:11:00Z",
+ "durationInMinutes": 4,
+ "moduleUids": [
+ "learn-dynamics.work-with-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-reports.5-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-reports/5-summary",
+ "lastModified": "2026-08-20T17:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-reports.set-layout",
+ "title": "Set the layout used by a report",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-reports/set-layout",
+ "lastModified": "2026-08-20T17:11:00Z",
+ "durationInMinutes": 20,
+ "moduleUids": [
+ "learn-dynamics.work-with-reports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.10-snippets",
+ "title": "Create a table in Visual Studio Code with snippets",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/10-snippets",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.11-exercise",
+ "title": "Exercise - Create a table",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/11-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.12-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/12-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.13-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/13-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.2-get-started",
+ "title": "Get started with tables",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/2-get-started",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 2,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.3-types",
+ "title": "Identify the different table types",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/3-types",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.4-properties",
+ "title": "Configure the different table properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/4-properties",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 12,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.5-fields",
+ "title": "Define fields and their properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/5-fields",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.6-linking",
+ "title": "Link different tables with table relations",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/6-linking",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.7-keys",
+ "title": "Create primary and secondary keys on a table",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/7-keys",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 15,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.8-dropdown",
+ "title": "Work with DropDown and Brick field groups",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/8-dropdown",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.9-calculated",
+ "title": "Create and use calculated fields",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/9-calculated",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-tables.text-search",
+ "title": "Enable optimized text search on table fields",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-tables/text-search",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-tables"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/1-introduction",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.10-use-soap",
+ "title": "Use SOAP web services",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/10-use-soap",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.11-request-records-soap",
+ "title": "Request records with SOAP",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/11-request-records-soap",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.12-ui-interaction",
+ "title": "Handle UI interaction when working with web services",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/12-ui-interaction",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.14-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/14-check",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.15-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/15-summary",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.2-differences",
+ "title": "Define differences between SOAP, OData, REST, and API",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/2-differences",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.3-authentication",
+ "title": "Web service authentication",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/3-authentication",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.4-enable-access",
+ "title": "Enable access to OData web services",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/4-enable-access",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.5-return-documents",
+ "title": "Work with different OData return documents",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/5-return-documents",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.6-request-records-odata",
+ "title": "Request records with OData",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/6-request-records-odata",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.7-query-options",
+ "title": "Work with OData query options",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/7-query-options",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.8-new-records",
+ "title": "Create new records with OData",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/8-new-records",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-web-services.9-update-records",
+ "title": "Update records with OData",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-web-services/9-update-records",
+ "lastModified": "2026-08-19T17:07:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-web-services"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.1-introduction",
+ "title": "Introduction",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/1-introduction",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.10-summary",
+ "title": "Summary",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/10-summary",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.2-get-started",
+ "title": "Get started with XMLports",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/2-get-started",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 3,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.3-configure",
+ "title": "Configure different XMLport properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/3-configure",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 8,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.4-define-nodes",
+ "title": "Define nodes and their properties",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/4-define-nodes",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 6,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.5-design",
+ "title": "Design XMLports",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/5-design",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 7,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.6-create",
+ "title": "Create an XMLport by using snippets in Visual Studio Code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/6-create",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.7-al-functions",
+ "title": "Use XMLports in AL code",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/7-al-functions",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 5,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.8-exercise",
+ "title": "Exercise - Create an XMLport to export XML data",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/8-exercise",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ },
+ {
+ "uid": "learn-dynamics.work-with-xmlports.9-check",
+ "title": "Check your knowledge",
+ "url": "https://learn.microsoft.com/en-us/training/modules/work-with-xmlports/9-check",
+ "lastModified": "2026-06-11T23:11:00Z",
+ "durationInMinutes": 10,
+ "moduleUids": [
+ "learn-dynamics.work-with-xmlports"
+ ]
+ }
+ ]
+}
diff --git a/evaluation/README.md b/evaluation/README.md
index 7063baf..40954eb 100644
--- a/evaluation/README.md
+++ b/evaluation/README.md
@@ -54,3 +54,50 @@ This credential-free check proves every selected leaf maps to a same-named knowl
For a single combined stress-test result, use `-ResultsPath` instead.
The committed gate requires full expected recall, the exact convention-derived article ID, and no findings on clean controls.
+
+## AL development evaluation
+
+`development-fixtures.json` defines end-to-end development requests rather than
+prewritten good/bad snippets. Each case declares its execution mode, the
+Business Central capabilities it exercises, the knowledge that should shape
+the implementation, acceptance criteria, and the real checks an external
+runner must perform.
+
+Validate the fixture and capability manifests and prepare opaque requests:
+
+```powershell
+pwsh ./tools/Test-DevelopmentFixtures.ps1 -Root . -PrepareDirectory ./.development-evaluation
+```
+
+Each request runs `al-development` in a fresh writable AL repository. Cases
+may exercise feature, bug, refactor, upgrade, or maintenance mode.
+The runner compiles the generated project, runs its tests, invokes the review
+quality gate, and stores the resulting implementation report using the opaque
+`caseId` from its request, for example `result-case-a1b2c3d4.json`. It keeps the
+generated repository available at the wrapper's `workspaceRoot` so scoring can
+verify reported changed paths. Score all results with:
+
+```powershell
+pwsh ./tools/Test-DevelopmentFixtures.ps1 -Root . -ResultsDirectory ./.development-evaluation
+```
+
+The initial fixtures cover setup-backed master data, document header/line
+workflows, versioned API integrations, and surgical diagnosis and repair of a
+batch-processing bug. The broader capability roadmap lives in
+`coverage/development-capabilities.json`.
+
+### Read-only plan guidance
+
+`development-guidance-fixtures.json` evaluates the planning interface used by
+specialized orchestrators. It supplies an existing development plan and expects
+a referenced set of implementation constraints without any target-repository
+changes.
+
+```powershell
+pwsh ./tools/Test-DevelopmentGuidanceFixtures.ps1 -Root . -PrepareDirectory ./.development-guidance-evaluation
+```
+
+An external runner stores `result-.json` beside the generated request
+and retains the clean fixture repository at `workspaceRoot`. Score the result
+with `-ResultsDirectory`; the scorer verifies knowledge recall and precision
+and fails if the planning pass changed the repository.
diff --git a/evaluation/development-fixtures.json b/evaluation/development-fixtures.json
new file mode 100644
index 0000000..dcedde4
--- /dev/null
+++ b/evaluation/development-fixtures.json
@@ -0,0 +1,188 @@
+{
+ "version": 1,
+ "skill": "microsoft/skills/development/al-development.md",
+ "minimumKnowledgeRecall": 1.0,
+ "minimumKnowledgePrecision": 0.5,
+ "cases": [
+ {
+ "id": "setup-backed-master-data",
+ "title": "Build setup-backed loyalty member master data",
+ "capabilities": [
+ "setup-and-master-data"
+ ],
+ "expectedKind": "feature",
+ "development-request": {
+ "kind": "feature",
+ "description": "Add a Loyalty Member feature to an existing Business Central AL app. Administrators configure the member number series on a singleton setup card. Users create members through list and card pages, the table assigns numbers, and blocked members cannot be selected by consuming records. Include least-privilege permission sets and automated tests.",
+ "acceptance-criteria": [
+ "The setup is a blank-key singleton surfaced by a Card page.",
+ "Member numbers use the current No. Series codeunit and support manual numbers according to setup.",
+ "Blocked validation occurs where a member is consumed, not only on the member table.",
+ "The feature includes assignable least-privilege permissions and automated tests."
+ ]
+ },
+ "context": {
+ "technologies": [
+ "al"
+ ],
+ "countries": [
+ "w1"
+ ],
+ "application-area": [
+ "all"
+ ]
+ },
+ "requiredKnowledge": [
+ "microsoft/knowledge/data-modeling/setup-table-is-a-singleton.md",
+ "microsoft/knowledge/data-modeling/master-table-no-from-number-series-in-oninsert.md",
+ "microsoft/knowledge/data-modeling/check-blocked-in-referencing-code-not-in-master.md",
+ "microsoft/knowledge/security/permission-set-avoid-wildcard-grants.md",
+ "microsoft/knowledge/testing/use-library-codeunits-for-test-fixtures.md"
+ ],
+ "optionalKnowledge": [
+ "microsoft/knowledge/data-modeling/use-no-series-codeunit-not-noseriesmanagement.md",
+ "microsoft/knowledge/security/compose-permission-sets-with-included-sets.md",
+ "microsoft/knowledge/style/applicationarea-required-on-page-controls.md",
+ "microsoft/knowledge/style/tooltip-required-on-page-fields.md",
+ "microsoft/knowledge/ui/showmandatory-on-code-required-page-fields.md"
+ ],
+ "requiredChecks": [
+ "compile",
+ "tests",
+ "review"
+ ]
+ },
+ {
+ "id": "document-header-and-lines",
+ "title": "Build a document header and lines workflow",
+ "capabilities": [
+ "document-workflows"
+ ],
+ "expectedKind": "feature",
+ "development-request": {
+ "kind": "feature",
+ "description": "Implement a Service Quote feature with a header, lines, document page, number series, posting and document dates, calculated totals, and tests. Line edits must refresh the total shown on the header. Structure initialization so API, UI, and test creation paths behave consistently.",
+ "acceptance-criteria": [
+ "The header assigns its number before InitRecord establishes document defaults.",
+ "The document page links lines correctly and refreshes parent totals after edits.",
+ "Tests exercise creation outside the UI as well as the document-page behavior.",
+ "The implementation contains no obsolete NoSeriesManagement dependency."
+ ]
+ },
+ "context": {
+ "technologies": [
+ "al"
+ ],
+ "countries": [
+ "w1"
+ ],
+ "application-area": [
+ "service"
+ ]
+ },
+ "requiredKnowledge": [
+ "microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.md",
+ "microsoft/knowledge/data-modeling/use-no-series-codeunit-not-noseriesmanagement.md",
+ "microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.md",
+ "microsoft/knowledge/testing/use-library-codeunits-for-test-fixtures.md"
+ ],
+ "optionalKnowledge": [
+ "microsoft/knowledge/events/publish-thin-onbefore-onafter-integration-events.md",
+ "microsoft/knowledge/style/applicationarea-required-on-page-controls.md",
+ "microsoft/knowledge/style/tooltip-required-on-page-fields.md"
+ ],
+ "requiredChecks": [
+ "compile",
+ "tests",
+ "review"
+ ]
+ },
+ {
+ "id": "versioned-master-data-api",
+ "title": "Expose master data through a versioned API",
+ "capabilities": [
+ "api-integrations"
+ ],
+ "expectedKind": "feature",
+ "development-request": {
+ "kind": "auto",
+ "plan": "Expose Loyalty Member master data through a Business Central API page. Use a stable v1.0 contract, address records by SystemId, support insert and update, use conventional entity naming, and include permissions and automated API-oriented tests.",
+ "acceptance-criteria": [
+ "The API declares all routing properties and a stable APIVersion.",
+ "ODataKeyFields uses SystemId and the exposed SystemId field is not editable.",
+ "EntityName is singular, EntitySetName is plural, and both are lower camel case.",
+ "The API is covered by least-privilege permissions and automated tests."
+ ]
+ },
+ "context": {
+ "technologies": [
+ "al"
+ ],
+ "countries": [
+ "w1"
+ ],
+ "application-area": [
+ "all"
+ ]
+ },
+ "requiredKnowledge": [
+ "microsoft/knowledge/web-services/set-required-api-page-properties.md",
+ "microsoft/knowledge/web-services/expose-systemid-as-the-api-key.md",
+ "microsoft/knowledge/style/api-page-delayedinsert-true.md",
+ "microsoft/knowledge/style/api-page-entity-naming-singular-plural.md",
+ "microsoft/knowledge/security/permission-set-avoid-wildcard-grants.md"
+ ],
+ "optionalKnowledge": [
+ "microsoft/knowledge/style/api-page-camelcase-properties.md",
+ "microsoft/knowledge/web-services/version-apis-by-adding-not-mutating-published-versions.md"
+ ],
+ "requiredChecks": [
+ "compile",
+ "tests",
+ "review"
+ ]
+ },
+ {
+ "id": "fix-filtered-batch-processing",
+ "title": "Fix a batch routine that processes only one record",
+ "capabilities": [
+ "bug-diagnosis-and-fix"
+ ],
+ "expectedKind": "bug",
+ "development-request": {
+ "kind": "bug",
+ "description": "Users report that an existing filtered batch routine updates only the first matching record. Reproduce the defect, identify why iteration stops, make the smallest safe correction, and add a regression test that selects multiple records and proves every selected record is processed.",
+ "acceptance-criteria": [
+ "The defect is reproduced or demonstrated by a failing regression test before the fix.",
+ "The root cause is corrected without widening the supplied record filters.",
+ "The routine processes every selected record with the appropriate update locking behavior.",
+ "A regression test covers more than one selected record."
+ ]
+ },
+ "context": {
+ "technologies": [
+ "al"
+ ],
+ "countries": [
+ "w1"
+ ],
+ "application-area": [
+ "all"
+ ]
+ },
+ "requiredKnowledge": [
+ "microsoft/knowledge/performance/pair-findset-with-next-loop.md",
+ "microsoft/knowledge/testing/use-library-codeunits-for-test-fixtures.md"
+ ],
+ "optionalKnowledge": [
+ "microsoft/knowledge/performance/findset-true-applies-updlock-on-read.md",
+ "microsoft/knowledge/performance/pass-var-record-to-preserve-partial-load-enumerator.md"
+ ],
+ "requiredChecks": [
+ "compile",
+ "tests",
+ "review"
+ ]
+ }
+ ]
+}
diff --git a/evaluation/development-guidance-fixtures.json b/evaluation/development-guidance-fixtures.json
new file mode 100644
index 0000000..9da4d0a
--- /dev/null
+++ b/evaluation/development-guidance-fixtures.json
@@ -0,0 +1,50 @@
+{
+ "version": 1,
+ "skill": "microsoft/skills/development/al-development-plan.md",
+ "minimumKnowledgeRecall": 1.0,
+ "minimumKnowledgePrecision": 0.5,
+ "cases": [
+ {
+ "id": "bcapps-filtered-batch-bug-plan",
+ "title": "Select guidance for a filtered batch bug fix",
+ "development-plan": {
+ "kind": "bug",
+ "request": "Fix a filtered batch routine that updates only the first matching record.",
+ "root-cause": "The routine calls FindFirst and updates the current record without entering an enumerator loop.",
+ "affected-files": [
+ "src/Batch/UpdateSelectedEntries.Codeunit.al",
+ "test/Batch/UpdateSelectedEntries.Codeunit.al"
+ ],
+ "proposed-changes": [
+ "Iterate the supplied filtered record set and update every selected entry.",
+ "Add a regression test with multiple selected entries."
+ ],
+ "test-strategy": "Establish a red test where only one of several selected records is updated, then require all selected records to be updated after the fix.",
+ "acceptance-criteria": [
+ "The supplied filters are preserved.",
+ "Every selected record is updated.",
+ "The regression test demonstrates red-to-green behavior."
+ ]
+ },
+ "context": {
+ "technologies": [
+ "al"
+ ],
+ "countries": [
+ "w1"
+ ],
+ "application-area": [
+ "all"
+ ]
+ },
+ "requiredKnowledge": [
+ "microsoft/knowledge/performance/pair-findset-with-next-loop.md",
+ "microsoft/knowledge/performance/findset-true-applies-updlock-on-read.md",
+ "microsoft/knowledge/testing/use-library-codeunits-for-test-fixtures.md"
+ ],
+ "optionalKnowledge": [
+ "microsoft/knowledge/performance/pass-var-record-to-preserve-partial-load-enumerator.md"
+ ]
+ }
+ ]
+}
diff --git a/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.bad.al b/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.bad.al
new file mode 100644
index 0000000..0c87bb2
--- /dev/null
+++ b/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.bad.al
@@ -0,0 +1,28 @@
+table 50603 "Sample Order Header Bad"
+{
+ fields
+ {
+ field(1; "No."; Code[20])
+ {
+ DataClassification = CustomerContent;
+ }
+ field(2; "Document Date"; Date)
+ {
+ DataClassification = CustomerContent;
+ }
+ }
+
+ trigger OnInsert()
+ var
+ SalesSetup: Record "Sales & Receivables Setup";
+ NoSeries: Codeunit "No. Series";
+ begin
+ "Document Date" := WorkDate();
+
+ if "No." = '' then begin
+ SalesSetup.Get();
+ SalesSetup.TestField("Order Nos.");
+ "No." := NoSeries.GetNextNo(SalesSetup."Order Nos.");
+ end;
+ end;
+}
diff --git a/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.good.al b/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.good.al
new file mode 100644
index 0000000..355d3d5
--- /dev/null
+++ b/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.good.al
@@ -0,0 +1,45 @@
+table 50602 "Sample Order Header Good"
+{
+ fields
+ {
+ field(1; "No."; Code[20])
+ {
+ DataClassification = CustomerContent;
+ }
+ field(2; "Document Date"; Date)
+ {
+ DataClassification = CustomerContent;
+ }
+ }
+
+ trigger OnInsert()
+ var
+ SalesSetup: Record "Sales & Receivables Setup";
+ NoSeries: Codeunit "No. Series";
+ begin
+ if "No." = '' then begin
+ SalesSetup.Get();
+ SalesSetup.TestField("Order Nos.");
+ "No." := NoSeries.GetNextNo(SalesSetup."Order Nos.");
+ end;
+
+ InitRecord();
+ end;
+
+ procedure InitRecord()
+ begin
+ OnBeforeInitRecord(Rec);
+ "Document Date" := WorkDate();
+ OnAfterInitRecord(Rec);
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeInitRecord(var SampleOrderHeader: Record "Sample Order Header Good")
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterInitRecord(var SampleOrderHeader: Record "Sample Order Header Good")
+ begin
+ end;
+}
diff --git a/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.md b/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.md
new file mode 100644
index 0000000..fbdec6e
--- /dev/null
+++ b/microsoft/knowledge/data-modeling/initialize-document-defaults-in-initrecord.md
@@ -0,0 +1,30 @@
+---
+bc-version: [all]
+domain: data-modeling
+keywords: [document-header, initrecord, number-series, default-values, oninsert, initialization]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# Initialize document defaults in `InitRecord` after assigning the number
+
+## Description
+
+Business Central document headers assign their number series first and then call an `InitRecord` procedure that owns the remaining business defaults, such as posting and document dates. Keeping that sequence and extensibility point makes initialization consistent for every creation path and lets extensions subscribe around one documented operation. Defaults scattered across page triggers or unrelated helpers can differ between UI, API, test, and background creation.
+
+## Best Practice
+
+In the document table's insert path, assign the document number and then call `InitRecord`. Keep the default assignments in that procedure and expose narrow before/after events when other extensions must participate.
+
+See sample: `initialize-document-defaults-in-initrecord.good.al`.
+
+## Anti Pattern
+
+Assigning document defaults in a page trigger, or scattering them directly through `OnInsert` with no `InitRecord` boundary. Non-page creation paths can then miss the defaults, and extensions have no stable initialization hook.
+
+See sample: `initialize-document-defaults-in-initrecord.bad.al`.
+
+## Reference
+
+[Use the InitRecord function](https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/3-use-initrecord-function)
diff --git a/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.bad.al b/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.bad.al
new file mode 100644
index 0000000..f8e11cc
--- /dev/null
+++ b/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.bad.al
@@ -0,0 +1,8 @@
+codeunit 50601 "Directed Rounding Bad"
+{
+ procedure FloorAmount(Value: Decimal; Precision: Decimal): Decimal
+ begin
+ // For negative values, '<' rounds toward zero rather than toward negative infinity.
+ exit(Round(Value, Precision, '<'));
+ end;
+}
diff --git a/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.good.al b/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.good.al
new file mode 100644
index 0000000..cd8a80f
--- /dev/null
+++ b/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.good.al
@@ -0,0 +1,10 @@
+codeunit 50600 "Directed Rounding Good"
+{
+ procedure RoundAmount(Value: Decimal; Precision: Decimal; IncreaseMagnitude: Boolean): Decimal
+ begin
+ if IncreaseMagnitude then
+ exit(Round(Value, Precision, '>'));
+
+ exit(Round(Value, Precision, '<'));
+ end;
+}
diff --git a/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.md b/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.md
new file mode 100644
index 0000000..9fb0ba3
--- /dev/null
+++ b/microsoft/knowledge/data-modeling/round-direction-symbols-use-magnitude.md
@@ -0,0 +1,30 @@
+---
+bc-version: [all]
+domain: data-modeling
+keywords: [round, rounding, direction, precision, negative-decimal, amount]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# `Round` direction symbols follow magnitude, not mathematical ordering
+
+## Description
+
+AL's `Round(Number, Precision, Direction)` uses `'>'` to round away from zero and `'<'` to round toward zero. For a negative value this reverses mathematical ordering: `Round(-1234.56789, 0.001, '<')` returns `-1234.567`, while direction `'>'` returns `-1234.568`. Code that treats the symbols as mathematical ceiling and floor produces sign-dependent amount errors, commonly on credit documents and negative adjustments.
+
+## Best Practice
+
+Choose the direction from the business meaning: `'>'` increases absolute magnitude and `'<'` decreases absolute magnitude for both positive and negative values. Include positive and negative cases whenever a directed rounding rule is tested.
+
+See sample: `round-direction-symbols-use-magnitude.good.al`.
+
+## Anti Pattern
+
+Using `'<'` as a mathematical floor or `'>'` as a mathematical ceiling. The result looks correct for positive amounts but moves in the opposite mathematical direction for negative amounts.
+
+See sample: `round-direction-symbols-use-magnitude.bad.al`.
+
+## Reference
+
+[Use the Round function](https://learn.microsoft.com/en-us/training/modules/use-document-standards-business-central/4a-use-round-function)
diff --git a/microsoft/knowledge/interfaces/guard-interface-casts-with-is.bad.al b/microsoft/knowledge/interfaces/guard-interface-casts-with-is.bad.al
new file mode 100644
index 0000000..4fd98be
--- /dev/null
+++ b/microsoft/knowledge/interfaces/guard-interface-casts-with-is.bad.al
@@ -0,0 +1,20 @@
+interface "I Quote Amount Bad"
+{
+ procedure GetAmount(): Decimal;
+}
+
+interface "I Quote Date Bad"
+{
+ procedure GetDate(): Date;
+}
+
+codeunit 50611 "Quote Reader Bad"
+{
+ procedure GetDate(Quote: Interface "I Quote Amount Bad"): Date
+ var
+ DatedQuote: Interface "I Quote Date Bad";
+ begin
+ DatedQuote := Quote as "I Quote Date Bad";
+ exit(DatedQuote.GetDate());
+ end;
+}
diff --git a/microsoft/knowledge/interfaces/guard-interface-casts-with-is.good.al b/microsoft/knowledge/interfaces/guard-interface-casts-with-is.good.al
new file mode 100644
index 0000000..f58a19d
--- /dev/null
+++ b/microsoft/knowledge/interfaces/guard-interface-casts-with-is.good.al
@@ -0,0 +1,24 @@
+interface "I Quote Amount Good"
+{
+ procedure GetAmount(): Decimal;
+}
+
+interface "I Quote Date Good"
+{
+ procedure GetDate(): Date;
+}
+
+codeunit 50610 "Quote Reader Good"
+{
+ procedure TryGetDate(Quote: Interface "I Quote Amount Good"; var QuoteDate: Date): Boolean
+ var
+ DatedQuote: Interface "I Quote Date Good";
+ begin
+ if not (Quote is "I Quote Date Good") then
+ exit(false);
+
+ DatedQuote := Quote as "I Quote Date Good";
+ QuoteDate := DatedQuote.GetDate();
+ exit(true);
+ end;
+}
diff --git a/microsoft/knowledge/interfaces/guard-interface-casts-with-is.md b/microsoft/knowledge/interfaces/guard-interface-casts-with-is.md
new file mode 100644
index 0000000..1962e69
--- /dev/null
+++ b/microsoft/knowledge/interfaces/guard-interface-casts-with-is.md
@@ -0,0 +1,30 @@
+---
+bc-version: [25..]
+domain: interfaces
+keywords: [interface, is-operator, as-operator, type-test, cast, variant, runtime-error]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# Guard optional interface casts with `is`
+
+## Description
+
+From runtime 14.0, AL can type-test an interface or `Variant` with `is` and cast it to another interface with `as`. The test is non-throwing, but `as` raises a runtime error when the underlying codeunit does not implement the target interface. This matters when an extended capability is optional or implementations can come from other extensions.
+
+## Best Practice
+
+Use `is` to establish that the value supports the target interface before using `as`. Cast directly only where the target implementation is an invariant guaranteed by the surrounding contract.
+
+See sample: `guard-interface-casts-with-is.good.al`.
+
+## Anti Pattern
+
+Using `as` unconditionally for an optional extended interface. An otherwise valid implementation of the base interface then fails at runtime merely because it does not implement the additional contract.
+
+See sample: `guard-interface-casts-with-is.bad.al`.
+
+## Reference
+
+[Understand type testing and casting operators for interfaces](https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/type-testing)
diff --git a/microsoft/knowledge/style/applicationarea-required-on-page-controls.bad.al b/microsoft/knowledge/style/applicationarea-required-on-page-controls.bad.al
index 8da7777..0e26a4b 100644
--- a/microsoft/knowledge/style/applicationarea-required-on-page-controls.bad.al
+++ b/microsoft/knowledge/style/applicationarea-required-on-page-controls.bad.al
@@ -8,9 +8,6 @@ page 50375 "Sample App Area Bad"
{
group(General)
{
- // Anti-pattern: no ApplicationArea. AS0062 flags this control,
- // and it is silently hidden in the Web client for profiles whose
- // enabled areas do not already cover it.
field("No."; Rec."No.")
{
ToolTip = 'Specifies the number that identifies the customer.';
@@ -23,3 +20,18 @@ page 50375 "Sample App Area Bad"
}
}
}
+
+pageextension 50377 "Customer App Area Bad" extends "Customer Card"
+{
+ layout
+ {
+ addlast(General)
+ {
+ // Extension controls do not inherit ApplicationArea from the base page.
+ field("Language Code Sample"; Rec."Language Code")
+ {
+ ToolTip = 'Specifies the language used for the customer.';
+ }
+ }
+ }
+}
diff --git a/microsoft/knowledge/style/applicationarea-required-on-page-controls.good.al b/microsoft/knowledge/style/applicationarea-required-on-page-controls.good.al
index d344337..76c48cf 100644
--- a/microsoft/knowledge/style/applicationarea-required-on-page-controls.good.al
+++ b/microsoft/knowledge/style/applicationarea-required-on-page-controls.good.al
@@ -2,6 +2,8 @@ page 50374 "Sample App Area Good"
{
PageType = Card;
SourceTable = Customer;
+ ApplicationArea = All;
+
layout
{
area(Content)
@@ -10,12 +12,10 @@ page 50374 "Sample App Area Good"
{
field("No."; Rec."No.")
{
- ApplicationArea = All;
ToolTip = 'Specifies the number that identifies the customer.';
}
field(Name; Rec.Name)
{
- ApplicationArea = All;
ToolTip = 'Specifies the customer''s name.';
}
}
@@ -27,7 +27,6 @@ page 50374 "Sample App Area Good"
{
action(Refresh)
{
- ApplicationArea = All;
ToolTip = 'Reloads the current record.';
trigger OnAction()
@@ -38,3 +37,18 @@ page 50374 "Sample App Area Good"
}
}
}
+
+pageextension 50376 "Customer App Area Good" extends "Customer Card"
+{
+ layout
+ {
+ addlast(General)
+ {
+ field("Language Code Sample"; Rec."Language Code")
+ {
+ ApplicationArea = All;
+ ToolTip = 'Specifies the language used for the customer.';
+ }
+ }
+ }
+}
diff --git a/microsoft/knowledge/style/applicationarea-required-on-page-controls.md b/microsoft/knowledge/style/applicationarea-required-on-page-controls.md
index 606e08a..3a74a05 100644
--- a/microsoft/knowledge/style/applicationarea-required-on-page-controls.md
+++ b/microsoft/knowledge/style/applicationarea-required-on-page-controls.md
@@ -1,28 +1,32 @@
---
bc-version: [all]
domain: style
-keywords: [application-area, page-control, as0062, appsourcecop, hidden-control, web-client]
+keywords: [application-area, page-control, inheritance, as0062, appsourcecop, web-client]
technologies: [al]
countries: [w1]
application-area: [all]
---
-# Every page control needs an `ApplicationArea` (AppSourceCop AS0062)
+# Page-level `ApplicationArea` inheritance does not apply to extensions
## Description
-A field control on a page or pageextension that has no `ApplicationArea` property is silently hidden in the Web client for every profile whose enabled application areas do not cover it. There is no error and no warning at runtime — the field simply does not appear, which reads as data loss to the user. AppSourceCop AS0062 flags any page control or action that is missing the `ApplicationArea` property, and AppSource technical validation rejects the app until it is set.
+A page control or action needs an effective `ApplicationArea` to appear in cloud experiences. From runtime 10.0, controls on a page object inherit the page-level value, so repeating it on every child is unnecessary when the parent defines a suitable default. This inheritance does not apply to controls added or modified by page and report extensions: extension controls must still set the property explicitly.
-Set the property to an area the app actually enables. `All` makes the control visible under every profile and is the common default; if the app declares narrower areas in `app.json`, use one of those. The property applies to field controls and to actions. This is a sibling concern to `caption-required-on-page-fields.md` and `tooltip-required-on-page-fields.md`; note that the ToolTip requirement is the separate CodeCop rule AA0218, not AS0062.
+For targets before runtime 10.0, child controls do not inherit and must also set the property. AppSourceCop AS0062 and PTE0008 account for page-level inheritance on runtime 10.0 and later but continue to require explicit values in extensions.
## Best Practice
-Every field control and action carries `ApplicationArea = All;` (or a declared area of the app). The value is set once per control and keeps the control visible in the Web client.
+On runtime 10.0 or later, set a suitable page-level default and override only controls that belong to a narrower area. Set `ApplicationArea` explicitly on every control or action introduced by a page or report extension.
See sample: `applicationarea-required-on-page-controls.good.al`.
## Anti Pattern
-A field control with no `ApplicationArea`. AS0062 flags it, and the control is invisible in the Web client for any profile that does not already enable a matching area.
+A page object that defines neither a parent nor child value, or an extension control that assumes it inherits from the base page. The control has no effective application area and can be hidden or rejected by analyzer validation.
See sample: `applicationarea-required-on-page-controls.bad.al`.
+
+## Reference
+
+[Set different control properties](https://learn.microsoft.com/en-us/training/modules/work-with-pages/8-controls)
diff --git a/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.bad.al b/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.bad.al
new file mode 100644
index 0000000..78602b4
--- /dev/null
+++ b/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.bad.al
@@ -0,0 +1,9 @@
+tableextension 50622 "Ship-to Dropdown Bad" extends "Ship-to Address"
+{
+ fieldgroups
+ {
+ addlast(DropDown; "Address 2")
+ {
+ }
+ }
+}
diff --git a/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.good.al b/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.good.al
new file mode 100644
index 0000000..c8a8c28
--- /dev/null
+++ b/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.good.al
@@ -0,0 +1,20 @@
+tableextension 50620 "Ship-to Dropdown Good" extends "Ship-to Address"
+{
+ fieldgroups
+ {
+ addlast(DropDown; "Address 2")
+ {
+ }
+ }
+}
+
+pageextension 50621 "Ship-to Lookup Good" extends "Ship-to Address List"
+{
+ layout
+ {
+ modify("Address 2")
+ {
+ Visible = true;
+ }
+ }
+}
diff --git a/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.md b/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.md
new file mode 100644
index 0000000..656d1a2
--- /dev/null
+++ b/microsoft/knowledge/ui/dropdown-fieldgroup-respects-lookup-page-visibility.md
@@ -0,0 +1,30 @@
+---
+bc-version: [all]
+domain: ui
+keywords: [fieldgroup, dropdown, addlast, lookup-page, visible, tableextension, pageextension]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# A `DropDown` field remains hidden when its lookup-page control is hidden
+
+## Description
+
+A tableextension can append a field to the `DropDown` field group with `addlast`, but the client still omits that field when its control on the underlying lookup page has `Visible = false`. Changing only the table field group therefore compiles while producing no visible UI change. The field-group name is case-sensitive and must be written as `DropDown`.
+
+## Best Practice
+
+When adding a hidden field to a `DropDown` field group, also extend the page used for the lookup and make that field control visible. Verify the actual lookup page rather than assuming the table definition alone controls the drop-down.
+
+See sample: `dropdown-fieldgroup-respects-lookup-page-visibility.good.al`.
+
+## Anti Pattern
+
+Adding the field with `addlast(DropDown; ...)` while leaving its lookup-page control hidden, then expecting the field to appear in the drop-down.
+
+See sample: `dropdown-fieldgroup-respects-lookup-page-visibility.bad.al`.
+
+## Reference
+
+[Add a new FieldGroup to an existing table](https://learn.microsoft.com/en-us/training/modules/extend-modify-existing-table/add-field-group)
diff --git a/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.bad.al b/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.bad.al
new file mode 100644
index 0000000..f5d2b2b
--- /dev/null
+++ b/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.bad.al
@@ -0,0 +1,26 @@
+page 50631 "Sample Order Bad"
+{
+ PageType = Document;
+ SourceTable = "Sales Header";
+
+ layout
+ {
+ area(Content)
+ {
+ group(General)
+ {
+ field(Amount; Rec.Amount)
+ {
+ ApplicationArea = All;
+ ToolTip = 'Specifies the total amount of the order.';
+ }
+ }
+ part(Lines; "Sales Order Subform")
+ {
+ ApplicationArea = All;
+ SubPageLink = "Document Type" = field("Document Type"),
+ "Document No." = field("No.");
+ }
+ }
+ }
+}
diff --git a/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.good.al b/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.good.al
new file mode 100644
index 0000000..3462098
--- /dev/null
+++ b/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.good.al
@@ -0,0 +1,27 @@
+page 50630 "Sample Order Good"
+{
+ PageType = Document;
+ SourceTable = "Sales Header";
+
+ layout
+ {
+ area(Content)
+ {
+ group(General)
+ {
+ field(Amount; Rec.Amount)
+ {
+ ApplicationArea = All;
+ ToolTip = 'Specifies the total amount of the order.';
+ }
+ }
+ part(Lines; "Sales Order Subform")
+ {
+ ApplicationArea = All;
+ SubPageLink = "Document Type" = field("Document Type"),
+ "Document No." = field("No.");
+ UpdatePropagation = Both;
+ }
+ }
+ }
+}
diff --git a/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.md b/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.md
new file mode 100644
index 0000000..55324bd
--- /dev/null
+++ b/microsoft/knowledge/ui/updatepropagation-both-refreshes-main-page.md
@@ -0,0 +1,30 @@
+---
+bc-version: [all]
+domain: ui
+keywords: [updatepropagation, page-part, subpage, main-page, refresh, flowfield, document-lines]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# Use `UpdatePropagation = Both` when line edits must refresh the main page
+
+## Description
+
+A page part does not automatically refresh its parent page when the subpage changes. `UpdatePropagation = Subpage` updates only the part; `Both` also refreshes the main page. Without `Both`, header totals, FlowFields, and FactBoxes that depend on edited lines can remain stale until another user action refreshes the page.
+
+## Best Practice
+
+Set `UpdatePropagation = Both` on a part when edits in that subpage must immediately update values rendered by the main page. Leave propagation at `Subpage` when the parent has no dependent presentation to avoid unnecessary refreshes.
+
+See sample: `updatepropagation-both-refreshes-main-page.good.al`.
+
+## Anti Pattern
+
+Displaying a line-dependent total on the main page while the editable lines part updates only itself. The persisted values can be correct while the parent page continues to show an old total.
+
+See sample: `updatepropagation-both-refreshes-main-page.bad.al`.
+
+## Reference
+
+[Set different control properties](https://learn.microsoft.com/en-us/training/modules/work-with-pages/8-controls)
diff --git a/microsoft/knowledge/upgrade/appversion-meaning-depends-on-execution-context.md b/microsoft/knowledge/upgrade/appversion-meaning-depends-on-execution-context.md
new file mode 100644
index 0000000..61e7422
--- /dev/null
+++ b/microsoft/knowledge/upgrade/appversion-meaning-depends-on-execution-context.md
@@ -0,0 +1,26 @@
+---
+bc-version: [all]
+domain: upgrade
+keywords: [appversion, dataversion, moduleinfo, install-codeunit, upgrade-codeunit, version-context]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# `ModuleInfo.AppVersion` changes meaning with execution context
+
+## Description
+
+`ModuleInfo.AppVersion()` is the installed version during normal operation, the version being installed inside install code, and the target version inside upgrade code. It is therefore not the source data version during an upgrade. In upgrade code, `DataVersion()` describes the version of the existing data, whether from the currently installed app or the version most recently uninstalled.
+
+## Best Practice
+
+Interpret `AppVersion()` as the code package entering the context and `DataVersion()` as the existing data state. Prefer upgrade tags for controlling individual migration steps; when version information is needed for diagnostics or preconditions, name variables so target app version and source data version cannot be confused.
+
+## Anti Pattern
+
+Reading `AppVersion()` from an upgrade codeunit and treating it as the version being upgraded from. The comparison actually observes the target package and can skip or misroute migration logic.
+
+## Reference
+
+[Create proper installation and upgrade codeunits](https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/3-installation-upgrade-codeunits)
diff --git a/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.bad.al b/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.bad.al
new file mode 100644
index 0000000..2a92d11
--- /dev/null
+++ b/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.bad.al
@@ -0,0 +1,28 @@
+codeunit 50641 "Sample Upgrade Part One"
+{
+ Subtype = Upgrade;
+
+ trigger OnUpgradePerCompany()
+ begin
+ CreateUpgradeState();
+ end;
+
+ local procedure CreateUpgradeState()
+ begin
+ end;
+}
+
+codeunit 50642 "Sample Upgrade Part Two"
+{
+ Subtype = Upgrade;
+
+ trigger OnUpgradePerCompany()
+ begin
+ // This can run before Part One; object IDs do not sequence upgrade codeunits.
+ MigrateDataThatRequiresUpgradeState();
+ end;
+
+ local procedure MigrateDataThatRequiresUpgradeState()
+ begin
+ end;
+}
diff --git a/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.good.al b/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.good.al
new file mode 100644
index 0000000..42346a8
--- /dev/null
+++ b/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.good.al
@@ -0,0 +1,18 @@
+codeunit 50640 "Sample Upgrade Good"
+{
+ Subtype = Upgrade;
+
+ trigger OnUpgradePerCompany()
+ begin
+ CreateUpgradeState();
+ MigrateDependentData();
+ end;
+
+ local procedure CreateUpgradeState()
+ begin
+ end;
+
+ local procedure MigrateDependentData()
+ begin
+ end;
+}
diff --git a/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.md b/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.md
new file mode 100644
index 0000000..2271b2a
--- /dev/null
+++ b/microsoft/knowledge/upgrade/install-and-upgrade-codeunits-have-no-order.md
@@ -0,0 +1,30 @@
+---
+bc-version: [all]
+domain: upgrade
+keywords: [install-codeunit, upgrade-codeunit, execution-order, subtype-install, subtype-upgrade, sequencing]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# Separate install or upgrade codeunits have no execution order
+
+## Description
+
+An extension can contain multiple `Install` or `Upgrade` codeunits, but Business Central does not guarantee the order in which codeunits of the same subtype execute. Upgrade trigger phases are ordered globally, yet one codeunit's `OnUpgradePerCompany` must not assume another codeunit's same-phase trigger already ran. Object ID and source-file order do not provide sequencing.
+
+## Best Practice
+
+Keep separate install or upgrade codeunits independent. When two steps have a real dependency, coordinate them from one owning trigger in the required order; use upgrade tags to make each completed step idempotent.
+
+See sample: `install-and-upgrade-codeunits-have-no-order.good.al`.
+
+## Anti Pattern
+
+Splitting dependent steps into separate codeunits and relying on names, object IDs, or declaration order. The dependent codeunit can run first and fail or observe partially migrated data.
+
+See sample: `install-and-upgrade-codeunits-have-no-order.bad.al`.
+
+## Reference
+
+[Create proper installation and upgrade codeunits](https://learn.microsoft.com/en-us/training/modules/easy-application-upgrade/3-installation-upgrade-codeunits)
diff --git a/microsoft/skills/development/al-development-plan.md b/microsoft/skills/development/al-development-plan.md
new file mode 100644
index 0000000..f824b68
--- /dev/null
+++ b/microsoft/skills/development/al-development-plan.md
@@ -0,0 +1,68 @@
+---
+kind: action-skill
+id: al-development-plan
+version: 1
+title: AL development plan guidance
+description: Produces a read-only BCQuality knowledge bundle for an existing Business Central AL development plan.
+inputs: [development-plan, repository]
+outputs: [development-guidance-report]
+bc-version: [all]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+---
+
+# AL development plan guidance
+
+Selects the BCQuality knowledge that should constrain an existing AL development plan. It does not implement, edit, stage, commit, or publish anything in the target repository. Repository-specific orchestrators can consume this skill before their own test and implementation phases while retaining ownership of workflow, tooling, and delivery.
+
+Both a readable `repository` and a non-empty `development-plan` are required. The plan may be structured data or text, but it must identify the intended change. Return `not-applicable` without changing files when either input is absent or the repository is not an AL project.
+
+## Source
+
+Read the BCQuality knowledge index once. Use entries from every enabled layer and domain. The index supplies candidate paths, applicability dimensions, keywords, titles, and descriptions; it never substitutes for opening selected articles in full.
+
+Inspect the target repository read-only for `app.json`, affected files and symbols named by the plan, relevant tests, permission sets, dependencies, target/runtime versions, countries, application areas, and repository conventions. Do not create scratch or generated files inside the target repository.
+
+## Relevance
+
+Apply READ's matching semantics using:
+
+- `bc-version` from the plan, target application, or supplied context; for upgrades, distinguish source and target versions.
+- `technologies` from the affected files, beginning with `[al]`.
+- `countries` from the plan, `app.json`, or workspace configuration.
+- `application-area` from the plan and affected objects.
+
+When a dimension cannot be resolved, retain conditionally applicable candidates only when they can materially constrain the plan. Record the dimension in `context.unknown` and explain it in `unresolved`; do not silently treat it as a match.
+
+## Worklist
+
+1. Normalize the plan into: request summary, development kind, assumptions, root cause or design intent, affected files and symbols, proposed changes, test strategy, and acceptance criteria. When the plan has no normalized kind, apply the same categories as `al-development`: new or expanded behavior is `feature`, a defect correction is `bug`, behavior-preserving restructuring is `refactor`, migration is `upgrade`, and other bounded work is `maintenance`. A repository-specific additive event or extensibility request maps to `feature`; retain its original work-item type in the request summary. Do not redesign the repository-specific workflow.
+2. Build retrieval vocabulary from the plan and confirmed repository symbols. Give exact object types, properties, methods, analyzers, errors, and affected domains more weight than broad business nouns.
+3. Search the index in separate passes:
+ - data ownership, keys, setup, numbering, validation, transactions, and upgrade;
+ - behavior, events, interfaces, errors, permissions, privacy, and telemetry;
+ - pages, reports, APIs, integrations, localization, and accessibility;
+ - tests, analyzers, packaging, and deployment constraints.
+4. Add an article when its keywords or indexed topic match a concrete planned change, affected symbol, acceptance criterion, or validation obligation. Applicability alone is not enough.
+5. Open every selected article in full. Read any referenced `.good.*` and `.bad.*` sibling needed to make the constraint concrete. Never cite an index row that was not opened.
+6. Resolve contradictory normative guidance with READ's layer precedence and record losing candidates in `suppressed`.
+7. Check the resulting worklist across the whole plan. A bug fix may require testing, data, performance, and upgrade guidance at once; a feature plan may require security and lifecycle constraints that are not named in its title.
+
+Keep the worklist focused. Do not include generic engineering advice, an entire domain, or an article that would not change implementation or validation.
+
+## Action
+
+For each worklist article:
+
+1. Copy its exact path and optional commit SHA.
+2. State `used-for` as the concrete plan decision or affected surface.
+3. Translate its normative Best Practice and Anti Pattern into short implementation constraints without adding facts or weakening conditions.
+4. Include only opened, existing sibling samples in `sample-paths`.
+5. Derive validation considerations only where the plan or selected knowledge requires observable evidence. Describe the evidence to obtain; do not claim it already exists or passed.
+
+Do not change the target repository. Before emitting, verify every knowledge and sample path exists in the live BCQuality checkout and was opened during this run. If reference integrity cannot be established, return `failed` rather than fabricating guidance.
+
+## Output
+
+Return one `development-guidance-report` conforming to DO. `completed` requires that every selected article was opened and faithfully converted into constraints. `no-knowledge` is valid when the plan is applicable but BCQuality contains no relevant article. `partial` names every unevaluated candidate or unresolved applicability gap.
diff --git a/microsoft/skills/development/al-development.md b/microsoft/skills/development/al-development.md
new file mode 100644
index 0000000..c4eefd7
--- /dev/null
+++ b/microsoft/skills/development/al-development.md
@@ -0,0 +1,91 @@
+---
+kind: action-skill
+id: al-development
+version: 1
+title: AL development
+description: Implements Business Central AL features, bug fixes, refactors, upgrades, and maintenance changes using BCQuality knowledge.
+inputs: [development-request, repository]
+outputs: [implementation-report]
+bc-version: [all]
+technologies: [al]
+countries: [w1]
+application-area: [all]
+guidance-skill: microsoft/skills/development/al-development-plan.md
+quality-skill: microsoft/skills/review/al-code-review.md
+---
+
+# AL development
+
+Implements a Business Central change in an existing AL repository. Feature work, bug fixing, refactoring, upgrades, and maintenance share one public contract and one quality pipeline; their different investigation disciplines are execution modes within this skill.
+
+Both a writable `repository` and a `development-request` are required. A structured request has this shape:
+
+```yaml
+development-request:
+ kind: auto # feature | bug | refactor | upgrade | maintenance
+ description: string # optional when plan states the requested outcome
+ plan: string # optional
+ acceptance-criteria: [string] # optional
+```
+
+A plain-text request is normalized to `kind: auto` with the text as `description`. A plan-only request is valid when the plan states the requested outcome. Return `not-applicable` without changing files when either input is absent, both description and plan are empty, or the repository is not an AL project.
+
+## Source
+
+Read the frontmatter `guidance-skill`; it owns BCQuality discovery and returns the knowledge constraints for the implementation plan. Inspect the target repository for `app.json`, existing objects, tests, permission sets, analyzers, build scripts, naming and object-ID conventions, dependencies, target/runtime versions, localization layout, and uncommitted user changes. For bugs, refactors, and upgrades, inspect enough history and surrounding code to establish the behavior being changed.
+
+## Relevance
+
+Resolve and pass this context to the guidance-skill:
+
+- `bc-version` from the target application's platform/application/runtime settings or supplied context. For an upgrade, distinguish source and target versions.
+- `technologies: [al]`, plus any additional technology actually required by the request.
+- `countries` from `app.json`, workspace configuration, or supplied context.
+- `application-area` from the request and affected objects.
+
+Record unresolved dimensions in the development plan rather than silently substituting broad values. The guidance-skill applies READ's matching semantics and returns any conditional applicability in its report.
+
+## Worklist
+
+1. Normalize the request, deriving a concise description from a plan-only input, and classify `kind: auto` as:
+ - `feature` for new or intentionally expanded behavior;
+ - `bug` for observed behavior that contradicts an expected result;
+ - `refactor` for structural change with no intended behavior change;
+ - `upgrade` for schema, data, dependency, runtime, or application-version migration;
+ - `maintenance` for bounded development work that fits none of the above.
+ Preserve an explicit valid kind. When repository evidence conflicts with it, record the mismatch and ask for clarification before changing files rather than silently switching disciplines.
+2. Establish the mode-specific implementation contract:
+ - **Feature:** define user-visible behavior and cover data lifecycle, UI/API, permissions, extensibility, upgrade impact, telemetry, and tests where applicable.
+ - **Bug:** state expected versus actual behavior, reproduce or otherwise prove the defect, trace the root cause, and define a regression test that fails for that cause.
+ - **Refactor:** identify the behavior and public contracts that must remain invariant, plus the checks that establish a before/after baseline.
+ - **Upgrade:** identify source and target states, data migration, compatibility, idempotency, and validation requirements.
+ - **Maintenance:** define the bounded outcome and the behavior that must not change.
+3. Treat a supplied plan as an input constraint, not as proof. Reconcile it with repository reality and BCQuality; preserve its intent, correct unsafe assumptions, and record consequential deviations.
+4. Discover existing implementation patterns and reusable objects before proposing new ones. Preserve repository conventions and current user changes.
+5. Materialize a `development-plan` containing the classified kind, request, assumptions, affected files and symbols, design or root cause, proposed changes, validation strategy, and acceptance criteria.
+6. Invoke the frontmatter `guidance-skill` with that plan, the repository, and the resolved context. It performs Source, Relevance, and knowledge worklisting independently and read-only.
+7. Require a complete guidance result before editing product code:
+ - `completed` — use every returned constraint and validation consideration.
+ - `no-knowledge` — return `no-knowledge` without implementing a Business Central-specific change.
+ - `not-applicable`, `partial`, or `failed` — return the corresponding non-completed outcome without editing product code; preserve its reason in `remaining`.
+8. Copy the guidance report's selected paths into the eventual implementation report only when the corresponding constraint materially shaped the implementation. Carry its suppression records forward.
+
+## Action
+
+1. Record the starting working-tree state so unrelated changes are preserved and excluded from `changes`.
+2. Apply the execution mode:
+ - **Feature:** implement the smallest complete vertical slice; do not leave placeholder surfaces.
+ - **Bug:** reproduce first when feasible, fix the root cause rather than the symptom, keep the patch surgical, and add a regression test.
+ - **Refactor:** capture a behavioral baseline, avoid unrelated behavior changes, and prove the declared invariants afterward.
+ - **Upgrade:** make migrations rerunnable where required, preserve data and compatibility, and validate both upgraded and fresh-install paths when applicable.
+ - **Maintenance:** make only the bounded requested change and preserve surrounding behavior.
+3. Produce a coherent design that satisfies the implementation contract and every constraint returned by the guidance-skill. Reuse existing abstractions and object ranges. Do not hard-code a Business Central fact in this skill or invent a rule absent from both the repository and reliable platform knowledge.
+4. Implement the request end to end. Include all surfaces required by the mode, acceptance criteria, and repository conventions. Do not create success-shaped stubs.
+5. Treat the guidance report as design constraints throughout implementation. Adapt its referenced companion samples to the target codebase; never copy demonstration IDs or names blindly.
+6. Run the smallest existing build, analyzer, and test commands that cover the change. Fix failures caused by the implementation. Record every command and real outcome in `validation`; unavailable checks are `not-run`, never `passed`.
+7. Invoke the frontmatter `quality-skill` against the final implementation diff. Fix all justified knowledge-backed `blocker` and `major` findings and concrete defects introduced by this work, then rerun affected validation and review. Preserve the last findings-report in `review` and add a `validation` entry with `id: "review"`. If review is disabled or unavailable, record `not-run` and return `partial`.
+8. Verify the persisted files against the implementation contract, acceptance criteria, and mode-specific evidence. If behavior, validation, or review remains incomplete, return `partial` and list the exact gap in `remaining`.
+
+## Output
+
+Return one `implementation-report` conforming to DO. Set `plan.kind` to the classified execution mode. `knowledge` lists only articles opened in full and materially used. `changes` lists only files changed by this skill. `completed` requires a persisted implementation, passing required validation, and no unresolved `blocker` or `major` finding in `review`.
diff --git a/microsoft/skills/review/al-data-modeling-review.md b/microsoft/skills/review/al-data-modeling-review.md
index 2386613..234589e 100644
--- a/microsoft/skills/review/al-data-modeling-review.md
+++ b/microsoft/skills/review/al-data-modeling-review.md
@@ -39,7 +39,7 @@ Narrow the relevant files to the subset that applies to the changes under review
- The changed AL object names and types — especially `* Setup` singleton tables and Card pages, custom master tables, tableextensions that add master-data fields, and document or journal lines that reference a master.
- The changed fields, keys, triggers, and procedures, weighted toward `Primary Key`, `No.`, `No. Series`, `Blocked`, `Last Date Modified`, `OnInsert`, `OnModify`, `OnRename`, reference-field `OnValidate`, and posting validation.
-- Tokens extracted from the diff that relate to data modeling (`setup`, `master`, `Primary Key`, `Code[10]`, `Code[20]`, `AutoIncrement`, `SystemId`, `No.`, `No. Series`, `NoSeriesManagement`, `Codeunit "No. Series"`, `GetNextNo`, `IsManual`, `TestManual`, `Blocked`, `TestField`, `Last Date Modified`, `Today`, `WorkDate`, `InsertAllowed`, `DeleteAllowed`, `PageType = Card`, `OnOpenPage`, `GetRecordOnce`, `OnInsert`, `OnModify`, `OnRename`, `TableRelation`, `tableextension`, `enumextension`, `Media`, `MediaSet`, `Item`, `Count`).
+- Tokens extracted from the diff that relate to data modeling (`setup`, `master`, `Primary Key`, `Code[10]`, `Code[20]`, `AutoIncrement`, `SystemId`, `No.`, `No. Series`, `NoSeriesManagement`, `Codeunit "No. Series"`, `GetNextNo`, `IsManual`, `TestManual`, `Blocked`, `TestField`, `Last Date Modified`, `Today`, `WorkDate`, `InsertAllowed`, `DeleteAllowed`, `PageType = Card`, `OnOpenPage`, `GetRecordOnce`, `OnInsert`, `OnModify`, `OnRename`, `InitRecord`, `Round`, `Precision`, `Direction`, `TableRelation`, `tableextension`, `enumextension`, `Media`, `MediaSet`, `Item`, `Count`).
A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed object type. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone. When the diff contains no data-modeling changes by any of the above signals, return `outcome: "not-applicable"` without evaluating files.
@@ -52,6 +52,8 @@ The following targeted checks cover every current `data-modeling` article. Treat
- A master table adds or changes `Last Date Modified`, `OnModify`, or `OnRename`, but the non-editable field is not assigned `Today()` in both triggers — `set-last-date-modified-in-onmodify-and-onrename`.
- A `tableextension` appends a conditional `TableRelation` as if it overrides an earlier unconditional relation, or relation branches are otherwise designed without accounting for additive top-down evaluation — `table-relation-extensions-are-additive-and-top-down`.
- A `Media` or `MediaSet` field is assigned directly between different table types or different field IDs instead of registering each shared item with `MediaSet.Insert` — `share-mediaset-items-with-insert-not-field-assignment`.
+- A custom document header assigns defaults outside an `InitRecord` boundary, calls `InitRecord` before assigning its number, or places UI-independent defaults only in a page trigger — `initialize-document-defaults-in-initrecord`.
+- Directed `Round` calls use `'<'` as mathematical floor or `'>'` as mathematical ceiling, especially where negative amounts are possible — `round-direction-symbols-use-magnitude`.
Once the candidate worklist is known, resolve layer-precedence conflicts per READ. Drop lower-precedence files whose normative guidance (`## Best Practice` or `## Anti Pattern`) directly contradicts a higher-precedence candidate, and record each dropped file in `suppressed` with `reason: "layer-precedence"`. Files that would have been candidates but are hidden because their layer is disabled in consumer configuration are recorded with `reason: "configuration"`. Files that never became candidates are NOT recorded in `suppressed`.
diff --git a/microsoft/skills/review/al-interfaces-review.md b/microsoft/skills/review/al-interfaces-review.md
index 0031e8f..59c9333 100644
--- a/microsoft/skills/review/al-interfaces-review.md
+++ b/microsoft/skills/review/al-interfaces-review.md
@@ -39,7 +39,7 @@ Narrow the relevant files to the subset that applies to the changes under review
- The changed AL object names and types — especially `interface` objects, codeunits and enums declared with the `implements` keyword, and consumers that declare or assign an `Interface` variable.
- The changed procedures and triggers, weighted toward factory or dispatch routines that resolve a variant to behaviour, setter-injection procedures that take an `Interface` parameter, and `case`-over-enum blocks that select between strategies.
-- Tokens extracted from the diff that relate to interfaces and enum-backed implementation (`interface`, `extends`, `implements`, `Implementation`, `DefaultImplementation`, `UnknownValueImplementation`, `enum`, `Extensible`, `Interface`, `case`, and the `case of` anti-pattern signal — a `case` over an enum value whose branches choose between variant computations).
+- Tokens extracted from the diff that relate to interfaces and enum-backed implementation (`interface`, `extends`, `implements`, `Implementation`, `DefaultImplementation`, `UnknownValueImplementation`, `enum`, `Extensible`, `Interface`, `Variant`, `is`, `as`, `case`, and the `case of` anti-pattern signal — a `case` over an enum value whose branches choose between variant computations).
A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed object type. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone.
@@ -54,6 +54,7 @@ The following targeted checks map diff signals to specific `interfaces` articles
- `DefaultImplementation` used as the only fallback where a persisted ordinal may no longer match any declared enum value, or a persisted enum lacks `UnknownValueImplementation` on BC18 or later — `handle-unknown-enum-ordinals-with-unknownvalueimplementation`.
- A method added directly to an interface that exists in the baseline, instead of adding a BC25+ interface that `extends` it or a versioned sibling for older targets — `extend-published-interfaces-dont-edit-them`.
- A declared enum value with no `Implementation` and no enum-level `DefaultImplementation` — `set-defaultimplementation-on-enum`.
+- An `Interface` or `Variant` is cast with `as` to an optional extended interface without first establishing support with `is` — `guard-interface-casts-with-is`.
For `set-defaultimplementation-on-enum`, inspect the complete containing enum before emitting. An enum-level `DefaultImplementation = = ;` conclusively covers every declared value that omits its own `Implementation`; do not flag such a value and do not replace the intentional fallback with a per-value mapping.
diff --git a/microsoft/skills/review/al-style-review.md b/microsoft/skills/review/al-style-review.md
index bffef4d..d89d74e 100644
--- a/microsoft/skills/review/al-style-review.md
+++ b/microsoft/skills/review/al-style-review.md
@@ -41,7 +41,7 @@ Narrow the relevant files to the subset that applies to the changes under review
- Changed AL objects — especially API pages (`PageType = API`), tables and pages declaring Labels/TextConsts, codeunits issuing `Error`/`Message`/`Confirm`, and any file whose name violates the `..al` convention.
- Changed declarations, weighted toward `: Label '...'`, `: TextConst '...'`, temporary record variables, option fields, error-handling call sites, and codeunit-internal method calls.
-- Tokens extracted from the diff (`Label`, `TextConst`, `Locked`, `Comment`, `MaxLength`, `temporary`, `OptionMembers`, `OptionCaption`, `APIPublisher`, `APIGroup`, `APIVersion`, `EntityName`, `EntitySetName`, `DelayedInsert`, `FieldCaption`, `TableCaption`, `FieldName`, `TableName`, `Page.RunModal`, `Report.Run`, `this.`, `StrSubstNo`).
+- Tokens extracted from the diff (`Label`, `TextConst`, `Locked`, `Comment`, `MaxLength`, `temporary`, `OptionMembers`, `OptionCaption`, `ApplicationArea`, `APIPublisher`, `APIGroup`, `APIVersion`, `EntityName`, `EntitySetName`, `DelayedInsert`, `FieldCaption`, `TableCaption`, `FieldName`, `TableName`, `Page.RunModal`, `Report.Run`, `this.`, `StrSubstNo`).
A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed object or declaration. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone.
@@ -51,6 +51,7 @@ Apply these high-signal mappings before fuzzy topic ranking:
- A `Label` or `TextConst` contains multiple or ambiguous placeholders but has no `Comment`, or its Comment does not explain every placeholder — `label-comment-explains-placeholders.md`. A single placeholder whose meaning is explicit in the text, such as `Customer %1`, is allowed without a Comment and must not be flagged.
- `function-call-parentheses-required.md` applies only to a zero-argument invocation written without `()`. Never worklist it from an invocation that already has parentheses or supplies arguments, including `Error(Label, Arg1, Arg2)`.
+- On runtime 10.0 or later, a page child may inherit `ApplicationArea` from its page object; do not flag that shape. A control added by a page or report extension still requires an explicit value — `applicationarea-required-on-page-controls.md`.
Once the candidate worklist is known, resolve layer-precedence conflicts per READ and record suppressions.
diff --git a/microsoft/skills/review/al-ui-review.md b/microsoft/skills/review/al-ui-review.md
index c0af5af..f26cf48 100644
--- a/microsoft/skills/review/al-ui-review.md
+++ b/microsoft/skills/review/al-ui-review.md
@@ -41,10 +41,15 @@ Narrow the relevant files to the subset that applies to the changes under review
- **UI-file filter.** UI review applies to files declaring `page`, `pageextension`, or `pagecustomization`, and to JavaScript/CSS/HTML that implements a control add-in's rendering or Business Central communication. When the diff contains no such files, return `outcome: "not-applicable"` without evaluating knowledge files.
- For each relevant knowledge file, compute overlap against changed page declarations and control add-in files, weighted toward `Caption`, `ToolTip`, `AboutTitle`, `AboutText`, `OptionCaption`, `ShowCaption`, `InstructionalText`, `GridLayout`, `Style`, `StyleExpr`, promoted action definitions, field importance, page background tasks, DOM creation, ARIA attributes, keyboard/focus handlers, packaged-resource AJAX, and calls from JavaScript into AL.
-- Tokens extracted from the diff (`Caption`, `ToolTip`, `AboutTitle`, `AboutText`, `PageType`, `ShowCaption`, `InstructionalText`, `grid`, `fixed`, `GridLayout`, `Style`, `StyleExpr`, `Importance`, `Promoted`, `Additional`, `area(Promoted)`, `actionref`, `PromotedCategory`, `PromotedOnly`, `PromotedIsBig`, `ShowAs`, `SplitButton`, `EnqueueBackgroundTask`, `OnAfterGetCurrRecord`, `OnAfterGetRecord`, `OnPageBackgroundTaskCompleted`, `OnPageBackgroundTaskError`, `RunPageBackgroundTask`, `Favorable`, `Unfavorable`, `Ambiguous`, `cuegroup`, `controladdin`, `control-add-in`, `usercontrol`, `aria-`, `tabindex`, `keydown`, `focus`, `innerHTML`, `createElement`, `packaged-resource`, `ajax`, `$.get`, `$.ajax`, `XMLHttpRequest`, `xhrFields`, `withCredentials`, `withcredentials`, `InvokeExtensibilityMethod`, `invokeextensibilitymethod`, `skipIfBusy`, `successCallback`, `success-callback`, `errorCallback`, `setInterval`, `JSON.stringify`, `payload`, `throttling`, `reduced-functionality`, `ClientServicesMaxUploadSize`, `&`, `Specifies`, `Message(`, `Confirm(`, `Error(` in a page context, `Disabled`, `Invalid`, `Whitelist`, `Blacklist`, trailing punctuation patterns on captions).
+- Tokens extracted from the diff (`Caption`, `ToolTip`, `AboutTitle`, `AboutText`, `PageType`, `ShowCaption`, `InstructionalText`, `grid`, `fixed`, `GridLayout`, `Style`, `StyleExpr`, `Importance`, `Promoted`, `Additional`, `area(Promoted)`, `actionref`, `PromotedCategory`, `PromotedOnly`, `PromotedIsBig`, `ShowAs`, `SplitButton`, `fieldgroups`, `DropDown`, `UpdatePropagation`, `EnqueueBackgroundTask`, `OnAfterGetCurrRecord`, `OnAfterGetRecord`, `OnPageBackgroundTaskCompleted`, `OnPageBackgroundTaskError`, `RunPageBackgroundTask`, `Favorable`, `Unfavorable`, `Ambiguous`, `cuegroup`, `controladdin`, `control-add-in`, `usercontrol`, `aria-`, `tabindex`, `keydown`, `focus`, `innerHTML`, `createElement`, `packaged-resource`, `ajax`, `$.get`, `$.ajax`, `XMLHttpRequest`, `xhrFields`, `withCredentials`, `withcredentials`, `InvokeExtensibilityMethod`, `invokeextensibilitymethod`, `skipIfBusy`, `successCallback`, `success-callback`, `errorCallback`, `setInterval`, `JSON.stringify`, `payload`, `throttling`, `reduced-functionality`, `ClientServicesMaxUploadSize`, `&`, `Specifies`, `Message(`, `Confirm(`, `Error(` in a page context, `Disabled`, `Invalid`, `Whitelist`, `Blacklist`, trailing punctuation patterns on captions).
A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed page element. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone.
+Apply these high-signal mappings before fuzzy topic ranking:
+
+- A tableextension adds a field to `DropDown` while the corresponding lookup-page control remains `Visible = false` — `dropdown-fieldgroup-respects-lookup-page-visibility`.
+- An editable page part affects a total, FlowField, or FactBox on the parent but does not set `UpdatePropagation = Both` — `updatepropagation-both-refreshes-main-page`.
+
Once the candidate worklist is known, resolve layer-precedence conflicts per READ and record suppressions.
When the post-conflict worklist is empty because no applicable UI knowledge exists, or because configuration suppressed every candidate, emit `outcome: "no-knowledge"`. When the worklist is empty because no applicable UI knowledge matched the page changes, emit `outcome: "completed"` with an empty `findings` array.
diff --git a/microsoft/skills/review/al-upgrade-review.md b/microsoft/skills/review/al-upgrade-review.md
index 667ea32..4d69118 100644
--- a/microsoft/skills/review/al-upgrade-review.md
+++ b/microsoft/skills/review/al-upgrade-review.md
@@ -39,10 +39,12 @@ Narrow the relevant files to the subset that applies to the changes under review
- The changed AL object names and types — especially codeunits with `Subtype = Upgrade` or `Subtype = Install`, tables and tableextensions adding or changing fields, enums and enumextensions, and objects under `Hybrid*`/`Migration`/`Upgrade` namespaces.
- The changed triggers and procedures, weighted toward `OnCheckPreconditionsPerCompany`/`PerDatabase`, `OnUpgradePerCompany`/`PerDatabase`, `OnValidateUpgradePerCompany`/`PerDatabase`, `OnInstallAppPerCompany`/`PerDatabase`, the `OnGetPerCompanyUpgradeTags`/`OnGetPerDatabaseUpgradeTags` subscribers, and helper procedures transitively reachable from those entry points.
-- Tokens extracted from the diff that relate to upgrade concerns (`Subtype = Upgrade`, `Subtype = Install`, `Upgrade Tag`, `HasUpgradeTag`, `SetUpgradeTag`, `OnCheckPreconditions`, `OnUpgrade`, `OnValidateUpgrade`, `OnInstallApp`, `DataTransfer`, `CopyFields`, `Insert`, `Modify`, `Delete`, `Rename`, `InitValue`, `ObsoleteState`, `ObsoleteReason`, `ObsoleteTag`, `DataVersion`, `ExecutionContext`, `PrimaryKey`, `key(`, `field(`, `value(`, `enum`, `enumextension`, `HybridSL`, `HybridGP`, `HybridBC`, `HybridBaseDeployment`).
+- Tokens extracted from the diff that relate to upgrade concerns (`Subtype = Upgrade`, `Subtype = Install`, `Upgrade Tag`, `HasUpgradeTag`, `SetUpgradeTag`, `OnCheckPreconditions`, `OnUpgrade`, `OnValidateUpgrade`, `OnInstallApp`, `DataTransfer`, `CopyFields`, `Insert`, `Modify`, `Delete`, `Rename`, `InitValue`, `ObsoleteState`, `ObsoleteReason`, `ObsoleteTag`, `ModuleInfo`, `AppVersion`, `DataVersion`, `NavApp.GetCurrentModuleInfo`, `ExecutionContext`, `PrimaryKey`, `key(`, `field(`, `value(`, `enum`, `enumextension`, `HybridSL`, `HybridGP`, `HybridBC`, `HybridBaseDeployment`).
- For each `OnCheckPreconditions...` and `OnValidateUpgrade...` trigger, build the best available call graph from surrounding unchanged source as well as changed hunks, tracing resolved calls through reachable local or internal helpers. Worklist the check-only rule when a database write occurs either directly in the trigger or in any helper procedure reachable from it. Writes include `Insert`, `Modify`, `ModifyAll`, `Delete`, `DeleteAll`, `Rename`, and `DataTransfer`. Also perform the reverse check when a PR changes a writing helper body: worklist the rule when that helper is invoked directly or transitively by an unchanged check or validation trigger.
- Treat a direct write or a fully resolved call chain as high-confidence evidence. When cross-object dispatch, unavailable declarations, or an incomplete call graph prevents proving the complete chain, cap confidence at `medium`, name the unresolved edge in the finding, and do not claim a violation without a resolved path from a check or validation trigger to a write.
- Worklist the install-versus-upgrade rule when migration helpers are reachable only from an install codeunit.
+- Worklist `install-and-upgrade-codeunits-have-no-order.md` when a change adds multiple install or upgrade codeunits whose same-phase triggers share state or depend on one another.
+- Worklist `appversion-meaning-depends-on-execution-context.md` when install or upgrade code branches on `ModuleInfo.AppVersion()` or confuses it with `DataVersion()`.
A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed object type. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone. When the diff contains no upgrade-related changes by any of the above signals, return `outcome: "not-applicable"` without evaluating files.
diff --git a/plugin.json b/plugin.json
index c99785b..d74e69a 100644
--- a/plugin.json
+++ b/plugin.json
@@ -1,7 +1,7 @@
{
"name": "bcquality",
- "description": "Quality skills and knowledge for Business Central development. Exposes a standalone AL review adapter backed by BCQuality's Entry protocol.",
- "version": "0.2.0",
+ "description": "Quality skills and knowledge for Business Central development. Exposes AL development and code-review adapters backed by BCQuality's Entry protocol.",
+ "version": "0.3.0",
"author": {
"name": "microsoft/BCQuality",
"url": "https://github.com/microsoft/BCQuality"
@@ -13,6 +13,7 @@
"al",
"business-central",
"code-review",
+ "development",
"quality"
],
"skills": [
diff --git a/skills/README.md b/skills/README.md
index 3d8fdfb..a5f78ef 100644
--- a/skills/README.md
+++ b/skills/README.md
@@ -1,7 +1,7 @@
# BCQuality global skills
This folder contains BCQuality's layer-independent protocol files and the
-host-native adapter used by standalone plugin installations.
+host-native adapters used by standalone plugin installations.
The protocol files have two kinds:
@@ -31,8 +31,9 @@ READ and DO are read on demand — typically by the first action skill the agent
| Path | Role |
|---|---|
| [`al-code-review/SKILL.md`](al-code-review/SKILL.md) | Exposes BCQuality through the standard `SKILL.md` format when this repository is installed as a plugin. |
+| [`al-development/SKILL.md`](al-development/SKILL.md) | Exposes knowledge-backed AL development through the standard `SKILL.md` format. |
-The adapter is deliberately thin. It translates the caller's request into an
+Each adapter is deliberately thin. It translates the caller's request into an
Entry task context, then follows Entry's dispatch without owning routing,
review, index, or output policy. It is not an action skill, is not considered
by Entry, and should not accumulate behavior already defined by `entry.md`,
@@ -40,20 +41,23 @@ by Entry, and should not accumulate behavior already defined by `entry.md`,
This gives the two skill formats distinct roles:
-- `skills/al-code-review/SKILL.md` is the public host integration surface for a
- standalone plugin installation.
+- `skills/al-code-review/SKILL.md` and
+ `skills/al-development/SKILL.md` are the public host integration
+ surfaces for a standalone plugin installation.
- `microsoft/skills/review/al-code-review.md` is BCQuality's internal
Microsoft-layer super-skill for coordinating a broad AL review.
+- `microsoft/skills/development/al-development.md` is the internal
+ Microsoft-layer implementation skill for all supported development modes.
+- `microsoft/skills/development/al-development-plan.md` is the read-only
+ planning interface for repository-specific orchestrators that retain
+ implementation ownership.
-The host adapter and internal coordinator deliberately share the
-`al-code-review` name because they represent the same user-facing operation in
-their respective formats. Their locations distinguish their roles. The
-adapter remains distinct from BC-ALAgents' separately installed `al-review`
-skill, avoiding a collision in hosts that use one shared skill inventory. The
-reference from the adapter to Entry, and from a dispatched super-skill to its
-leaf skills, is intentional progressive disclosure. It avoids registering
-every internal BCQuality protocol file as an ambient host skill while allowing
-each review domain to run in an isolated context.
+Each host adapter deliberately shares its name with the internal action skill
+for the same operation. Their locations distinguish the host integration from
+the layered policy. `al-code-review` remains distinct from BC-ALAgents'
+separately installed `al-review` skill, avoiding a collision in hosts that use
+one shared skill inventory. References from adapters to Entry, and from a
+dispatched super-skill to its leaves, are intentional progressive disclosure.
These contracts are stable. Changes require a PR approved by both maintainers.
diff --git a/skills/al-development/SKILL.md b/skills/al-development/SKILL.md
new file mode 100644
index 0000000..5f76980
--- /dev/null
+++ b/skills/al-development/SKILL.md
@@ -0,0 +1,29 @@
+---
+name: al-development
+description: Implement Business Central AL features, bug fixes, refactors, upgrades, and maintenance changes using BCQuality's curated platform knowledge.
+---
+
+# AL development
+
+This is BCQuality's host-native adapter for standalone plugin installations. It translates a coding request into Entry's task context; the internal action skill owns classification, investigation, design, implementation, validation, and review policy.
+
+When the target repository exposes a more specific local workflow for the request, such as an end-to-end bug-fix skill with its own environment and delivery gates, prefer that repository workflow unless the caller explicitly asks to use BCQuality's generic development skill.
+
+## Execute
+
+1. Resolve `PLUGIN_ROOT` to the directory containing this plugin's root `plugin.json`. This file is `PLUGIN_ROOT/skills/al-development/SKILL.md`; when the host does not expose the plugin root, resolve it two levels above this file.
+2. Build the `task-context` required by `PLUGIN_ROOT/skills/entry.md`:
+ - Copy the caller's request verbatim into `goal`.
+ - Set `inputs-available: [development-request, repository]`.
+ - Set `technologies: [al]` when the repository is an AL project.
+ - Pass `bc-version`, `countries`, and `application-area` only when supplied or reliably determined.
+ - Apply `BCQUALITY_ENABLED_LAYERS` and `BCQUALITY_DISABLED_SKILLS` exactly as the `al-code-review` adapter does.
+3. Read and execute `PLUGIN_ROOT/skills/entry.md`, including Preparation. Resolve every path it names against `PLUGIN_ROOT`, not the user's repository. If knowledge-index generation is unavailable, use READ's path-based fallback.
+4. Follow Entry's dispatch exactly. The normal result is `microsoft/skills/development/al-development.md`; do not select it directly or duplicate its behavior in this adapter.
+5. Normalize the caller's input as `development-request`:
+ - Plain text becomes `{ kind: auto, description: }`.
+ - Preserve an explicit `kind`, supplied plan, and `acceptance-criteria`.
+ - A plan-only input becomes `{ kind: auto, description: "Implement the supplied development plan.", plan: }`.
+ Pass the writable current workspace as `repository`, execute the dispatched skill, and return its `implementation-report` unchanged.
+
+The adapter never edits BCQuality itself unless BCQuality is the caller's target repository. The target of implementation is the repository supplied by the caller.
diff --git a/skills/do.md b/skills/do.md
index a79c5fc..154e14a 100644
--- a/skills/do.md
+++ b/skills/do.md
@@ -19,7 +19,7 @@ An action skill is a single markdown file with YAML frontmatter. It lives inside
- `/community/skills/` — community-contributed action skills.
- `/custom/skills/` — partner or customer action skills (typically in a consumer repo, not in BCQuality itself).
-Action skills do not live at the repo root. The files in `/skills/` — the three meta-skill contracts (READ, DO, WRITE) and the entry-point skill (`entry.md`, `kind: entry-point`) — are the only skills that sit outside a layer. The entry-point skill structurally follows this same four-step pattern but produces a dispatch record rather than a findings-report; see `skills/entry.md` for its contract.
+Action skills do not live at the repo root. The files in `/skills/` — the three meta-skill contracts (READ, DO, WRITE) and the entry-point skill (`entry.md`, `kind: entry-point`) — are the only skills that sit outside a layer. The entry-point skill structurally follows this same four-step pattern but produces a dispatch record rather than an action-skill report; see `skills/entry.md` for its contract.
## Skills hold mechanics; knowledge files hold BC facts
@@ -56,10 +56,20 @@ application-area: [all]
`bc-version`, `technologies`, `countries`, `application-area` are optional filters that let an orchestrator pre-select applicable skills for a task. They follow the same semantics as in READ.
-`inputs` is a list of abstract input types the skill **accepts**. Standard values: `pr-diff`, `object-list`, `file-path`, `repository`, `telemetry-query`. Semantics are any-of: the orchestrator supplies whichever listed input types it has, and the skill is invoked with a non-empty subset of its declared `inputs`. A skill that cannot proceed with the supplied subset MUST return `outcome: "not-applicable"`. `outputs` is always a single-element list naming the output kind; today only `findings-report` is defined.
+`inputs` is a list of abstract input types the skill **accepts**. Standard values: `pr-diff`, `object-list`, `file-path`, `repository`, `telemetry-query`, `development-request`, `development-plan`. Semantics are any-of: the orchestrator supplies whichever listed input types it has, and the skill is invoked with a non-empty subset of its declared `inputs`. A skill that cannot proceed with the supplied subset MUST return `outcome: "not-applicable"`.
+
+`outputs` is always a single-element list naming the output kind:
+
+- `findings-report` — evaluates an input and reports defects or observations.
+- `implementation-report` — changes a repository to satisfy a development request and reports the plan, knowledge used, changed files, validation, and post-implementation review.
+- `development-guidance-report` — selects and summarizes applicable BCQuality knowledge for an existing development plan without changing the target repository.
`sub-skills` is an optional field. When present and non-empty, the skill is a **super-skill** that composes other action skills; see *Composition* below. Values are repo-relative paths to action-skill files.
+`quality-skill` is optional on an action skill that emits an `implementation-report`. It names one repo-relative review action skill to run over the completed diff. It is a post-implementation gate, not a composed sub-skill: Entry does not route through it, and its complete findings-report is returned in `review`. Consumer configuration still applies; if the named quality skill is disabled or unavailable, record its validation as `not-run` and do not claim `completed`.
+
+`guidance-skill` is optional on an action skill that emits an `implementation-report`. It names one repo-relative read-only action skill that accepts a `development-plan` and emits a `development-guidance-report`. The implementation skill invokes it after forming its plan and before editing product code. Consumer configuration still applies; when guidance is disabled or unavailable, the implementation skill must not claim knowledge-backed development.
+
## Required sections
Every action skill MUST contain these five sections, in order:
@@ -80,7 +90,7 @@ Every action skill MUST contain these five sections, in order:
**Action.** Execute the skill's work against the worklist. Evaluate each item in the worklist against the task input and emit findings. The action step is where skill behavior differs; the preceding three steps are uniform.
-## Output contract
+## Findings-report contract
Every action skill emits a single JSON document that conforms to this schema:
@@ -242,6 +252,136 @@ Severity taxonomy:
- `minor` — quality concern; worth flagging but not a gate.
- `info` — observation or context; not actionable on its own.
+## Development-guidance-report contract
+
+An action skill with `outputs: [development-guidance-report]` emits one JSON document:
+
+```json
+{
+ "skill": { "id": "string", "version": 1 },
+ "outcome": "completed | not-applicable | no-knowledge | partial | failed",
+ "outcome-reason": "string",
+ "summary": {
+ "request": "string",
+ "kind": "feature | bug | refactor | upgrade | maintenance",
+ "candidates": 0,
+ "selected": 0
+ },
+ "context": {
+ "bc-version": "string",
+ "technologies": ["string"],
+ "countries": ["string"],
+ "application-area": ["string"],
+ "unknown": ["bc-version | technologies | countries | application-area"]
+ },
+ "knowledge": [
+ {
+ "path": "string",
+ "sha": "string",
+ "used-for": "string",
+ "constraints": ["string"],
+ "sample-paths": ["string"]
+ }
+ ],
+ "validation-considerations": [
+ {
+ "id": "string",
+ "reason": "string",
+ "evidence": "string"
+ }
+ ],
+ "suppressed": [
+ {
+ "reference": { "path": "string", "sha": "string" },
+ "reason": "layer-precedence | configuration"
+ }
+ ],
+ "unresolved": ["string"]
+}
+```
+
+The skill is read-only with respect to the target repository. `completed` means every selected article was opened and converted into faithful implementation constraints. `no-knowledge` means no applicable article survived filtering; `knowledge` is empty. `partial` means candidate evaluation stopped early, with the gap named in `outcome-reason` and `unresolved`.
+
+`knowledge[].constraints` summarizes only normative `## Best Practice` and `## Anti Pattern` content from the referenced article. It must not introduce a Business Central fact absent from that article. `sample-paths` contains only sibling samples that exist and were opened. Every path is subject to the reference-integrity gate.
+
+`validation-considerations` states evidence the implementation workflow should obtain; it does not claim that a command or test has run. `unresolved` records missing repository context or plan decisions that prevent a reliable constraint. Unknown applicability dimensions must appear in both `context.unknown` and a relevant unresolved entry.
+
+## Implementation-report contract
+
+An action skill with `outputs: [implementation-report]` emits one JSON document:
+
+```json
+{
+ "skill": { "id": "string", "version": 1 },
+ "outcome": "completed | not-applicable | no-knowledge | partial | failed",
+ "outcome-reason": "string",
+ "summary": {
+ "request": "string",
+ "files-created": 0,
+ "files-modified": 0,
+ "files-deleted": 0
+ },
+ "plan": {
+ "kind": "feature | bug | refactor | upgrade | maintenance",
+ "assumptions": ["string"],
+ "decisions": ["string"],
+ "objects": ["string"]
+ },
+ "knowledge": [
+ { "path": "string", "sha": "string", "used-for": "string" }
+ ],
+ "changes": [
+ {
+ "path": "string",
+ "action": "created | modified | deleted",
+ "purpose": "string"
+ }
+ ],
+ "validation": [
+ {
+ "id": "string",
+ "command": "string",
+ "status": "passed | failed | not-run",
+ "details": "string"
+ }
+ ],
+ "review": { "...full findings-report from the post-implementation review..." : null },
+ "suppressed": [
+ {
+ "reference": { "path": "string", "sha": "string" },
+ "reason": "layer-precedence | configuration"
+ }
+ ],
+ "remaining": ["string"]
+}
+```
+
+### Implementation outcome semantics
+
+- `completed` — the requested change is persisted in the repository, required validation passed, and the post-implementation review has no unresolved `blocker` or `major` finding.
+- `not-applicable` — the request is not an implementation task accepted by the skill, or the supplied repository does not contain the required technology.
+- `no-knowledge` — no applicable BCQuality knowledge survived filtering and the skill cannot safely implement the Business Central-specific request. No request changes are made.
+- `partial` — useful changes were persisted, but part of the requested scope, validation, or post-implementation review could not be completed. `outcome-reason` and `remaining` identify the unfinished work.
+- `failed` — the skill could not produce a reliable implementation. `outcome-reason` is required. Any working-tree changes remain visible and MUST still be listed in `changes`.
+
+### Implementation field semantics
+
+**`summary.request`** is a concise statement of the implemented change. File counts describe only changes made by this skill; pre-existing user changes are excluded.
+
+**`plan`** records the implementation decisions needed to understand the result. `kind` is the classified development mode: `feature`, `bug`, `refactor`, `upgrade`, or `maintenance`. `assumptions` contains only assumptions actually made; `decisions` captures consequential design choices; `objects` names the Business Central objects or other artifacts created or changed.
+
+**`knowledge`** lists every knowledge file whose normative guidance materially shaped the implementation. `path` and optional `sha` follow the same reference format as a findings-report. `used-for` briefly names the design or implementation decision. The reference-integrity gate applies: every path must exist in the live checkout, be copied verbatim from discovery, and have been opened in full. Applicability alone is not enough to list an article.
+
+**`changes`** is an exhaustive list of files created, modified, or deleted by the skill. Paths are repository-relative and use forward slashes. Do not include unrelated pre-existing changes.
+
+**`validation`** records commands actually run. `passed` and `failed` require a real command result; unavailable tooling or an intentionally skipped check is `not-run` with `details`. A skill MUST NOT manufacture a successful check or replace a failed command with a success-shaped fallback.
+
+**`review`** is optional for generic implementation skills and required when a skill's instructions mandate post-implementation review. When present, it is the complete findings-report returned by that review skill, not a rewritten summary.
+
+**`suppressed`** has the same semantics as in a findings-report and records applicable knowledge excluded by layer precedence or configuration.
+
+**`remaining`** contains concrete unfinished work only. It is empty for `completed`.
+
## Composition (super-skills)
A **super-skill** is an action skill whose frontmatter declares a non-empty `sub-skills: [...]`. A super-skill does not evaluate knowledge files directly; it invokes other action skills and composes their output.
@@ -316,4 +456,4 @@ Conforms to the DO output contract.
## How orchestrators consume output
-An orchestrator invokes an action skill with an input appropriate to the skill's declared `inputs`, receives the JSON output, and maps findings to its delivery surface (PR comments, build gates, IDE diagnostics). The orchestrator MUST NOT interpret skill-specific fields beyond the schema above. Skills that need richer semantics MUST encode them within the schema (for example, by adding structured `message` text) rather than extending the output shape.
+An orchestrator invokes an action skill with an input appropriate to the skill's declared `inputs` and uses the single output kind declared in frontmatter. It maps a `findings-report` to PR comments, build gates, or IDE diagnostics; a `development-guidance-report` to constraints for a downstream implementation workflow; and an `implementation-report` to a coding-session summary, changed-file view, validation status, and any remaining work. The orchestrator MUST NOT interpret fields beyond the three schemas above.
diff --git a/skills/entry.md b/skills/entry.md
index 0196c35..4a1b613 100644
--- a/skills/entry.md
+++ b/skills/entry.md
@@ -21,6 +21,9 @@ The agent invokes Entry with a **task context** supplied by the orchestrator:
task-context:
goal: string # free-text description of what needs doing
inputs-available: # values the orchestrator has ready to pass to a chosen skill
+ - development-request
+ - development-plan
+ - repository
- pr-diff
- file-path
technologies: [al]
@@ -174,7 +177,7 @@ Populated example (PR review on a repo where only `al-performance-review` is ena
1. Invoke Entry with the orchestrator-supplied task context.
2. Receive the dispatch record.
-3. For each entry in `dispatch[]`, read the referenced action skill, execute its Source → Relevance → Worklist → Action steps per DO, and produce a findings-report.
-4. Return the findings-reports to the orchestrator. When `outcome` is `no-match` or `failed`, return the dispatch record itself so the orchestrator can log the reason.
+3. For each entry in `dispatch[]`, read the referenced action skill, execute its Source → Relevance → Worklist → Action steps per DO, and produce the report kind declared by that skill's single `outputs` value.
+4. Return the action-skill reports to the orchestrator. When Entry's `outcome` is `no-match` or `failed`, return the dispatch record itself so the orchestrator can log the reason.
READ and DO are the contracts that govern what the dispatched skills do. An agent that has not yet read READ and DO reads them when it executes the first dispatched skill — they are not prerequisites for invoking Entry.
diff --git a/tools/Test-DevelopmentFixtures.ps1 b/tools/Test-DevelopmentFixtures.ps1
new file mode 100644
index 0000000..ecd5259
--- /dev/null
+++ b/tools/Test-DevelopmentFixtures.ps1
@@ -0,0 +1,516 @@
+<#
+.SYNOPSIS
+ Validates and prepares BCQuality AL development fixtures.
+
+.DESCRIPTION
+ Static validation checks fixture IDs, capability links, knowledge references,
+ and the development skill. -PrepareDirectory emits opaque requests for model
+ runs. -ResultsDirectory scores implementation reports produced by an
+ external runner that performed the declared compile, test, and review checks.
+#>
+[CmdletBinding()]
+param(
+ [string] $Root = (Resolve-Path (Join-Path $PSScriptRoot '..')),
+ [string] $ManifestPath,
+ [string] $CapabilitiesPath,
+ [string] $PrepareDirectory,
+ [string] $ResultsDirectory
+)
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+$Root = (Resolve-Path -LiteralPath $Root).Path
+if (-not $ManifestPath) {
+ $ManifestPath = Join-Path $Root 'evaluation/development-fixtures.json'
+}
+if (-not $CapabilitiesPath) {
+ $CapabilitiesPath = Join-Path $Root 'coverage/development-capabilities.json'
+}
+
+$manifest = Get-Content -LiteralPath $ManifestPath -Raw | ConvertFrom-Json
+$capabilityManifest = Get-Content -LiteralPath $CapabilitiesPath -Raw | ConvertFrom-Json
+$problems = [System.Collections.Generic.List[string]]::new()
+
+function Get-ModelCaseId {
+ param([string] $ManifestId)
+
+ $sha = [System.Security.Cryptography.SHA256]::Create()
+ try {
+ $bytes = [System.Text.Encoding]::UTF8.GetBytes($ManifestId)
+ $hash = $sha.ComputeHash($bytes)
+ $token = ([System.BitConverter]::ToString($hash) -replace '-', '').Substring(0, 8).ToLowerInvariant()
+ return "case-$token"
+ } finally {
+ $sha.Dispose()
+ }
+}
+
+if ($manifest.version -ne 1) {
+ $problems.Add("Unsupported development fixture version: $($manifest.version)") | Out-Null
+}
+if ($capabilityManifest.version -ne 1) {
+ $problems.Add("Unsupported capability manifest version: $($capabilityManifest.version)") | Out-Null
+}
+foreach ($thresholdName in @('minimumKnowledgeRecall', 'minimumKnowledgePrecision')) {
+ $threshold = [double]$manifest.$thresholdName
+ if ($threshold -lt 0 -or $threshold -gt 1) {
+ $problems.Add("$thresholdName must be between 0 and 1.") | Out-Null
+ }
+}
+
+$skillPath = [string]$manifest.skill
+if (-not (Test-Path -LiteralPath (Join-Path $Root $skillPath) -PathType Leaf)) {
+ $problems.Add("Development skill does not exist: $skillPath") | Out-Null
+}
+
+$validChecks = @('compile', 'tests', 'review')
+$validInputKinds = @('auto', 'feature', 'bug', 'refactor', 'upgrade', 'maintenance')
+$validOutputKinds = @('feature', 'bug', 'refactor', 'upgrade', 'maintenance')
+$caseById = @{}
+foreach ($case in @($manifest.cases)) {
+ $id = [string]$case.id
+ if ($id -notmatch '^[a-z0-9]+(?:-[a-z0-9]+)*$') {
+ $problems.Add("Fixture id must be kebab-case: '$id'.") | Out-Null
+ } elseif ($caseById.ContainsKey($id)) {
+ $problems.Add("Duplicate fixture id: $id") | Out-Null
+ } else {
+ $caseById[$id] = $case
+ }
+
+ if ($case.PSObject.Properties.Name -notcontains 'development-request') {
+ $problems.Add("${id}: development-request is required.") | Out-Null
+ continue
+ }
+ $request = $case.'development-request'
+ if ($validInputKinds -notcontains [string]$request.kind) {
+ $problems.Add("${id}: development-request.kind must be one of $($validInputKinds -join ', ').") | Out-Null
+ }
+ $description = if ($request.PSObject.Properties.Name -contains 'description') {
+ [string]$request.description
+ } else {
+ ''
+ }
+ $planText = if ($request.PSObject.Properties.Name -contains 'plan') {
+ [string]$request.plan
+ } else {
+ ''
+ }
+ if ([string]::IsNullOrWhiteSpace($description) -and [string]::IsNullOrWhiteSpace($planText)) {
+ $problems.Add("${id}: development-request requires description or plan.") | Out-Null
+ }
+ if ($request.PSObject.Properties.Name -notcontains 'acceptance-criteria' -or
+ -not @($request.'acceptance-criteria').Count) {
+ $problems.Add("${id}: development-request.acceptance-criteria must not be empty.") | Out-Null
+ }
+ $expectedKind = if ($case.PSObject.Properties.Name -contains 'expectedKind') {
+ [string]$case.expectedKind
+ } else {
+ ''
+ }
+ if ($validOutputKinds -notcontains $expectedKind) {
+ $problems.Add("${id}: expectedKind must be one of $($validOutputKinds -join ', ').") | Out-Null
+ }
+ if ([string]$request.kind -ne 'auto' -and [string]$request.kind -ne $expectedKind) {
+ $problems.Add("${id}: explicit request kind '$($request.kind)' must equal expectedKind '$expectedKind'.") | Out-Null
+ }
+
+ $expectedKnowledge = @($case.requiredKnowledge) + @($case.optionalKnowledge)
+ if (@($expectedKnowledge | Sort-Object -Unique).Count -ne $expectedKnowledge.Count) {
+ $problems.Add("${id}: requiredKnowledge and optionalKnowledge contain duplicates.") | Out-Null
+ }
+ foreach ($reference in $expectedKnowledge) {
+ $reference = [string]$reference
+ if ($reference.Contains('\') -or -not $reference.EndsWith('.md')) {
+ $problems.Add("${id}: invalid knowledge path: $reference") | Out-Null
+ } elseif (-not (Test-Path -LiteralPath (Join-Path $Root $reference) -PathType Leaf)) {
+ $problems.Add("${id}: knowledge article does not exist: $reference") | Out-Null
+ }
+ }
+ foreach ($check in @($case.requiredChecks)) {
+ if ($validChecks -notcontains [string]$check) {
+ $problems.Add("${id}: unsupported required check '$check'.") | Out-Null
+ }
+ }
+}
+
+$validCapabilityStatuses = @('planned', 'fixture', 'validated')
+$capabilityIds = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
+foreach ($capability in @($capabilityManifest.capabilities)) {
+ $id = [string]$capability.id
+ if (-not $capabilityIds.Add($id)) {
+ $problems.Add("Duplicate capability id: $id") | Out-Null
+ }
+ if ($validCapabilityStatuses -notcontains [string]$capability.status) {
+ $problems.Add("${id}: invalid capability status '$($capability.status)'.") | Out-Null
+ }
+ $fixtureIds = @($capability.fixtureIds)
+ if ($capability.status -in @('fixture', 'validated') -and -not $fixtureIds.Count) {
+ $problems.Add("${id}: status '$($capability.status)' requires at least one fixture.") | Out-Null
+ }
+ foreach ($fixtureId in $fixtureIds) {
+ if (-not $caseById.ContainsKey([string]$fixtureId)) {
+ $problems.Add("${id}: unknown fixture id '$fixtureId'.") | Out-Null
+ } elseif (@($caseById[[string]$fixtureId].capabilities) -notcontains $id) {
+ $problems.Add("${id}: fixture '$fixtureId' does not link back to the capability.") | Out-Null
+ }
+ }
+}
+
+foreach ($case in @($manifest.cases)) {
+ foreach ($capabilityId in @($case.capabilities)) {
+ if (-not $capabilityIds.Contains([string]$capabilityId)) {
+ $problems.Add("$($case.id): unknown capability '$capabilityId'.") | Out-Null
+ continue
+ }
+ $capability = @(
+ $capabilityManifest.capabilities |
+ Where-Object id -eq ([string]$capabilityId)
+ )[0]
+ if (@($capability.fixtureIds) -notcontains [string]$case.id) {
+ $problems.Add("$($case.id): capability '$capabilityId' does not link back to the fixture.") | Out-Null
+ }
+ }
+}
+
+if ($problems.Count) {
+ Write-Host "Development fixture validation FAILED ($($problems.Count) problem(s)):" -ForegroundColor Red
+ $problems | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
+ exit 1
+}
+
+if ($PrepareDirectory) {
+ $markerPath = Join-Path $PrepareDirectory '.bcquality-development-evaluation'
+ if (Test-Path -LiteralPath $PrepareDirectory) {
+ $existing = @(Get-ChildItem -LiteralPath $PrepareDirectory -Force)
+ if ($existing.Count -and -not (Test-Path -LiteralPath $markerPath -PathType Leaf)) {
+ throw "PrepareDirectory is not empty and is not a BCQuality development evaluation directory: $PrepareDirectory"
+ }
+ if (Test-Path -LiteralPath $markerPath -PathType Leaf) {
+ Get-ChildItem -LiteralPath $PrepareDirectory -File |
+ Where-Object {
+ $_.Name -eq 'knowledge-index.json' -or
+ $_.Name -like 'request-*.json' -or
+ $_.Name -like 'result-*.json'
+ } |
+ Remove-Item -Force
+ }
+ } else {
+ New-Item -ItemType Directory -Force -Path $PrepareDirectory | Out-Null
+ }
+ Set-Content -LiteralPath $markerPath -Value 'BCQuality generated development evaluation directory' -Encoding UTF8
+
+ $indexPath = Join-Path $PrepareDirectory 'knowledge-index.json'
+ & (Join-Path $Root 'tools/Build-KnowledgeIndex.ps1') -BCQualityRoot $Root -IndexPath $indexPath | Out-Null
+ $skillInstructions = Get-Content -LiteralPath (Join-Path $Root $skillPath) -Raw
+
+ foreach ($case in @($manifest.cases)) {
+ $modelId = Get-ModelCaseId ([string]$case.id)
+ $request = [ordered]@{
+ protocol = 'Run the supplied AL development skill in a fresh writable fixture repository. Persist the implementation, run real checks, and return only implementationReport using the supplied schema.'
+ caseId = $modelId
+ skill = $skillPath
+ skillInstructions = $skillInstructions
+ knowledgeIndex = 'knowledge-index.json'
+ 'task-context' = [ordered]@{
+ goal = if ($case.'development-request'.PSObject.Properties.Name -contains 'description') {
+ [string]$case.'development-request'.description
+ } else {
+ [string]$case.'development-request'.plan
+ }
+ 'inputs-available' = @('development-request', 'repository')
+ technologies = @($case.context.technologies)
+ countries = @($case.context.countries)
+ 'application-area' = @($case.context.'application-area')
+ }
+ 'development-request' = [ordered]@{
+ kind = [string]$case.'development-request'.kind
+ description = if ($case.'development-request'.PSObject.Properties.Name -contains 'description') {
+ [string]$case.'development-request'.description
+ } else {
+ $null
+ }
+ plan = if ($case.'development-request'.PSObject.Properties.Name -contains 'plan') {
+ [string]$case.'development-request'.plan
+ } else {
+ $null
+ }
+ 'acceptance-criteria' = @($case.'development-request'.'acceptance-criteria')
+ }
+ resultSchema = [ordered]@{
+ caseId = $modelId
+ workspaceRoot = 'absolute path to the retained fixture repository'
+ implementationReport = [ordered]@{
+ skill = [ordered]@{ id = 'al-development'; version = 1 }
+ outcome = 'completed | not-applicable | no-knowledge | partial | failed'
+ 'outcome-reason' = 'required for partial or failed'
+ summary = [ordered]@{
+ request = 'implemented change'
+ 'files-created' = 0
+ 'files-modified' = 0
+ 'files-deleted' = 0
+ }
+ plan = [ordered]@{
+ kind = 'feature | bug | refactor | upgrade | maintenance'
+ assumptions = @()
+ decisions = @()
+ objects = @()
+ }
+ knowledge = @([ordered]@{ path = 'repo-relative knowledge article path'; sha = 'optional commit sha'; 'used-for' = 'decision' })
+ changes = @([ordered]@{ path = 'repo-relative changed file'; action = 'created | modified | deleted'; purpose = 'reason' })
+ validation = @([ordered]@{ id = 'compile | tests | review'; command = 'command or quality-skill path'; status = 'passed | failed | not-run'; details = 'non-empty evidence' })
+ review = [ordered]@{
+ skill = [ordered]@{ id = 'al-code-review'; version = 1 }
+ outcome = 'completed | partial | failed'
+ summary = [ordered]@{
+ counts = [ordered]@{ blocker = 0; major = 0; minor = 0; info = 0 }
+ coverage = [ordered]@{ 'worklist-size' = 0; 'items-evaluated' = 0 }
+ }
+ findings = @()
+ suppressed = @()
+ }
+ suppressed = @()
+ remaining = @()
+ }
+ }
+ }
+ $request | ConvertTo-Json -Depth 12 |
+ Set-Content -LiteralPath (Join-Path $PrepareDirectory "request-$modelId.json") -Encoding UTF8
+ }
+}
+
+if ($ResultsDirectory) {
+ $failures = [System.Collections.Generic.List[string]]::new()
+ foreach ($case in @($manifest.cases)) {
+ $modelId = Get-ModelCaseId ([string]$case.id)
+ $resultPath = Join-Path $ResultsDirectory "result-$modelId.json"
+ if (-not (Test-Path -LiteralPath $resultPath -PathType Leaf)) {
+ $failures.Add("$($case.id): missing result file.") | Out-Null
+ continue
+ }
+ try {
+ $result = Get-Content -LiteralPath $resultPath -Raw | ConvertFrom-Json
+ } catch {
+ $failures.Add("$($case.id): result is not valid JSON: $($_.Exception.Message)") | Out-Null
+ continue
+ }
+ if ($result.PSObject.Properties.Name -notcontains 'caseId' -or [string]$result.caseId -ne $modelId) {
+ $failures.Add("$($case.id): result caseId mismatch.") | Out-Null
+ continue
+ }
+ if ($result.PSObject.Properties.Name -notcontains 'implementationReport') {
+ $failures.Add("$($case.id): implementationReport is missing.") | Out-Null
+ continue
+ }
+ $report = $result.implementationReport
+ foreach ($requiredField in @('skill', 'outcome', 'summary', 'plan', 'knowledge', 'changes', 'validation', 'review', 'suppressed', 'remaining')) {
+ if ($report.PSObject.Properties.Name -notcontains $requiredField) {
+ $failures.Add("$($case.id): implementation report is missing '$requiredField'.") | Out-Null
+ }
+ }
+ $reportedSkillId = if (
+ $report.PSObject.Properties.Name -contains 'skill' -and
+ $report.skill.PSObject.Properties.Name -contains 'id'
+ ) {
+ [string]$report.skill.id
+ } else {
+ ''
+ }
+ if ($reportedSkillId -ne 'al-development') {
+ $failures.Add("$($case.id): implementation report skill is '$reportedSkillId'.") | Out-Null
+ }
+ $summaryRequest = if (
+ $report.PSObject.Properties.Name -contains 'summary' -and
+ $report.summary.PSObject.Properties.Name -contains 'request'
+ ) {
+ [string]$report.summary.request
+ } else {
+ ''
+ }
+ if ([string]::IsNullOrWhiteSpace($summaryRequest)) {
+ $failures.Add("$($case.id): summary.request is missing or empty.") | Out-Null
+ }
+ $reportedKind = if (
+ $report.PSObject.Properties.Name -contains 'plan' -and
+ $report.plan.PSObject.Properties.Name -contains 'kind'
+ ) {
+ [string]$report.plan.kind
+ } else {
+ ''
+ }
+ if ($reportedKind -ne [string]$case.expectedKind) {
+ $failures.Add("$($case.id): plan.kind '$reportedKind' does not match expected mode '$($case.expectedKind)'.") | Out-Null
+ }
+ $outcome = if ($report.PSObject.Properties.Name -contains 'outcome') { [string]$report.outcome } else { '' }
+ if ($outcome -ne 'completed') {
+ $failures.Add("$($case.id): implementation outcome is '$outcome'.") | Out-Null
+ }
+
+ [object[]]$knowledgeEntries = @()
+ if ($report.PSObject.Properties.Name -contains 'knowledge') {
+ $knowledgeEntries = @($report.knowledge)
+ }
+ if (-not $knowledgeEntries.Count) {
+ $failures.Add("$($case.id): implementation report contains no knowledge entries.") | Out-Null
+ }
+ $usedKnowledge = @(
+ $knowledgeEntries |
+ Where-Object { $_.PSObject.Properties.Name -contains 'path' } |
+ ForEach-Object { [string]$_.path }
+ )
+ if (@($usedKnowledge | Sort-Object -Unique).Count -ne $usedKnowledge.Count) {
+ $failures.Add("$($case.id): knowledge contains duplicate paths.") | Out-Null
+ }
+ foreach ($entry in $knowledgeEntries) {
+ $path = if ($entry.PSObject.Properties.Name -contains 'path') { [string]$entry.path } else { '' }
+ $usedFor = if ($entry.PSObject.Properties.Name -contains 'used-for') { [string]$entry.'used-for' } else { '' }
+ if ([string]::IsNullOrWhiteSpace($path) -or
+ [System.IO.Path]::IsPathRooted($path) -or
+ @($path -split '/|\\') -contains '..' -or
+ -not (Test-Path -LiteralPath (Join-Path $Root $path) -PathType Leaf)) {
+ $failures.Add("$($case.id): knowledge entry has a missing or invalid path '$path'.") | Out-Null
+ }
+ if ([string]::IsNullOrWhiteSpace($usedFor)) {
+ $failures.Add("$($case.id): knowledge entry '$path' has no used-for explanation.") | Out-Null
+ }
+ }
+ $requiredKnowledge = @($case.requiredKnowledge | ForEach-Object { [string]$_ })
+ $matched = @($requiredKnowledge | Where-Object { $usedKnowledge -contains $_ }).Count
+ $recall = if ($requiredKnowledge.Count) { $matched / $requiredKnowledge.Count } else { 1.0 }
+ if ($recall -lt [double]$manifest.minimumKnowledgeRecall) {
+ $failures.Add("$($case.id): knowledge recall $recall is below $($manifest.minimumKnowledgeRecall).") | Out-Null
+ }
+ $acceptedKnowledge = @(
+ @($case.requiredKnowledge) + @($case.optionalKnowledge) |
+ ForEach-Object { [string]$_ } |
+ Sort-Object -Unique
+ )
+ $acceptedUsed = @($usedKnowledge | Where-Object { $acceptedKnowledge -contains $_ }).Count
+ $precision = if ($usedKnowledge.Count) { $acceptedUsed / $usedKnowledge.Count } else { 0.0 }
+ if ($precision -lt [double]$manifest.minimumKnowledgePrecision) {
+ $failures.Add("$($case.id): knowledge precision $precision is below $($manifest.minimumKnowledgePrecision).") | Out-Null
+ }
+
+ [object[]]$validationEntries = @()
+ if ($report.PSObject.Properties.Name -contains 'validation') {
+ $validationEntries = @($report.validation)
+ }
+ foreach ($requiredCheck in @($case.requiredChecks)) {
+ $check = @($validationEntries | Where-Object {
+ $_.PSObject.Properties.Name -contains 'id' -and [string]$_.id -eq $requiredCheck
+ })
+ $checkStatus = if ($check.Count -eq 1 -and $check[0].PSObject.Properties.Name -contains 'status') {
+ [string]$check[0].status
+ } else {
+ ''
+ }
+ if ($check.Count -ne 1 -or $checkStatus -ne 'passed') {
+ $failures.Add("$($case.id): required check '$requiredCheck' did not pass exactly once.") | Out-Null
+ continue
+ }
+ $command = if ($check[0].PSObject.Properties.Name -contains 'command') { [string]$check[0].command } else { '' }
+ $details = if ($check[0].PSObject.Properties.Name -contains 'details') { [string]$check[0].details } else { '' }
+ if ([string]::IsNullOrWhiteSpace($command) -or [string]::IsNullOrWhiteSpace($details)) {
+ $failures.Add("$($case.id): required check '$requiredCheck' lacks command or evidence details.") | Out-Null
+ }
+ }
+
+ [object[]]$changes = @()
+ if ($report.PSObject.Properties.Name -contains 'changes') {
+ $changes = @($report.changes)
+ }
+ if (-not $changes.Count) {
+ $failures.Add("$($case.id): implementation report contains no changed files.") | Out-Null
+ }
+
+ $workspaceRoot = if ($result.PSObject.Properties.Name -contains 'workspaceRoot') { [string]$result.workspaceRoot } else { '' }
+ if ([string]::IsNullOrWhiteSpace($workspaceRoot) -or
+ -not (Test-Path -LiteralPath $workspaceRoot -PathType Container)) {
+ $failures.Add("$($case.id): workspaceRoot is missing or unavailable.") | Out-Null
+ } else {
+ & git -C $workspaceRoot rev-parse --is-inside-work-tree 2>$null | Out-Null
+ if ($LASTEXITCODE -ne 0) {
+ $failures.Add("$($case.id): workspaceRoot is not a readable git worktree.") | Out-Null
+ continue
+ }
+ $actualChanges = @(
+ @(& git -C $workspaceRoot diff --name-only HEAD) +
+ @(& git -C $workspaceRoot ls-files --others --exclude-standard) |
+ Where-Object { -not [string]::IsNullOrWhiteSpace([string]$_) } |
+ ForEach-Object { ([string]$_).Replace('\', '/') } |
+ Sort-Object -Unique
+ )
+ if ($LASTEXITCODE -ne 0) {
+ $failures.Add("$($case.id): unable to read the workspace diff.") | Out-Null
+ } else {
+ $reportedChanges = @(
+ $changes |
+ Where-Object { $_.PSObject.Properties.Name -contains 'path' } |
+ ForEach-Object {
+ $path = ([string]$_.path).Replace('\', '/')
+ if ([System.IO.Path]::IsPathRooted($path) -or @($path -split '/') -contains '..') {
+ $failures.Add("$($case.id): changed path is not repository-relative: $path") | Out-Null
+ }
+ $path
+ } |
+ Sort-Object -Unique
+ )
+ foreach ($path in @($reportedChanges | Where-Object { $actualChanges -notcontains $_ })) {
+ $failures.Add("$($case.id): reported change is absent from the worktree diff: $path") | Out-Null
+ }
+ foreach ($path in @($actualChanges | Where-Object { $reportedChanges -notcontains $_ })) {
+ $failures.Add("$($case.id): worktree change is absent from the implementation report: $path") | Out-Null
+ }
+ }
+ }
+
+ if ($report.PSObject.Properties.Name -notcontains 'review') {
+ $failures.Add("$($case.id): complete post-implementation review is missing.") | Out-Null
+ } else {
+ $review = $report.review
+ foreach ($requiredField in @('skill', 'outcome', 'summary', 'findings', 'suppressed')) {
+ if ($review.PSObject.Properties.Name -notcontains $requiredField) {
+ $failures.Add("$($case.id): review is missing '$requiredField'.") | Out-Null
+ }
+ }
+ [object[]]$reviewFindings = @()
+ if ($review.PSObject.Properties.Name -contains 'findings') {
+ $reviewFindings = @($review.findings)
+ }
+ $reviewOutcome = if ($review.PSObject.Properties.Name -contains 'outcome') { [string]$review.outcome } else { '' }
+ if ($reviewOutcome -ne 'completed') {
+ $failures.Add("$($case.id): post-implementation review outcome is '$reviewOutcome'.") | Out-Null
+ }
+ $gatingFindings = @(
+ $reviewFindings |
+ Where-Object {
+ $_.PSObject.Properties.Name -contains 'severity' -and
+ [string]$_.severity -in @('blocker', 'major')
+ }
+ )
+ if ($gatingFindings.Count) {
+ $failures.Add("$($case.id): post-implementation review has $($gatingFindings.Count) gating finding(s).") | Out-Null
+ }
+ }
+ [object[]]$remaining = @()
+ if ($report.PSObject.Properties.Name -contains 'remaining') {
+ $remaining = @($report.remaining)
+ }
+ if ($remaining.Count) {
+ $failures.Add("$($case.id): completed report still lists remaining work.") | Out-Null
+ }
+ }
+
+ if ($failures.Count) {
+ Write-Host "Development fixture scoring FAILED ($($failures.Count) problem(s)):" -ForegroundColor Red
+ $failures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
+ exit 1
+ }
+ Write-Host "Development fixture scoring PASSED: $(@($manifest.cases).Count) case(s)."
+} else {
+ $fixtureBackedCapabilities = @(
+ $capabilityManifest.capabilities |
+ Where-Object status -in @('fixture', 'validated')
+ ).Count
+ Write-Host "Development fixture validation PASSED: $(@($manifest.cases).Count) cases; $fixtureBackedCapabilities of $($capabilityIds.Count) capabilities have fixtures."
+}
diff --git a/tools/Test-DevelopmentGuidanceFixtures.ps1 b/tools/Test-DevelopmentGuidanceFixtures.ps1
new file mode 100644
index 0000000..d8709ff
--- /dev/null
+++ b/tools/Test-DevelopmentGuidanceFixtures.ps1
@@ -0,0 +1,298 @@
+<#
+.SYNOPSIS
+ Validates, prepares, and scores read-only AL development-guidance fixtures.
+#>
+[CmdletBinding()]
+param(
+ [string] $Root = (Resolve-Path (Join-Path $PSScriptRoot '..')),
+ [string] $ManifestPath,
+ [string] $PrepareDirectory,
+ [string] $ResultsDirectory
+)
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+$Root = (Resolve-Path -LiteralPath $Root).Path
+if (-not $ManifestPath) {
+ $ManifestPath = Join-Path $Root 'evaluation/development-guidance-fixtures.json'
+}
+
+$manifest = Get-Content -LiteralPath $ManifestPath -Raw | ConvertFrom-Json
+$problems = [System.Collections.Generic.List[string]]::new()
+$validKinds = @('feature', 'bug', 'refactor', 'upgrade', 'maintenance')
+
+function Get-ModelCaseId {
+ param([string] $ManifestId)
+
+ $sha = [System.Security.Cryptography.SHA256]::Create()
+ try {
+ $bytes = [System.Text.Encoding]::UTF8.GetBytes($ManifestId)
+ $hash = $sha.ComputeHash($bytes)
+ $token = ([System.BitConverter]::ToString($hash) -replace '-', '').Substring(0, 8).ToLowerInvariant()
+ return "case-$token"
+ } finally {
+ $sha.Dispose()
+ }
+}
+
+if ($manifest.version -ne 1) {
+ $problems.Add("Unsupported guidance fixture version: $($manifest.version)") | Out-Null
+}
+foreach ($thresholdName in @('minimumKnowledgeRecall', 'minimumKnowledgePrecision')) {
+ $threshold = [double]$manifest.$thresholdName
+ if ($threshold -lt 0 -or $threshold -gt 1) {
+ $problems.Add("$thresholdName must be between 0 and 1.") | Out-Null
+ }
+}
+
+$skillPath = [string]$manifest.skill
+if (-not (Test-Path -LiteralPath (Join-Path $Root $skillPath) -PathType Leaf)) {
+ $problems.Add("Guidance skill does not exist: $skillPath") | Out-Null
+}
+
+$seenIds = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
+foreach ($case in @($manifest.cases)) {
+ $id = [string]$case.id
+ if ($id -notmatch '^[a-z0-9]+(?:-[a-z0-9]+)*$') {
+ $problems.Add("Fixture id must be kebab-case: '$id'.") | Out-Null
+ } elseif (-not $seenIds.Add($id)) {
+ $problems.Add("Duplicate fixture id: $id") | Out-Null
+ }
+ if ($case.PSObject.Properties.Name -notcontains 'development-plan') {
+ $problems.Add("${id}: development-plan is required.") | Out-Null
+ continue
+ }
+ $plan = $case.'development-plan'
+ if ($validKinds -notcontains [string]$plan.kind) {
+ $problems.Add("${id}: development-plan.kind is invalid.") | Out-Null
+ }
+ if ([string]::IsNullOrWhiteSpace([string]$plan.request)) {
+ $problems.Add("${id}: development-plan.request is required.") | Out-Null
+ }
+
+ $expectedKnowledge = @($case.requiredKnowledge) + @($case.optionalKnowledge)
+ if (@($expectedKnowledge | Sort-Object -Unique).Count -ne $expectedKnowledge.Count) {
+ $problems.Add("${id}: requiredKnowledge and optionalKnowledge contain duplicates.") | Out-Null
+ }
+ foreach ($reference in $expectedKnowledge) {
+ $reference = [string]$reference
+ if ($reference.Contains('\') -or -not $reference.EndsWith('.md')) {
+ $problems.Add("${id}: invalid knowledge path: $reference") | Out-Null
+ } elseif (-not (Test-Path -LiteralPath (Join-Path $Root $reference) -PathType Leaf)) {
+ $problems.Add("${id}: knowledge article does not exist: $reference") | Out-Null
+ }
+ }
+}
+
+if ($problems.Count) {
+ Write-Host "Development guidance fixture validation FAILED ($($problems.Count) problem(s)):" -ForegroundColor Red
+ $problems | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
+ exit 1
+}
+
+if ($PrepareDirectory) {
+ $markerPath = Join-Path $PrepareDirectory '.bcquality-development-guidance-evaluation'
+ if (Test-Path -LiteralPath $PrepareDirectory) {
+ $existing = @(Get-ChildItem -LiteralPath $PrepareDirectory -Force)
+ if ($existing.Count -and -not (Test-Path -LiteralPath $markerPath -PathType Leaf)) {
+ throw "PrepareDirectory is not empty and is not a BCQuality development-guidance evaluation directory: $PrepareDirectory"
+ }
+ if (Test-Path -LiteralPath $markerPath -PathType Leaf) {
+ Get-ChildItem -LiteralPath $PrepareDirectory -File |
+ Where-Object {
+ $_.Name -eq 'knowledge-index.json' -or
+ $_.Name -like 'request-*.json' -or
+ $_.Name -like 'result-*.json'
+ } |
+ Remove-Item -Force
+ }
+ } else {
+ New-Item -ItemType Directory -Force -Path $PrepareDirectory | Out-Null
+ }
+ Set-Content -LiteralPath $markerPath -Value 'BCQuality generated development-guidance evaluation directory' -Encoding UTF8
+
+ $indexPath = Join-Path $PrepareDirectory 'knowledge-index.json'
+ & (Join-Path $Root 'tools/Build-KnowledgeIndex.ps1') -BCQualityRoot $Root -IndexPath $indexPath | Out-Null
+ $skillInstructions = Get-Content -LiteralPath (Join-Path $Root $skillPath) -Raw
+
+ foreach ($case in @($manifest.cases)) {
+ $modelId = Get-ModelCaseId ([string]$case.id)
+ [ordered]@{
+ protocol = 'Run the supplied AL development-plan skill read-only in a clean fixture repository. Return only guidanceReport using the supplied schema and retain the repository for read-only verification.'
+ caseId = $modelId
+ skill = $skillPath
+ skillInstructions = $skillInstructions
+ knowledgeIndex = 'knowledge-index.json'
+ 'task-context' = [ordered]@{
+ goal = [string]$case.'development-plan'.request
+ 'inputs-available' = @('development-plan', 'repository')
+ technologies = @($case.context.technologies)
+ countries = @($case.context.countries)
+ 'application-area' = @($case.context.'application-area')
+ }
+ 'development-plan' = $case.'development-plan'
+ resultSchema = [ordered]@{
+ caseId = $modelId
+ workspaceRoot = 'absolute path to the retained clean fixture repository'
+ guidanceReport = [ordered]@{
+ skill = [ordered]@{ id = 'al-development-plan'; version = 1 }
+ outcome = 'completed | not-applicable | no-knowledge | partial | failed'
+ 'outcome-reason' = 'required for partial or failed'
+ summary = [ordered]@{
+ request = 'planned change'
+ kind = 'feature | bug | refactor | upgrade | maintenance'
+ candidates = 0
+ selected = 0
+ }
+ context = [ordered]@{
+ 'bc-version' = 'resolved target or unknown'
+ technologies = @('al')
+ countries = @('w1')
+ 'application-area' = @('all')
+ unknown = @()
+ }
+ knowledge = @([ordered]@{
+ path = 'repo-relative article path'
+ sha = 'optional commit sha'
+ 'used-for' = 'plan decision'
+ constraints = @('faithful normative constraint')
+ 'sample-paths' = @()
+ })
+ 'validation-considerations' = @([ordered]@{
+ id = 'stable id'
+ reason = 'why evidence is needed'
+ evidence = 'evidence implementation should obtain'
+ })
+ suppressed = @()
+ unresolved = @()
+ }
+ }
+ } | ConvertTo-Json -Depth 15 |
+ Set-Content -LiteralPath (Join-Path $PrepareDirectory "request-$modelId.json") -Encoding UTF8
+ }
+}
+
+if ($ResultsDirectory) {
+ $failures = [System.Collections.Generic.List[string]]::new()
+ foreach ($case in @($manifest.cases)) {
+ $modelId = Get-ModelCaseId ([string]$case.id)
+ $resultPath = Join-Path $ResultsDirectory "result-$modelId.json"
+ if (-not (Test-Path -LiteralPath $resultPath -PathType Leaf)) {
+ $failures.Add("$($case.id): missing result file.") | Out-Null
+ continue
+ }
+ try {
+ $result = Get-Content -LiteralPath $resultPath -Raw | ConvertFrom-Json
+ } catch {
+ $failures.Add("$($case.id): result is not valid JSON: $($_.Exception.Message)") | Out-Null
+ continue
+ }
+ if ($result.PSObject.Properties.Name -notcontains 'caseId' -or [string]$result.caseId -ne $modelId) {
+ $failures.Add("$($case.id): result caseId mismatch.") | Out-Null
+ continue
+ }
+ if ($result.PSObject.Properties.Name -notcontains 'guidanceReport') {
+ $failures.Add("$($case.id): guidanceReport is missing.") | Out-Null
+ continue
+ }
+ $report = $result.guidanceReport
+ foreach ($requiredField in @('skill', 'outcome', 'summary', 'context', 'knowledge', 'validation-considerations', 'suppressed', 'unresolved')) {
+ if ($report.PSObject.Properties.Name -notcontains $requiredField) {
+ $failures.Add("$($case.id): guidance report is missing '$requiredField'.") | Out-Null
+ }
+ }
+ $skillId = if (
+ $report.PSObject.Properties.Name -contains 'skill' -and
+ $report.skill.PSObject.Properties.Name -contains 'id'
+ ) { [string]$report.skill.id } else { '' }
+ if ($skillId -ne 'al-development-plan') {
+ $failures.Add("$($case.id): guidance skill is '$skillId'.") | Out-Null
+ }
+ if ($report.PSObject.Properties.Name -notcontains 'outcome' -or [string]$report.outcome -ne 'completed') {
+ $failures.Add("$($case.id): guidance outcome is not completed.") | Out-Null
+ }
+ $kind = if (
+ $report.PSObject.Properties.Name -contains 'summary' -and
+ $report.summary.PSObject.Properties.Name -contains 'kind'
+ ) { [string]$report.summary.kind } else { '' }
+ if ($kind -ne [string]$case.'development-plan'.kind) {
+ $failures.Add("$($case.id): summary.kind '$kind' does not match the plan.") | Out-Null
+ }
+
+ [object[]]$knowledgeEntries = @()
+ if ($report.PSObject.Properties.Name -contains 'knowledge') {
+ $knowledgeEntries = @($report.knowledge)
+ }
+ $usedKnowledge = @()
+ foreach ($entry in $knowledgeEntries) {
+ $path = if ($entry.PSObject.Properties.Name -contains 'path') { [string]$entry.path } else { '' }
+ $usedFor = if ($entry.PSObject.Properties.Name -contains 'used-for') { [string]$entry.'used-for' } else { '' }
+ [object[]]$constraints = @()
+ if ($entry.PSObject.Properties.Name -contains 'constraints') {
+ $constraints = @($entry.constraints)
+ }
+ if ([string]::IsNullOrWhiteSpace($path) -or
+ -not (Test-Path -LiteralPath (Join-Path $Root $path) -PathType Leaf)) {
+ $failures.Add("$($case.id): invalid knowledge path '$path'.") | Out-Null
+ } else {
+ $usedKnowledge += $path
+ }
+ if ([string]::IsNullOrWhiteSpace($usedFor) -or -not $constraints.Count) {
+ $failures.Add("$($case.id): '$path' lacks used-for or constraints.") | Out-Null
+ }
+ if ($entry.PSObject.Properties.Name -contains 'sample-paths') {
+ foreach ($samplePath in @($entry.'sample-paths')) {
+ $samplePath = [string]$samplePath
+ if ([string]::IsNullOrWhiteSpace($samplePath) -or
+ -not (Test-Path -LiteralPath (Join-Path $Root $samplePath) -PathType Leaf)) {
+ $failures.Add("$($case.id): invalid sample path '$samplePath'.") | Out-Null
+ }
+ }
+ }
+ }
+
+ $required = @($case.requiredKnowledge | ForEach-Object { [string]$_ })
+ $matched = @($required | Where-Object { $usedKnowledge -contains $_ }).Count
+ $recall = if ($required.Count) { $matched / $required.Count } else { 1.0 }
+ if ($recall -lt [double]$manifest.minimumKnowledgeRecall) {
+ $failures.Add("$($case.id): knowledge recall $recall is below $($manifest.minimumKnowledgeRecall).") | Out-Null
+ }
+ $accepted = @(
+ @($case.requiredKnowledge) + @($case.optionalKnowledge) |
+ ForEach-Object { [string]$_ } |
+ Sort-Object -Unique
+ )
+ $acceptedUsed = @($usedKnowledge | Where-Object { $accepted -contains $_ }).Count
+ $precision = if ($usedKnowledge.Count) { $acceptedUsed / $usedKnowledge.Count } else { 0.0 }
+ if ($precision -lt [double]$manifest.minimumKnowledgePrecision) {
+ $failures.Add("$($case.id): knowledge precision $precision is below $($manifest.minimumKnowledgePrecision).") | Out-Null
+ }
+
+ $workspaceRoot = if ($result.PSObject.Properties.Name -contains 'workspaceRoot') {
+ [string]$result.workspaceRoot
+ } else {
+ ''
+ }
+ if ([string]::IsNullOrWhiteSpace($workspaceRoot) -or
+ -not (Test-Path -LiteralPath $workspaceRoot -PathType Container)) {
+ $failures.Add("$($case.id): workspaceRoot is missing or unavailable.") | Out-Null
+ } else {
+ $status = @(& git -C $workspaceRoot status --porcelain)
+ if ($LASTEXITCODE -ne 0) {
+ $failures.Add("$($case.id): workspaceRoot is not a readable git worktree.") | Out-Null
+ } elseif ($status.Count) {
+ $failures.Add("$($case.id): guidance skill changed the target repository.") | Out-Null
+ }
+ }
+ }
+
+ if ($failures.Count) {
+ Write-Host "Development guidance scoring FAILED ($($failures.Count) problem(s)):" -ForegroundColor Red
+ $failures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
+ exit 1
+ }
+ Write-Host "Development guidance scoring PASSED: $(@($manifest.cases).Count) case(s)."
+} else {
+ Write-Host "Development guidance fixture validation PASSED: $(@($manifest.cases).Count) case(s)."
+}
diff --git a/tools/Test-LearnCoverage.ps1 b/tools/Test-LearnCoverage.ps1
new file mode 100644
index 0000000..ccd8f82
--- /dev/null
+++ b/tools/Test-LearnCoverage.ps1
@@ -0,0 +1,240 @@
+<#
+.SYNOPSIS
+ Validates Microsoft Learn ingestion coverage and reports progress.
+#>
+[CmdletBinding()]
+param(
+ [string] $Root = (Resolve-Path (Join-Path $PSScriptRoot '..')),
+ [string] $CatalogPath,
+ [string] $CoveragePath,
+ [switch] $Json
+)
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+$Root = (Resolve-Path -LiteralPath $Root).Path
+if (-not $CatalogPath) {
+ $CatalogPath = Join-Path $Root 'coverage/microsoft-learn-developer-catalog.json'
+}
+if (-not $CoveragePath) {
+ $CoveragePath = Join-Path $Root 'coverage/learn-coverage.json'
+}
+
+foreach ($path in @($CatalogPath, $CoveragePath)) {
+ if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
+ throw "Coverage input not found: $path"
+ }
+}
+
+$catalog = Get-Content -LiteralPath $CatalogPath -Raw | ConvertFrom-Json
+$coverage = Get-Content -LiteralPath $CoveragePath -Raw | ConvertFrom-Json
+$problems = [System.Collections.Generic.List[string]]::new()
+
+if ($catalog.version -ne 1) {
+ $problems.Add("Unsupported catalog version: $($catalog.version)") | Out-Null
+}
+if ($coverage.version -ne 1) {
+ $problems.Add("Unsupported coverage version: $($coverage.version)") | Out-Null
+}
+if ([string]$coverage.catalog -ne 'coverage/microsoft-learn-developer-catalog.json') {
+ $problems.Add("Coverage catalog path must be coverage/microsoft-learn-developer-catalog.json.") | Out-Null
+}
+
+$catalogUnits = @{}
+foreach ($unit in @($catalog.units)) {
+ $uid = [string]$unit.uid
+ if ($catalogUnits.ContainsKey($uid)) {
+ $problems.Add("Duplicate catalog unit uid: $uid") | Out-Null
+ } else {
+ $catalogUnits[$uid] = $unit
+ }
+ if ([string]::IsNullOrWhiteSpace([string]$unit.title)) {
+ $problems.Add("${uid}: catalog unit title is empty.") | Out-Null
+ }
+ if ([string]::IsNullOrWhiteSpace([string]$unit.url) -or
+ -not ([string]$unit.url).StartsWith('https://learn.microsoft.com/', [System.StringComparison]::OrdinalIgnoreCase)) {
+ $problems.Add("${uid}: catalog unit URL is missing or not a Microsoft Learn URL.") | Out-Null
+ }
+}
+
+$catalogModules = @{}
+foreach ($module in @($catalog.modules)) {
+ $uid = [string]$module.uid
+ if ($catalogModules.ContainsKey($uid)) {
+ $problems.Add("Duplicate catalog module uid: $uid") | Out-Null
+ } else {
+ $catalogModules[$uid] = $module
+ }
+ foreach ($unitUid in @($module.unitUids)) {
+ if (-not $catalogUnits.ContainsKey([string]$unitUid)) {
+ $problems.Add("${uid}: references unknown unit '$unitUid'.") | Out-Null
+ }
+ }
+}
+
+$catalogPaths = @{}
+foreach ($path in @($catalog.learningPaths)) {
+ $uid = [string]$path.uid
+ if ($catalogPaths.ContainsKey($uid)) {
+ $problems.Add("Duplicate catalog learning-path uid: $uid") | Out-Null
+ } else {
+ $catalogPaths[$uid] = $path
+ }
+ foreach ($moduleUid in @($path.moduleUids)) {
+ if (-not $catalogModules.ContainsKey([string]$moduleUid)) {
+ $problems.Add("${uid}: references unknown module '$moduleUid'.") | Out-Null
+ }
+ }
+}
+
+if ([int]$catalog.counts.units -ne $catalogUnits.Count) {
+ $problems.Add("Catalog unit count does not match units array.") | Out-Null
+}
+if ([int]$catalog.counts.modules -ne $catalogModules.Count) {
+ $problems.Add("Catalog module count does not match modules array.") | Out-Null
+}
+if ([int]$catalog.counts.learningPaths -ne $catalogPaths.Count) {
+ $problems.Add("Catalog learning-path count does not match learningPaths array.") | Out-Null
+}
+
+foreach ($unit in @($catalog.units)) {
+ foreach ($moduleUid in @($unit.moduleUids)) {
+ if (-not $catalogModules.ContainsKey([string]$moduleUid)) {
+ $problems.Add("$($unit.uid): references unknown module '$moduleUid'.") | Out-Null
+ } elseif (@($catalogModules[[string]$moduleUid].unitUids) -notcontains [string]$unit.uid) {
+ $problems.Add("$($unit.uid): module '$moduleUid' does not link back to the unit.") | Out-Null
+ }
+ }
+}
+
+$validStatuses = @('in-progress', 'complete')
+$validDispositions = @('candidate', 'authored', 'covered-existing', 'rejected', 'deferred')
+$seenUnits = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
+$seenOutcomes = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
+$articlePaths = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
+$dispositionCounts = @{}
+foreach ($disposition in $validDispositions) {
+ $dispositionCounts[$disposition] = 0
+}
+
+foreach ($unitCoverage in @($coverage.units)) {
+ $uid = [string]$unitCoverage.uid
+ if (-not $seenUnits.Add($uid)) {
+ $problems.Add("Duplicate coverage unit uid: $uid") | Out-Null
+ }
+ if (-not $catalogUnits.ContainsKey($uid)) {
+ $problems.Add("Coverage unit is absent from the catalog: $uid") | Out-Null
+ }
+
+ $reviewStatus = [string]$unitCoverage.reviewStatus
+ if ($validStatuses -notcontains $reviewStatus) {
+ $problems.Add("${uid}: invalid reviewStatus '$reviewStatus'.") | Out-Null
+ }
+
+ [object[]]$outcomes = @()
+ if ($unitCoverage.PSObject.Properties.Name -contains 'outcomes') {
+ $outcomes = @($unitCoverage.outcomes)
+ }
+ if ($reviewStatus -eq 'in-progress' -and -not $outcomes.Count) {
+ $problems.Add("${uid}: an in-progress unit must contain at least one outcome.") | Out-Null
+ }
+
+ foreach ($outcome in $outcomes) {
+ $id = [string]$outcome.id
+ if ($id -notmatch '^[a-z0-9]+(?:-[a-z0-9]+)*$') {
+ $problems.Add("${uid}: outcome id must be kebab-case: '$id'.") | Out-Null
+ } elseif (-not $seenOutcomes.Add($id)) {
+ $problems.Add("Duplicate outcome id: $id") | Out-Null
+ }
+
+ $disposition = [string]$outcome.disposition
+ if ($validDispositions -notcontains $disposition) {
+ $problems.Add("${id}: invalid disposition '$disposition'.") | Out-Null
+ continue
+ }
+ $dispositionCounts[$disposition]++
+
+ if ([string]::IsNullOrWhiteSpace([string]$outcome.title)) {
+ $problems.Add("${id}: title is required.") | Out-Null
+ }
+
+ if ($disposition -in @('candidate', 'authored', 'covered-existing')) {
+ if ([string]::IsNullOrWhiteSpace([string]$outcome.domain)) {
+ $problems.Add("${id}: domain is required for disposition '$disposition'.") | Out-Null
+ }
+ }
+
+ [object[]]$paths = @()
+ if ($outcome.PSObject.Properties.Name -contains 'articlePaths') {
+ $paths = @($outcome.articlePaths)
+ }
+ if ($disposition -in @('authored', 'covered-existing')) {
+ if (-not $paths.Count) {
+ $problems.Add("${id}: articlePaths is required for disposition '$disposition'.") | Out-Null
+ }
+ foreach ($relativePath in $paths) {
+ $relativePath = [string]$relativePath
+ if ($relativePath.Contains('\') -or -not $relativePath.EndsWith('.md')) {
+ $problems.Add("${id}: article path must be a forward-slash .md path: $relativePath") | Out-Null
+ continue
+ }
+ if (-not (Test-Path -LiteralPath (Join-Path $Root $relativePath) -PathType Leaf)) {
+ $problems.Add("${id}: article does not exist: $relativePath") | Out-Null
+ }
+ $articlePaths.Add($relativePath) | Out-Null
+ }
+ } elseif ($paths.Count) {
+ $problems.Add("${id}: disposition '$disposition' must not set articlePaths.") | Out-Null
+ }
+
+ $rationale = if ($outcome.PSObject.Properties.Name -contains 'rationale') {
+ [string]$outcome.rationale
+ } else {
+ ''
+ }
+ if ($disposition -in @('rejected', 'deferred') -and
+ [string]::IsNullOrWhiteSpace($rationale)) {
+ $problems.Add("${id}: rationale is required for disposition '$disposition'.") | Out-Null
+ }
+ }
+}
+
+if ($problems.Count) {
+ Write-Host "Learn coverage validation FAILED ($($problems.Count) problem(s)):" -ForegroundColor Red
+ $problems | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
+ exit 1
+}
+
+$complete = @($coverage.units | Where-Object reviewStatus -eq 'complete').Count
+$inProgress = @($coverage.units | Where-Object reviewStatus -eq 'in-progress').Count
+$summary = [ordered]@{
+ catalogUnits = $catalogUnits.Count
+ completeUnits = $complete
+ inProgressUnits = $inProgress
+ unreviewedUnits = $catalogUnits.Count - $complete - $inProgress
+ candidateOutcomes = $dispositionCounts.candidate
+ authoredOutcomes = $dispositionCounts.authored
+ coveredExistingOutcomes = $dispositionCounts.'covered-existing'
+ rejectedOutcomes = $dispositionCounts.rejected
+ deferredOutcomes = $dispositionCounts.deferred
+ referencedArticles = $articlePaths.Count
+}
+
+if ($Json) {
+ $summary | ConvertTo-Json
+} else {
+ $message = (
+ 'Learn coverage: {0} units; {1} complete, {2} in progress, {3} unreviewed; ' +
+ '{4} candidate outcomes, {5} authored outcomes, {6} existing-coverage outcomes.'
+ ) -f @(
+ $summary.catalogUnits,
+ $summary.completeUnits,
+ $summary.inProgressUnits,
+ $summary.unreviewedUnits,
+ $summary.candidateOutcomes,
+ $summary.authoredOutcomes,
+ $summary.coveredExistingOutcomes
+ )
+ Write-Host $message
+}
diff --git a/tools/Update-LearnCatalog.ps1 b/tools/Update-LearnCatalog.ps1
new file mode 100644
index 0000000..2368f60
--- /dev/null
+++ b/tools/Update-LearnCatalog.ps1
@@ -0,0 +1,262 @@
+<#
+.SYNOPSIS
+ Updates the committed Microsoft Learn Business Central developer catalog.
+
+.DESCRIPTION
+ Filters a Microsoft Learn catalog payload to modules tagged for both
+ dynamics-business-central and developer. The output is intentionally only
+ source metadata; editorial dispositions live in coverage/learn-coverage.json.
+
+ The legacy unauthenticated catalog endpoint remains the default while it is
+ available. Use -CatalogPath with an export from the authenticated Learn
+ Platform API when the legacy endpoint is retired.
+#>
+[CmdletBinding(DefaultParameterSetName = 'Remote')]
+param(
+ [string] $Root = (Resolve-Path (Join-Path $PSScriptRoot '..')),
+
+ [Parameter(ParameterSetName = 'Remote')]
+ [uri] $CatalogUri = 'https://learn.microsoft.com/api/catalog/?locale=en-us',
+
+ [Parameter(Mandatory, ParameterSetName = 'File')]
+ [string] $CatalogPath,
+
+ [string] $OutputPath
+)
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+$Root = (Resolve-Path -LiteralPath $Root).Path
+if (-not $OutputPath) {
+ $OutputPath = Join-Path $Root 'coverage/microsoft-learn-developer-catalog.json'
+}
+
+function Get-CanonicalUrl {
+ param([string] $Url)
+
+ if ([string]::IsNullOrWhiteSpace($Url)) {
+ return $null
+ }
+
+ $parsed = [uri]$Url
+ return "$($parsed.Scheme)://$($parsed.Host)$($parsed.AbsolutePath)".TrimEnd('/')
+}
+
+function Get-CatalogProperty {
+ param(
+ [object] $Object,
+ [string] $Name,
+ [object] $Default = $null
+ )
+
+ $property = $Object.PSObject.Properties[$Name]
+ if ($property) {
+ return $property.Value
+ }
+ return $Default
+}
+
+function Get-LatestTimestamp {
+ param([object[]] $Values)
+
+ $timestamps = @(
+ $Values |
+ Where-Object { -not [string]::IsNullOrWhiteSpace([string]$_) } |
+ ForEach-Object { [datetimeoffset]::Parse([string]$_) } |
+ Sort-Object
+ )
+ if (-not $timestamps.Count) {
+ return $null
+ }
+
+ return $timestamps[-1].ToUniversalTime().ToString(
+ "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ [System.Globalization.CultureInfo]::InvariantCulture
+ )
+}
+
+function Convert-ToUtcTimestamp {
+ param([object] $Value)
+
+ return ([datetimeoffset]$Value).ToUniversalTime().ToString(
+ "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ [System.Globalization.CultureInfo]::InvariantCulture
+ )
+}
+
+$catalog = if ($PSCmdlet.ParameterSetName -eq 'File') {
+ Get-Content -LiteralPath $CatalogPath -Raw | ConvertFrom-Json
+} else {
+ Invoke-RestMethod -Uri $CatalogUri
+}
+
+$product = 'dynamics-business-central'
+$role = 'developer'
+$modules = @(
+ $catalog.modules |
+ Where-Object {
+ @(Get-CatalogProperty $_ 'products' @()) -contains $product -and
+ @(Get-CatalogProperty $_ 'roles' @()) -contains $role
+ } |
+ Sort-Object uid
+)
+
+$moduleIds = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
+foreach ($module in $modules) {
+ $moduleIds.Add([string]$module.uid) | Out-Null
+}
+
+$learningPaths = @(
+ $catalog.learningPaths |
+ Where-Object {
+ $path = $_
+ $pathModules = @(Get-CatalogProperty $path 'modules' @())
+ @($pathModules | Where-Object { $moduleIds.Contains([string]$_) }).Count -gt 0 -and
+ @(Get-CatalogProperty $path 'products' @()) -contains $product -and
+ @(Get-CatalogProperty $path 'roles' @()) -contains $role
+ } |
+ Sort-Object uid
+)
+
+$pathIdsByModule = @{}
+foreach ($path in $learningPaths) {
+ foreach ($moduleId in @(Get-CatalogProperty $path 'modules' @())) {
+ if (-not $moduleIds.Contains([string]$moduleId)) {
+ continue
+ }
+ if (-not $pathIdsByModule.ContainsKey([string]$moduleId)) {
+ $pathIdsByModule[[string]$moduleId] = [System.Collections.Generic.List[string]]::new()
+ }
+ $pathIdsByModule[[string]$moduleId].Add([string]$path.uid)
+ }
+}
+
+$unitById = @{}
+foreach ($unit in @(Get-CatalogProperty $catalog 'units' @())) {
+ $unitById[[string]$unit.uid] = $unit
+}
+
+$moduleIdsByUnit = @{}
+$moduleById = @{}
+$unitIds = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
+foreach ($module in $modules) {
+ $moduleById[[string]$module.uid] = $module
+ foreach ($unitId in @(Get-CatalogProperty $module 'units' @())) {
+ $unitId = [string]$unitId
+ $unitIds.Add($unitId) | Out-Null
+ if (-not $moduleIdsByUnit.ContainsKey($unitId)) {
+ $moduleIdsByUnit[$unitId] = [System.Collections.Generic.List[string]]::new()
+ }
+ $moduleIdsByUnit[$unitId].Add([string]$module.uid)
+ }
+}
+
+$pathRecords = @(
+ foreach ($path in $learningPaths) {
+ [ordered]@{
+ uid = [string]$path.uid
+ title = [string]$path.title
+ url = Get-CanonicalUrl ([string]$path.url)
+ lastModified = if (Get-CatalogProperty $path 'last_modified') {
+ Convert-ToUtcTimestamp (Get-CatalogProperty $path 'last_modified')
+ } else {
+ $null
+ }
+ durationInMinutes = [int](Get-CatalogProperty $path 'duration_in_minutes' 0)
+ moduleUids = @(
+ @(Get-CatalogProperty $path 'modules' @()) |
+ Where-Object { $moduleIds.Contains([string]$_) } |
+ ForEach-Object { [string]$_ } |
+ Sort-Object -Unique
+ )
+ }
+ }
+)
+
+$moduleRecords = @(
+ foreach ($module in $modules) {
+ [ordered]@{
+ uid = [string]$module.uid
+ title = [string]$module.title
+ summary = [string](Get-CatalogProperty $module 'summary' '')
+ url = Get-CanonicalUrl ([string]$module.url)
+ lastModified = Convert-ToUtcTimestamp (Get-CatalogProperty $module 'last_modified')
+ durationInMinutes = [int](Get-CatalogProperty $module 'duration_in_minutes' 0)
+ levels = @(@(Get-CatalogProperty $module 'levels' @()) | ForEach-Object { [string]$_ } | Sort-Object -Unique)
+ subjects = @(@(Get-CatalogProperty $module 'subjects' @()) | ForEach-Object { [string]$_ } | Sort-Object -Unique)
+ learningPathUids = if ($pathIdsByModule.ContainsKey([string]$module.uid)) {
+ @($pathIdsByModule[[string]$module.uid] | Sort-Object -Unique)
+ } else {
+ @()
+ }
+ unitUids = @(@(Get-CatalogProperty $module 'units' @()) | ForEach-Object { [string]$_ })
+ }
+ }
+)
+
+$unitRecords = @(
+ foreach ($unitId in @($unitIds | Sort-Object)) {
+ if (-not $unitById.ContainsKey($unitId)) {
+ throw "Catalog module references missing unit '$unitId'."
+ }
+ $unit = $unitById[$unitId]
+ $unitUrl = [string](Get-CatalogProperty $unit 'url' '')
+ if ([string]::IsNullOrWhiteSpace($unitUrl)) {
+ $moduleId = [string]@($moduleIdsByUnit[$unitId])[0]
+ $moduleUrl = Get-CanonicalUrl ([string]$moduleById[$moduleId].url)
+ $unitSlug = if ($unitId.StartsWith("$moduleId.", [System.StringComparison]::Ordinal)) {
+ $unitId.Substring($moduleId.Length + 1)
+ } else {
+ @($unitId -split '\.')[-1]
+ }
+ $unitUrl = "$moduleUrl/$unitSlug"
+ }
+ [ordered]@{
+ uid = $unitId
+ title = [string]$unit.title
+ url = Get-CanonicalUrl $unitUrl
+ lastModified = if (Get-CatalogProperty $unit 'last_modified') {
+ Convert-ToUtcTimestamp (Get-CatalogProperty $unit 'last_modified')
+ } else {
+ $null
+ }
+ durationInMinutes = [int](Get-CatalogProperty $unit 'duration_in_minutes' 0)
+ moduleUids = @($moduleIdsByUnit[$unitId] | Sort-Object -Unique)
+ }
+ }
+)
+
+$snapshot = [ordered]@{
+ version = 1
+ source = [ordered]@{
+ provider = 'Microsoft Learn'
+ catalogUri = if ($PSCmdlet.ParameterSetName -eq 'Remote') { [string]$CatalogUri } else { $null }
+ locale = 'en-us'
+ filters = [ordered]@{
+ product = $product
+ role = $role
+ }
+ catalogLastModified = Get-LatestTimestamp @(
+ @($moduleRecords | ForEach-Object lastModified) +
+ @($unitRecords | ForEach-Object lastModified) +
+ @($pathRecords | ForEach-Object lastModified)
+ )
+ }
+ counts = [ordered]@{
+ learningPaths = $pathRecords.Count
+ modules = $moduleRecords.Count
+ units = $unitRecords.Count
+ }
+ learningPaths = $pathRecords
+ modules = $moduleRecords
+ units = $unitRecords
+}
+
+$outputDirectory = Split-Path -Parent $OutputPath
+if (-not (Test-Path -LiteralPath $outputDirectory -PathType Container)) {
+ New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null
+}
+$snapshot | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $OutputPath -Encoding UTF8
+Write-Host "Microsoft Learn developer catalog: $($pathRecords.Count) paths, $($moduleRecords.Count) modules, $($unitRecords.Count) units."
+Write-Host "Catalog: $OutputPath"