Merge "Welcome screen for guided tour added."
diff --git a/Changes b/Changes
index 14e1098..d11686a 100755
--- a/Changes
+++ b/Changes
@@ -1,4 +1,4 @@
-0.37 2019-10-17
+0.37 2019-10-27
         - Removed deprecated 'kalamar_test_port' helper.
         - Separated KalamarHelpers and KalamarPages.
         - Renamed 'doc_link_to' to 'embedded_link_to'
@@ -8,6 +8,13 @@
         - Renamed 'doc_uc' to 'under_construction'
           and deprecated 'doc_uc'.
         - Introduced 'page_title' helper.
+        - Simplified documentation routing.
+        - Added 'realm' parameter to 'embedded_link_to' helper.
+        - Introduced 'navigation' helper with 'realm' parameter.
+        - Deprecated 'doc_navi' helper in favor of 'navigation'
+          helper.
+        - Added 'navi->set' and 'navi->add' helper.
+        - Added settings skeleton. 
 
 0.36 2019-09-19
         - Rename all cookies to be independent
diff --git a/dev/scss/main/main.scss b/dev/scss/main/main.scss
index 36d668c..c97973b 100644
--- a/dev/scss/main/main.scss
+++ b/dev/scss/main/main.scss
@@ -37,6 +37,18 @@
     margin-top: 0;
     padding-top: 1em;
   }
+
+  &.page {
+    margin-left: $logo-left-distance + 15px;
+    p,li, dd, dt {
+      code {
+        background-color: $ids-grey-2;
+        color: $ids-grey-1;
+        padding: 0 .5em;
+        border-radius: $standard-border-radius;
+      }
+    }
+  }
 }
 
 blockquote {
diff --git a/dev/scss/main/tutorial.scss b/dev/scss/main/tutorial.scss
index bc95a92..526a190 100644
--- a/dev/scss/main/tutorial.scss
+++ b/dev/scss/main/tutorial.scss
@@ -68,16 +68,6 @@
 }
 
 main.tutorial {
-  margin-left: $logo-left-distance + 15px;
-  p,li, dd, dt {
-    code {
-      background-color: $ids-grey-2;
-      color: $ids-grey-1;
-      padding: 0 .5em;
-      border-radius: $standard-border-radius;
-    }
-  }
-
   // Link to documentation
   a.embedded-link::after {
     font-family: FontAwesome;
diff --git a/dev/scss/media.scss b/dev/scss/media.scss
index 2e350da..1a61392 100644
--- a/dev/scss/media.scss
+++ b/dev/scss/media.scss
@@ -163,7 +163,7 @@
       line-height: 1em;
     }
     &.active ~ main div.intro,
-    &.active ~ main.tutorial {
+    &.active ~ main.page {
       margin-left: $standard-margin !important;
     }
 
@@ -205,7 +205,7 @@
     }
   }
 
-  main.tutorial {
+  main.page {
     margin-right: 20px;
   }
 }
@@ -218,7 +218,7 @@
   header, aside {
     display: none;
   }
-  main.tutorial {
+  main.page {
     margin: 1em;
   }
   #kalamar-bg {
diff --git a/kalamar.dict b/kalamar.dict
index 1637965..6c30001 100644
--- a/kalamar.dict
+++ b/kalamar.dict
@@ -59,6 +59,7 @@
     },
     privacy => 'Datenschutz',
     imprint => 'Impressum',
