diff --git a/README.md b/README.md
index 264545b7ce9dd8133fe7e2b28636ccf2b3c14dbe..404d022e5f0b79fbcb214b88ca00380694cc6409 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,8 @@ This module is an add-on for Django REST Framework that serves a django model re
 
 It aims at enabling people with little development skills to serve their own data, to be used with a LDP application.
 
+Building a Startin' Blox application? Read this: https://git.happy-dev.fr/startinblox/devops/doc
+
 ## Requirements
 
 * Django (known to work with django 1.11)
@@ -26,7 +28,18 @@ $ pip install djangoldp
 $ django-admin startproject myldpserver
 ```
 
-3. Create your django model inside a file myldpserver/myldpserver/models.py
+3. Add DjangoLDP to INSTALLED_APPS
+```python
+INSTALLED_APPS = [
+    ...
+    # make sure all of your own apps are installed BEFORE DjangoLDP
+    'djangoldp.apps.DjangoldpConfig',
+]
+```
+
+IMPORTANT: DjangoLDP will register any models which haven't been registered, with the admin. As such it is important to add your own apps above DjangoLDP, so that you can use custom Admin classes if you wish
+
+4. Create your django model inside a file myldpserver/myldpserver/models.py
 Note that container_path will be use to resolve instance iri and container iri
 In the future it could also be used to auto configure django router (e.g. urls.py)
 
@@ -38,14 +51,14 @@ class Todo(Model):
     deadline = models.DateTimeField()
 ```
 
-3.1. Configure container path (optional)
+4.1. Configure container path (optional)
 By default it will be "todos/" with an S for model called Todo
 
 ```python
 <Model>._meta.container_path = "/my-path/"
 ```
 
-3.2. Configure field visibility (optional) 
+4.2. Configure field visibility (optional) 
 Note that at this stage you can limit access to certain fields of models using
 
 ```python
@@ -64,7 +77,7 @@ User._meta.serializer_fields  = ('username','first_name','last_name')
 
 Note that this will be overridden if you explicitly set the fields= parameter as an argument to LDPViewSet.urls(), and filtered if you set the excludes= parameter.
 
-4. Add a url in your urls.py:
+5. Add a url in your urls.py:
 
 ```python
 from django.conf.urls import url
@@ -86,14 +99,23 @@ You could also only use this line in settings.py instead:
 ROOT_URLCONF = 'djangoldp.urls'
 ```
 
-5. In the settings.py file, add your application name at the beginning of the application list, and add the following lines
+6. In the settings.py file, add your application name at the beginning of the application list, and add the following lines
 
 ```python
 STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static')
 LDP_RDF_CONTEXT = 'https://cdn.happy-dev.fr/owl/hdcontext.jsonld'
+DJANGOLDP_PACKAGES = []
+SITE_URL = 'http://localhost:8000'
+BASE_URL = SITE_URL
 ```
 
-6. You can also register your model for the django administration site
+* `LDP_RDF_CONTEXT` tells DjangoLDP where our RDF [ontology](https://www.w3.org/standards/semanticweb/ontology) is defined, which will be returned as part of our views in the 'context' field. This is a web URL and you can visit the value to view the full ontology online
+* `DJANGOLDP_PACKAGES` defines which other [DjangoLDP packages](https://git.happy-dev.fr/startinblox/djangoldp-packages) we're using in this installation
+* `SITE_URL` is the URL serving the site, e.g. `https://example.com/`
+* `BASE_URL` may be different from SITE_URL, e.g. `https://example.com/app/`
+
+
+7. You can also register your model for the django administration site
 
 ```python
 from django.contrib import admin
@@ -102,15 +124,15 @@ from .models import Todo
 admin.site.register(Todo)
 ```
 
-7. You then need to have your WSGI server pointing on myldpserver/myldpserver/wsgi.py
+8. You then need to have your WSGI server pointing on myldpserver/myldpserver/wsgi.py
 
