diff --git a/shapes/README.md b/shapes/README.md
index 5698f940..4f491b42 100644
--- a/shapes/README.md
+++ b/shapes/README.md
@@ -1,106 +1,235 @@
+# Solid User Profile
+
+We don't currently have a specific Shape defined for user profiles. But the
+original Solid specification provides good guidance on the basic requirements
+for the Profile Document expected to be returned when de-referencing a WebID.
+
+See here for details: https://github.com/solid/solid-spec#webid-profile-documents
+
+We'd certainly be open to ideas on how to model these basic discovery
+requirements differently, and also on how to model the actual human user profile
+information (such as date-of-birth, gender, address, etc.).
+
+## The 'country' problem?
+An interesting discussion point would be how to model something as seemingly
+trivial as the 'country' field of a user's address. If we take the ISO as just
+an example of a recognized 'authority' when referring to "countries of the
+world" (of course they are by no means the only such authority), then a problem
+arises in that the ISO do not provide IRIs for the countries they otherwise
+standardize identifiers for (e.g., 'ie' for Ireland, 'de' for Germany).
+
+(About 7 years ago I specifically asked the ISO if they might consider minting
+official IRIs for countries. Their reply was, literally, "**_We do not product
+(sic) any RDF formats, I am sorry"_**!)
+
+By way of example of how long-running a fundamental modelling question this is,
+see this mailing list thread I started 6 years ago (and specifically see the
+guidance from Martin Hepp, re-iterated in the final email from Bernard Vatant),
+which basically recommends just using the standardized string values for
+countries, and not using IRIs at all(!):
+- Martin Hepp: https://lists.w3.org/Archives/Public/public-vocabs/2015Mar/0165.html
+- Bernard Vatant (last email): https://lists.w3.org/Archives/Public/public-vocabs/2015Mar/0181.html
+
# Shapes
+The remainder of this document describes the overall contents of this
+directory, and attempts to explain some of the rationale for the modelling.
+
+This directory also includes a series of Turtle files demonstrating expected
+usage.
+
+### Note: Use of triples versus quads for user data
+
+Currently our modelling does not use quads for user data at all.
+
+Instead we propose using Named Graphs to support various forms of meta-data
+that might be associated with any resource, for example, server-managed
+meta-data (e.g., the date/time the resource was created or last modified, or
+the backend storage node used, etc.), or Access Control List (ACL) data
+associated with the resource, or perhaps ShEx shapes the resource must conform
+to, or client-side meta-data associated with Non-RDF resources (e.g., the 'name'
+of a JPEG image resource, or the camera aperture settings of the image), etc.
+
+## Structure of the Shapes, and example Turtle contained here.
+
+This directory contains a `bookmark` directory and a `contact` directory. Each
+contains ShEx Shapes and an `/example` folder showing demonstration Turtle files
+conforming to the relevant Shapes.
+
+The Turtle files of the `contact` examples also demonstrate how instances of Pod
+Resources are currently interlinked (e.g., it demonstrates groups of people
+referenced from address books).
+
+## Use of the `#this` fragment identifier
+
+This modelling follows a naming convention whereby the fragment identifier
+`#this` can be used to denote the main RDF Subject in the dataset that makes up
+all the triples of a single Pod resource.
+
+For example, in `shapes/contact/example/group/group3-soccer-team.ttl` we use the
+`#this` fragment identifier on the RDF Subject of the triples associated with
+the Soccer Team Group itself. The resource is free to include triples using as
+many other RDF Subjects as it likes, but `#this` is intended to identify the
+main entity of the resource.
+
+## Indexes
+
+We use the term 'index' throughout our modelling with two very different
+interpretations:
+
+ - Index in the sense of a single Pod resource containing a collection of
+ entities. E.g., a single Person-Index resource might contain a list of 50
+ Person instances, where each instance contains a reference (or link) to the
+ actual Person resource elsewhere in my Pod, but may also contain a copy of
+ the Person's name and profile image perhaps, directly in the index too.
+ - Index in the sense of a '_default resource to look for when navigating to a
+ Container_'. In much the same way as browsers will automatically look for a
+ resource named 'index.html' when browsing to a website, our modelling can
+ store resources named 'index.ttl' in the root of containers, which our
+ applications can then expect to contain app-specific information.
+
+### Indexes as 'efficient containers for a collection of entities'
+
+We chose not to model these collections using either native RDF lists (e.g.,
+`rdf:Seq`), nor LDP containers, nor some existing list or set vocabulary (e.g.,
+such as Schema.org's [ItemList](https://schema.org/ItemList), or the Ordered
+List Ontology ([OLO](http://smiy.sourceforge.net/olo/spec/orderedlistontology.html))).
+The reasons for this were:
+ - This was originally modelled around limitations of the first Solid server
+ (NSS).
+ - Efficiency reasons, i.e., where we wish to retrieve a collection of entities
+ in a single HTTP resource request (e.g., a list of people, perhaps with just
+ their first name and date-of-birth values), as opposed to needing to make
+ multiple HTTP requests, one for each Person resource in our list.
+
+
+#### Example of index use
+
+For example, a single AddressBook resource may reference two indexes, one for
+the collection of email addresses in that AddressBook (i.e., using the
+predicate `vcard:nameEmailIndex`), and one for the collection of groups in that
+AddressBook (i.e., using the predicate `vcard:groupIndex`).
+
+
## Bookmarks
-We've decided to keep the structure of bookmarks simple, only storing `terms:created`, `terms:title`, and
-`bookmark:recalls`. Note that some Solid bookmarking apps also use `foaf:maker`, but we didn't think it necessary in the
+We've decided to keep the structure of bookmarks simple, only storing
+`dcterms:created`, `dcterms:title`, and `bookmark:recalls`. Note that some Solid
+bookmarking apps also use `foaf:maker`, but we didn't think it necessary in the
context of the PodBrowser, so we've chosen to make it optional.
-We've also decided to omit the use of an index using `dct:references`, as this would require us to keep the index
-up-to-date manually, and we think it's better to find the bookmarks using the `bookmark:Bookmark` class.
+We've also decided to omit the use of an index using `dcterms:references`, as
+this would require us to keep the index up-to-date manually, and we think it's
+better to find the bookmarks using the `bookmark:Bookmark` class.
-At some point we might need to group bookmarks, but at this point we've chosen to keep it simple and simply
-implement bookmarks as a set of bookmarks that are stored in one file.
+At some point we might need to group bookmarks, but at this point we've chosen
+to keep it simple and simply implement bookmarks as a set of bookmarks that are
+stored in one file.
## Contacts
-Because there are some differences between the ShEx shapes we've described and previous work on SHACL shapes we wanted
-to explain the differences those shapes. Once they have been resolved, we might remove this README altogether.
+Because there are some differences between the ShEx shapes we've described and
+previous work on SHACL shapes, we wanted to explain the differences between
+those shapes. Once these differences have all been resolved, we might remove
+this README altogether.
### Address Book: Differences between ShEx and SHACL
-The following is how the SHACL shape in `https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl` differs from the ShEx shape in `contacts/address-book.shex`.
+The following is how the SHACL shape in
+`https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl`
+differs from the ShEx shape in `contacts/address-book.shex`.
- vcard:AddressBook
- vcard:fn (instead of dc:title)
- - There can be one or more instances
+ - There can be one or more instances.
- vcard:nameEmailIndex
- - There can be one or more instances
- - There is not a specific datatype set
- - vcard:vcard:groupIndex
- - Using terms (sh:count, sh:FollowMe) that isn't formalized
+ - There can be one or more instances.
+ - There is no specific datatype set.
+ - vcard:groupIndex
+ - Uses terms (e.g., sh:count, sh:FollowMe) that aren't formalized.
### Group Index: Differences between ShEx and SHACL
-The following is how the SHACL shape in `https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl` differ from the ShEx shape in `contacts/group-index.shex`.
+The following is how the SHACL shape in
+`https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl`
+differs from the ShEx shape in `contacts/group-index.shex`.
- vcard:AddressBook
- vcard:fn
- - Different cardinality ({1,m} vs {1,1})
+ - Different cardinality ({1,m} vs {1,1}).
- vcard:includesGroup
- - We used an inverse triple constraint instead (putting this term under vcard:Group shape instead)
+ - We used an inverse triple constraint instead (putting this term under
+ vcard:Group shape instead).
### Group: Differences between ShEx and SHACL
-The following is how the SHACL shape in `https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl` differ from the ShEx shape in `contacts/group.shex`.
+The following is how the SHACL shape in
+`https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl`
+differs from the ShEx shape in `contacts/group.shex`.
- vcard:AddressBook
- vcard:includesGroup
- - Using informal terms (sh:count, sh:FollowMe)
+ - Using informal terms (sh:count, sh:FollowMe).
- vcard:Group
- - vcard:fn cardinality difference (one or more instead of just one)
- - vcard:member (informal term) instead of vcard:hasMember
+ - vcard:fn cardinality difference (one or more instead of just one).
+ - vcard:member (informal term) instead of vcard:hasMember.
### People Index: Differences between ShEx and SHACL
-The following is how the SHACL shape in `https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl` differ from the ShEx shape in `contacts/people-index.shex`.
+The following is how the SHACL shape in
+`https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl`
+differs from the ShEx shape in `contacts/person-index.shex`.
- vcard:Individual
- vcard:inAddressBook
- - uses informal term sh:BackwardLink
- - minimum and maximum one instance of IRI (can be part of only one address book)
+ - uses informal term sh:BackwardLink.
+ - minimum and maximum one instance of IRI (i.e., can only be referenced from
+ one address book).
### Person: Differences between ShEx and SHACL
-The following is how the SHACL shape in `https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl` differ from the ShEx shape in `contacts/person.shex`.
+The following is how the SHACL shape in
+`https://raw.githubusercontent.com/solid/contacts-pane/master/shapes/contacts-shapes.ttl`
+differs from the ShEx shape in `contacts/person.shex`.
- vcard:Individual
- - is closed
- - using informal term sh:count
+ - is closed.
+ - using informal term sh:count.
- vcard:fn
- - uses sh:pattern ".* .*"
+ - uses sh:pattern ".* .*".
- vcard:hasUID
- - different cardinality ({1, 1} vs {0, 1})
- - uses sh:pattern "^urn:uuid:"
+ - different cardinality ({1, 1} vs {0, 1}).
+ - uses sh:pattern "^urn:uuid:".
- vcard:hasName
- - has a shape of its own (:NameShape)
+ - has a shape of its own (:NameShape):
- vcard:family-name
- vcard:given-name
- vcard:additional-name
- vcard:honorific-prefix
- vcard:honorific-suffix
- - we used string, but added a comment
+ - we used string, but added a comment.
- vcard:hasImage
- - don't specify type dc:Image
+ - don't specify type dc:Image.
- vcard:hasRelated
- - don't specify node or sub-shape (we specified a shape for vcard:RelatedType in ShEx)
+ - don't specify node or sub-shape (we specified a shape for
+ vcard:RelatedType in ShEx).
- vcard:url
- - has a shape of its own (:WebPageShape)
- - uses vcard:value (vs rdf:value)
- - uses sh:pattern "^https?:"
- - uses informal term sh:count
- - we specified type rdf:Resource in the ShEx shape
+ - has a shape of its own (:WebPageShape):
+ - uses vcard:value (vs rdf:value).
+ - uses sh:pattern "^https?:".
+ - uses informal term sh:count.
+ - we specified type rdf:Resource in the ShEx shape.
- vcard:hasAddress
- - don't specify node or sub-shape (vcard:Address)
+ - don't specify node or sub-shape (vcard:Address).
- vcard:anniversary
- - we used vcard:bday in the ShEx shape
+ - we used vcard:bday in the ShEx shape.
- vcard:hasEmail
- - uses sh:pattern "^mailto:" (vs /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/ in ShEx)
- - uses vcard:value (vs rdf:value)
- - uses informal term sh:count
- - different cardinality (ShEx is *)
+ - uses sh:pattern "^mailto:" (vs /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/ in ShEx).
+ - uses vcard:value (vs rdf:value).
+ - uses informal term sh:count.
+ - different cardinality (ShEx is *).
- vcard:hasTelephone
- - uses sh:pattern "^tel:" (vs /^\+?[0-9]+[0-9-]*[0-9]$/ in ShEx)
- - uses vcard:value (vs rdf:value)
- - uses informal term sh:count
- - different cardinality (ShEx is *)
+ - uses sh:pattern "^tel:" (vs /^\+?[0-9]+[0-9-]*[0-9]$/ in ShEx).
+ - uses vcard:value (vs rdf:value).
+ - uses informal term sh:count.
+ - different cardinality (ShEx is *).
diff --git a/shapes/bookmark/README.md b/shapes/bookmark/README.md
new file mode 100644
index 00000000..deb47192
--- /dev/null
+++ b/shapes/bookmark/README.md
@@ -0,0 +1,5 @@
+# Bookmark-related Turtle files
+
+Bookmarks are modelled very simply. Due to this simplicity at the moment, we've
+choosen to model a collection of bookmarks as simply being entities contained
+within a single resource (as opposed to defining a resource-per-bookmark).
diff --git a/shapes/bookmarks/bookmark.shex b/shapes/bookmark/bookmark.shex
similarity index 59%
rename from shapes/bookmarks/bookmark.shex
rename to shapes/bookmark/bookmark.shex
index 338540f5..59712860 100644
--- a/shapes/bookmarks/bookmark.shex
+++ b/shapes/bookmark/bookmark.shex
@@ -3,6 +3,12 @@ PREFIX foaf:
PREFIX terms:
PREFIX xsd:
+#
+# This shape describes the information we store for a bookmark.
+# In Pod Browser we store all bookmarks within the one resource (as opposed to
+# storing one bookmark per resource and containing them all within an
+# `ldp:Container`).
+#
bookmark:Bookmark {
terms:created xsd:dateTime {1} ;
terms:title xsd:string {1} ;
diff --git a/shapes/bookmark/example/bookmark/index.ttl b/shapes/bookmark/example/bookmark/index.ttl
new file mode 100644
index 00000000..8d6965ac
--- /dev/null
+++ b/shapes/bookmark/example/bookmark/index.ttl
@@ -0,0 +1,16 @@
+@prefix : <#>.
+@prefix bookm: .
+@prefix terms: .
+@prefix xsd: .
+
+:16115748945888512870652861511
+ a bookm:Bookmark;
+ terms:created "2021-01-25T11:41:34.589Z"^^xsd:dateTime;
+ terms:title "Solid Project";
+ bookm:recalls .
+
+:12391230834289702394820340982
+ a bookm:Bookmark;
+ terms:created "2021-01-30T12:30:21.321Z"^^xsd:dateTime;
+ terms:title "Inrupt";
+ bookm:recalls .
diff --git a/shapes/contact/address-book.shex b/shapes/contact/address-book.shex
new file mode 100644
index 00000000..a69d695b
--- /dev/null
+++ b/shapes/contact/address-book.shex
@@ -0,0 +1,24 @@
+PREFIX acl:
+PREFIX dc:
+PREFIX vcard:
+PREFIX xsd:
+
+# This shape describes some of the information we store for an address book.
+# It's intended to represent a single address book. We use the ID "#this" to
+# refer to the subject of the address book.
+
+# This model was originally developed as part of the
+# SolidOS/Data Browser project, and we strive to keep it interoperable with
+# their work. Some custom terms have been introduced to vocabularies we think
+# they could belong to (e.g. vcard:nameEmailIndex). We'll make a note of the
+# custom term when used.
+
+# vcard:AddressBook is a custom class
+vcard:AddressBook {
+ dc:title xsd:string {1} ;
+ # vcard:nameEmailIndex is a custom term
+ vcard:nameEmailIndex IRI {1} ;
+ # vcard:groupIndex is a custom term
+ vcard:groupIndex IRI {1} ;
+ acl:owner IRI +
+}
diff --git a/shapes/contact/example/README.md b/shapes/contact/example/README.md
new file mode 100644
index 00000000..43d2795a
--- /dev/null
+++ b/shapes/contact/example/README.md
@@ -0,0 +1,47 @@
+# Contacts-related Turtle files
+
+The example Turtle files here describe the structure and modelling of the
+following Contact-related concepts:
+
+### Two address books
+
+Modelled as **_containers_**:
+
+- Work colleagues (the `/addressBookWork` container).
+- Friends (the `/addressBookFriend` container).
+
+### Four groups
+
+Modelled as individual **_resources_** within the `/group` container, and with
+that `/group` container having an `index.ttl` Group-Index.
+
+- Work colleagues (`/group/group1-work-colleague.ttl`).
+- Friends (`/group/group2-friend.ttl`).
+- Local soccer team (`/group/group3-soccer-team.ttl`).
+- Just an empty group (`/group/group4-empty.ttl`).
+
+And the Group-Index - `/group/index.ttl`.
+
+### Three people
+
+Each person modelled as a **_child container_** within the `/person` container,
+with the parent `/person` container containing an `index.ttl` Person-Index.
+
+- Arne H, who I work with, is a friend I play D&G, and is the striker on my
+ local soccer team!
+- Vincent T, who I work with.
+- Tommy Mc, who is a friend.
+
+And the Person-Index - `/person/index.ttl`.
+
+
+# Notes:
+
+- The use of `index.ttl` is a convention, but it seems to be used for both
+ 'indexes' (i.e., a Group index (e.g., `/group/index.ttl`) listing a number of
+ contained groups), and the 'default resource' of a container (e.g., the
+ `index.ttl` resource within the individual person container (e.g.,
+ `/person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl`).
+
+- In Group-Indexes, is it necessary to duplicate the triple stating that each
+ contained group is of `rdf:type` `vcard:Group`?
diff --git a/shapes/contact/example/addressBookFriend/index.ttl b/shapes/contact/example/addressBookFriend/index.ttl
new file mode 100644
index 00000000..ce90cdc9
--- /dev/null
+++ b/shapes/contact/example/addressBookFriend/index.ttl
@@ -0,0 +1,16 @@
+prefix : <#>
+prefix acl:
+prefix dcterms:
+prefix vcard:
+
+#
+# This is my address book that I use to list just my friends...
+# It contains references to two indexes:
+# - one listing my friends
+# - one listing my groups of friends
+#
+:this a vcard:AddressBook ;
+ acl:owner ;
+ dcterms:title "Contacts of all my friends" ;
+ vcard:nameEmailIndex <../person/index.ttl> ;
+ vcard:groupIndex <../group/index.ttl> .
diff --git a/shapes/contact/example/addressBookWork/index.ttl b/shapes/contact/example/addressBookWork/index.ttl
new file mode 100644
index 00000000..5c998200
--- /dev/null
+++ b/shapes/contact/example/addressBookWork/index.ttl
@@ -0,0 +1,16 @@
+prefix : <#>
+prefix acl:
+prefix dcterms:
+prefix vcard:
+
+#
+# This is my address book that I use to list just my work colleagues...
+# It contains references to two indexes:
+# - one listing my work colleagues
+# - one listing my groups of work colleagues
+#
+:this a vcard:AddressBook ;
+ acl:owner ;
+ dcterms:title "Contacts of all my work colleagues" ;
+ vcard:nameEmailIndex ;
+ vcard:groupIndex .
diff --git a/shapes/contact/example/group/group1-work-colleague.ttl b/shapes/contact/example/group/group1-work-colleague.ttl
new file mode 100644
index 00000000..f22c0426
--- /dev/null
+++ b/shapes/contact/example/group/group1-work-colleague.ttl
@@ -0,0 +1,22 @@
+prefix : <#>
+prefix vcard:
+
+:this
+ a vcard:Group ;
+ vcard:fn "Group 1 - my work colleagues" ;
+ vcard:hasMember <../person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl#this> ;
+ vcard:hasMember <../person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl#this> .
+
+<../addressBookFriend/index.ttl#this> vcard:includesGroup :this .
+
+#
+# This is caching some data from an external resource by copying it here (just
+# so that we don't need to fetch each `vcard:hasMember` instance to get their
+# `vcard:fn` values.
+#
+<../person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl#this>
+ vcard:fn "Arne - who I work with" .
+
+<../person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl#this>
+ vcard:fn "Vincent - but name could be different here (since it's a copy)" .
+
diff --git a/shapes/contact/example/group/group2-friend.ttl b/shapes/contact/example/group/group2-friend.ttl
new file mode 100644
index 00000000..25c46d37
--- /dev/null
+++ b/shapes/contact/example/group/group2-friend.ttl
@@ -0,0 +1,22 @@
+prefix : <#>
+prefix vcard:
+
+:this
+ a vcard:Group ;
+ vcard:fn "Group 2 - my friends" ;
+ vcard:hasMember <../person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl#this> ;
+ vcard:hasMember <../person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl#this> .
+
+<../addressBookFriend/index.ttl#this> vcard:includesGroup :this .
+
+#
+# This is caching some data from an external resource by copying it here (just
+# so that we don't need to fetch each `vcard:hasMember` instance to get their
+# `vcard:fn` values.
+#
+<../person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl#this>
+ vcard:fn "Arne - from work, but my mate from D&G" .
+
+<../person/76344edd-b1c7-67c2-ec3e-89ab5494e233/index.ttl#this>
+ vcard:fn "Tommy - friend from the soccer team" .
+
diff --git a/shapes/contact/example/group/group3-soccer-team.ttl b/shapes/contact/example/group/group3-soccer-team.ttl
new file mode 100644
index 00000000..d480011c
--- /dev/null
+++ b/shapes/contact/example/group/group3-soccer-team.ttl
@@ -0,0 +1,23 @@
+prefix : <#>
+prefix vcard:
+
+:this
+ a vcard:Group ;
+ vcard:fn "Group 3 - local soccer team" ;
+ vcard:hasMember
+ <../person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl#this> ,
+ <../person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl#this> .
+
+<../addressBookFriend/index.ttl#this> vcard:includesGroup :this .
+
+#
+# This is caching some data from an external resource by copying it here (just
+# so that we don't need to fetch each `vcard:hasMember` instance to get their
+# `vcard:fn` values.
+#
+<../person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl#this>
+ vcard:fn "Arne - soccer team striker!" .
+
+<../person/76344edd-b1c7-67c2-ec3e-89ab5494e233/index.ttl#this>
+ vcard:fn "Tommy - soccer team goalkeeper" .
+
diff --git a/shapes/contact/example/group/group4-empty.ttl b/shapes/contact/example/group/group4-empty.ttl
new file mode 100644
index 00000000..20f58dda
--- /dev/null
+++ b/shapes/contact/example/group/group4-empty.ttl
@@ -0,0 +1,11 @@
+prefix : <#>
+prefix vcard:
+
+# This is simply an empty group (i.e., no members, yet).
+:this
+ a vcard:Group ;
+ vcard:fn "Group 4 - empty, for now..." .
+
+<../addressBookFriend/index.ttl#this>
+ vcard:includesGroup :this .
+
diff --git a/shapes/contact/example/group/index.ttl b/shapes/contact/example/group/index.ttl
new file mode 100644
index 00000000..0cc0d361
--- /dev/null
+++ b/shapes/contact/example/group/index.ttl
@@ -0,0 +1,36 @@
+prefix : <#>
+prefix vcard:
+
+#
+# This is a Group-specific index.
+#
+# Here we cache (copy) some data from our 'contained' groups, in this case just
+# the formatted name of each group (and since they are 'copies', they can have
+# different values), and the fact that each is of `rdf:type` `vcard:Group`.
+#
+<./group1-work-colleague.ttl#this>
+ a vcard:Group ;
+ vcard:fn "Group 1 - all my work colleagues" .
+
+<./group2-friend.ttl#this>
+ a vcard:Group ;
+ vcard:fn "Group 2 - all my friends" .
+
+<./group3-soccer-team.ttl#this>
+ a vcard:Group ;
+ vcard:fn "Group 3 - my local soccer team" .
+
+<./group4-empty.ttl#this>
+ a vcard:Group ;
+ vcard:fn "Group 4 - which I expect to be empty" .
+
+
+<../addressBookWork/index.ttl#this>
+ vcard:includesGroup
+ <./group1-work-colleague.ttl#this> .
+
+<../addressBookFriend/index.ttl#this>
+ vcard:includesGroup
+ <./group2-friend.ttl#this> ,
+ <./group3-soccer-team.ttl#this> ,
+ <./group4-empty.ttl#this> .
diff --git a/shapes/contact/example/person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl b/shapes/contact/example/person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl
new file mode 100644
index 00000000..52ef805e
--- /dev/null
+++ b/shapes/contact/example/person/2d73ccc1-9d76-4398-8840-3c23a8ddf04c/index.ttl
@@ -0,0 +1,25 @@
+prefix : <#>
+prefix dcterms:
+prefix XML:
+prefix vcard:
+
+# This data was generated when this 'Person' container was created initially
+# via Data Browser and rdflib.js.
+<>
+ dcterms:created "2021-02-04T06:19:42Z"^^XML:dateTime .
+
+#
+# Here we describe the actual entity - in this case a Person.
+#
+:this
+ a vcard:Individual ;
+ vcard:fn "Arne H - work colleague, friend and soccer striker" ;
+ vcard:url [
+ a vcard:WebID;
+ vcard:value "https://megoth-demo1.inrupt.net/profile/card#me"
+ ] ,
+ # Perhaps other forms of dereferencable URL's (but not email!)...
+ [
+ a vcard:DID;
+ vcard:value "did:sovrin:34537453453-2432424-23424324"
+ ] .
diff --git a/shapes/contact/example/person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl b/shapes/contact/example/person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl
new file mode 100644
index 00000000..30462aa0
--- /dev/null
+++ b/shapes/contact/example/person/347429c1-e6b5-40c0-bd6f-61ba1265d357/index.ttl
@@ -0,0 +1,17 @@
+prefix : <#>
+prefix vcard:
+
+#
+# Person instance saved via Pod Browser...
+#
+:this
+ a vcard:Individual ;
+ vcard:fn "Vincent T - work colleague" ;
+ vcard:url :16112499761464744406237652592 .
+
+#
+# Using a named node (as opposed to a Blank Node).
+#
+:16112499761464744406237652592
+ a vcard:WebId ;
+ vcard:value .
diff --git a/shapes/contact/example/person/76344edd-b1c7-67c2-ec3e-89ab5494e233/index.ttl b/shapes/contact/example/person/76344edd-b1c7-67c2-ec3e-89ab5494e233/index.ttl
new file mode 100644
index 00000000..f3d0919a
--- /dev/null
+++ b/shapes/contact/example/person/76344edd-b1c7-67c2-ec3e-89ab5494e233/index.ttl
@@ -0,0 +1,17 @@
+prefix : <#>
+prefix vcard:
+
+#
+# Person instance saved via Pod Browser...
+#
+:this
+ a vcard:Individual ;
+ vcard:fn "Tommy - friend and goalkeeper extraordinaire" ;
+ vcard:url :56456268332379795455777077312 .
+
+#
+# Using a named node (as opposed to a Blank Node).
+#
+:56456268332379795455777077312
+ a vcard:WebId ;
+ vcard:value .
diff --git a/shapes/contact/example/person/index.ttl b/shapes/contact/example/person/index.ttl
new file mode 100644
index 00000000..878f0094
--- /dev/null
+++ b/shapes/contact/example/person/index.ttl
@@ -0,0 +1,23 @@
+prefix : <#>
+prefix vcard:
+
+#
+# This is a Person-specific index.
+#
+# We define a container for each Person (but for Groups we don't), and we
+# can cache (or copy) specific data from each person to here in this index too
+# (so that we can access that data without having to read all the individual
+# people resources when just listing all the people with their names).
+
+ vcard:fn "Arne H" ;
+ vcard:inAddressBook
+ <../addressBookFriend/index.ttl#this> ,
+ <../addressBookWork/index.ttl#this> .
+
+
+ vcard:fn "Vincent" ;
+ vcard:inAddressBook <../addressBookWork/index.ttl#this> .
+
+
+ vcard:fn "Tommy Mc" ;
+ vcard:inAddressBook <../addressBookFriend/index.ttl#this> .
diff --git a/shapes/contact/group-index.shex b/shapes/contact/group-index.shex
new file mode 100644
index 00000000..7c23524a
--- /dev/null
+++ b/shapes/contact/group-index.shex
@@ -0,0 +1,20 @@
+PREFIX vcard:
+PREFIX xsd:
+
+# This shape describes part of the information we store when adding a group to
+# an address book. The resource it is used for is an index of groups. There will
+# be multiple groups added in this resource, and each referring to the group
+# resource where there are more information on the group (e.g. members).
+
+# This model was originally developed as part of the
+# SolidOS/Data Browser project, and we strive to keep it interoperable with
+# their work. Some custom terms have been introduced to vocabularies we think
+# they could belong to (e.g. vcard:includesGroup). We'll make a note of the
+# custom term when used.
+
+vcard:Group {
+ vcard:fn xsd:string {1} ;
+ # vcard:includesGroup is a custom term
+ # vcard:AddressBook is a custom class
+ ^ vcard:includesGroup vcard:AddressBook ;
+}
diff --git a/shapes/contact/group.shex b/shapes/contact/group.shex
new file mode 100644
index 00000000..0c673918
--- /dev/null
+++ b/shapes/contact/group.shex
@@ -0,0 +1,26 @@
+PREFIX vcard:
+PREFIX xsd:
+
+# This shape describes some of the information we store when adding a group to
+# an address book. The resource it is used for is to describe the group itself
+# (meaning the resource should only contain one group). We use the id "#this"
+# to refer to the subject of the group.
+
+# This model was originally developed as part of the
+# SolidOS/Data Browser project, and we strive to keep it interoperable with
+# their work. Some custom terms have been introduced to vocabularies we think
+# they could belong to (e.g. vcard:includesGroup). We'll make a note of the
+# custom term when used.
+
+vcard:Group {
+ vcard:fn xsd:string {1} ;
+ vcard:note xsd:string ? ;
+ vcard:hasMember vcard:Individual * OR vcard:Organization * ;
+ # vcard:includesGroup is a custom term
+ # vcard:AddressBook is a custom class
+ ^vcard:includesGroup vcard:AddressBook
+}
+
+# Note that we also cache the name of each member, so that we don't have to
+# fetch the profile of each member to get their name. An example of this can
+# be seen in example/Group/Group_1.ttl.
diff --git a/shapes/contact/person-index.shex b/shapes/contact/person-index.shex
new file mode 100644
index 00000000..01ef18c1
--- /dev/null
+++ b/shapes/contact/person-index.shex
@@ -0,0 +1,22 @@
+PREFIX vcard:
+PREFIX xsd:
+
+# This shape describes part of the information we store when adding a person to
+# an address book. The resource it is used for is an index of people. There will
+# be multiple people added in this resource, and each referring to the person
+# resource where there are more information on the person (e.g. photo, email,
+# etc).
+
+# This model is originally developed as part of the
+# SolidOS/Data Browser project, and we strive to keep it interoperable with
+# their work. Some custom terms have been introduced to vocabularies we think
+# they could belong to (e.g. vcard:inAddressBook). We'll make a note of the
+# custom term when used.
+
+vcard:Individual {
+ vcard:fn xsd:string {1} ;
+
+ # vcard:inAddressBook is a custom term
+ # vcard:AddressBook is a custom class
+ vcard:inAddressBook vcard:AddressBook ?
+}
diff --git a/shapes/contacts/person.shex b/shapes/contact/person.shex
similarity index 51%
rename from shapes/contacts/person.shex
rename to shapes/contact/person.shex
index df04fb05..cad4605d 100644
--- a/shapes/contacts/person.shex
+++ b/shapes/contact/person.shex
@@ -1,18 +1,30 @@
-PREFIX vcard:
-PREFIX xsd:
-PREFIX owl:
-PREFIX dc:
-PREFIX rdf:
+PREFIX vcard:
+PREFIX xsd:
+PREFIX owl:
+PREFIX dcterms:
+PREFIX rdf:
-# We should store the preferred WebId for each person, since sameAs can be multiple WebIds
+# This shape describes the information we store when adding a person to an
+# address book. The resource it is used for represents a local copy of a
+# person's profile. We use the id "#this" to refer to the subject of the person.
+
+# This model is originally developed as part of the SolidOS/Data
+# Browser project, and we strive to keep it interoperable with their work.
+# Some custom terms have been introduced to vocabularies we think they could
+# belong to (e.g. vcard:inAddressBook). We'll make a note of the custom term
+# when used.
vcard:Individual {
vcard:fn xsd:string {1} ;
- vcard:inAddressBook vcard:AddressBook + ;
- vcard:url vcard:WebId {1};
+
+ # vcard:WebId is a custom term
+ vcard:url vcard:WebId {1};
+
+ # Not sure if we use this anymore
vcard:hasUID xsd:string ? ;
+
vcard:hasName xsd:string ? ; # structured name
- vcard:hasPhoto dc:Image * ;
+ vcard:hasPhoto dcterms:Image * ;
vcard:hasRelated vcard:RelatedType * ;
vcard:hasAddress vcard:Address * ;
vcard:bday xsd:date ? ;
@@ -22,8 +34,16 @@ vcard:Individual {
vcard:role xsd:string ? ;
vcard:title xsd:string ? ;
vcard:note xsd:string ? ;
+ vcard:inAddressBook vcard:AddressBook + ;
+ # vcard:inAddressBook is a custom term
+ # vcard:AddressBook is a custom class
}
+# We store the preferred WebID for each person. The use of vcard:WebId
+# refer to the Individual's WebIDs, but the idea is that we could expand it
+# to refer to other type of unique identifiers later
+# vcard:WebId is a custom term
+# Big question - SHOULD something as fundamental as WebID be defined in vCard?
vcard:WebId {
vcard:value xsd:string {1};
}
diff --git a/shapes/contacts/address-book.shex b/shapes/contacts/address-book.shex
deleted file mode 100644
index abd19a36..00000000
--- a/shapes/contacts/address-book.shex
+++ /dev/null
@@ -1,11 +0,0 @@
-PREFIX acl:
-PREFIX dc:
-PREFIX vcard:
-PREFIX xsd:
-
-vcard:AddressBook {
- dc:title xsd:string {1} ;
- vcard:nameEmailIndex IRI {1} ;
- vcard:groupIndex IRI {1} ;
- acl:owner IRI +
-}
diff --git a/shapes/contacts/group-index.shex b/shapes/contacts/group-index.shex
deleted file mode 100644
index 29c3c96f..00000000
--- a/shapes/contacts/group-index.shex
+++ /dev/null
@@ -1,7 +0,0 @@
-PREFIX vcard:
-PREFIX xsd:
-
-vcard:Group {
- vcard:fn xsd:string {1} ;
- ^ vcard:includesGroup vcard:AddressBook ;
-}
diff --git a/shapes/contacts/group.shex b/shapes/contacts/group.shex
deleted file mode 100644
index 8fda45bd..00000000
--- a/shapes/contacts/group.shex
+++ /dev/null
@@ -1,9 +0,0 @@
-PREFIX vcard:
-PREFIX xsd:
-
-vcard:Group {
- vcard:fn xsd:string {1} ;
- vcard:note xsd:string ? ;
- vcard:hasMember vcard:Individual * OR vcard:Organization * ;
- ^vcard:includesGroup vcard:AddressBook
-}
diff --git a/shapes/contacts/people-index.shex b/shapes/contacts/people-index.shex
deleted file mode 100644
index 1821de42..00000000
--- a/shapes/contacts/people-index.shex
+++ /dev/null
@@ -1,7 +0,0 @@
-PREFIX vcard:
-PREFIX xsd:
-
-vcard:Individual {
- vcard:fn xsd:string {1} ;
- vcard:inAddressBook vcard:AddressBook ?
-}