ActiveMDX

With ActiveMDX, you can extract meaningful information from the content of your writing. Structured writing can become structured data. Combine this with the power of React and MDX, and ActiveMDX can be used to build applications that are powered by your writing.

MDX gives us the ability to display markdown writing with React components.

Traditional markdown renders static HTML. MDX renders as React components and gives you the ability to control how each standard markdown html element gets rendered. By itself, this is a very powerful way to display your writing and gives you a lot of creative power. People have used it to build interactive code demos which you can live edit and see the results rendered in real time, and much more.

MDX for displaying your writing

Below, you can see the markdown code on the left, and the rendered React component after that.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 --- priority: high status: gathering-requirements --- # Authentication The Authentication stories cover users logging in and out of the application. It also covers the roles and permissions granted to these users and how they are enforced in the application. ## Stories ### A User should be able to register. As a User I would like to register so that I can use the application. #### Acceptance Criteria - A user can visit the signup form, supply their name, email, and password - The signup form should validate the user's information and supply errors - The user should receive a confirmation email - The user should show up in our database as confirmed after clicking the confirmation link #### Mockups - [Invision: Registration Form](https://invisionapp.com) - [Invision: Registration Form Error State](https://invisionapp.com) ### A User should be able to login. As a User I would like to login so that I can use the application. #### Acceptance Criteria - A user can visit the signup form, supply their name, email, and password - The signup form should validate the user's information and supply errors - The user should receive a confirmation email - The user should show up in our database as confirmed after clicking the confirmation link #### Mockups - [Invision: Login Form](https://invisionapp.com) - [Invision: Login Form Error State ](https://invisionapp.com)

Authentication

The Authentication stories cover users logging in and out of the application, as well as the roles and permissions granted to these users and how they are enforced in the application.

Stories

A User should be able to register.

As a User I would like to register so that I can use the application.

Acceptance Criteria

  • A user can visit the signup form, supply their name, email, and password
  • The signup form should validate the user's information and supply errors
  • The user should receive a confirmation email
  • The user should show up in our database as confirmed after clicking the confirmation link

Mockups

A User should be able to login.

As a User I would like to login so that I can use the application.

Acceptance Criteria

  • A user can visit the signup form, supply their name, email, and password
  • The signup form should validate the user's information and supply errors
  • The user should receive a confirmation email
  • The user should show up in our database as confirmed after clicking the confirmation link

Mockups

With ActiveMDX, we can use the same markdown code which displays on the web, and turn it into structured data which can power other applications, or be used to build a rich presentation about the things and concepts you are writing about.

The above example is a real world example of software requirements documentation. A single Epic with two Stories defined. In the real world, we'd write dozens of epics and each epic would have at least a dozen stories. Those stories would get put into software like Jira or Github issues, and get worked on by developers.

ActiveMDX provides you with a Model system that lets you define the structure of your Document, and tools for turning the different sections of your document into objects.

ActiveMDX for using your writing

On the left, we have ActiveMDX Model code which lets us define the structure of our document types and how they relate to other documents.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import { Model } from 'active-mdx' class Epic extends Model { stories() { return this.hasMany(Story, { heading: "stories" }) } } export default class Story extends Model { get defaults() { return { meta: { status: "created" } } } get isComplete() { return this.meta.status === "complete" } epic() { return this.belongsTo(Epic, { id: (document) => document.meta.epic }) } get mockupLinks() { const { toString } = this.document.utils return Object.fromEntries( this.document .querySection("Mockups") .selectAll("link") .map((link) => [toString(link), link.url]) ) } get acceptanceCriteria() { const { toString } = this.document.utils return this.document .querySection("Acceptance Criteria") .selectAll("listItem") .map(toString) } }

ActiveMDX Code

collection.getModel('epics/authentication').toJSON({ related: ['stories'] })

Result

{ "id": "epics/authentication", "meta": { "priority": "high", "status": "gathering-requirements" }, "title": "Authentication", "stories": [ { "id": "stories/authentication/a-user-should-be-able-to-register.", "meta": { "epic": "authentication", "status": "created" }, "title": "A User should be able to register." }, { "id": "stories/authentication/a-user-should-be-able-to-login.", "meta": { "epic": "authentication", "status": "created" }, "title": "A User should be able to login." } ] }