-8. You will probably need to create a super user
+9. You will probably need to create a super user
 
 ```bash
 $ ./manage.py createsuperuser
 ```
 
-9. If you have no CSS on the admin screens :
+10. If you have no CSS on the admin screens :
 
 ```bash
 $ ./manage.py collectstatic
diff --git a/djangoldp/admin.py b/djangoldp/admin.py
index dffdc236ff97205748b9dcaa3626bbb1f35adcfd..2627925705f5bb2cfb378a73eb099ff4779dc565 100644
--- a/djangoldp/admin.py
+++ b/djangoldp/admin.py
@@ -4,6 +4,7 @@ from django.conf import settings
 from django.contrib import admin
 from .models import LDPSource, Model
 
+# automatically import selected DjangoLDP packages from settings
 for package in settings.DJANGOLDP_PACKAGES:
     try:
         import_module('{}.admin'.format(package))
@@ -18,6 +19,7 @@ for package in settings.DJANGOLDP_PACKAGES:
 
 model_classes = {cls.__name__: cls for cls in Model.__subclasses__()}
 
+# automatically register models with the admin panel (which have not been added manually)
 for class_name in model_classes:
     model_class = model_classes[class_name]
     if not admin.site.is_registered(model_class):
diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py
index 5e886e15ef59fdbd3b33ad3727fa75e06c074e23..3a19bbf35d9d8f8e4aaa4083f53888453ce51428 100644
--- a/djangoldp/serializers.py
+++ b/djangoldp/serializers.py
@@ -27,13 +27,17 @@ from djangoldp.permissions import LDPPermissions
 
 
 class LDListMixin:
+    '''A Mixin used by the custom Serializers in this file'''
     child_attr = 'child'
 
+    # converts primitive data representation to the representation used within our application
     def to_internal_value(self, data):
         try:
+            # if this is a container, the data will be stored in ldp:contains
             data = data['ldp:contains']
         except (TypeError, KeyError):
             pass
+
         if len(data) == 0:
             return []
         if isinstance(data, dict):
@@ -43,6 +47,7 @@ class LDListMixin:
 
         return [getattr(self, self.child_attr).to_internal_value(item) for item in data]
 
+    # converts internal representation to primitive data representation
     def to_representation(self, value):
         '''
         Permission on container :
@@ -53,7 +58,9 @@ class LDListMixin:
             child_model = getattr(self, self.child_attr).Meta.model
         except AttributeError:
             child_model = value.model
+
         parent_model = None
+
         if isinstance(value, QuerySet):
             value = list(value)
 
@@ -61,11 +68,13 @@ class LDListMixin:
             filtered_values = value
             container_permissions = Model.get_permissions(child_model, self.context['request'].user, ['view', 'add'])
         else:
+            # this is a container. Parent model is the containing object, child the model contained
             try:
                 parent_model = Model.resolve_parent(self.context['request'].path)
             except:
                 parent_model = child_model
 
+            # remove objects from the list which I don't have permission to view
             filtered_values = list(
                 filter(lambda v: Model.get_permission_classes(v, [LDPPermissions])[0]().has_object_permission(
                     self.context['request'], self.context['view'], v), value))
diff --git a/djangoldp/views.py b/djangoldp/views.py
index d9fc066fc58f4e6a4b5b4b82b6ea2a2106ed8b5e..8889220f557fe22240e3e56cd4658a4a2aea0511 100644
--- a/djangoldp/views.py
+++ b/djangoldp/views.py
@@ -24,6 +24,8 @@ from djangoldp.permissions import LDPPermissions
 get_user_model()._meta.rdf_context = {"get_full_name": "rdfs:label"}
 
 
+# renders into JSONLD format by applying context to the data
+# https://github.com/digitalbazaar/pyld
 class JSONLDRenderer(JSONRenderer):
     media_type = 'application/ld+json'
 
@@ -38,15 +40,18 @@ class JSONLDRenderer(JSONRenderer):
                 data["@context"] = settings.LDP_RDF_CONTEXT
         return super(JSONLDRenderer, self).render(data, accepted_media_type, renderer_context)
 
-
+# https://github.com/digitalbazaar/pyld
 class JSONLDParser(JSONParser):
     media_type = 'application/ld+json'
 
     def parse(self, stream, media_type=None, parser_context=None):
         data = super(JSONLDParser, self).parse(stream, media_type, parser_context)
+        # compact applies the context to the data and makes it a format which is easier to work with
+        # see: http://json-ld.org/spec/latest/json-ld/#compacted-document-form
         return jsonld.compact(data, ctx=settings.LDP_RDF_CONTEXT)
 
 
+# an authentication class which exempts CSRF authentication
 class NoCSRFAuthentication(SessionAuthentication):
     def enforce_csrf(self, request):
         return
@@ -81,6 +86,7 @@ class LDPViewSetGenerator(ModelViewSet):
 
     @classonlymethod
     def urls(cls, **kwargs):
+        '''constructs urls list for model passed in kwargs'''
         kwargs['model'] = cls.get_model(**kwargs)
         model_name = kwargs['model']._meta.object_name.lower()
         if kwargs.get('model_prefix'):
@@ -93,12 +99,14 @@ class LDPViewSetGenerator(ModelViewSet):
                 name='{}-detail'.format(model_name)),
         ]
 
+        # append nested fields to the urls list
         for field in kwargs.get('nested_fields') or cls.nested_fields:
             urls.append(url('^' + detail_expr + field + '/', LDPNestedViewSet.nested_urls(field, **kwargs)))
 
         return include(urls)
 
 
+# LDPViewSetGenerator is a ModelViewSet (DRF) with methods to automatically generate model urls
 class LDPViewSet(LDPViewSetGenerator):
     """An automatically generated viewset that serves models following the Linked Data Platform convention"""
     fields = None
@@ -109,6 +117,8 @@ class LDPViewSet(LDPViewSetGenerator):
 
     def __init__(self, **kwargs):
         super().__init__(**kwargs)
+        # attach filter backends based on permissions classes, to reduce the queryset based on these permissions
+        # https://www.django-rest-framework.org/api-guide/filtering/#generic-filtering
         if self.permission_classes:
             for p in self.permission_classes:
                 if hasattr(p, 'filter_class') and p.filter_class:
@@ -136,11 +146,13 @@ class LDPViewSet(LDPViewSetGenerator):
         return self.build_serializer(meta_args, 'Write')
 
     def build_serializer(self, meta_args, name_prefix):
+        # create the Meta class to associate to LDPSerializer, using meta_args param
         if self.fields:
             meta_args['fields'] = self.fields
         else:
             meta_args['exclude'] = self.exclude or ()
         meta_class = type('Meta', (), meta_args)
+
         from djangoldp.serializers import LDPSerializer
         return type(LDPSerializer)(self.model._meta.object_name.lower() + name_prefix + 'Serializer', (LDPSerializer,),
                                    {'Meta': meta_class})
@@ -148,6 +160,7 @@ class LDPViewSet(LDPViewSetGenerator):
     def create(self, request, *args, **kwargs):
         serializer = self.get_write_serializer(data=request.data)
         serializer.is_valid(raise_exception=True)
+
         self.perform_create(serializer)
         response_serializer = self.get_serializer()
         data = response_serializer.to_representation(serializer.instance)
@@ -210,6 +223,7 @@ class LDPViewSet(LDPViewSetGenerator):
             return super(LDPView, self).get_queryset(*args, **kwargs)
 
     def dispatch(self, request, *args, **kwargs):
+        '''overriden dispatch method to append some custom headers'''
         response = super(LDPViewSet, self).dispatch(request, *args, **kwargs)
         response["Access-Control-Allow-Origin"] = request.META.get('HTTP_ORIGIN')
         response["Access-Control-Allow-Methods"] = "GET,POST,PUT,PATCH,DELETE"