+    settings => 'Einstellungen',
     Template => {
       intro => 'de/intro',
       doc => {
@@ -153,6 +154,7 @@
     },
     privacy => 'Privacy',
     imprint => 'Imprint',
+    settings => 'Settings',
     Template => {
       intro => 'intro',
       doc => {
diff --git a/lib/Kalamar.pm b/lib/Kalamar.pm
index a47bb2d..8470db6 100644
--- a/lib/Kalamar.pm
+++ b/lib/Kalamar.pm
@@ -214,14 +214,20 @@
   };
 
   # Configure documentation navigation
-  my $navi = Mojo::File->new($self->home->child('templates','doc','navigation.json'))->slurp;
-  $navi = $navi ? decode_json($navi) : [];
+  my $doc_navi = Mojo::File->new($self->home->child('templates','doc','navigation.json'))->slurp;
+  $doc_navi = $doc_navi ? decode_json($doc_navi) : [];
 
+  # TODO:
+  #   Use navi->add()
   if ($conf->{navi_ext}) {
-    push @$navi, @{$conf->{navi_ext}};
+    push @$doc_navi, @{$conf->{navi_ext}};
   };
 
-  $self->config(navi => $navi);
+  # TODO:
+  #   Remove navi entry
+  $self->config(doc_navi => $doc_navi);
+
+  $self->navi->set(doc => $doc_navi);
 
   $self->log->info('API expected at ' . $self->korap->api);
 
@@ -230,7 +236,7 @@
 
   # Set footer value
   $self->content_block(footer => {
-    inline => '<%= embedded_link_to "V ' . $Kalamar::VERSION . '", "korap", "kalamar" %>',
+    inline => '<%= embedded_link_to "doc", "V ' . $Kalamar::VERSION . '", "korap", "kalamar" %>',
     position => 100
   });
 
@@ -239,8 +245,11 @@
 
   # Documentation routes
   $r->get('/doc')->to('documentation#page', page => 'korap')->name('doc_start');
-  $r->get('/doc/:page')->to('documentation#page')->name('doc1');
-  $r->get('/doc/*scope/:page')->to('documentation#page')->name('doc2');
+  $r->get('/doc/:scope/:page')->to('documentation#page', scope => undef)->name('doc');
+
+  # Settings routes (deactivated)
+  # $r->get('/settings')->to(cb => sub { shift->render('settings') })->name('settings_start');
+  # $r->get('/settings/:scope/:page')->to(scope => undef, page => undef)->name('settings');
 
   # Contact route
   $r->get('/contact')->to('documentation#contact');
diff --git a/lib/Kalamar/Controller/Documentation.pm b/lib/Kalamar/Controller/Documentation.pm
index abcaadb..6698f55 100644
--- a/lib/Kalamar/Controller/Documentation.pm
+++ b/lib/Kalamar/Controller/Documentation.pm
@@ -22,13 +22,13 @@
   # Set navigation to sidebar
   $c->content_block(
     sidebar => {
-      inline => '<nav>' . $c->doc_navi($c->config('navi')) . '</nav>'
+      inline => '<nav>' . $c->navigation('doc', $c->config('doc_navi')) . '</nav>'
     }
   );
 
   # Render template
   $c->stash(sidebar_active => 1);
-  $c->stash(main_class => 'tutorial');
+  $c->stash(main_class => 'page tutorial');
   $c->stash(documentation => 1);
 
   return $c->render_maybe(
diff --git a/lib/Kalamar/Plugin/KalamarPages.pm b/lib/Kalamar/Plugin/KalamarPages.pm
index 66ee72b..b887e7d 100644
--- a/lib/Kalamar/Plugin/KalamarPages.pm
+++ b/lib/Kalamar/Plugin/KalamarPages.pm
@@ -4,6 +4,7 @@
 use Mojo::ByteStream 'b';
 use Mojo::Util qw/xml_escape deprecated/;
 
+our $navi = {};
 
 # TODO:
 #   Add documentation plugin to programmatically
@@ -19,14 +20,22 @@
   $mojo->helper(
     embedded_link_to => sub {
       my $c = shift;
+
+      # The embedded link now expects at least 3 parameters:
+      #   - The realm, which is identical to the named route
+      #   - The title of the link
+      #   - An optional scope, which is a first level path for navigation
+      #   - The page to link to (accepting a fragment)
+      my $realm = shift;
       my $title = shift;
       my $page = pop;
       my $scope = shift;
 
       ($page, my $fragment) = split '#', $page;
 
-      my $url = $c->doc->url($scope, $page);
+      my $url = $c->url_with($realm, page => $page, scope => $scope);
       $url->fragment($fragment) if $fragment;
+      $url->path->canonicalize;
 
       return $c->link_to(
         $title,
@@ -41,7 +50,7 @@
     doc_link_to => sub {
       my $c = shift;
       deprecated 'Deprecated "doc_link_to" in favor of "embedded_link_to"';
-      return $c->embedded_link_to(@_)
+      return $c->embedded_link_to('doc', @_)
     }
   );
 
@@ -96,7 +105,7 @@
       my $scope = shift;
       my $url;
       if ($page) {
-        $url = $c->doc->url($scope, $page);
+        $url = $c->url_with('doc', scope => $scope, page => $page);
         $url->path->canonicalize;
       }
       else {
@@ -107,35 +116,46 @@
   );
 
 
+  # DEPRECATED: 2019-10-24
   $mojo->helper(
     'doc.url' => sub {
+      deprecated 'Deprecated "doc->url" in favor of direct usage with "url_with"';
       my $c = shift;
       my $page = pop;
       my $scope = shift;
-      if ($scope) {
-        return $c->url_with(
-          'doc2',
-          page => $page,
-          scope => $scope
-        );
-      };
-
       return $c->url_with(
-        'doc1',
-        page => $page
+        'doc',
+        page => $page,
+        scope => $scope
       );
     }
   );
 
   # Documentation navigation helper
+  # DEPRECATED: 2019-10-24
   $mojo->helper(
     doc_navi => sub {
+      deprecated 'Deprecated "docnavi" in favor of "navigation"';
       my $c = shift;
+      return $c->navigation('doc', @_)
+    }
+  );
+
+  # Navigation helper
+  $mojo->helper(
+    'navigation' => sub {
+      my $c = shift;
+      my $realm = shift;
       my $items = pop;
       my $scope = shift;
 
+      # Take items from central list
+      unless ($items) {
+        $items = $navi->{$realm};
+      };
+
       # Create unordered list
-      my $html = '<ul class="nav">'."\n";
+      my $html = '<ul class="nav nav-'.$realm.'">'."\n";
 
       # Embed all link tags
       foreach (@$items) {
@@ -151,7 +171,10 @@
           my $id = $_->{id};
           $id =~ s/^#//;
 
-          $url = $c->doc->url($part_scope, $page);
+          $url = $c->url_with($realm, scope => $part_scope, page => $page);
+
+          # Canonicalize (for empty scopes)
+          $url->path->canonicalize;
           $url->fragment($id);
         }
 
@@ -164,7 +187,7 @@
           };
 
           # Generate url with query parameter inheritance
-          $url = $c->doc->url($scope, $_->{id});
+          $url = $c->url_with($realm, scope => $scope, page => $_->{id});
 
           # Canonicalize (for empty scopes)
           $url->path->canonicalize;
@@ -175,7 +198,6 @@
         push(@classes, $_->{'class'}) if $_->{'class'};
         push(@classes, 'active') if $active;
 
-
         # New list item
         $html .= '<li';
         if (@classes) {
@@ -193,7 +215,7 @@
         if ($_->{items} && ref($_->{items}) eq 'ARRAY') {
           $html .= "\n";
           my $subscope = $scope ? scalar($scope) . '/' . $_->{id} : $_->{id};
-          $html .= $c->doc_navi($subscope, $_->{items});
+          $html .= $c->navigation($realm, $subscope, $_->{items});
           $html .= "</li>\n";
         }
         else {
@@ -237,6 +259,31 @@
     }
   );
 
+  # Set a navigation list to a realm
+  $mojo->helper(
+    'navi.set' => sub {
+      my $c = shift;
+      my $realm = shift;
+      my $list = shift;
+
+      $navi->{$realm} = $list;
+    }
+  );
+
+  $mojo->helper(
+    'navi.add' => sub {
+      my $c = shift;
+      my $realm = shift;
+      my $navi_realm = ($navi->{$realm} //= []);
+      my $title = shift;
+      my $id = shift;
+
+      push @$navi_realm, {
+        title => $title,
+        id => $id
+      }
+    }
+  );
 }
 
 1;
@@ -265,9 +312,9 @@
 =head2 embedded_link_to
 
   %# In templates
-  %= embedded_link_to 'Kalamar', 'korap', 'kalamar'
+  %= embedded_link_to 'doc','Kalamar', 'korap', 'kalamar'
 
-Create a link to the documentation. Accepts a name, a scope, and a page.
+Create a link to the documentation. Accepts a realm, a title, a scope, and a page.
 
 
 =head2 ext_link_to
@@ -291,9 +338,9 @@
 Currently not used.
 
 
-=head2 doc_navi
+=head2 navigation
 
-Returns an HTML representation of the documentation navigation,
+Returns an HTML representation of a navigation structure
 based on active navigation items.
 
 
diff --git a/t/docnavi.t b/t/navigation.t
similarity index 92%
rename from t/docnavi.t
rename to t/navigation.t
index 5b8447f..f9518e8 100644
--- a/t/docnavi.t
+++ b/t/navigation.t
@@ -11,8 +11,7 @@
 push(@{$app->plugins->namespaces}, 'Kalamar::Plugin');
 
 # Establish test route
-$app->routes->get('/doc/:page')->to(cb => sub {})->name('doc1');
-$app->routes->get('/doc/*scope/:page')->to(cb => sub {})->name('doc2');
+$app->routes->get('/doc/:scope/:page')->to(cb => sub {}, scope => undef)->name('doc');
 
 # Load plugin to test
 $app->plugin('KalamarPages');
@@ -41,7 +40,7 @@
   }
 ];
 
-my $render = $app->doc_navi($navi);
+my $render = $app->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!KorAP!, 'Title matches');
 
@@ -56,7 +55,7 @@
   }
 ];
 
-$render = $app->doc_navi($navi);
+$render = $app->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!KorAP!, 'Title matches');
 like($render, qr!/doc/krill!, 'Path matches doc/krill');
@@ -79,7 +78,7 @@
   }
 ];
 
-$render = $app->doc_navi($navi);
+$render = $app->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!/doc/korap/krill!, 'Path matches korap/krill');
 like($render, qr!/doc/faq!, 'Path matches doc/faq');
