diff --git a/ActiveRecord/doc/ActiveRecordUserGuide.page b/ActiveRecord/doc/ActiveRecordUserGuide.page
new file mode 100644
index 000000000..2038151f2
--- /dev/null
+++ b/ActiveRecord/doc/ActiveRecordUserGuide.page
@@ -0,0 +1,378 @@
+POCO C++ Libraries ActiveRecord Framework
+POCO ActiveRecord User Guide
+
+!!!Introduction
+
+POCO ActiveRecord is a simple and lightweight object-relational mapping (ORM) framework
+built on top of the POCO Data library. The main goal of POCO ActiveRecord is
+to relieve developers from having to write lots of boilerplate database
+query code for common operations like finding an object by ID, updating an object, deleting
+an object or running paged queries. As its name implies, the framework follows
+the well-known [[https://en.wikipedia.org/wiki/Active_record_pattern Active Record]]
+architectural pattern. It's based on a code generator (named *Active Record Compiler*,
+or <[arc]>) and uses a convention-over-configuration approach.
+
+!!!Getting Started
+
+The starting point for using the ActiveRecord framework is an XML file.
+The XML file describes the classes that correspond to database tables,
+and their relationships. From that XML file, the ActiveRecord Compiler
+generates corresponding header and source files defining and implementing
+the respective C++ classes, as well as type handlers for the POCO Data
+library.
+
+Following is a first example for such an XML file. The file defines two
+classes, an `Employee` class (mapped to a table named `employees`), and
+a `Role` class (mapped to a table names `roles`).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+----
+
+There is a n:1 relationship between `Employee` and `Role` (each employee
+has exactly one role). Furthermore, each employee can optionally have
+a manager, which is again an `Employee`.
+
+The generated C++ classes will be in the `Sample` namespace, as specified
+in the <[project]> element.
+
+The definitions in the XML file correspond to the database schema built
+by the following <[CREATE TABLE]> statements:
+
+ CREATE TABLE employees (
+ id CHAR(36),
+ name VARCHAR(64),
+ ssn VARCHAR(32),
+ role INTEGER,
+ manager CHAR(36)
+ );
+
+ CREATE TABLE roles (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ name VARCHAR(64),
+ description VARCHAR(256)
+ );
+----
+
+Running the ActiveRecord Compiler with the above XML file (sample.xml) with the
+following statement:
+
+ $ arc sample.xml
+----
+
+will create the following files in the current working directory:
+
+ include/
+ Sample/
+ Employee.h
+ Role.h
+ src/
+ Employee.cpp
+ Role.cpp
+----
+
+The generated classes are derived from the Poco::ActiveRecord::ActiveRecord class
+template and have accessor methods for all properties, as well as methods
+for creating, updating and deleting instances in the database.
+
+ActiveRecord objects are reference counted, and every generated class contains
+a `Ptr` type alias for an appropriate Poco::AutoPtr<>.
+
+!!The Context
+
+ActiveRecord uses a Context (Poco::ActiveRecord::Context) class to bind objects to
+a database session (Poco::Data::Session). In addition to the database session,
+the Context also holds a connector-specific
+Poco::ActiveRecord::StatementPlaceholderProvider. This class makes sure generated
+SQL statements have the correct placeholders for the respective database backend.
+For most database backends, the `?` placeholders will be fine, but PostgreSQL
+has a different placeholder format (`$1`, `$2`, etc). The Context's StatementPlaceholderProvider
+takes care of that.
+
+Every ActiveRecord object must be associated with a Context, before any database
+operations can take place. Context objects are relatively lightweight, so they
+can be created whenever needed. Context objects are reference-counted, so a Context
+object will be kept alive as long as at least one ActiveRecord object still references it.
+
+!!Creating an Object
+
+The following code snippet shows how to create a new `Role` object and insert it into
+the `roles` table.
+
+ Poco::Data::Session session("SQLite", "data.sqlite");
+ Context::Ptr pContext = new Context(session);
+
+ Role::Ptr pDeveloper = new Role;
+ pDeveloper->name("Developer")
+ .description("Developer role");
+
+ pDeveloper->create(pContext);
+----
+
+As can be seen, setters (`name()`, `description()` in this case) can be chained.
+The `create()` method will bind the object to a Context and then execute
+an `INSERT` statement to insert the object into the `roles` table.
+
+!!Finding an Object
+
+The following code snippet shows how to find a `Role` object by its ID (1).
+
+ Poco::Data::Session session("SQLite", "data.sqlite");
+ Context::Ptr pContext = new Context(session);
+
+ Role::Ptr pRole = Role::find(pContext, 1);
+ std::cout
+ << "name: " << pRole->name() << "\n"
+ << "description: " << pRole->description() << std::endl;
+----
+
+!!Updating an Object
+
+Updating an object involves first updating the respective properties using
+the setter functions, then calling the `update()` method. To update an
+ActiveRecord object, the object must already be bound to a Context.
+Objects returned from `find()`, or from a query will already be bound to a Context.
+Note that the following snippets will omit the session and context setup code.
+
+ Role::Ptr pRole = Role::find(pContext, 1);
+ pRole->description("New developer role");
+ pRole->update();
+----
+
+!!Deleting an Object
+
+An object bound to a Context can be deleted by calling the `remove()` method.
+
+ Role::Ptr pRole = Role::find(pContext, 1);
+ pRole->remove();
+----
+
+!!Queries
+
+Finding objects by their IDs alone is fine if the respective IDs are already known.
+However, in most cases, ActiveRecord objects will be obtained by executing
+a query. To do that, the ActiveRecord framework provides the
+Poco::ActiveRecord::Query class template. The Query template must be instantiated
+with the class of the resulting objects. The Query class will generate a
+`SELECT` statement. Query parameters can be specified via data binding. The
+`?` placeholder can be used regardless of the underlying database backend. The
+Query class will replace it with the appropriate placeholder for the backend.
+Actual query parameters are bound with the `bind()` method. The query is then
+executed by calling the `execute()` method.
+
+The result of a Query is a `std::vector` containing pointers (Poco::AutoPtr)
+to returned objects.
+
+ Poco::ActiveRecord::Query query(pContext);
+ const auto result = query
+ .where("name = ?")
+ .bind("Developer"s)
+ .execute();
+ for (const auto& pRole: result)
+ {
+ std::cout << pRole->description() << std::endl;
+ }
+----
+
+The argument to the `where()` method can be any SQL WHERE clause. Please note
+that you must use column names from the actual database tables in the WHERE
+clause, not property names.
+
+!Ordering
+
+The results of a Query can be ordered, by calling the `orderBy()` method.
+Note that the argument to `orderBy` must be the actual column name in the table,
+not the property name of the object. The column name can be followed by
+`ASC` or `DESC` to specify the direction.
+
+ Poco::ActiveRecord::Query query(pContext);
+ const auto result = query
+ .where("name = ?")
+ .bind("Developer"s)
+ .orderBy("name ASC")
+ .execute();
+ for (const auto& pRole: result)
+ {
+ std::cout << pRole->description() << std::endl;
+ }
+----
+
+!Paging
+
+The result of a query can be paged, by specifying an offset and a limit.
+The offset specifies the index of the first result to be returned, the
+limit specifies the maximum number of objects returned.
+
+To retrieve all roles, split up into pages of 10 roles, the following
+code could be used:
+
+ std::size_t offset = 0;
+ const std::size_t pageSize = 10;
+ Poco::ActiveRecord::Query query(pContext);
+ bool done = false;
+ while (!done)
+ {
+ const auto result = query
+ .orderBy("name")
+ .offset(offset)
+ .limit(pageSize)
+ .execute();
+
+ offset += result.size();
+ done = result.empty();
+
+ for (const auto& pRole: result)
+ {
+ // ...
+ }
+
+ query.reset();
+ }
+----
+
+In order to re-execute a Query, the `reset()` method must be called first, as is
+shown above at the end of the `while` loop.
+
+!Filtering Results
+
+In addition to filtering results with a `WHERE` clause, it's also possible to
+filter results with a lambda expression. While `WHERE` is evaluated in the
+database engine, and therefore much more efficient, the `filter()` method
+allows some additional flexibility.
+
+ Poco::ActiveRecord::Query query(pContext);
+ query.filter(
+ [](const Role& role)
+ {
+ return role.name() == "Senior Developer";
+ }
+ );
+
+ const auto result = query.execute();
+----
+
+!Relations
+
+Relations (defined in the XML file as properties with a `references` attribute)
+can be accessed via two kinds accessor methods. The first accepts an
+ActiveObject::Ptr as parameter or returns it, the second kind takes a key as
+parameter or returns it. Accessors that take a key/ID value instead of an
+ActiveRecord have their method name suffixed with `ID`.
+
+In the following sample, the `role` property is set with the key value, whereas the
+`manager` property is set via the ActiveRecord object.
+
+ Employee::Ptr pManager = new Employee;
+ pManager->name("Bill Lumbergh").ssn("23452343").roleID(3);
+ pManager->create(pContext);
+
+ Employee::Ptr pEmployee = new Employee;
+ pEmployee->name("Michael Bolton").ssn("123987123").roleID(2).manager(pManager);
+ pEmployee->create(pContext);
+----
+
+!Auto-increment Keys and Auto-generated UUIDs on Insert
+
+ActiveRecord supports auto-incrementing keys when inserting an ActiveRecord. T
+o enable this feature, the `autoIncrementID` attribute in the `class` element needs
+to be set to `true`.
+When inserting such an ActiveRecord object, after executing the `INSERT` statement, the
+actual value of the key will be obtained from the database. This is currently
+implemented for SQLite, MySQL/MariaDB and PostgreSQL, using appropriate database-specific
+mechanisms.
+
+When inserting an ActiveRecord with an all-null UUID, a random UUID will be generated
+before executing the `INSERT` statement.
+
+!!!XML Reference
+
+!!Supported Data Types
+
+The following data types can be specified for properties in the `type` attribute
+and are mapped to the indicated C++ types.
+
+ Type in XML C++ Type
+ ----------------------------
+ bool bool
+ char char
+ int8 Poco::Int8
+ uint8 Poco::UInt8
+ int16 Poco::Int16
+ uint16 Poco::UInt16
+ int32 Poco::Int32
+ uint32 Poco::UInt32
+ int64 Poco::Int64
+ uint64 Poco::UInt64
+ float float
+ double double
+ dateTime Poco::DateTime
+ timestamp Poco::Timestamp
+ time Poco::Data::Time
+ date Poco::Data::Date
+ uuid Poco::UUID
+ string std::string
+----
+
+Note: When creating the underlying database schema, it's the developer's responsibility
+to use a database-specific column type compatible with the data type specified in the XML.
+
+!!Elements and Attributes
+
+!The project Element
+
+The `project` element must be the root element in the XML file.
+The `project` element accepts the following attributes:
+
+ - `namespace`: Specifies the C++ namespace for the generated classes. A multi-level
+ namespace can be specified, e.g. "MyProject::Data".
+ - `convertCamelCase`: If set to `true`, property and class names specified in
+ camel case (e.g., `firstName`) will be converted to snake case (`first_name`) to
+ identify the respective column or table. Defaults to `false`.
+
+!The class Element
+
+The `class` element must be inside of a `project` element and accepts the following attributes:
+
+ - `name`: Specifies the name of the class. Must be a valid C++ class name. Required.
+ - `table`: Specifies the name of the related database table. If not specified, the
+ table name will be derived from the class name (see the `convertCamelCase` attribute
+ in the `project` element).
+ - `key`: Specifies the name of the primary key column. If not specified, defaults
+ to `id`.
+ - `autoIncrementID`: If set to `true`, the primary key is considered to be
+ auto-incremented. A new ActiveObject is inserted with a NULL primary key, which
+ causes the database to assign a new key value. The actual key value is then
+ obtained from the database after executing the `INSERT` statement.
+
+!The property Element
+
+The `property` element must be inside of a `class` element and accepts the following attributes:
+
+ - `name`: Specifies the name of the variable, which is also used for the getter and setter
+ methods. Must be a valid C++ variable or method name. Required.
+ - `column`: Specifies the name of the related database column. If not specified, the
+ column name will be derived from the property name (see the `convertCamelCase` attribute
+ in the `project` element).
+ - `type`: Specifies the data type of the property. See <*Supported Data Types*> for
+ a list of supported values. Required.
+ - `references`: Specifies the name of the target class for a relation. Must be the name
+ of another class defined in the same XML document.
+ - `cardinality`: Specifies the cardinality of the relation. The following values can be
+ specified: `?` means zero or one, `1` means exactly one (default). Additionally, `*` means zero
+ or more and `+` means one or more, but no accessor is currently generated for the latter
+ two cardinalities.
+ - `nullable`: If set to `true`, marks the property or column as nullable. In this case,
+ the accessor methods will accept or return a Poco::Nullable<> value.