feat: Nestable Hosts — allow hosts to have parent hosts/folders for path-based URL hierarchies
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Problem
dotCMS sites/hosts are currently flat — every host lives directly under the System Host. There is no way to nest a host under another host or folder to create URL hierarchies like dotcms.com/en/nestedHost1/page. This prevents modeling multi-tenant, multi-region, or multi-language architectures where sub-sites share a root domain and URL prefix with their parent.
Goal
Allow a host to declare a parent host or folder via a parentHost HostFolderField on the Host content type. The system resolves incoming requests through a nested-host routing layer, strips the host prefix from the URI, and sets the resolved host on the request. Permissions propagate through the host hierarchy. Push-publish and archive operations are hierarchy-aware.
Target Personas
- System administrators (dotCMS)
- Developer teams
- DevOps teams
Demo Expectations
In the demo we will show:
- Create a child host under
dotcms.comwith parent =dotcms.comand segmenten. - Browse to
https://dotcms.com/en/mypage— the system resolves the host toenand the URI to/mypage. - Create a grandchild host under
en— multi-level nesting works end-to-end. - Archive the parent host with
cascade=true— all descendants are archived. - Show the site selector in the Angular admin with indented child hosts.
- Show the folder tree in Content Drive with nested host nodes using host icons.
Acceptance Criteria
- Host can be created with a
parentHostHostFolderField pointing to another host or folder identifier. -
https://parent.com/childSegment/pageresolves to host=childHost, URI=/pageviaNestedHostResolutionFilter. - Multi-level nesting works (grandparent → parent → child).
-
Host.getParentPermissionable()returns the parent host (not System Host) for nested hosts. -
Host.getAbsoluteBaseUrl()returns the full path-based URL including all ancestor segments. -
NestedHostPatternCacheis built per-top-level-host with longest-first regex matching and invalidated via PostgreSQL LISTEN/NOTIFY. -
CMS_FILTER_URI_OVERRIDEis rewritten with the remaining URI after the host prefix is stripped. -
CMS_RESOLVED_HOSTrequest attribute is set for downstream consumers;HostWebAPIImpl.getCurrentHost()checks it first. - Deleting a host with descendants is blocked with an error reporting descendant count.
- Archiving a host cascades to all descendants when
cascade=true; unarchive is manual (no auto-cascade). - Push publish auto-includes ancestor hosts; import sorts HOST+FOLDER records by path length ascending.
- Site selector shows flat list with indentation derived from
parentPathdepth. - BrowserResource/ContentDriveResource support
showSubHostsparameter. - Nested host nodes appear in the folder tree with a host icon; clicking switches the local context.
- Content editor accepts
?hostId=query param forHostFolderFieldpre-fill. - Startup task adds
parentHostHostFolderField to Host content type on first run. - Startup task syncs
Identifier.asset_name = hostnamefor all host records on first run. - Cycle detection throws
DotRuntimeExceptionbefore any data is persisted. - Vanity URLs and search are fully isolated per-host.
- Reparenting a host fires
HostReparentPayloadwitholdTopLevelHostIdandnewTopLevelHostId. - Sitemap, preview, and canonical URLs all use
getAbsoluteBaseUrl(). - No new database columns — reuses
Identifier.host_inode,parent_path,asset_name. - Angular UI uses modern syntax (
@if,input(), signals). - All 47 integration tests and 140 unit tests pass.
User Stories
- As a system administrator, I want to create a host under
dotcms.com/enso that I can model a regional sub-site without a separate domain. - As a developer, I want
Host.getAbsoluteBaseUrl()to return the full hierarchical URL so that sitemaps and canonical tags work correctly. - As a content editor, I want the site selector to show indented child hosts so that I can understand the hierarchy at a glance.
Links
- Implementation branch:
allow-host-nesting - Spec:
docs/nestable-hosts-requirements.md - Seed:
docs/nestable-hosts-seed.md
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with docs/nestable-hosts-requirements.md and docs/nestable-hosts-seed.md, then review the allow-host-nesting implementation branch and group the acceptance criteria by routing, persistence, publishing, and Angular UI. Done means the listed hierarchy behaviors work end to end and all 47 integration tests and 140 unit tests pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, java, postgresql
- Domain
- backend, content, database, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100