@@ -129,7 +128,7 @@
   }
 ];
 
-$render = $app->doc_navi($navi);
+$render = $app->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!/doc/korap/krill!, 'Path matches korap/krill');
 like($render, qr!/doc/korap/koral!, 'Path matches korap/koral');
@@ -145,7 +144,7 @@
 
 my $c = $app->build_controller;
 $c->stash(page => 'korap');
-$render = $c->doc_navi($navi);
+$render = $c->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!/doc/korap/krill!, 'Path matches korap/krill');
 like($render, qr!/doc/ql!, 'Path matches doc/ql');
@@ -156,7 +155,7 @@
 like($render, qr!class="active".*?KorAP!, 'Active value for KorAP');
 
 $c->stash(page => 'poliqarp-plus');
-$render = $c->doc_navi($navi);
+$render = $c->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!/doc/korap/krill!, 'Path matches korap/krill');
 like($render, qr!/doc/ql!, 'Path matches doc/ql');
@@ -212,7 +211,7 @@
     title => 'F.A.Q.'
   }
 ];
-$render = $c->doc_navi($navi);
+$render = $c->navigation('doc', $navi);
 
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!/doc/korap/krill!, 'Path matches korap/krill');
@@ -242,7 +241,7 @@
   }
 ];
 
-$render = $app->doc_navi($navi);
+$render = $app->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!/doc/korap/krill!, 'Path matches korap/krill');
 like($render, qr!<a href="/doc/korap/krill(?:#[^"]+)?">Krill</a>!,
@@ -253,7 +252,7 @@
 # Change preferred language
 $languages = [qw/de en/];
 
-$render = $app->doc_navi($navi);
+$render = $app->navigation('doc', $navi);
 like($render, qr!/doc/korap!, 'Path matches doc/korap');
 like($render, qr!/doc/korap/krill!, 'Path matches korap/krill');
 like($render, qr!<a href="/doc/korap/krill(?:#[^"]+)?">Krill</a>!,
diff --git a/t/page.t b/t/page.t
index 61c02d6..fee1205 100644
--- a/t/page.t
+++ b/t/page.t
@@ -10,8 +10,8 @@
 
 is($app->under_construction, '<p>Under Construction!</p>');
 
-is($app->embedded_link_to('privacy', 'privacy'), '<a class="embedded-link" href="/doc/privacy">privacy</a>');
-is($app->embedded_link_to('privacy', 'korap', 'privacy'), '<a class="embedded-link" href="/doc/korap/privacy">privacy</a>');
+is($app->embedded_link_to('doc', 'privacy', 'privacy'), '<a class="embedded-link" href="/doc/privacy">privacy</a>');
+is($app->embedded_link_to('doc', 'privacy', 'korap', 'privacy'), '<a class="embedded-link" href="/doc/korap/privacy">privacy</a>');
 
 
 my $c = $app->build_controller;
diff --git a/t/settings.t b/t/settings.t
new file mode 100644
index 0000000..9620504
--- /dev/null
+++ b/t/settings.t
@@ -0,0 +1,52 @@
+package Kalamar::Plugin::Test;
+use Mojo::Base 'Mojolicious::Plugin';
+
+
+sub register {
+  my ($plugin, $app, $param) = @_;
+
+  # Add entry to settings navigation
+  $app->navi->add(settings => (
+    'OAuth Token Management', 'oauth'
+  ));
+
+  $app->routes->get('/settings/oauth')->to(
+    cb => sub {
+      my $c = shift;
+      $c->content_with(settings => '<p id="abc">My Settings</p>');
+      return $c->render('settings');
+    }
+  );
+};
+
+package main;
+use Mojo::Base -strict;
+use Test::More;
+use Test::Mojo;
+use Mojo::ByteStream 'b';
+
+my $t = Test::Mojo->new('Kalamar' => {
+  Kalamar => {
+    plugins => ['Test']
+  }
+});
+
+my $app = $t->app;
+
+$app->routes->get('/settings')->to(cb => sub { shift->render('settings') })->name('settings_start');
+$app->routes->get('/settings/:scope/:page')->to(scope => undef, page => undef)->name('settings');
+
+
+$t->get_ok('/settings')
+  ->text_is('a[href~/settings/oauth]','OAuth Token Management')
+  ->text_is('h2#page-top', 'Settings')
+  ;
+
+$t->get_ok('/settings/oauth')
+  ->text_is('a[href~/settings/oauth]','OAuth Token Management')
+  ->text_is('h2#page-top', 'Settings')
+  ->text_is('#abc', 'My Settings')
+  ;
+
+done_testing;
+__END__
diff --git a/templates/de/doc/korap/koral.html.ep b/templates/de/doc/korap/koral.html.ep
index 861eb52..a76762d 100644
--- a/templates/de/doc/korap/koral.html.ep
+++ b/templates/de/doc/korap/koral.html.ep
@@ -6,6 +6,6 @@
 
 <p><strong>Hauptentwickler:</strong> Joachim Bingel</p>
 
-<p>Koral ist eine Bibliothek, die für die Übersetzung verschiedener Korpus-Abfragesprachen nach <%= embedded_link_to('KoralQuery', 'api', 'koralquery')%> konzipiert ist. Derzeit unterstützte Abfragesprachen sind <%= embedded_link_to 'Cosmas II', 'ql', 'cosmas2'%>, <%= embedded_link_to('Annis QL', 'ql', 'annis')%>, <%= embedded_link_to ( 'Poliqarp +', 'ql', 'poliqarp-plus')%> (eine erweiterte Version von Poliqarp) und <%= embedded_link_to('CQL', 'ql', 'cql')%>.
+<p>Koral ist eine Bibliothek, die für die Übersetzung verschiedener Korpus-Abfragesprachen nach <%= embedded_link_to('doc', 'KoralQuery', 'api', 'koralquery')%> konzipiert ist. Derzeit unterstützte Abfragesprachen sind <%= embedded_link_to 'doc', 'Cosmas II', 'ql', 'cosmas-2'%>, <%= embedded_link_to('doc', 'Annis QL', 'ql', 'annis')%>, <%= embedded_link_to('doc',  'Poliqarp+', 'ql', 'poliqarp-plus')%> (eine erweiterte Version von Poliqarp) und <%= embedded_link_to('doc', 'CQL', 'ql', 'cql')%>.
 
 <p>Koral ist Open Source und steht unter <%= ext_link_to 'GitHub', "https://github.com/KorAP/Koral"%> zur Verfügung.</p>
diff --git a/templates/de/doc/korap/krill.html.ep b/templates/de/doc/korap/krill.html.ep
index 64aab10..ba138d0 100644
--- a/templates/de/doc/korap/krill.html.ep
+++ b/templates/de/doc/korap/krill.html.ep
@@ -6,6 +6,6 @@
 
 <p><strong>Hauptentwickler:</strong> Nils Diewald, Eliza Margaretha</p>
 
