Abitti 2 Application Specification

The Abitti 2 application is designed to operate on the client-side and should be deployed from a Docker container. At the moment this documentation may change since we're taking the baby steps with the architecture. Contact us before you start working on your Abitti HTML5 application!

Want to read the code instead of spec? Take a look at the example implementation with Draw.io.

Application Entry Point

GET /apps/{appId}/

This is the main entry point to the app. The app server MAY serve additional assets only under this path.

If the app supports files, it will be launched with the filename query parameter. A client-side script MUST first check the file's existence with a WebDAV PROPFIND request, and load the app with its contents if it exists. Otherwise the app SHOULD present a new, blank file to the user.

The app MUST use the path /wd/{filename} to access the file.

const url = `/wd/${encodeURIComponent(filename)}`
const result = await fetch(url, { method: "PROPFIND" })
switch (result.status) {
    case 207: {
        // The file exists; open the app with its contents.
        return startApp(await fetch(url).then(response => response.blob()))
    }
    case 404: {
        // No such file; it will be created when first saved.
        return startApp(new File())
    }
    default: {
        // An error happened; do not start the app.
        return
    }
}

The app MAY automatically save the file, or when prompted by the user, via a PUT request with the new contents to the same URL.

const url = `/wd/${encodeURIComponent(filename)}`
await fetch(url, { method: "PUT", body: file })

Session cookies determine the exam and student whose files are being used, but the app MUST NOT make any use or assumptions of such cookies.

App discovery

The Abitti 2 exam server discovers available apps using DNS-SD. Each app server runs in a container in the same Docker network as the Abitti 2 exam server, and MUST advertise an HTTP service (type _http._tcp) with the following:

Record type Record value
TXT path=/.well-known/appspecific/dev.abitti.json

Abitti 2 exam server will then start proxying requests to /apps/{appId}/* to each discovered app.

GET /.well-known/appspecific/dev.abitti.json

The JSON object defines apps available from this container. This endpoint is not exposed to the outside world directly, instead the Abitti 2 exam server combines all discovered apps into one JSON document of similar structure and serves it to the users.

The keys MUST match the {appId} parameter in the corresponding object's path property, and they MUST only contain the characters in the range of [a–z], [0-9], and -.

Example response:

{
    "example-app": {
        "name": "Example App",
        "path": "/apps/example-app/",
        "filetypes": [
            {
            "mime": "text/plain",
            "glob": "*.txt"
            }
        ]
    },
    "no-file-app": {
        "name": "No-file App",
        "path": "/apps/no-file-app/"
    },
    "cas-app": {
        "name": "CAS App",
        "path": "/apps/cas-app/",
        "categories": [
        "cas"
        ]
    }
}