ActiveMDX Code

collection .getModel('stories/authentication/a-user-should-be-able-to-register') .toJSON({ attributes: ['mockupLinks','acceptanceCriteria'] })

Result

{ "id": "stories/authentication/a-user-should-be-able-to-login.", "meta": { "epic": "authentication", "status": "created" }, "title": "A User should be able to login.", "mockupLinks": { "Invision: Login Form": "https://invisionapp.com", "Invision: Login Form Error State ": "https://invisionapp.com" }, "acceptanceCriteria": [ "A user can visit the signup form, supply their name, email, and password", "The signup form should validate the user's information and supply errors", "The user should receive a confirmation email", "The user should show up in our database as confirmed after clicking the confirmation link" ] }

Collections of structured documents

ActiveMDX provides a Collection class that turns a folder of MDX documents into a queryable database. Each different type of document is a Model, or a table in a database. Each document of those types are the rows in that database.

import { Collection } from "active-mdx"

import Epic from "./models/Epic"
import Story from "./models/Story"

const collection = new Collection({
  rootPath: "./docs"
})

await collection.load()

const completedStories = await Story.query((qb) =>
  qb.where("status", "completed")
).fetchAll()

// register a common query
Epic.query("completedStories", (qb) => qb.where("status", "completed"))

// run the common query
Epic.query("completedStories")

ActiveMDX provides an action system

With the action system, you can run functions using your collection and different models. In the example I've written about here, you could do things like publish all the stories to Github or Jira using their API. To do that we just define the action publish-to-github

Story.action("publish-to-github", async function (story) {
  await githubAPI.issues.create({
    title,
    body: story.document.content,
    labels: story.meta.labels
  })
})

We can then use the AMDX CLI to run that action

$ amdx action publish-to-github stories/authentication/a-user-should-be-able-to-register

The Rest is up to you

ActiveMDX

With ActiveMDX, you can extract meaningful information from the content of your writing. Structured writing can become structured data. Combine this with the power of React and MDX, and ActiveMDX can be used to build applications that are powered by your writing.

MDX gives us the ability to display markdown writing with React components.

Traditional markdown renders static HTML. MDX renders as React components and gives you the ability to control how each standard markdown html element gets rendered. By itself, this is a very powerful way to display your writing and gives you a lot of creative power. People have used it to build interactive code demos which you can live edit and see the results rendered in real time, and much more.

MDX for displaying your writing

Below, you can see the markdown code on the left, and the rendered React component after that.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 --- priority: high status: gathering-requirements --- # Authentication The Authentication stories cover users logging in and out of the application. It also covers the roles and permissions granted to these users and how they are enforced in the application. ## Stories ### A User should be able to register. As a User I would like to register so that I can use the application. #### Acceptance Criteria - A user can visit the signup form, supply their name, email, and password - The signup form should validate the user's information and supply errors - The user should receive a confirmation email - The user should show up in our database as confirmed after clicking the confirmation link #### Mockups - [Invision: Registration Form](https://invisionapp.com) - [Invision: Registration Form Error State](https://invisionapp.com) ### A User should be able to login. As a User I would like to login so that I can use the application. #### Acceptance Criteria - A user can visit the signup form, supply their name, email, and password - The signup form should validate the user's information and supply errors - The user should receive a confirmation email - The user should show up in our database as confirmed after clicking the confirmation link #### Mockups - [Invision: Login Form](https://invisionapp.com) - [Invision: Login Form Error State ](https://invisionapp.com)

Authentication

The Authentication stories cover users logging in and out of the application, as well as the roles and permissions granted to these users and how they are enforced in the application.

Stories

A User should be able to register.

As a User I would like to register so that I can use the application.

Acceptance Criteria

  • A user can visit the signup form, supply their name, email, and password
  • The signup form should validate the user's information and supply errors
  • The user should receive a confirmation email
  • The user should show up in our database as confirmed after clicking the confirmation link

