Read this file first. It tells you where to find context in this repo.
| What you need | Where to look |
|---|---|
| How this repo is structured | ARCHITECTURE.md |
| How to build/test/run | CONTRIBUTING.md |
| Why decisions were made | docs/ADRs/ |
| What this repo does | README.md |
| PR review rules | .bito/guidelines/ |
| Active specs/work | docs/specs/ |
- Link resolution order matters —
ResourceUtils.resolveLinks()must run after localization and raw-field capture. Never reorder the post-processing pipeline inResourceFactory.array()without understanding all downstream side effects. - Unresolved links are silent, not exceptions — if an included entry's depth exceeds the API limit (10), unresolved links remain as placeholder objects. Code that dereferences resolved links must handle null/stub gracefully.
sysfields are always present — the SDK enforces thatsys.*attributes are always returned. When using.select()withfields.*selections,.withContentType()must be called first or the SDK throws a client-sideIllegalStateExceptionbefore the request is sent. Selecting onlysysfields does not require a content type.rawFieldsis the only path to raw rich text JSON —TransformQuery(unwrapping) does not expose raw rich text; useCDAEntry.rawFieldsor make a direct HTTP request.- Cross-space token limit is 20 —
setCrossSpaceTokens()accepts at most 20 extra spaces (21 total). Only the first level of cross-space references is resolved. - Sync tokens are stateful and environment-aware — passing a
SynchronizedSpacefrom the wrong environment toclient.sync()will produce incorrect deltas. - Android: never depend on
okhttp-jvmdirectly when usingokhttp-android— excludeokhttp-jvmfrom this library to avoid duplicate-class errors on Android (see README and ADR 0002). TlsSocketFactoryonly activates below Android API 20 — do not remove or gate it differently; it protects older devices.TransformQuery.observeAndTransform()auto-injects aselectfilter — if the annotation scanner has a bug, fields are silently dropped, not thrown as errors. Always validate field mapping in tests.logSensitiveDatadefaults totrue— always set this tofalsein production builds to avoid logging auth tokens.- Release requires GPG signing — the Maven Central publication flow requires the Contentful GPG key imported locally. Do not attempt to release without it.
masteris the trunk — there is nomainbranch. All CI and release flows targetmaster.
- Commit format: Conventional Commits preferred (
feat:,fix:,chore:,docs:, etc.) — see recent history for examples - Branch strategy: Trunk-based development off
master; feature branches merged via PR with squash or merge commit - Test location:
src/test/java/…/cda/mirroring the main package; fixtures insrc/test/resources/ - Java version: Java 8 source/target (
java.version=1.8inpom.xml); devcontainer useseclipse-temurin:8-jdk-jammyby default - Build tool: Maven Wrapper (
./mvnw) — do not require a globally installed Maven
Upstream (this repo consumes):
- Contentful Content Delivery API —
https://cdn.contentful.com - Contentful Content Preview API —
https://preview.contentful.com
Downstream (consumes this repo):
- Java/Kotlin server and Android applications via Maven Central (
com.contentful.java:java-sdk) rich-text-renderer-javacompanion library (consumes theCDARich*node model)
# Spin up the devcontainer (first time or after Docker changes)
devcontainer up --workspace-folder .
# Full verification loop inside the container
devcontainer exec --workspace-folder . bash -lc "./mvnw -B test"
# Checkstyle only
devcontainer exec --workspace-folder . bash -lc "./mvnw -B checkstyle:checkstyle"