@@ -45,6 +45,81 @@ Uploads are performed through the eVault `uploadFile` GraphQL mutation, which
4545takes base64 content and returns the ` w3ds://file ` URI, the Meta Envelope ID,
4646and the public object-storage URL.
4747
48+ ## The ` uploadFile ` mutation
49+
50+ ``` graphql
51+ uploadFile (input : UploadFileInput ! ): UploadFilePayload !
52+ ```
53+
54+ Uploads a file to object storage and creates an addressable ** File Meta
55+ Envelope** (ontology ` w3ds-file-v1 ` ). The request ** must** carry an
56+ ` X-ENAME: @<user-ename> ` header — uploads are rejected without it. Object
57+ storage must be configured on the eVault (DigitalOcean Spaces / S3-compatible);
58+ otherwise the mutation returns an error.
59+
60+ ### Input — ` UploadFileInput `
61+
62+ | Field | Type | Description |
63+ | ------------- | ----------- | -------------------------------------------------------------------- |
64+ | ` filename ` | ` String! ` | Original file name. |
65+ | ` contentType ` | ` String! ` | MIME type of the file. |
66+ | ` content ` | ` String! ` | Base64-encoded file content — raw base64 ** or** a ` data: ` URI. |
67+ | ` acl ` | ` [String!]! ` | Access-control list for the created File Meta Envelope (e.g. ` ["*"] ` ).|
68+
69+ Constraints: content must be valid base64 (malformed input is rejected) and the
70+ decoded size must not exceed ** 50 MB** .
71+
72+ ### Payload — ` UploadFilePayload `
73+
74+ | Field | Type | Description |
75+ | ---------------- | -------------- | ----------------------------------------------------------------- |
76+ | ` uri ` | ` String ` | The ` w3ds://file ` URI addressing the upload; ` null ` on error. |
77+ | ` metaEnvelopeId ` | ` String ` | ID of the File Meta Envelope describing the upload. |
78+ | ` publicUrl ` | ` String ` | Public object-storage URL of the file. |
79+ | ` errors ` | ` [UserError!] ` | Errors that occurred during the upload (` field ` , ` message ` , ` code ` ).|
80+
81+ ### Stored Meta Envelope payload
82+
83+ The mutation persists a Meta Envelope with ontology ` w3ds-file-v1 ` and payload:
84+
85+ ``` json
86+ { " filename" , " contentType" , " size" , " blobKey" , " publicUrl" , " uploadedAt" }
87+ ```
88+
89+ where ` size ` is the decoded byte length, ` blobKey ` is the object-storage key
90+ (` files/{owner}/{id}-{filename} ` ), and ` uploadedAt ` is an ISO-8601 timestamp.
91+
92+ > ** Note:** this ` w3ds-file-v1 ` storage envelope is ** not** the same as the
93+ > platform-level ` File ` ontology (` a1b2c3d4-e5f6-7890-abcd-ef1234567890 ` ). See
94+ > [ File ontology vs. ` w3ds-file-v1 ` ] ( #file-ontology-vs-w3ds-file-v1 ) below.
95+
96+ ### Example
97+
98+ ``` graphql
99+ mutation UploadFile ($input : UploadFileInput ! ) {
100+ uploadFile (input : $input ) {
101+ uri
102+ metaEnvelopeId
103+ publicUrl
104+ errors { field message code }
105+ }
106+ }
107+ ```
108+
109+ ``` json
110+ {
111+ "input" : {
112+ "filename" : " contract.pdf" ,
113+ "contentType" : " application/pdf" ,
114+ "content" : " data:application/pdf;base64,JVBERi0x..." ,
115+ "acl" : [" *" ]
116+ }
117+ }
118+ ```
119+
120+ On failure after the blob is written, the orphaned object is deleted
121+ (compensating cleanup), so a failed upload leaves no dangling storage object.
122+
48123## Resolving (dereferencing) a URI
49124
50125There are two dereferencers.
@@ -87,6 +162,38 @@ or `Error` for:
87162- A non-existent ` ename ` (eVault cannot be resolved).
88163- A non-existent or non-file Meta Envelope.
89164
165+ ## File ontology vs. ` w3ds-file-v1 `
166+
167+ There are ** two distinct file schemas** in the system. They are easy to confuse
168+ but serve different layers, and conflating them is a common source of bugs.
169+
170+ | | ` w3ds-file-v1 ` | ` File ` ontology |
171+ | --- | --- | --- |
172+ | ** Identifier** | ` w3ds-file-v1 ` (string) | ` a1b2c3d4-e5f6-7890-abcd-ef1234567890 ` (UUID) |
173+ | ** Created by** | ` uploadFile ` mutation, at upload time | Platform apps (file-manager, esigner) via the Web3 Adapter mapping |
174+ | ** Layer** | Storage / transport — describes a blob in object storage | Application domain — a file record in a platform's database |
175+ | ** Payload** | ` filename ` , ` contentType ` , ` size ` , ` blobKey ` , ` publicUrl ` , ` uploadedAt ` | ` id ` , ` name ` , ` displayName ` , ` description ` , ` mimeType ` , ` size ` , ` md5Hash ` , ` data ` , ` url ` , ` ownerId ` , ` folderId ` , ` createdAt ` , ` updatedAt ` |
176+ | ** Addressed by** | ` w3ds://file?id=@ename/<meta-envelope-id> ` | Synced as a normal Meta Envelope through platform mappings |
177+ | ** Defined in** | ` evault-core/src/core/utils/w3ds-uri.ts ` (` FILE_SCHEMA_ID ` ) | ` services/ontology/schemas/file.json ` |
178+
179+ ** They are not the same envelope.** The payload documented above
180+ (` { filename, contentType, size, blobKey, publicUrl, uploadedAt } ` ) belongs to
181+ ` w3ds-file-v1 ` only — it is the low-level record the ` uploadFile ` mutation
182+ creates so a blob can be dereferenced via a ` w3ds://file ` URI.
183+
184+ The ` File ` ontology (` a1b2c3d4-... ` ) is a higher-level platform concept: a
185+ file-manager/esigner record with folders, owners, display names and an MD5
186+ hash, mapped to/from the global layer by the Web3 Adapter (see
187+ ` platforms/file-manager/api/src/web3adapter/mappings/file.mapping.json ` ). Note
188+ the field names differ — e.g. ` name ` vs ` filename ` , ` mimeType ` vs
189+ ` contentType ` , ` url ` vs ` publicUrl ` /` blobKey ` — so they are ** not**
190+ interchangeable payloads.
191+
192+ In short: use ` w3ds-file-v1 ` + ` w3ds://file ` URIs to store and dereference raw
193+ blobs; use the ` File ` ontology when modelling a platform's file records. A
194+ single user-facing "file" may involve both — a ` File ` ontology record whose
195+ ` url ` points at a blob uploaded via ` uploadFile ` .
196+
90197## Mapper integration
91198
92199The [ Web3 Adapter] ( /docs/Infrastructure/Web3-Adapter ) exposes a ` __file() `
0 commit comments