-<p>Krill ist eine <%= ext_link_to 'Lucene', "https://lucene.apache.org/"%> basierte Suchmaschine für große kommentierte Korpora, die als Backend-Komponente für KorAP verwendet wird. Es ist die Referenzimplementierung für <%= embedded_link_to('KoralQuery', 'api', 'koralquery')%>, die die meisten Protokolleigenschaften abdeckt.</p>
+<p>Krill ist eine <%= ext_link_to 'Lucene', "https://lucene.apache.org/"%> basierte Suchmaschine für große kommentierte Korpora, die als Backend-Komponente für KorAP verwendet wird. Es ist die Referenzimplementierung für <%= embedded_link_to('doc', 'KoralQuery', 'api', 'koralquery')%>, die die meisten Protokolleigenschaften abdeckt.</p>
 
 <p>Krill ist Open Source und steht unter <%= ext_link_to 'GitHub', "https://github.com/KorAP/Krill"%> zur Verfügung.</p>
diff --git a/templates/de/doc/ql/poliqarp-plus.html.ep b/templates/de/doc/ql/poliqarp-plus.html.ep
index 9080f8e..d203a98 100644
--- a/templates/de/doc/ql/poliqarp-plus.html.ep
+++ b/templates/de/doc/ql/poliqarp-plus.html.ep
@@ -23,7 +23,7 @@
 
   <h4 id="regexp">Reguläre Ausdrücke</h4>
 
-  <p>Segmente können auch durch <%= embedded_link_to 'Reguläre Ausdrücke', 'ql', 'regexp' %> abgefragt werden - indem das Segment mit doppelten Anführungszeichen umschlossen wird.</p>
+  <p>Segmente können auch durch <%= embedded_link_to 'doc', 'Reguläre Ausdrücke', 'ql', 'regexp' %> abgefragt werden - indem das Segment mit doppelten Anführungszeichen umschlossen wird.</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_re', '** "r(u|a)n"'), cutoff => 1
 
@@ -72,12 +72,12 @@
 
   %= doc_query poliqarp => loc('Q_poliqarp_complexre', '** [orth="r(u|a)n"/xi]'), cutoff => 1
 
-  <p>Ein weiterer spezieller Schlüssel ist <code>base</code>, bezogen auf die Lemma-Annotation der <%= embedded_link_to 'Standard-Foundry', 'data', 'annotation'%>.
+  <p>Ein weiterer spezieller Schlüssel ist <code>base</code>, bezogen auf die Lemma-Annotation der <%= embedded_link_to 'doc', 'Standard-Foundry', 'data', 'annotation'%>.
     Die folgende Abfrage findet alle Vorkommen von Segmenten, die mit dem eingegebenen Lemma in der Standard-Foundry annotiert wurden.</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_complexlemma', '** [base=Tree]'), cutoff => 1
 
-  <p>Der dritte Sonderschlüssel ist <code>pos</code> und bezieht sich auf die Wortarten-Annotation der <%= embedded_link_to 'Standard-Foundry', 'data', 'annotation'%>.
+  <p>Der dritte Sonderschlüssel ist <code>pos</code> und bezieht sich auf die Wortarten-Annotation der <%= embedded_link_to 'doc', 'Standard-Foundry', 'data', 'annotation'%>.
     Die folgende Abfrage findet alle attributiven Adjektive:</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_complexpos', '** [pos=ADJA]'), cutoff => 1
@@ -99,7 +99,7 @@
 
   <blockquote class="warning">
     <p>Vorsicht: Negierte komplexe Segmente können nicht alleinstehend gesucht werden.
-      Allerdings funktionieren sie, wenn sie Teil einer <%= embedded_link_to 'Sequenz', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence'%> sind.</p>
+      Allerdings funktionieren sie, wenn sie Teil einer <%= embedded_link_to 'doc', 'Sequenz', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence'%> sind.</p>
   </blockquote>
 
   <h4 id="empty-segments">Leere Segmente</h4>
@@ -108,11 +108,11 @@
 
   %= doc_query poliqarp => '[]', cutoff => 1
 
-  <p>Leere Segmente sind nützlich, um Abstände von Wörtern auszudrücken, indem sie <%= embedded_link_to 'Wiederholungen', 'ql', 'poliqarp-plus#syntagmatic-operators-repetitions' %> verwenden.</p>
+  <p>Leere Segmente sind nützlich, um Abstände von Wörtern auszudrücken, indem sie <%= embedded_link_to 'doc', 'Wiederholungen', 'ql', 'poliqarp-plus#syntagmatic-operators-repetitions' %> verwenden.</p>
 
   <blockquote class="warning">
     <p>Vorsicht: Leere Segmente können nicht alleinstehend gesucht werden. 
-      Allerdings funktionieren sie, wenn sie Teil einer <%= embedded_link_to 'Sequenz', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence' %> sind.</p>
+      Allerdings funktionieren sie, wenn sie Teil einer <%= embedded_link_to 'doc', 'Sequenz', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence' %> sind.</p>
   </blockquote>
 </section>
 
@@ -193,7 +193,7 @@
 
   <h4 id="syntagmatic-operators-repetitions">Wiederholungen</h4>
 
-  <p>Wiederholungen in Poliqarp werden wie in <%= embedded_link_to 'regulären Ausdrücken', 'ql', 'regexp'%> realisiert, indem Quantifizierer in geschweifte Klammern gesetzt werden.</p>
+  <p>Wiederholungen in Poliqarp werden wie in <%= embedded_link_to 'doc', 'regulären Ausdrücken', 'ql', 'regexp'%> realisiert, indem Quantifizierer in geschweifte Klammern gesetzt werden.</p>
 
     <p>Um eine Sequenz von drei Vorkommen eines Wortes zu suchen, können Sie Ihre Abfrage auf eine der folgenden Arten formulieren - sie werden die selben Ergebnisse erhalten:</p>
 
@@ -234,7 +234,7 @@
     <p>Denken Sie daran, dass Optionalität auf unterschiedliche Arten <i>vererbt</i> sein kann, zum Beispiel wird eine ganze Abfrage optional, sobald ein Segment der Alternative optional ist.</p>
   </blockquote>
 
-  <p>Die Wiederholung kann auch verwendet werden, um Distanzen zwischen Segmenten auszudrücken, indem Sie <%= embedded_link_to 'leere Segmente', 'ql', 'poliqarp-plus # leere Segmente'%> verwenden.</p>
+  <p>Die Wiederholung kann auch verwendet werden, um Distanzen zwischen Segmenten auszudrücken, indem Sie <%= embedded_link_to 'doc', 'leere Segmente', 'ql', 'poliqarp-plus # leere Segmente'%> verwenden.</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_seqdistance1', '** [base=the][][base=Tree]'), cutoff => 1
   %= doc_query poliqarp => loc('Q_poliqarp_seqdistance2', '** [base=the][]{2}[base=Tree]'), cutoff => 1
@@ -249,7 +249,7 @@
     
   <h4>Positionen</h4>
 
