diff --git a/.github/workflows/build-and-deploy-docs.yml b/.github/workflows/build-and-deploy-docs.yml
new file mode 100644
index 00000000..172fbd66
--- /dev/null
+++ b/.github/workflows/build-and-deploy-docs.yml
@@ -0,0 +1,31 @@
+name: "Build docs with Sphinx and deploy to Github Pages"
+
+on:
+ push:
+ branches: docs/gh-pages
+
+jobs:
+ build_and_deploy:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ id-token: write
+ pages: write
+ env:
+ INPUT_DOCS-FOLDER: docs
+ steps:
+ - uses: actions/checkout@v4
+ - name: Build HTML
+ uses: civilx64/sphinx-action@master
+ with:
+ docs-folder: docs/
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ # Upload html docs
+ path: './docs/_build/html'
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
new file mode 100644
index 00000000..f1f25772
--- /dev/null
+++ b/.github/workflows/build-docs.yml
@@ -0,0 +1,28 @@
+name: "Build docs with Sphinx"
+
+on:
+ pull_request:
+ branches: docs/gh-pages
+
+jobs:
+ build_and_deploy:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ id-token: write
+ pages: write
+ env:
+ INPUT_DOCS-FOLDER: docs
+ steps:
+ - uses: actions/checkout@v4
+ - name: Build HTML
+ uses: civilx64/sphinx-action@master
+ with:
+ docs-folder: docs/
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ # Upload html docs
+ path: './docs/_build/html'
diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml
index 7a3fad07..a8ba9a79 100644
--- a/.github/workflows/ci_cd.yml
+++ b/.github/workflows/ci_cd.yml
@@ -79,7 +79,16 @@ jobs:
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
- pip install ifcopenshell # TEMP workaround
+
+ - name: Install ifcopenshell package (temp)
+ run: |
+ cd backend
+ source venv/bin/activate
+ # use version of ifcopenshell with desired schema parsing
+ # TODO: revert to pyPI when schema parsing is published in the future
+ wget -O /tmp/ifcopenshell_python.zip "https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.8.1-92b63a0-linux64.zip"
+ mkdir -p venv/lib/python3.11/site-packages
+ unzip -d venv/lib/python3.11/site-packages /tmp/ifcopenshell_python.zip
- name: Check Django config
run: |
diff --git a/Makefile b/Makefile
index dc65941d..96403781 100644
--- a/Makefile
+++ b/Makefile
@@ -71,4 +71,6 @@ clean-all:
fetch-modules:
git submodule update --init --recursive
- git submodule update --remote
\ No newline at end of file
+ git submodule foreach git clean -f .
+ git submodule foreach git reset --hard
+ git submodule update --remote --recursive
diff --git a/backend/Makefile b/backend/Makefile
index 9d7202a1..baf435af 100644
--- a/backend/Makefile
+++ b/backend/Makefile
@@ -13,7 +13,7 @@ install: venv
. $(VIRTUAL_ENV)/bin/activate && \
pip install --upgrade pip && \
pip install -r requirements.txt && \
- wget -O /tmp/ifcopenshell_python.zip "https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.9-c18e4ea-linux64.zip" && \
+ wget -O /tmp/ifcopenshell_python.zip "https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.8.1-92b63a0-linux64.zip" && \
mkdir -p $(VIRTUAL_ENV)/lib/python3.11/site-packages && \
unzip -f -d $(VIRTUAL_ENV)/lib/python3.11/site-packages /tmp/ifcopenshell_python.zip && \
rm /tmp/ifcopenshell_python.zip
@@ -22,7 +22,7 @@ install-macos: venv
. $(VIRTUAL_ENV)/bin/activate && \
pip install --upgrade pip && \
pip install -r requirements.txt && \
- wget -O /tmp/ifcopenshell_python.zip "https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.9-c18e4ea-macos64.zip" && \
+ wget -O /tmp/ifcopenshell_python.zip "https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.8.1-92b63a0-macos64.zip" && \
mkdir -p $(VIRTUAL_ENV)/lib/python3.11/site-packages && \
unzip /tmp/ifcopenshell_python.zip -d .dev/venv/lib/python3.11/site-packages && \
rm /tmp/ifcopenshell_python.zip
diff --git a/backend/apps/ifc_validation/checks/ifc_gherkin_rules b/backend/apps/ifc_validation/checks/ifc_gherkin_rules
index e9f4441c..24294494 160000
--- a/backend/apps/ifc_validation/checks/ifc_gherkin_rules
+++ b/backend/apps/ifc_validation/checks/ifc_gherkin_rules
@@ -1 +1 @@
-Subproject commit e9f4441c9a20b8d446918cae711892905ccebabe
+Subproject commit 242944946b45e7aacd6a7ba0bb15c704d97caee0
diff --git a/backend/apps/ifc_validation/tasks.py b/backend/apps/ifc_validation/tasks.py
index 81f64e00..d5904ffd 100644
--- a/backend/apps/ifc_validation/tasks.py
+++ b/backend/apps/ifc_validation/tasks.py
@@ -330,6 +330,17 @@ def parse_info_subtask(self, prev_result, id, file_name, *args, **kwargs):
task.mark_as_initiated()
+ # try to open IFC file (catch segfaults)
+ try:
+ code = "import ifcopenshell; ifcopenshell.open('" + file_path + "')"
+ check_program = [sys.executable, '-c', code, file_path]
+ logger.debug(f'Command for {self.__qualname__}: {" ".join(check_program)}')
+ subprocess.run(check_program, check=True)
+
+ except subprocess.CalledProcessError as err:
+ task.mark_as_failed(err)
+ raise
+
# retrieve IFC info
try:
task.set_process_details(None, f"(module) ifcopenshell.open() for file '{file_path}')")
diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile
index f8433795..08dbbaf4 100644
--- a/docker/backend/Dockerfile
+++ b/docker/backend/Dockerfile
@@ -37,7 +37,7 @@ RUN --mount=type=cache,target=/root/.cache \
pip install --no-cache-dir -r /app/backend/requirements.txt && \
# use version of ifcopenshell with desired schema parsing
# TODO: revert to pyPI when schema parsing is published in the future
- wget -O /tmp/ifcopenshell_python.zip "https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.7.9-c18e4ea-linux64.zip" && \
+ wget -O /tmp/ifcopenshell_python.zip "https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-311-v0.8.1-92b63a0-linux64.zip" && \
mkdir -p /opt/venv/lib/python3.11/site-packages && \
unzip -d /opt/venv/lib/python3.11/site-packages /tmp/ifcopenshell_python.zip && \
# some cleanup
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..c6a151b3
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+_build/
\ No newline at end of file
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000..d4bb2cbb
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/_static/dev_system_architecture_sketch.png b/docs/_static/dev_system_architecture_sketch.png
new file mode 100644
index 00000000..2719d6f4
Binary files /dev/null and b/docs/_static/dev_system_architecture_sketch.png differ
diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico
new file mode 100644
index 00000000..635011ff
Binary files /dev/null and b/docs/_static/favicon.ico differ
diff --git a/docs/_static/user_auth.png b/docs/_static/user_auth.png
new file mode 100644
index 00000000..a07b5b81
Binary files /dev/null and b/docs/_static/user_auth.png differ
diff --git a/docs/_static/user_include_passed_na_etc.png b/docs/_static/user_include_passed_na_etc.png
new file mode 100644
index 00000000..e70418aa
Binary files /dev/null and b/docs/_static/user_include_passed_na_etc.png differ
diff --git a/docs/_static/user_results_icons.png b/docs/_static/user_results_icons.png
new file mode 100644
index 00000000..54f569ae
Binary files /dev/null and b/docs/_static/user_results_icons.png differ
diff --git a/docs/_static/user_results_icons_no_bSDD.png b/docs/_static/user_results_icons_no_bSDD.png
new file mode 100644
index 00000000..c77b413f
Binary files /dev/null and b/docs/_static/user_results_icons_no_bSDD.png differ
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 00000000..90cc0f7b
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,33 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = 'buildingSMART Validation Service'
+copyright = '2024, buildingSMART International'
+author = 'buildingSMART International'
+release = '0.6'
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = [
+ 'sphinx_rtd_theme',
+ 'myst_parser',
+]
+
+templates_path = ['_templates']
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+html_favicon = '_static/favicon.ico'
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = 'sphinx_rtd_theme'
+html_static_path = ['_static']
+
+myst_links_external_new_tab = True
diff --git a/docs/dev/functional_parts.md b/docs/dev/functional_parts.md
new file mode 100644
index 00000000..9ce3a134
--- /dev/null
+++ b/docs/dev/functional_parts.md
@@ -0,0 +1,76 @@
+# Functional parts
+
+Functional parts refer to logical grouping of rules that involve similar types of validation.
+
+These functional part prefixes are used in the naming of the normative rules
+and are reported in the results listed by the validation service.
+
+## Catalog
+
+Below is the list of the IFC functional parts.
+
+| TAG | FUNCTIONAL PART | DESCRIPTION |
+|-----|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| PJS | Project definition | The ability to define the overall context and directory of objects within the model. Among others, the context definition includes default units and geometric representation context for shape representations. |
+| GRF | Georeferencing | The ability to accurately define the geographic location and orientation of the model relative to a reference coordinate system, such as a national or global coordinate system. |
+| BLT | Built elements (kickable) | The ability to model various building and infrastructure elements, including walls, floors, roofs, stairs, doors, windows, columns, road pavements, bridge decks, railway track elements, etc. |
+| ASM | Assemblies (kickable) | The ability to model elements composed of / constructed by other elements. For example, a roof might be assembled from a series of prefabricated truss components. |
+| SPA | Spaces (non-kickable) | The ability to model spaces, such as rooms, hallways, clearance zones, and circulation areas. |
+| VRT | Virtual elements (non-kickable) | The ability to model spatial element used to provide imaginary, placeholder, or provisional areas (e.g. clearance), volumes, and boundaries. Virtual elements are not displayed, do not have quantities, materials, or other measures. |
+| GEM | *Geometry representation | The ability to represent built elements and spaces using various geometry types, including parametric, mesh, and voxel-based representations. |
+| OJP | *Object placement | The ability to define the location, orientation, and scale of built elements and systems within the building model. |
+| POS | *Positioning elements | The ability to define (virtual) objects that are used to position other elements relatively. Includes grids, alignments, and referents. |
+| OJT | Objects typing | The ability to define elements (and unfortunately not systems) based on their type or function within the model, allowing reusability of information by the occurrence of such types. |
+| GRP | Groups (non-kickable) | The ability to group objects related by functional or logical criteria. Used, for example to model building systems, such as HVAC (heating, ventilation, and air conditioning) systems; to group assets that have the same maintenance schedule; to group all terminals of a fire-protection system. |
+| SPS | Spatial breakdown | The ability to define spatial organisation within a building or infrastructure project. This includes the hierarchical relationships between spatial containers, such as buildings within a site, storeys within a building and rooms within a storey. |
+| MAT | Materials | The ability to define materials assigned to elements. |
+| PSE | Properties for object | The ability to define properties of elements and systems, such as their performance characteristics. |
+| QTY | Quantities for objects | The ability to define quantities of elements, such as their dimensions, volume, area, weight. |
+| CLS | Classification reference | The ability to classify elements, materials, and systems according to various classification systems, such as the UNIFORMAT or Omniclass classification systems. |
+| ANN | Annotations | The ability to add annotations to elements and spaces, such as labels, notes, and dimensions. |
+| LAY | Presentation layer | The ability to assign layers (also known as, CAD layer) to collection of elements. This is used mainly for grouping and visibility control, and in general to organise geometry into groups that may be shown or hidden. |
+| CTX | Presentation Colours and Textures | The ability to assign colour, texture and other presentation appearance information to objects. |
+| POR | Port connectivity & nesting | The ability to define ports (as means for an element to connect to other elements) and the relationship that is made between two ports. |
+| STR | Structural items and actions | The ability to define structural members and structural connections, as analysis idealizations of built elements. And the ability to define actions (such as forces, displacements, etc.) and reactions (support reactions, internal forces, deflections, etc.) associated to structural items and specified by using the basic load definitions. |
+| CST | Costing | The ability to assign costing information to objects. |
+| SDL | Scheduling of activities | The ability to assign scheduling information to objects. |
+| LIB | Library reference | The ability to associate library entities, such as from a product library or external database to objects and object types. |
+| DOC | Documentation reference | The ability to associate reference to documentation to objects. |
+| CTR | Constraints | The ability to model constraints on building elements, such as minimum and maximum dimensions or clearances, and to enforce these constraints during design and construction. |
+| VER | Versioning / revision control | The ability to track changes to building data over time and to maintain a history of changes. |
+
+*These 3 functional parts are further decomposed as indicated below.
+
+### Geometry representation sub-parts
+
+| TAG | FUNCTIONAL PART | DESCRIPTION |
+|-----|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| AXG | Axis geometry | This involves representing the geometry using a set of axes, where each axis consists of a position in 3D space and a direction vector. This can be useful for representing geometry that follows a certain pattern or direction, such as walls, beams, columns, or other elements. In IFC, axis geometry can be represented using the IfcCartesianPoint and IfcDirection classes, which define the position and direction of the axes, respectively. |
+| ALS | Alignment geometry | This involves representing the geometry using a collection of segments that define a linear path in 3D space. This can be useful for representing linear objects such as roads, railways, or pipelines. |
+| PBG | Point-based geometry | This involves representing geometry using a collection of individual points in 3D space. Point-based geometry can be useful for representing large-scale environments or for creating simplified representations of more complex geometry. Point-based geometry can be represented in IFC using a range of different point types, such as 3D point clouds or scattered point data. |
+| TAS | Tessellated (i.e. meshes) | This involves representing geometry using a collection of interconnected vertices, edges, and faces, which are used to approximate a smooth surface. Tessellated geometry can be useful for representing organic or irregular shapes, or for creating low-resolution representations of more complex geometry. In IFC, tessellated geometry can be represented using a range of different mesh types, such as triangular, quadrilateral, or polyhedral meshes. |
+| BRP | Boundary Representation (BREP) | This involves representing geometry using a collection of connected surfaces and edges. BREP geometry can be used to represent complex shapes with curved surfaces or unusual topology. BREP geometry can be represented in IFC using IfcFacetedBrep for polygonal meshes or IfcManifoldSolidBrep for more complex solid geometry. These entities can be further described using a collection of geometric representations such as IfcCartesianPoint, IfcPolyLoop, and IfcSurface. |
+| CSG | Constructive Solid Geometry (CSG) | This involves creating complex geometry by combining simpler shapes using Boolean operations such as union, intersection, and difference. CSG can be useful for creating complex shapes with predictable and repeatable geometry. CSG can be represented in IFC using the IfcBooleanResult entity, which defines the Boolean operation to be applied to a set of one or more shape representations. |
+| SWE | Sweeps (i.e., extrusions, lofts, blends) | This involves taking a 2D shape (often called the "profile") and moving it along a 3D path, generating a 3D shape. The resulting shape is typically smooth and continuous, with its cross-section changing gradually along the length of the path. Sweep geometry can be useful for representing a variety of objects, such as pipes, cables, and architectural details like moldings. In IFC, sweep geometry can be represented using the IfcExtrudedAreaSolid, IfcRevolvedAreaSolid, and IfcSweptAreaSolid entities. |
+| TFM | Transformations | Transformation geometry involves representing geometry using spatial transformations, such as rotations, translations, and scaling. It allows for the modification of existing geometry without the need to create new geometry from scratch. Transformation geometry can be used to represent various types of transformations, including cartesian transformations, placement transformations, and composite transformations, among others. These transformations can be applied to a range of geometric entities, including points, curves, surfaces, and solids, to create new or modified geometry. In IFC, transformation geometry is represented using the IfcCartesianTransformationOperator and IfcObjectPlacement entities. |
+| BBX | Bounding box | This involves defining an orthogonal box, oriented parallel to the axes of the object coordinate system in which it is defined and containing a geometry object, which defines the spatial extent of the latter. |
+| MPD | Mapped geometry | This involves identifying a representation and a representation item in that representation for the purpose of mapping. The representation item defines the origin of the mapping. The representation map is used as the source of a mapping by a mapped item. |
+| RCO | Relational constructs | Such as connection geometry, space boundaries, interference geometries. This is not a geometry category per se, but it's a specific way geometry is used in IFC |
+| CPD | Clipped representations | This involves visualizations of a 3D model where part of the model is "clipped" or cut away to allow for better examination of the internal structures or components. This is often done using clipping planes or sections. |
+
+### Object placement sub-parts
+
+| TAG | FUNCTIONAL PART | DESCRIPTION |
+|-----|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| LOP | Local placement | The ability to define the placement of a product in relation to the placement of another product; or its absolute placement within the geometric representation context of the project. |
+| LIP | Linear placement | The ability to define the placement of a product in relation to a curve. |
+| GDP | Grid placement | The ability to define the placement of a product in relation to a design grid. |
+
+### Positioning elements sub-parts
+
+| TAG | FUNCTIONAL PART | DESCRIPTION |
+|----------|-----------------|--------------------------------------------------------------------------------------------------------------------|
+| GRD | Grid | The ability to define a design grid to be used as reference for object placement. |
+| ALA, ALB | Alignment | The ability to define an alignment curve, and its components. These can be used as reference for object placement. |
+| RFT | Referent | The ability to define a referent to be used as reference for object placement. |
+
diff --git a/docs/dev/gherkin_deep_dive.md b/docs/dev/gherkin_deep_dive.md
new file mode 100644
index 00000000..67a40820
--- /dev/null
+++ b/docs/dev/gherkin_deep_dive.md
@@ -0,0 +1,36 @@
+# A deep dive into gherkin rule implementations
+
+## Decorators
+
+### `@gherkin_ifc`
+
+This is used in place of `behave`'s default `@step_implementation` decorator
+to provide additional capabilities related to context stacking and other concerns
+related to tracking and evaluating instances in the IFC model.
+
+### `@register_enum_type`
+
+This is a small new decorator for registering enumeration types in a simpler way.
+
+## Step handling
+
+### `execute_step()`
+
+Checks whether the current step being processed is a `Given` or `Then`.
+
+### `handle_given()`
+
+Handles a `Given` step.
+
+### `handle_then()`
+
+Handles a `Then` step.
+
+## Context stacking
+
+As steps are processed, they are captured in a persistent object of type `behave.runner.Context`.
+This context object includes a hidden attribute `_stack` that is used to 'stack' information
+and results for each step that is processed.
+
+It can be helpful to monitor the content of the `instances` attribute of each item in the
+`context._stack` list.
diff --git a/docs/dev/ifc_gherkin_rules_readme.md b/docs/dev/ifc_gherkin_rules_readme.md
new file mode 100644
index 00000000..88aa539f
--- /dev/null
+++ b/docs/dev/ifc_gherkin_rules_readme.md
@@ -0,0 +1,62 @@
+# IFC Gherkin rules
+
+## Usage as part of buildingSMART validation service
+
+This repository is one of three submodules in the overall validation service.
+See [application_structure](#application-structure) for more information.
+
+## Making changes
+
+The rules developed in this repository follow the general ideas of Gherkin and its python implementation behave.
+
+This means there are human-readable definitions of rules and Python implementations.
+
+A third component of this repository are minimal sample files with expected outcomes, which means that extensions and modifications can be suggested with confidence of not breaking existing functionality.
+
+## Command line usage
+
+Informal propositions and implementer agreements written in Gherkin for automatic validation of IFC building models using steps implemented in IfcOpenShell.
+
+```shell
+$ python -m ifc-gherkin-rules ifc-gherkin-rules\test\files\gem001\fail-gem001-cube-advanced-brep.ifc
+Feature: Shell geometry propositions/IfcClosedShell.v1
+ URL: /blob/8dbd61e/features/geometry.shells.feature
+
+ Step: Every oriented edge shall be referenced exactly 1 times by the loops of the face
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (-0.183012701892219,
+ 0.683012701892219, 1.0) -> (-0.683012701892219, -0.183012701892219, 1.0) was
+ referenced 2 times
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (-0.5, -0.5, 0.0) ->
+ (-0.5, 0.5, 0.0) was referenced 2 times
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (-0.5, 0.5, 0.0) ->
+ (0.5, 0.5, 0.0) was referenced 2 times
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (-0.683012701892219,
+ -0.183012701892219, 1.0) -> (0.183012701892219, -0.683012701892219, 1.0) was
+ referenced 2 times
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (0.183012701892219,
+ -0.683012701892219, 1.0) -> (0.683012701892219, 0.183012701892219, 1.0) was
+ referenced 2 times
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (0.5, -0.5, 0.0) ->
+ (-0.5, -0.5, 0.0) was referenced 2 times
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (0.5, 0.5, 0.0) ->
+ (0.5, -0.5, 0.0) was referenced 2 times
+
+ * #29=IfcClosedShell((#104,#115,#131,#147,#163,#179))
+ On instance #29=IfcClosedShell((#104,...,#179)) the edge (0.683012701892219,
+ 0.183012701892219, 1.0) -> (-0.183012701892219, 0.683012701892219, 1.0) was
+ referenced 2 times
+```
diff --git a/docs/dev/index.md b/docs/dev/index.md
new file mode 100644
index 00000000..3e3e42b5
--- /dev/null
+++ b/docs/dev/index.md
@@ -0,0 +1,21 @@
+# Developer Guide
+
+```{include} validate_readme.md
+:heading-offset: 1
+```
+
+```{include} ifc_gherkin_rules_readme.md
+:heading-offset: 1
+```
+
+```{include} rule_details.md
+:heading-offset: 1
+```
+
+```{include} functional_parts.md
+:heading-offset: 1
+```
+
+```{include} gherkin_deep_dive.md
+:heading-offset: 1
+```
diff --git a/docs/dev/outcome_severities.md b/docs/dev/outcome_severities.md
new file mode 100644
index 00000000..cf6ccc28
--- /dev/null
+++ b/docs/dev/outcome_severities.md
@@ -0,0 +1,151 @@
+# Outcome Severities
+
+Note: This documentation was developed in Nov 2024 based on the codebase at version 0.6.8.
+
+## Overview - Database model enumerations
+
+Severities are an enumeration of possible values for the severity of a
+[Validation Outcome](https://github.com/buildingSMART/ifc-validation-data-model/blob/main/models.py#L978).
+
+| String Value | Integer Enumeration Value |
+|----------------|---------------------------|
+| EXECUTED | 1 |
+| PASSED | 2 |
+| WARNING | 3 |
+| ERROR | 4 |
+| NOT_APPLICABLE | 0 |
+
+## Severity Usage
+
+### Schema Check
+
+Schema checks are always applicable and therefore the only possible enumeration values are `PASSED` and `ERROR`.
+[Passing outcomes for schema checks are stored to the database](https://github.com/buildingSMART/validate/blob/8f04bcc6d1f400240485a33b2c81e2f7d0edbeab/backend/apps/ifc_validation/tasks.py#L607).
+
+### Syntax Check
+
+Syntax checks are also always applicable and therefore the only possible enumeration values are `PASSED` and `ERROR`.
+[Passing outcomes for syntax checks are stored to the database](https://github.com/buildingSMART/validate/blob/8f04bcc6d1f400240485a33b2c81e2f7d0edbeab/backend/apps/ifc_validation/tasks.py#L607).
+
+### Gherkin Rules (Normative Rules and Industry Best Practices)
+
+These rules are generally processed in similar fashion.
+Unlike syntax and schema checks, a gherkin rule may or may not be applicable to a given model depending on the schema
+and content of the model.
+For example, alignment rules are only applicable to models with schema `IFC4X3_ADD2` as those entities were not part of
+the
+`IFC2X3` or `IFC4` schema versions.
+
+Therefore, both sets of validation checks can potentially also return outcomes with severity of `NOT_APPLICABLE`.
+
+#### Normative Rules
+
+Normative rules enforce requirements from implementer agreements and informal propositions.
+Therefore, the potential outcomes are:
+
+- `NOT_APPLICABLE`
+- `ERROR`
+- `PASSED`
+
+#### Industry Best Practices
+
+Industry Best Practice checks enforce items that are not required,
+but rather represent the preferred or most idiomatic way of implementing the IFC standard.
+
+Therefore, the potential outcomes are:
+
+- `NOT_APPLICABLE`
+- `WARNING`
+- `PASSED`
+
+#### Gherkin Rule processing
+
+Currently there are no individual instance outcomes from gherkin rules stored with severity=`PASSED`.
+The initial idea was to pass them to the DB but it was quickly flooded with outcomes of this severity
+and is currently [commented out](https://github.com/buildingSMART/ifc-gherkin-rules/blob/b363041433f252fc1b9e043ee3aac0bd6fcfad3d/features/steps/validation_handling.py#L254-L268).
+
+_(potentially remove the following paragraph to avoid confusion...)_
+
+When processing gherkin rules (*.feature files) with `behave`, Severity=`PASSED` is used only for `Given` statements.
+A `PASSED` outcome is added to the temporary outcomes when the conditions of a `Given` statement are met.
+
+The entire processing loop is as follows:
+
+1. Severity=`NOT_APPLICABLE` is applied to all entity instances
+2. The `Given` statements are executed
+3. If there is *at least one* entity instance that meets the requirement of *ALL* `Given` statements,
+ the rule is considered to be "activated" and severity=`EXECUTED` is applied to these instance(s).
+ This is an 'all or nothing' situation where all `Given` statements must be "activated" in order for the rule
+ to be considered "activated".
+4. Those instance(s) are then tested against the `Then` statements.
+5. Severity=`ERROR` is applied to each instance that fails a requirement of a `Then` statement.
+
+If there is at least one instance with an `ERROR` outcome then an aggregated status for the rule is returned as follows:
+
+- Severity=`ERROR` for normative rules (implementer agreements and informal propositions)
+- Severity=`WARNING` for industry best practices.
+
+This status is used to colour the "block" for each rule in the validation report.
+
+## Outcome display and reporting
+
+### Individual rules (Normative and Industry Best Practices)
+
+Outcomes are always reported in the web UI based on aggregated status of all instances
+activated by a given rule.
+
+| Aggregated Value of `Severity` for a rule | Display colour | Label reported in `Severity` column |
+|-------------------------------------------|----------------|-------------------------------------|
+| `NOT_APPLICABLE` | grey | 'N/A' |
+| `EXECUTED` | green | 'Applicable' |
+| `PASSED` | (not used) | |
+| `WARNING` | yellow | 'Warning' |
+| `ERROR` | red | 'Error' |
+
+Display colour is determined by the
+[statusToColor](https://github.com/buildingSMART/validate/blob/development/frontend/src/mappings.js#L1)
+mapping function.
+
+Display label is determined by the
+[statusToLabel](https://github.com/buildingSMART/validate/blob/development/frontend/src/mappings.js#L10)
+mapping function.
+
+### Overall status
+
+A single overall status for each type of check (syntax, schema, normative rules, best practices)
+is displayed on the Validation Service dashboard for each model.
+
+The overall status of each
+[ValidationTask](https://github.com/buildingSMART/ifc-validation-data-model/blob/main/models.py#L778)
+is captured in a different data structure of
+[Model.Status](https://github.com/buildingSMART/ifc-validation-data-model/blob/main/models.py#L324)
+with the following possible enumeration values:
+
+| Value of `Model.Status` | Display colour | Symbol |
+|-------------------------|----------------|------------------------------------------------------------------------------|
+| `VALID` | green | CheckCircleIcon |
+| `INVALID` | red | WarningIcon |
+| `NOT_VALIDATED` | grey | HourglassBottomIcon |
+| `WARNING` | yellow | ErrorIcon |
+| `NOT_APPLICABLE` | grey | BrowserNotSupportedIcon (technically possible but doesn't occur in practice) |
+
+The options for overall status of each category of ValidationTask are as follows:
+
+- Syntax and Schema
+ - `VALID`
+ - `INVALID`
+
+- Normative Rules
+ - `VALID`
+ - `INVALID`
+ - `NOT_APPLICABLE`
+
+- Best Practices
+ - `VALID`
+ - `WARNING`
+ - `NOT_APPLICABLE`
+
+The overall status of a normative rule ValidationTask is determined by
+[taking the highest severity](https://github.com/buildingSMART/ifc-validation-data-model/blob/f32164ab762fc695690d380e12e87c815b641912/models.py#L948)
+of outcomes for all the rules contained in that task.
+
diff --git a/docs/dev/rule_details.md b/docs/dev/rule_details.md
new file mode 100644
index 00000000..6dde7a1b
--- /dev/null
+++ b/docs/dev/rule_details.md
@@ -0,0 +1,492 @@
+# Detailed Information for Normative Rules
+
+Follow these steps to add a new rule to the Validation Service
+
+| n. | Step | Responsible |
+|----|------------------------------------------------------------------------------------------|-----------------------------|
+| 1 | Create a new branch in the bSI ifc-gherkin-rules repository | bSI Validation Service team |
+| 2 | In this branch, start developing the rule needed **following instructions below** | rule developer |
+| 3 | Create a pull request to further test the rule(s) behavior using the sandbox environment | rule developer |
+| 4 | Assign a reviewer to the pull request when you think the rule is ready to be merged | rule developer |
+| 5 | Review the pull request | bSI Validation Service team |
+| 6 | (optional) Fix the rule according to feedback from reviewer | rule developer |
+| 7 | Approve and merge the pull request | bSI Validation Service team |
+
+## 1. Branch creation
+
+In the buildingSMART [GitHub repository containing all rules](https://github.com/buildingSMART/ifc-gherkin-rules), create the branch that will be used to develop the new rule.
+
+- Name the branch with the name of the new rule. Example: `GEM900` for a new rule in the geometry functional part
+- Add 1 rule per branch, to facilitate review (1 rule = 1 `.feature` file)
+
+## 2. Rule development
+
+A rule is considered complete when it has:
+
+- a Gherkin [**feature file**](21-write-feature-files-gherkin-rules-for-ifc)
+- corresponding python implementation (aka, [**python steps**](22-write-python-steps))
+- a set of [**unit test files**](23-write-unit-test-files)
+
+Below are instructions for all these 3 components.
+
+(21-write-feature-files-gherkin-rules-for-ifc)=
+### 2.1) Write feature files (gherkin rules) for IFC
+
+A feature file is a file, written using Gherkin syntax, describing the rule behavior.
+In the branch just created, add a Gherkin feature file following these instructions.
+
+**File format**: `.feature`
+
+**Location**: https://github.com/buildingSMART/ifc-gherkin-rules/tree/main/features
+
+#### Naming convention for feature files
+
+- The file name is rule code_rule title
+- The rule code is made of 3 digits capital letters (taken from the list of [Functional parts](./functional_parts.md)) + 3 digits number
+- The rule code, and rule title, must be unique
+- The rule title shall have no space and shall use `-` as separator
+
+wrong
+
+```
+SPS001 - Basic-spatial-structure-for-buildings.feature
+SPS001_Basic spatial structure for buildings.feature
+SPS001 - Basic spatial structure for buildings.feature
+```
+right
+
+```
+SPS001_Basic-spatial-structure-for-buildings.feature
+```
+example
+
+ ```
+ @implementer-agreement
+ @GRF
+ @version1
+ @E00050
+ Feature: GRF001 - Identical....
+ ```
+
+ example
+
+ ```
+ @implementer-agreement
+ @ALS
+ @version1
+ Feature: ALS005 - Alignment shape representation
+
+ Background: ...
+
+ @E00020
+ Scenario: Agreement on ... representation - Value
+
+ @E00010
+ Scenario: Agreement on ... representation - Type
+ ```
+
+ wrong
+
+```
+Feature: ALB001_Alignment Layout
+
+Given ...
+Then ...
+```
+```
+@ALB
+Feature: ALB001_Alignment-Layout
+
+Given ...
+Then ...
+```
+```
+@ALB
+Feature: ALB001 - Alignment-Layout
+
+Given ...
+Then ...
+```
+
+right
+
+```
+@ALB
+Feature: ALB001 - Alignment Layout
+
+Given ...
+Then ...
+```
+example
+
+```
+@implementer-agreement
+@ALB
+Feature: ALB003 - Allowed entities nested in Alignment
+The rule verifies that an Alignment has a nesting relationship with its components (i.e., Horizontal, Vertical, Cant layouts) or with Referents (e.g., mileage markers). And not with any other entity.
+
+ Scenario: Agreement on nested elements of IfcAlignment
+ Given ...
+ Then ...
+```
+examples
+
+```
+Given A model with Schema "IFC2X3"
+Given A file with Model View Definition "CoordinationView"
+```
+```
+Given A model with Schema "IFC2X3" or "IFC4"
+Given A file with Model View Definition "CoordinationView" or "ReferenceView"
+```
+wrong
+
+```
+Given A model with Schema "IFC4.3"
+
+Then Each IfcAlignmentHorizontal must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentVertical must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentCant must be nested only by 1 IfcAlignment
+```
+right
+
+```
+Given A model with Schema "IFC4.3"
+Then Each IfcAlignmentHorizontal must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentVertical must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentCant must be nested only by 1 IfcAlignment
+```
+wrong
+
+```
+Given A model with Schema "IFC4.3"
+Then Each IfcAlignmentHorizontal must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentVertical must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentCant must be nested only by 1 IfcAlignment
+```
+right
+
+```
+Given A model with Schema "IFC4.3"
+Then Each IfcAlignmentHorizontal must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentVertical must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentCant must be nested only by 1 IfcAlignment
+```
+wrong
+
+```
+Given A model with Schema "IFC4.3",
+Then Each IfcAlignmentHorizontal must be nested only by 1 IfcAlignment;
+Then Each IfcAlignmentVertical must be nested only by 1 IfcAlignment;
+Then Each IfcAlignmentCant must be nested only by 1 IfcAlignment.
+```
+right
+
+```
+Given A model with Schema "IFC4.3"
+Then Each IfcAlignmentHorizontal must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentVertical must be nested only by 1 IfcAlignment
+Then Each IfcAlignmentCant must be nested only by 1 IfcAlignment
+```
+wrong
+
+```
+Given A model with schema "IFC4.3",
+```
+right
+
+```
+Given A model with Schema "IFC4.3"
+```
+wrong
+
+```
+Given A model with Schema "IFC2X3"
+Given A file with Model View Definition "CoordinationView"
+Then There shall be exactly 1 IfcSite element(s)
+```
+right
+
+```
+Given A model with Schema "IFC2X3"
+Given A file with Model View Definition "CoordinationView"
+Then There must be exactly 1 IfcSite element(s)
+```
+Examples
+
+```shell
+pass-alb001-short_informative_description.ifc
+fail-alb001-scenario01-short_informative_description.ifc
+fail-alb001-short_informative_description.ifc
+```
+
+