Document Version History
Problem
Design DocumentVersionHistory to manage documents with fixed user access, immutable numbered versions, one selected version, and permanent deletion.
Requirements
- Create a document.
createDocumentcreates version1with the supplied content, selects it, makes the caller the owner, and assigns the supplied editor and viewer lists. - Preserve updates. An owner or editor can append the next numbered version with new full content. Earlier versions stay unchanged, and the new version becomes selected.
- Select a version. An owner or editor can select any existing version without changing the stored history. A later update always uses the next number after the highest existing version.
- Read the selection. An owner, editor, or viewer can read an object containing exactly the selected
versionand itscontent. - Delete a document. Only its owner can permanently delete a document and all its versions. Every later operation for that document fails with
DocumentNotFoundError. - Enforce access. Users not listed on a document have no access, and viewers cannot update, select, or delete. A disallowed call raises
AccessDeniedErrorand leaves all state unchanged.
API
| Signature | Returns | Behavior |
|---|---|---|
DocumentVersionHistory() | Not applicable | Creates an empty service. |
createDocument(actorId: string, documentId: string, content: string, editors: string[], viewers: string[]) | integer | Creates the document and returns 1. Raises DocumentExistsError if the id is live. Raises InvalidArgumentError if an id or content is empty, the user lists overlap, or either list contains the actor. Failure changes no state. |
updateDocument(actorId: string, documentId: string, content: string) | integer | Appends and selects a version, then returns its number. Raises DocumentNotFoundError, AccessDeniedError, or InvalidArgumentError for empty content. Failure changes no state. |
changeVersion(actorId: string, documentId: string, version: integer) | void | Selects an existing version. Raises DocumentNotFoundError, AccessDeniedError, or VersionNotFoundError. Failure changes no state. |
getCurrentDocument(actorId: string, documentId: string) | object | Returns {"version": integer, "content": string} for the selected version. Raises DocumentNotFoundError or AccessDeniedError. |
deleteDocument(actorId: string, documentId: string) | void | Deletes the document and its history. Raises DocumentNotFoundError or AccessDeniedError. Failure changes no state. |
Examples
| Step | Operation | Result |
|---|---|---|
| 1 | createDocument("alice", "spec", "draft", ["bob"], ["cara"]) | 1 |
| 2 | updateDocument("bob", "spec", "reviewed") | 2 |
| 3 | changeVersion("alice", "spec", 1) | void |
| 4 | getCurrentDocument("cara", "spec") | {"version": 1, "content": "draft"} |
| 5 | updateDocument("cara", "spec", "blocked") | AccessDeniedError; state unchanged |
| 6 | deleteDocument("alice", "spec") | void |
| 7 | getCurrentDocument("alice", "spec") | DocumentNotFoundError |
Constraints
- User ids and document ids contain from
1through100Unicode scalar values. - Content contains from
1through10000Unicode scalar values. - A document has at most
1000users across all roles and10000versions. - At most
10000documents and100000method calls occur per testcase. - Role assignments do not change after creation.
Notes
Calls are sequential and take effect in invocation order. Concurrent calls are outside scope. Access is supplied through editor and viewer id lists.