-    <p>Sequenzen wie oben können in weiteren komplexen Abfragen verschachtelt und als Unterabfragen behandelt werden (siehe <%= embedded_link_to 'Klassenoperatoren', 'ql', 'poliqarp-plus#class-operator' %>, um direkten Zugriff auf Unterabfragen zu erhalten).</p>
+    <p>Sequenzen wie oben können in weiteren komplexen Abfragen verschachtelt und als Unterabfragen behandelt werden (siehe <%= embedded_link_to 'doc', 'Klassenoperatoren', 'ql', 'poliqarp-plus#class-operator' %>, um direkten Zugriff auf Unterabfragen zu erhalten).</p>
     
     <p>Positionsoperatoren vergleichen zwei Treffer von Unterabfragen und ergeben einen Treffer, falls eine bestimmte Bedingung bezüglich der Position von beiden wahr ist.</p>
 
diff --git a/templates/doc/api.html.ep b/templates/doc/api.html.ep
index 6aad5cb..4aaacf2 100644
--- a/templates/doc/api.html.ep
+++ b/templates/doc/api.html.ep
@@ -6,4 +6,4 @@
   The specification for KoralQuery is available on <%= ext_link_to 'GitHub', "http://korap.github.io/Koral" %>.
   All API endpoints either use KoralQuery or are (more or lest) REST-ful web APIs.</p>
 
-<p>All publicly available API endpoints including their requests and responses are described in the <%= ext_link_to 'GitHub Wiki', "https://github.com/KorAP/Kustvakt/wiki" %> of <%= embedded_link_to 'Kustvakt', 'korap', 'kustvakt' %>.</p>
+<p>All publicly available API endpoints including their requests and responses are described in the <%= ext_link_to 'GitHub Wiki', "https://github.com/KorAP/Kustvakt/wiki" %> of <%= embedded_link_to 'doc', 'Kustvakt', 'korap', 'kustvakt' %>.</p>
diff --git a/templates/doc/data.html.ep b/templates/doc/data.html.ep
index 514a461..eec65a1 100644
--- a/templates/doc/data.html.ep
+++ b/templates/doc/data.html.ep
@@ -9,7 +9,7 @@
 
 <p>In KorAP, corpus texts are allowed to have arbitrary metadata information, that partially can be used to create subcorpora (so-called virtual corpora).</p>
 
-<p>KorAP also supports an arbitrary number of <%= embedded_link_to 'Annotations', 'data', 'annotation' %> from different sources (called <em>foundries</em>) with different <em>layers</em>.</p>
+<p>KorAP also supports an arbitrary number of <%= embedded_link_to 'doc', 'Annotations', 'data', 'annotation' %> from different sources (called <em>foundries</em>) with different <em>layers</em>.</p>
 
 <dl>
   <p>Annotations of the following kind are supported:</p>
diff --git a/templates/doc/korap.html.ep b/templates/doc/korap.html.ep
index d38e4ae..b7e7091 100644
--- a/templates/doc/korap.html.ep
+++ b/templates/doc/korap.html.ep
@@ -7,22 +7,22 @@
 <p>The KorAP project was launched in 2011 at the <%= ext_link_to 'Leibniz Institute for the German Language (IDS)', "http://www.ids-mannheim.de/" %> in Mannheim, Germany. KorAP is a Corpus Analysis Platform, with an extensible and scalable architecture. It consists of multiple components, that are exchangable due to well defined APIs.</p>
 
 <dl>
-  <dt><%= embedded_link_to('Kalamar', 'korap', 'kalamar') %></dt>
+  <dt><%= embedded_link_to('doc', 'Kalamar', 'korap', 'kalamar') %></dt>
   <dd>Kalamar is the user frontend. Most users will access the search and analysis capabilities of KorAP through the user frontend. The user will formulate queries in one of several query languages that are passed to Kustvakt.</dd>
 
-  <dt><%= embedded_link_to('API', 'api') %></dt>
+  <dt><%= embedded_link_to('doc', 'API', 'api') %></dt>
   <dd>As an alternative to the user frontend, queries can be initiated using a REST web interface directly with Kustvakt.</dd>
 
-  <dt><%= embedded_link_to('Kustvakt', 'korap', 'kustvakt') %></dt>
-  <dd>Kustvakt is the central user and policy management service. It takes a query and rewrites it to restrict the scope of a search to documents the user is allowed to. It may also inject further properties the user has set up, like preferred annotation layers. To transfer a query written in a certain query language to the internal general query protocol <%= embedded_link_to('KoralQuery', 'api', 'koralquery') %>, Kustvakt uses <%= embedded_link_to('Koral', 'korap', 'koral') %>.</dd>
+  <dt><%= embedded_link_to('doc', 'Kustvakt', 'korap', 'kustvakt') %></dt>
+  <dd>Kustvakt is the central user and policy management service. It takes a query and rewrites it to restrict the scope of a search to documents the user is allowed to. It may also inject further properties the user has set up, like preferred annotation layers. To transfer a query written in a certain query language to the internal general query protocol <%= embedded_link_to('doc', 'KoralQuery', 'api', 'koralquery') %>, Kustvakt uses <%= embedded_link_to('doc', 'Koral', 'korap', 'koral') %>.</dd>
 
-  <dt><%= embedded_link_to('Koral', 'korap', 'koral') %></dt>
-  <dd>Koral is a library that translates queries written in one of several implemented query languages into a general query protocol, called <%= embedded_link_to('KoralQuery', 'api', 'koralquery') %>.</dd>
+  <dt><%= embedded_link_to('doc', 'Koral', 'korap', 'koral') %></dt>
+  <dd>Koral is a library that translates queries written in one of several implemented query languages into a general query protocol, called <%= embedded_link_to('doc', 'KoralQuery', 'api', 'koralquery') %>.</dd>
 
-  <dt><%= embedded_link_to('Krill', 'korap', 'krill') %></dt>
-  <dd>Krill is a Lucene based backend engine that can search large corpora for occurrences of search patterns formulated in <%= embedded_link_to('KoralQuery', 'api', 'koralquery') %>.</dd>
+  <dt><%= embedded_link_to('doc', 'Krill', 'korap', 'krill') %></dt>
+  <dd>Krill is a Lucene based backend engine that can search large corpora for occurrences of search patterns formulated in <%= embedded_link_to('doc', 'KoralQuery', 'api', 'koralquery') %>.</dd>
 
-  <dt><%= embedded_link_to('Karang', 'korap', 'karang') %></dt>
+  <dt><%= embedded_link_to('doc', 'Karang', 'korap', 'karang') %></dt>
   <dd>Karang is a Neo4j based backend engine that can traverse large corpora represented as graphs.</dd>
 </dl>
 
diff --git a/templates/doc/korap/koral.html.ep b/templates/doc/korap/koral.html.ep
index 9af7508..6f4eda0 100644
--- a/templates/doc/korap/koral.html.ep
+++ b/templates/doc/korap/koral.html.ep
@@ -6,6 +6,6 @@
 
 <p><strong>Main developer:</strong> Joachim Bingel</p>
 