Mockups

A User should be able to login.

As a User I would like to login so that I can use the application.

Acceptance Criteria

  • A user can visit the signup form, supply their name, email, and password
  • The signup form should validate the user's information and supply errors
  • The user should receive a confirmation email
  • The user should show up in our database as confirmed after clicking the confirmation link

Mockups

With ActiveMDX, we can use the same markdown code which displays on the web, and turn it into structured data which can power other applications, or be used to build a rich presentation about the things and concepts you are writing about.

The above example is a real world example of software requirements documentation. A single Epic with two Stories defined. In the real world, we'd write dozens of epics and each epic would have at least a dozen stories. Those stories would get put into software like Jira or Github issues, and get worked on by developers.

ActiveMDX provides you with a Model system that lets you define the structure of your Document, and tools for turning the different sections of your document into objects.

ActiveMDX for using your writing

On the left, we have ActiveMDX Model code which lets us define the structure of our document types and how they relate to other documents.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import { Model } from 'active-mdx' class Epic extends Model { stories() { return this.hasMany(Story, { heading: "stories" }) } } export default class Story extends Model { get defaults() { return { meta: { status: "created" } } } get isComplete() { return this.meta.status === "complete" } epic() { return this.belongsTo(Epic, { id: (document) => document.meta.epic }) } get mockupLinks() { const { toString } = this.document.utils return Object.fromEntries( this.document .querySection("Mockups") .selectAll("link") .map((link) => [toString(link), link.url]) ) } get acceptanceCriteria() { const { toString } = this.document.utils return this.document .querySection("Acceptance Criteria") .selectAll("listItem") .map(toString) } }

ActiveMDX Code

collection.getModel('epics/authentication').toJSON({ related: ['stories'] })

Result

{ "id": "epics/authentication", "meta": { "priority": "high", "status": "gathering-requirements" }, "title": "Authentication", "stories": [ { "id": "stories/authentication/a-user-should-be-able-to-register.", "meta": { "epic": "authentication", "status": "created" }, "title": "A User should be able to register." }, { "id": "stories/authentication/a-user-should-be-able-to-login.", "meta": { "epic": "authentication", "status": "created" }, "title": "A User should be able to login." } ] }

ActiveMDX Code

collection .getModel('stories/authentication/a-user-should-be-able-to-register') .toJSON({ attributes: ['mockupLinks','acceptanceCriteria'] })

Result

{ "id": "stories/authentication/a-user-should-be-able-to-login.", "meta": { "epic": "authentication", "status": "created" }, "title": "A User should be able to login.", "mockupLinks": { "Invision: Login Form": "https://invisionapp.com", "Invision: Login Form Error State ": "https://invisionapp.com" }, "acceptanceCriteria": [ "A user can visit the signup form, supply their name, email, and password", "The signup form should validate the user's information and supply errors", "The user should receive a confirmation email", "The user should show up in our database as confirmed after clicking the confirmation link" ] }

Collections of structured documents

ActiveMDX provides a Collection class that turns a folder of MDX documents into a queryable database. Each different type of document is a Model, or a table in a database. Each document of those types are the rows in that database.

import { Collection } from "active-mdx"

import Epic from "./models/Epic"
import Story from "./models/Story"

const collection = new Collection({
  rootPath: "./docs"
})

await collection.load()

const completedStories = await Story.query((qb) =>
  qb.where("status", "completed")
).fetchAll()

// register a common query
Epic.query("completedStories", (qb) => qb.where("status", "completed"))

// run the common query
Epic.query("completedStories")

ActiveMDX provides an action system

With the action system, you can run functions using your collection and different models. In the example I've written about here, you could do things like publish all the stories to Github or Jira using their API. To do that we just define the action publish-to-github

Story.action("publish-to-github", async function (story) {
  await githubAPI.issues.create({
    title,
    body: story.document.content,
    labels: story.meta.labels
  })
})

We can then use the AMDX CLI to run that action

$ amdx action publish-to-github stories/authentication/a-user-should-be-able-to-register

The Rest is up to you