Content Paths

Oak Chain uses wallet-based namespacing with deterministic ownership and routing. The path is itself a contract: it encodes who can write where, how content shards across nodes, and how the indexer organizes retrieval. Get the path structure wrong and you get unpredictable ownership semantics and brittle queries; get it right and ownership is wallet-cryptographic, sharding falls out for free, and AEM-style sub-paths (/content, /conf, /apps) work normally inside each wallet's scope.

Map one real wallet and organization structure to the template below before implementing write flows.

Path Structure

/oak-chain/{L1}/{L2}/{L3}/0x{wallet}/{organization}/content/...
Data Table
Component
Description
Example
{L1}/{L2}/{L3}
Shard levels (first 6 hex chars)
74/2d/35
0x{wallet}
Full Ethereum wallet address, lowercased
0x742d35cc...
{organization}
Optional brand/org scope
PixelPirates
content/
AEM content root
Standard AEM path

Example

For wallet 0x742d35cc6634c0532925a3b844bc454e4438f44e:

/oak-chain/74/2d/35/0x742d35cc6634c0532925a3b844bc454e4438f44e/
    ├── PixelPirates/
    │   ├── content/           ← Gaming brand content
    │   │   └── games/
    │   └── conf/              ← Gaming brand config
    ├── CryptoKitchenware/
    │   ├── content/           ← eCommerce content
    │   │   └── products/
    │   └── conf/
    └── PersonalBlog/
        └── content/           ← Personal content
            └── posts/

The write API creates each item directly under {organization}/content/, or under content/ when no organization is given. Deeper folders such as games/ and the conf/ scope, here and below, are a layout convention. The API does not create them today.

Why This Structure?

1. Wallet = Namespace

Your Ethereum wallet owns your namespace. The validator builds the path from the signing wallet, so in sepolia mode only a valid signature from that wallet can write to it. Mock mode, the default, does not verify signatures.

Only 0x742d35cc... can write to:
/oak-chain/74/2d/35/0x742d35cc.../...

2. Sharding for Scale

The {L1}/{L2}/{L3} prefix enables:

Clusters can own explicit ranges of the first level ({L1}). With -Doak.sharding.enabled=true, a validator redirects writes for a wallet owned by another cluster (307, wrong_shard) and refuses prefixes no cluster claims (503). Sharding is off by default, so a single cluster accepts every wallet. Remote clusters may mount a namespace read-only. Cross-cluster deployments are not yet validated.

3. Organization Scope

One wallet can own multiple brands:

# Gaming brand
/oak-chain/74/2d/35/0xWALLET/PixelPirates/content/games/nft-drop

# eCommerce brand  
/oak-chain/74/2d/35/0xWALLET/CryptoKitchenware/content/products/spatula

# Personal
/oak-chain/74/2d/35/0xWALLET/PersonalBlog/content/posts/hello-world

4. AEM Compatibility

Within each scope, standard AEM paths work:

{scope}/content/...     ← Content
{scope}/conf/...        ← Configuration
{scope}/apps/...        ← Components (future)

Path Validation

// WalletPathUtil.java (simplified)
public static String getContentPath(String wallet, String org) {
    String shardRoot = getShardRoot(wallet); // /oak-chain/{L1}/{L2}/{L3}/0x{lowercase wallet}
    if (org == null || org.isEmpty()) {
        return shardRoot + "/content";
    }
    return shardRoot + "/" + org + "/content";
}

Rules

Data Table
Rule
Valid
Invalid
Wallet format
0x742d35cc...
742d35Cc...
Org characters
My-Brand_123
My/Brand
Org length
≤ 64 chars
> 64 chars
Path traversal
/content/page
/../secret

Write Example

curl -X POST http://localhost:8090/v1/propose-write \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "proposalId=0x1111111111111111111111111111111111111111111111111111111111111111" \
  -d "walletAddress=0x742d35cc6634c0532925a3b844bc454e4438f44e" \
  -d "organization=PixelPirates" \
  --data-urlencode "message={\"title\":\"New NFT Drop!\",\"date\":\"2026-01-10\"}" \
  -d "contentType=page" \
  -d "ethereumTxHash=<tx hash; in mock mode, reuse the proposalId>" \
  -d "signature=<personal_sign of the exact message>"

See Authentication for how to sign the message.

The validator constructs the full path and returns it as storagePath in the 202 response. The item name is {contentType}-{milliseconds}-{first 8 hex characters of proposalId}:

/oak-chain/74/2d/35/0x742d35cc.../PixelPirates/content/page-1767225600000-11111111

Cross-Organization References

Content can reference other organizations (read-only):

{
  "title": "Partnership Announcement",
  "partner": {
    "ref": "/oak-chain/ab/cd/ef/0xPARTNER.../TheirBrand/content/about"
  }
}

Content Structure Within Namespaces

Each wallet/brand namespace should maintain consistent content structure for indexing and querying to work efficiently.

Key point: Oak Chain doesn't enforce content structure at the consensus layer, but brand maintainers should enforce consistency within their namespace for queries to work.

Operational Model

Next Steps