-<p>Koral is a library designed for the translation of different corpus query languages to <%= embedded_link_to('KoralQuery', 'api', 'koralquery') %>. Currently supported query languages include <%= embedded_link_to 'Cosmas II', 'ql', 'cosmas2' %>, <%= embedded_link_to('Annis QL', 'ql', 'annis') %>, <%= embedded_link_to('Poliqarp+', 'ql', 'poliqarp-plus') %> (an extended version of Poliqarp) and <%= embedded_link_to('CQL', 'ql', 'cql') %>.</p>
+<p>Koral is a library designed for the translation of different corpus query languages to <%= embedded_link_to('doc', 'KoralQuery', 'api', 'koralquery') %>. Currently supported query languages include <%= embedded_link_to 'doc', 'Cosmas II', 'ql', 'cosmas-2' %>, <%= embedded_link_to('doc', 'Annis QL', 'ql', 'annis') %>, <%= embedded_link_to('doc', 'Poliqarp+', 'ql', 'poliqarp-plus') %> (an extended version of Poliqarp) and <%= embedded_link_to('doc', 'CQL', 'ql', 'cql') %>.</p>
 
 <p>Koral is open source and available on <%= ext_link_to 'GitHub', "https://github.com/KorAP/Koral" %>.</p>
diff --git a/templates/doc/korap/krill.html.ep b/templates/doc/korap/krill.html.ep
index dcf1fe0..e36b6c8 100644
--- a/templates/doc/korap/krill.html.ep
+++ b/templates/doc/korap/krill.html.ep
@@ -6,6 +6,6 @@
 
 <p><strong>Main developer:</strong> Nils Diewald, Eliza Margaretha</p>
 
-<p>Krill is a <%= ext_link_to 'Lucene', "https://lucene.apache.org/" %> based search engine for large annotated corpora, used as a backend component for KorAP. It is the reference implementation for <%= embedded_link_to('KoralQuery', 'api', 'koralquery') %>, covering most of the protocols features.</p>
+<p>Krill is a <%= ext_link_to 'Lucene', "https://lucene.apache.org/" %> based search engine for large annotated corpora, used as a backend component for KorAP. It is the reference implementation for <%= embedded_link_to('doc', 'KoralQuery', 'api', 'koralquery') %>, covering most of the protocols features.</p>
 
 <p>Krill is open source and available on <%= ext_link_to 'GitHub', "https://github.com/KorAP/Krill" %>.</p>
diff --git a/templates/doc/ql.html.ep b/templates/doc/ql.html.ep
index d09eeb6..5bee3a5 100644
--- a/templates/doc/ql.html.ep
+++ b/templates/doc/ql.html.ep
@@ -9,34 +9,34 @@
 <section id="examples">
   <h3>Example Queries</h3>
   
-  <p><strong><%= embedded_link_to 'Poliqarp', 'ql', 'poliqarp-plus' %></strong>: Find all occurrences of the lemma &quot;baum&quot; as annotated by the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Poliqarp', 'ql', 'poliqarp-plus' %></strong>: Find all occurrences of the lemma &quot;baum&quot; as annotated by the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>.</p>
   %= doc_query poliqarp => '[base=Baum]'
 
-  <p><strong><%= embedded_link_to 'Poliqarp', 'ql', 'poliqarp-plus' %></strong>: Find all sequences of adjectives as annotated by Treetagger, that are repeated 3 to 5 times in a row.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Poliqarp', 'ql', 'poliqarp-plus' %></strong>: Find all sequences of adjectives as annotated by Treetagger, that are repeated 3 to 5 times in a row.</p>
   %= doc_query poliqarp => '[tt/p=ADJA]{3,5}'
 
-  <p><strong><%= embedded_link_to 'Cosmas-II', 'ql', 'cosmas-2' %></strong>: Find all occurrences of the words &quot;der&quot; and &quot;Baum&quot;, in case they are in a maximum distance of 5 tokens. The order is not relevant.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Cosmas-II', 'ql', 'cosmas-2' %></strong>: Find all occurrences of the words &quot;der&quot; and &quot;Baum&quot;, in case they are in a maximum distance of 5 tokens. The order is not relevant.</p>
   %= doc_query cosmas2 => 'der /w5 Baum'
 
-  <p><strong><%= embedded_link_to 'Cosmas-II', 'ql', 'cosmas-2' %></strong>: Find all sequences of a word starting with a &quot;d&quot; (using a wildcard) followed by an adjective as annotated in the mate foundry, followed by the word &quot;Baum&quot; (ignore the case), that is in a sentence element annotated by the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Cosmas-II', 'ql', 'cosmas-2' %></strong>: Find all sequences of a word starting with a &quot;d&quot; (using a wildcard) followed by an adjective as annotated in the mate foundry, followed by the word &quot;Baum&quot; (ignore the case), that is in a sentence element annotated by the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>.</p>
   <p><em>Be aware</em>: Minor incompatibilities with implemented languages may be announced with warnings.</p>
   %= doc_query cosmas2 => 'd* MORPH(mate/p=ADJA) $Baum #IN #ELEM(s)'
 
-  <p><strong><%= embedded_link_to 'Poliqarp+', 'ql', 'poliqarp-plus' %></strong>: Find all nominal phrases as annotated using CoreNLP, that contain an adverb as annotated by OpenNLP, that is annotated as something starting with an &quot;A&quot; using regular expressions in Treetagger.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Poliqarp+', 'ql', 'poliqarp-plus' %></strong>: Find all nominal phrases as annotated using CoreNLP, that contain an adverb as annotated by OpenNLP, that is annotated as something starting with an &quot;A&quot; using regular expressions in Treetagger.</p>
   %= doc_query poliqarp => 'contains(<corenlp/c=NP>,{[opennlp/p=ADV & tt/p="A.*"]})', cutoff => 1
 
-  <p><strong><%= embedded_link_to 'Poliqarp+', 'ql', 'poliqarp-plus' %></strong>: Find all sentences as annotated by the base foundry that start with a sequence of one token in present tense as annotated by Marmot and the lemma &quot;die&quot; annotated by the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>. Highlight both terms of the sequence.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Poliqarp+', 'ql', 'poliqarp-plus' %></strong>: Find all sentences as annotated by the base foundry that start with a sequence of one token in present tense as annotated by Marmot and the lemma &quot;die&quot; annotated by the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>. Highlight both terms of the sequence.</p>
   %= doc_query poliqarp => 'startswith(<base/s=s>, {1:[marmot/m=tense:pres]}{2:[base=die]})', cutoff => 1
 
-  <p><strong><%= embedded_link_to 'Poliqarp+', 'ql', 'poliqarp-plus' %></strong>: Find all sequences of an article, followed by three to four adjectives and a noun as annotated by the Treetagger foundry, that finish a sentence. Highlight all parts of the sequence.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Poliqarp+', 'ql', 'poliqarp-plus' %></strong>: Find all sequences of an article, followed by three to four adjectives and a noun as annotated by the Treetagger foundry, that finish a sentence. Highlight all parts of the sequence.</p>
   %= doc_query poliqarp => 'focus(3:endswith(<base/s=s>,{3:[tt/p=ART]{1:{2:[tt/p=ADJA]{3,4}}[tt/p=NN]}}))', cutoff => 1
 
