Appearance
Document
Documents in aeppic are represented in aeppic as a JSON data structure:
The document type is specified in @aeppic/types
.
Document
ts
export interface Document {
/**
* Unique identifier of this document. It can be any string, but must not
* contain `.`, `:`, `/` to allow for good searching.
*
* It is recommended to use a UUID or a UUID like string, but in cases
* of derived documents it can be a combination of the original document
* id and a suffix. E.g `originalId_suffix`
*/
id: string
/** Parent of this document */
p: string
/** Unique version stamp (Not globally unique only with respect to this document. 'initial' for first version.) */
v: string
/**
* Information about the document as it was before this version. Can be used to identify changes and calculate the
* previous state of the document
*/
previous?: PreviousDocumentInfo
/** Reference to the document's form */
f: Reference
/** Actual document data fields */
data: DocumentData
/**
* More meta data about the document.
*/
meta?: DocumentMetaData
/** Is the document visible in default queries ? A hidden document can still be retrieved when the id is known or via query options */
hidden?: boolean
/** Is the document attached to its parent ? Documents like these cannot move and get optimized handling for queries **/
attached?: boolean
/** Is document data changeable ? A readonly documents form or data can only be changed once readonly has been set to false again. **/
readonly?: boolean
// /**
// * Documents can be optionally tagged using tags. Each set of tags is defined via a unique application
// * specific tag cloud id (tag clouds ids SHOULD not contain `.` to improve searching)
// */
// tags?: TagClouds
/** Defines the language in which the data is to be interpreted .E.g undefined means not specified. Should be e.g 'en-US', 'de-DE', 'de'.*/
language?: string
/** Reference to the document's clone source */
cloneOf?: Reference
/** Reference to the document's original source (the first clone ever made in a chain of clones A->B->C. C.cloneOf == B C.originalCloneOf == A). */
originalCloneOf?: Reference
/** Locks applied to this document */
locks: Reference[]
/**
* Change Information time and source information
*
* The `modified` field is the time of the last change to this document which
* actually changed the content. Changes to meta information such as p or f are
* not reflected in this field. Those are reflected in `meta.modified` instead.
*
* */
created: ChangeSourceInfo
modified: ChangeSourceInfo
/** UNIX Epoch UTC timestamp of event as written by the server upon processing */
t?: number
/** UNIX Epoch UTC timestamp of first event for this instance see `t` */
ct?: number
/**
* UNIX Epoch UTC timestamp of most recent descendant timestamp change (added, modified, or removed)
*
* This is only tracked for some documents (see @aeppic/server features descendantTimestamps)
* */
dts?: number
/**
* The documented cause as to why this document was changed to become this. This is added by the initiator of the change
* and can often not be verified by the server. It server as documentation to process logs
*/
cause?: Cause
/**
* Documents representing stamps themselves store their stamp specific data in `data`,
* but the stamp meta information is stored in here.
*/
stampData?: StampData
/**
* If a document was stamped (referenced by another document representating a stamp), the
* stamp indexing data is added to this field to make is easy to search for.
* Like inherited information below this field can change whenever new stamps are discovered
* as it is not bound to data inside this document per se. It is possible and likely of course
* that a stamp becomes invalid once data changes or the document gets modified in some fashion.
*/
stamps?: Stamp[]
/**
* Inherited information:
*
* Inherited information is not guaranteed to be up to date and can change without
* `v` reflecting this change, since it is inherently not bound to the content of
* the document, but to data inherited from the document's ancestor chain.
*
* The inherited properties `a_depth`,`a_forms`, and `a` are updated atomically to be consistent though
**/
a_depth: number
a_forms: string[]
a: string[]
inheritedLocks: Reference[][]
}
The document's actual user data is stored in its data
field.
Data
ts
export interface DocumentData {
[key: string]: boolean|boolean[]|string|string[]|MailField|MailField[]|number|number[]|AddressField|AddressField[]|FileField|FileField[]|ImageField|ImageField[]|GeoLocationField|GeoLocationField[]|ReferenceField|ReferenceField[]
}
Which fields are actually stored in the document is defined by the form the document is based on. The form is used as the type or schema of the document's data.
Forms are also documents and explained in more detail here
Metadata
Most important metadata is stored directly inside the document object.
E.g a reference to the form of the document is stored in its f
field for example.
json
{
...
f: {
id: 'FORM-ID',
v: 'FORM-VERSION',
text: 'FORM-NAME'
},
...
}
Or the last time the data of the document was modified is stored in its 'modified` field.
json
{
...
modified: {
at: '',
...
},
...
}
But some more seldomly used metadata is stored in the meta
field. For example
Metadata Type
ts
export interface DocumentMetaData {
/**
* meta.modified
*
* This is the case when a document is modified without actually
* changing the data. E.g when a document is moved to a different
* parent, the form is upgraded,changed, or deleted.
* In those cases meta information is added to the document
* and the timestamp of the change is stored in `meta.modified` while
* the root level `modified` is not changed.
* */
modified?: ChangeSourceInfo
/**
* meta.fields
*
* Meta information about fields in the document. This is used
* to store information about fields that are not part of the
* form definition.
*
* It can be used by controls, services, business rules etc to store
* information about fields that is not part of the form definition.
*
* To use this field use a namespace to avoid collisions.
* E.g `fields.myField['com:aeppic:rules:ai:2024'].detected = { ... }`
*
* The namespace should be a reverse domain name of the entity
* storing the information. E.g `com:aeppic:rules:ai:2024` is
* the namespace for the `aeppic` company, the `rules` service,
* the `ai` business rule, and the `2024` version of that rule.
*
* The namespace is not validated by the system and can be any
* string but only include `a-z`, `A-Z`, `0-9`, `:`, and `-`.
*
* The writer needs to ensure to not store too much data in here. Otherwise
* the document will grow too large and the system will not be able to
* handle it anymore. Use references or stamps instead.
*
*/
fields?: {
[fieldName: string]: {
[namespace: string]: any
}
}
}