-  <p><strong><%= embedded_link_to 'Annis', 'ql', 'annis' %></strong>: Find all occurrences of the sequence of two tokens annotated as adverbs by the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Annis', 'ql', 'annis' %></strong>: Find all occurrences of the sequence of two tokens annotated as adverbs by the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>.</p>
   %= doc_query annis => 'pos="ADV" & pos="ADV" & #1 . #2'
 
-  <p><strong><%= embedded_link_to 'Annis', 'ql', 'annis' %></strong>: Find all determiner relations with the label <code>DET</code> by MALT where the relation sources are attributive possesive pronouns annotated by Tree Tagger.</p>
+  <p><strong><%= embedded_link_to 'doc', 'Annis', 'ql', 'annis' %></strong>: Find all determiner relations with the label <code>DET</code> by MALT where the relation sources are attributive possesive pronouns annotated by Tree Tagger.</p>
   %= doc_query annis => 'tt/p="PPOSAT" ->malt/d[func="DET"] node'
 
-  <p><strong><%= embedded_link_to 'CQL', 'ql', 'cql' %></strong>: Find all occurrences of the sequence &quot;der alte Mann&quot;.</p>
+  <p><strong><%= embedded_link_to 'doc', 'CQL', 'ql', 'cql' %></strong>: Find all occurrences of the sequence &quot;der alte Mann&quot;.</p>
   %= doc_query cql => '"der alte Mann"'	
 </section>
diff --git a/templates/doc/ql/annis.html.ep b/templates/doc/ql/annis.html.ep
index 24a2145..b1b17dc 100644
--- a/templates/doc/ql/annis.html.ep
+++ b/templates/doc/ql/annis.html.ep
@@ -9,7 +9,7 @@
   pairs, relations). The concept of AQL is similar to searching node elements and edges
   between them, where a node element can be a token or an attribute-value pair.</p>
 
-<p>KorAP supports the following keywords by using the <%= embedded_link_to 'default foundries', 'data', 'annotation' %>: </p>
+<p>KorAP supports the following keywords by using the <%= embedded_link_to 'doc', 'default foundries', 'data', 'annotation' %>: </p>
 <dl>
   <dt><code>node</code></dt>
   <dd>a node element</dd>
diff --git a/templates/doc/ql/cosmas-2.html.ep b/templates/doc/ql/cosmas-2.html.ep
index d320eb3..f0be87f 100644
--- a/templates/doc/ql/cosmas-2.html.ep
+++ b/templates/doc/ql/cosmas-2.html.ep
@@ -30,7 +30,7 @@
 
   <h4>Lemma Operator</h4>
   
-  <p>Instead of searching for the surface form of a word, a lemma (as annotated by the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>) can be requested by prepending the term with the <code>&amp;</code> operator. The form of the lemma is dependent on the annotation.</p>
+  <p>Instead of searching for the surface form of a word, a lemma (as annotated by the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>) can be requested by prepending the term with the <code>&amp;</code> operator. The form of the lemma is dependent on the annotation.</p>
   <%= doc_query cosmas2 => '&laufen' %>
 
   <h4>Case Insensitivity Operator</h4>
@@ -40,11 +40,11 @@
 
   <h4>Regular Expression Operator</h4>
 
-  <p>By using the <code>#REG(...)</code> operator, query terms can be formulated using <%= embedded_link_to 'regular expressions', 'ql', 'regexp' %>.</p>
+  <p>By using the <code>#REG(...)</code> operator, query terms can be formulated using <%= embedded_link_to 'doc', 'regular expressions', 'ql', 'regexp' %>.</p>
   
 
   <blockquote class="bug">
-    <p>Regular expressions in COSMAS II are not yet properly implemented in KorAP. If you want to use regular expressions, please refer to <%= embedded_link_to 'Poliqarp', 'ql', 'poliqarp-plus#regexp' %>.</p>
+    <p>Regular expressions in COSMAS II are not yet properly implemented in KorAP. If you want to use regular expressions, please refer to <%= embedded_link_to 'doc', 'Poliqarp', 'ql', 'poliqarp-plus#regexp' %>.</p>
   </blockquote>
 
 </section>
@@ -84,7 +84,7 @@
 %#    <p>Currently, intervals are interpreted as MIN:MAX only, while COSMAS 2 defines intervals as being MAX:MIN, while taking the smaller number as being the minimum value of the interval and the greater number as being the maximum value of the interval. <%= ext_link_to 'KorAP will adopt the behaviour of COSMAS II in the near future', "https://github.com/KorAP/Koral/issues/67" %>.</p>
 %#  </blockquote>
   
-  <p>Distance operators rely on the <%= embedded_link_to 'default foundry', 'data', 'annotation' %> annotation for document structures.</p>
+  <p>Distance operators rely on the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %> annotation for document structures.</p>
 
   <h4>Word Distance Operator</h4>
 
@@ -105,7 +105,7 @@
   <h4>Sentence Distance Operator</h4>
 
   <p>The sentence distance operator <code>s</code> defines how many sentences are allowed or are not allowed in-between two search operands.</p>
-  <p>The sentence distance relies on the <%= embedded_link_to 'default foundry', 'data', 'annotation' %> annotation for document structures.</p>
+  <p>The sentence distance relies on the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %> annotation for document structures.</p>
 
   <p>Search for two operands occuring in the same or a following sentence in arbitrary order:</p>
   %= doc_query cosmas2 => 'offen /s1 Geschäft'
@@ -119,7 +119,7 @@
   <h4>Paragraph Distance Operator</h4>
 
   <p>The paragraph distance operator <code>p</code> defines how many paragraphs are allowed or are not allowed in-between two search operands.</p>
-  <p>The paragraph distance relies on the <%= embedded_link_to 'default foundry', 'data', 'annotation' %> annotation for document structures.</p>
+  <p>The paragraph distance relies on the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %> annotation for document structures.</p>
 
   <p>Search for two operands occuring in the same or a following paragraph in arbitrary order:</p>
   %= doc_query cosmas2 => 'offen /p1 Geschäft'
diff --git a/templates/doc/ql/fcsql.html.ep b/templates/doc/ql/fcsql.html.ep
index 843438e..735ce8b 100644
--- a/templates/doc/ql/fcsql.html.ep
+++ b/templates/doc/ql/fcsql.html.ep
@@ -6,7 +6,7 @@
   <%= ext_link_to 'Clarin Federated Content Search (FCS)', "https://www.clarin.eu/content/federated-content-search-clarin-fcs" %>,
   that allows searching through annotated data.
 Accordingly, FCS-QL is primarily intended to represent queries involving annotation layers
-such as part-of-speech and lemma. FCS-QL grammar is fairly similar to <%= embedded_link_to 'Poliqarp', 'ql', 'poliqarp-plus' %> since it was
+such as part-of-speech and lemma. FCS-QL grammar is fairly similar to <%= embedded_link_to 'doc', 'Poliqarp', 'ql', 'poliqarp-plus' %> since it was
 built heavily based on Poliqarp/CQP.</p>
 
 <p>In FCS-QL, foundries are called qualifiers. A combination of a foundry and a layer is
@@ -43,7 +43,7 @@
   %= doc_query fcsql => '[text = "Semmel"]', cutoff => 1
   %= doc_query fcsql => '[text = "essen"/c]', cutoff => 1
 	
-	<p>Querying adverbs from the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>.</p>
+	<p>Querying adverbs from the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>.</p>
   %= doc_query fcsql => '[pos="ADV"]', cutoff => 1
 	
 
@@ -72,7 +72,7 @@
 	
 
   <h4>Empty token</h4>
-	<p>Like in <%= embedded_link_to 'Poliqarp', 'ql', 'poliqarp-plus' %>, an empty token is signified by <code>[]</code>
+	<p>Like in <%= embedded_link_to 'doc', 'Poliqarp', 'ql', 'poliqarp-plus' %>, an empty token is signified by <code>[]</code>
     which means any token. Due to the
 	excessive number of results, empty token is not allowed to be used independently, but in
 	combination with other tokens, for instance in a sequence query.</p>
diff --git a/templates/doc/ql/poliqarp-plus.html.ep b/templates/doc/ql/poliqarp-plus.html.ep
index 6dabcbc..e97fbdd 100644
--- a/templates/doc/ql/poliqarp-plus.html.ep
+++ b/templates/doc/ql/poliqarp-plus.html.ep
@@ -24,7 +24,7 @@
 
   <h4 id="regexp">Regular Expressions</h4>
 
-  <p>Segments can also be queried using <%= embedded_link_to 'regular expressions', 'ql', 'regexp' %> - by surrounding the segment with double quotes.</p>
+  <p>Segments can also be queried using <%= embedded_link_to 'doc', 'regular expressions', 'ql', 'regexp' %> - by surrounding the segment with double quotes.</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_re', '** "r(u|a)n"'), cutoff => 1
 
@@ -70,12 +70,12 @@
 
   %= doc_query poliqarp => loc('Q_poliqarp_complexre', '** [orth="r(u|a)n"/xi]'), cutoff => 1
 
-  <p>Another special key is <code>base</code>, refering to the lemma annotation of the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>.
+  <p>Another special key is <code>base</code>, refering to the lemma annotation of the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>.
     The following query finds all occurrences of segments annotated as a specified lemma by the default foundry.</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_complexlemma', '** [base=Tree]'), cutoff => 1
 
-  <p>The third special key is <code>pos</code>, refering to the part-of-speech annotation of the <%= embedded_link_to 'default foundry', 'data', 'annotation' %>.
+  <p>The third special key is <code>pos</code>, refering to the part-of-speech annotation of the <%= embedded_link_to 'doc', 'default foundry', 'data', 'annotation' %>.
     The following query finds all attributive adjectives:</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_complexpos', '** [pos=ADJA]'), cutoff => 1
@@ -97,7 +97,7 @@
 
   <blockquote class="warning">
     <p>Beware: Negated complex segments can't be searched as a single statement.
-      However, they work in case they are part of a <%= embedded_link_to 'sequence', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence' %>.</p>
+      However, they work in case they are part of a <%= embedded_link_to 'doc', 'sequence', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence' %>.</p>
   </blockquote>
 
   <h4 id="empty-segments">Empty Segments</h4>
@@ -106,11 +106,11 @@
 
   %= doc_query poliqarp => '[]', cutoff => 1
 
-  <p>Empty segments are useful to express distances of words by using <%= embedded_link_to 'repetitions', 'ql', 'poliqarp-plus#syntagmatic-operators-repetitions' %>.</p>
+  <p>Empty segments are useful to express distances of words by using <%= embedded_link_to 'doc', 'repetitions', 'ql', 'poliqarp-plus#syntagmatic-operators-repetitions' %>.</p>
 
   <blockquote class="warning">
     <p>Beware: Empty segments can't be searched as a single statement.
-      However, they work in case they are part of a <%= embedded_link_to 'sequence', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence' %>.</p>
+      However, they work in case they are part of a <%= embedded_link_to 'doc', 'sequence', 'ql', 'poliqarp-plus#syntagmatic-operators-sequence' %>.</p>
   </blockquote>
 </section>
 
@@ -191,7 +191,7 @@
 
   <h4 id="syntagmatic-operators-repetitions">Repetition</h4>
 
-  <p>Repetitions in Poliqarp are realized as in <%= embedded_link_to 'regular expressions', 'ql', 'regexp' %>, by giving quantifieres in curly brackets.</p>
+  <p>Repetitions in Poliqarp are realized as in <%= embedded_link_to 'doc', 'regular expressions', 'ql', 'regexp' %>, by giving quantifieres in curly brackets.</p>
   <p>To search for a sequence of three occurrences of a defined string, you can formulate your query in any of the following ways - they will have the same results:</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_repmanual', '** the the the'), cutoff => 1
@@ -231,7 +231,7 @@
     <p>Keep in mind that optionality may be somehow <i>inherited</i>, for example an entire query becomes optional as soon as one segment of an alternation is optional.</p>
   </blockquote>
 
-  <p>Repetition can also be used to express distances between segments by using <%= embedded_link_to 'empty segments', 'ql', 'poliqarp-plus#empty-segments' %>.</p>
+  <p>Repetition can also be used to express distances between segments by using <%= embedded_link_to 'doc', 'empty segments', 'ql', 'poliqarp-plus#empty-segments' %>.</p>
 
   %= doc_query poliqarp => loc('Q_poliqarp_seqdistance1', '** [base=the][][base=Tree]'), cutoff => 1
   %= doc_query poliqarp => loc('Q_poliqarp_seqdistance2', '** [base=the][]{2}[base=Tree]'), cutoff => 1
@@ -246,7 +246,7 @@
     
   <h4>Position</h4>
 
-  <p>Sequences as shown above can all be nested in further complex queries and treated as subqueries (see <%= embedded_link_to 'class operators', 'ql', 'poliqarp-plus#class-operators' %> on how to later access these subqueries directly).</p>
+  <p>Sequences as shown above can all be nested in further complex queries and treated as subqueries (see <%= embedded_link_to 'doc', 'class operators', 'ql', 'poliqarp-plus#class-operators' %> on how to later access these subqueries directly).</p>
   <p>Positional operators compare two matches of subqueries and will match, in case a certain condition regarding the position of both is true.</p>
   <p>The <code>contains()</code> operation will match, when a second subquery matches inside the span of a first subquery.</p>
 
diff --git a/templates/settings.html.ep b/templates/settings.html.ep
new file mode 100644
index 0000000..bd92eb6
--- /dev/null
+++ b/templates/settings.html.ep
@@ -0,0 +1,17 @@
+% if (param('embedded')) {
+%   stash(embedded => 1);
+% };
+
+% unless (stash('title')) {
+%   stash(title => loc('settings'))
+% }
+
+% content_block(sidebar => {
+%    inline => '<nav>' . navigation('settings') . '</nav>'
+% });
+
+% layout 'main', sidebar_active => 1, main_class => 'page settings';
+
+%= page_title
+
+%= content 'settings'