TAP5-2608: applying picodotdev's Quickstart fix patch
diff --git a/quickstart/build.gradle b/quickstart/build.gradle
index a499357..1a34cf6 100644
--- a/quickstart/build.gradle
+++ b/quickstart/build.gradle
@@ -1,38 +1,68 @@
 import org.apache.tools.ant.filters.FixCrLfFilter
 import org.apache.tools.ant.filters.ReplaceTokens
 
-// Copy the gradle wrapper files from the project root
-processResources { 
-  from(rootDir) { 
-    include "gradlew"
-    include "gradlew.bat"
-    include "gradle/**"
-    into "archetype-resources"
-  }
+task copyGradleWrapper(type: Copy) {
+    ext.srcDir = file("$buildDir/wrapper")
+
+    inputs.dir srcDir
+    outputs.dir file("$buildDir/resources/main/archetype-resources")
+
+    from srcDir
+    into file("$buildDir/resources/main/archetype-resources")
+
+    exclude '.gradle'
+}
+
+task addGradleWrapper(type: Exec) {
+    workingDir "$buildDir/wrapper"
+    commandLine "${rootProject.projectDir}/gradlew", 'wrapper', '--gradle-version', '5.2'
+
+    standardOutput = new ByteArrayOutputStream()
+
+    ext.output = {
+        return standardOutput.toString()
+    }
+
+    doFirst {
+        def wrapperDirectory = new File(buildDir, "wrapper")
+        wrapperDirectory.mkdirs()
+
+        def settings = new File(wrapperDirectory, "settings.gradle")
+        new FileOutputStream(settings).close();
+    }
+
+    finalizedBy 'copyGradleWrapper'
+}
+
+task addWrappers(dependsOn: [addGradleWrapper]) {
 }
 
 task processFiltered(type: Copy) {
+    ext.srcDir = file('src/main/resources-filtered')
 
-    ext.srcDir = file('filtered')
-
-    inputs.file srcDir
-    inputs.file file("${rootDir}/build.gradle")
-    outputs.dir sourceSets.main.java.outputDir
+    inputs.dir srcDir
+    outputs.dir sourceSets.main.output.resourcesDir
 
     from srcDir
-    into sourceSets.main.java.outputDir
+    into sourceSets.main.output.resourcesDir
 
-    // Use some of the filters provided by Ant
     filter(FixCrLfFilter)
     filter(ReplaceTokens, tokens: [
-            quickstartVersion: version,
-            tapestryReleaseVersion: version,
-            servletApiReleaseVersion: versions.servletapi,
-            testngReleaseVersion: versions.testng,
-            easymockReleaseVersion: versions.easymock,
-            slf4jReleaseVersion: versions.slf4j,
-            year: new GregorianCalendar()[Calendar.YEAR].toString()
+        quickstartVersion: version,
+        tapestryVersion: version,
+        tapestryTestifyVersion: '1.0.4',
+        tapestryXpathVersion: '1.0.1',
+        gebVersion: '2.3.1',
+        groovyVersion: '2.5.6',
+        htmlunitDriverVersion: '2.33.3',
+        jacksonVersion: '2.9.6',
+        jsonVersion: '1.1.2',
+        seleniumVersion: '3.141.59',
+        servletApiVersion: '3.0.1',
+        spockVersion: '1.3-RC1-groovy-2.5',
+        springBootVersion: '2.1.3.RELEASE',
+        yassonVersion: '1.0.1'
     ])
 }
 
-processResources.dependsOn processFiltered
+processResources.dependsOn([addWrappers, processFiltered])
diff --git a/quickstart/filtered/archetype-resources/build.gradle b/quickstart/filtered/archetype-resources/build.gradle
deleted file mode 100644
index a6889a5..0000000
--- a/quickstart/filtered/archetype-resources/build.gradle
+++ /dev/null
@@ -1,93 +0,0 @@
-description = "${artifactId} application"
-
-apply plugin: "war"
-apply plugin: "java"
-apply plugin: "gretty"
-
-sourceCompatibility = "1.8"
-targetCompatibility = "1.8"
-
-group = "${groupId}"
-version = "${version}"
-
-repositories {
-    mavenLocal()
-
-    mavenCentral()
-
-    // All things JBoss/Hibernate
-    maven {
-        name "JBoss"
-        url "http://repository.jboss.org/nexus/content/groups/public/"
-    }
-        
-
-    // For access to Apache Staging (Preview) packages
-    maven {
-        name "Apache Staging"
-        url "https://repository.apache.org/content/groups/staging"
-    }
-}
-
-// This simulates Maven's "provided" scope, until it is officially supported by Gradle
-// See http://jira.codehaus.org/browse/GRADLE-784
-
-configurations {
-    provided
-}
-
-sourceSets {
-    main {
-        compileClasspath += [configurations.provided]
-        // To give the same path as IDEA has
-        // output.resourcesDir = 'build/production/${artifactId}'
-        // output.classesDir = 'build/production/${artifactId}'
-    }
-    test {
-        compileClasspath += [configurations.provided]
-        runtimeClasspath += [configurations.provided]
-    }
-}
-
-dependencies {
-
-    compile "org.apache.tapestry:tapestry-core:@tapestryReleaseVersion@"
-
-    // Uncomment this to add support for file uploads:
-    // compile "org.apache.tapestry:tapestry-upload:@tapestryReleaseVersion@"
-
-    // CoffeeScript & Less support, plus resource minification:
-    compile "org.apache.tapestry:tapestry-webresources:@tapestryReleaseVersion@"
-
-    test "org.apache.tapestry:tapestry-test:@tapestryReleaseVersion@"
-
-    // Log implementation choose one:
-    // Log4j 1.x
-    runtime "log4j:log4j:1.2.17"
-    runtime "org.slf4j:slf4j-log4j12:@slf4jReleaseVersion@"
-    // Logback
-    // runtime "ch.qos.logback:logback-classic:1.0.13"
-
-    provided "javax.servlet:javax.servlet-api:@servletApiReleaseVersion@"
-}
-
-test {
-    useTestNG()
-
-    options.suites("src/test/conf/testng.xml")
-
-    systemProperties["tapestry.service-reloading-enabled"] = "false"
-    systemProperties["tapestry.execution-mode"] = "development"
-
-    maxHeapSize = "600M"
-
-    jvmArgs("-XX:MaxPermSize=256M")
-
-    enableAssertions = true
-}
-
-task wrapper(type: Wrapper) {
-    gradleVersion = '4.3.1'
-}
-
-// TODO: Configure execution mode for jettyRun task
diff --git a/quickstart/filtered/archetype-resources/pom.xml b/quickstart/filtered/archetype-resources/pom.xml
deleted file mode 100644
index 28ff3e0..0000000
--- a/quickstart/filtered/archetype-resources/pom.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>${groupId}</groupId>
-    <artifactId>${artifactId}</artifactId>
-    <version>${version}</version>
-    <packaging>war</packaging>
-    <name>${artifactId} Tapestry 5 Application</name>
-    #set( $D = '$' )
-    <dependencies>
-        <!-- To set up an application with a database, change the artifactId below to
-             tapestry-hibernate, and add a dependency on your JDBC driver. You'll also
-             need to add Hibernate configuration files, such as hibernate.cfg.xml. -->
-        <dependency>
-            <groupId>org.apache.tapestry</groupId>
-            <artifactId>tapestry-core</artifactId>
-            <version>${D}{tapestry-release-version}</version>
-        </dependency>
-
-        <!-- Include the Log4j implementation for the SLF4J logging framework -->
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${D}{slf4j-release-version}</version>
-        </dependency>
-
-
-        <dependency>
-            <groupId>org.apache.tapestry</groupId>
-            <artifactId>tapestry-webresources</artifactId>
-            <version>${D}{tapestry-release-version}</version>
-        </dependency>
-
-        <!-- Uncomment this to add support for file uploads: -->
-        <!--
-         <dependency>
-            <groupId>org.apache.tapestry</groupId>
-            <artifactId>tapestry-upload</artifactId>
-            <version>${D}{tapestry-release-version}</version>
-        </dependency>
-        -->
-
-        <!-- A dependency on either JUnit or TestNG is required, or the surefire plugin (which runs the tests)
-will fail, preventing Maven from packaging the WAR. Tapestry includes a large number
-of testing facilities designed for use with TestNG (http://testng.org/), so it's recommended. -->
-        <dependency>
-            <groupId>org.testng</groupId>
-            <artifactId>testng</artifactId>
-            <version>${D}{testng-release-version}</version>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.tapestry</groupId>
-            <artifactId>tapestry-test</artifactId>
-            <version>${D}{tapestry-release-version}</version>
-            <scope>test</scope>
-        </dependency>
-
-        <!-- Provided by the servlet container, but sometimes referenced in the application
-       code. -->
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
-            <version>${D}{servlet-api-release-version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <!-- Provide dependency to the Tapestry javadoc taglet which replaces the Maven component report -->
-        <dependency>
-            <groupId>org.apache.tapestry</groupId>
-            <artifactId>tapestry-javadoc</artifactId>
-            <version>${D}{tapestry-release-version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-    </dependencies>
-    <build>
-        <finalName>${artifactId}</finalName>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <version>2.3.2</version>
-                <configuration>
-                    <source>1.6</source>
-                    <target>1.6</target>
-                    <optimize>true</optimize>
-                </configuration>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.7.2</version>
-                <configuration>
-                    <systemPropertyVariables>
-                        <tapestry.execution-mode>Qa</tapestry.execution-mode>
-                    </systemPropertyVariables>
-                </configuration>
-            </plugin>
-
-            <!-- Run the application using "mvn jetty:run" -->
-            <plugin>
-                <groupId>org.mortbay.jetty</groupId>
-                <artifactId>maven-jetty-plugin</artifactId>
-                <version>6.1.16</version>
-                <configuration>
-                    <!-- Log to the console. -->
-                    <requestLog implementation="org.mortbay.jetty.NCSARequestLog">
-                        <!-- This doesn't do anything for Jetty, but is a workaround for a Maven bug
-                             that prevents the requestLog from being set. -->
-                        <append>true</append>
-                    </requestLog>
-                    <systemProperties>
-                        <systemProperty>
-                            <name>tapestry.execution-mode</name>
-                            <value>development</value>
-                        </systemProperty>
-                    </systemProperties>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <reporting/>
-
-    <repositories>
-
-      <repository>
-            <id>jboss</id>
-            <url>http://repository.jboss.org/nexus/content/groups/public/</url>
-        </repository>
-
-        <!-- This repository is only needed when the Tapestry version is a preview release, rather
-             than a final release. -->
-        <repository>
-            <id>apache-staging</id>
-            <url>https://repository.apache.org/content/groups/staging/</url>
-        </repository>
-    </repositories>
-
-    <properties>
-        <tapestry-release-version>@tapestryReleaseVersion@</tapestry-release-version>
-        <servlet-api-release-version>@servletApiReleaseVersion@</servlet-api-release-version>
-        <testng-release-version>@testngReleaseVersion@</testng-release-version>
-        <slf4j-release-version>@slf4jReleaseVersion@</slf4j-release-version>
-
-    </properties>
-</project>
diff --git a/quickstart/filtered/archetype-resources/src/main/java/components/Layout.java b/quickstart/filtered/archetype-resources/src/main/java/components/Layout.java
deleted file mode 100644
index eaa8301..0000000
--- a/quickstart/filtered/archetype-resources/src/main/java/components/Layout.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package ${package}.components;
-
-import org.apache.tapestry5.*;
-import org.apache.tapestry5.alerts.AlertManager;
-import org.apache.tapestry5.annotations.*;
-import org.apache.tapestry5.corelib.components.Form;
-import org.apache.tapestry5.corelib.components.PasswordField;
-import org.apache.tapestry5.corelib.components.TextField;
-import org.apache.tapestry5.corelib.components.Zone;
-import org.apache.tapestry5.ioc.annotations.*;
-import org.apache.tapestry5.BindingConstants;
-import org.apache.tapestry5.SymbolConstants;
-
-/**
- * Layout component for pages of application test-project.
- */
-@Import(module="bootstrap/collapse")
-public class Layout
-{
-  @Inject
-  private ComponentResources resources;
-
-  /**
-   * The page title, for the <title> element and the <h1> element.
-   */
-  @Property
-  @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL)
-  private String title;
-
-  @Property
-  private String pageName;
-
-  @Property
-  @Inject
-  @Symbol(SymbolConstants.APPLICATION_VERSION)
-  private String appVersion;
-
-  public String getClassForPageName()
-  {
-    return resources.getPageName().equalsIgnoreCase(pageName)
-        ? "active"
-        : null;
-  }
-
-  public String[] getPageNames()
-  {
-    return new String[]{"Index", "About", "Contact"};
-  }
-
-}
\ No newline at end of file
diff --git a/quickstart/filtered/archetype-resources/src/main/java/pages/About.java b/quickstart/filtered/archetype-resources/src/main/java/pages/About.java
deleted file mode 100644
index a30b35d..0000000
--- a/quickstart/filtered/archetype-resources/src/main/java/pages/About.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package ${package}.pages;
-
-import org.apache.tapestry5.annotations.PageActivationContext;
-
-public class About
-{
-  @PageActivationContext
-  private String learn;
-
-
-  public String getLearn() {
-    return learn;
-  }
-
-  public void setLearn(String learn) {
-    this.learn = learn;
-  }
-}
\ No newline at end of file
diff --git a/quickstart/filtered/archetype-resources/src/main/java/pages/Contact.java b/quickstart/filtered/archetype-resources/src/main/java/pages/Contact.java
deleted file mode 100644
index a445b3e..0000000
--- a/quickstart/filtered/archetype-resources/src/main/java/pages/Contact.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package ${package}.pages;
-
-public class Contact
-{
-
-}
diff --git a/quickstart/filtered/archetype-resources/src/main/java/pages/Index.java b/quickstart/filtered/archetype-resources/src/main/java/pages/Index.java
deleted file mode 100644
index 084c532..0000000
--- a/quickstart/filtered/archetype-resources/src/main/java/pages/Index.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package ${package}.pages;
-
-
-import org.apache.tapestry5.Block;
-import org.apache.tapestry5.EventContext;
-import org.apache.tapestry5.SymbolConstants;
-import org.apache.tapestry5.annotations.InjectPage;
-import org.apache.tapestry5.annotations.Log;
-import org.apache.tapestry5.annotations.Property;
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.annotations.Symbol;
-import org.apache.tapestry5.services.HttpError;
-import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
-import org.slf4j.Logger;
-
-import java.util.Date;
-
-/**
- * Start page of application ${artifactId}.
- */
-public class Index
-{
-  @Inject
-  private Logger logger;
-
-  @Inject
-  private AjaxResponseRenderer ajaxResponseRenderer;
-
-  @Property
-  @Inject
-  @Symbol(SymbolConstants.TAPESTRY_VERSION)
-  private String tapestryVersion;
-
-  @InjectPage
-  private About about;
-
-  @Inject
-  private Block block;
-
-
-  // Handle call with an unwanted context
-  Object onActivate(EventContext eventContext)
-  {
-    return eventContext.getCount() > 0 ?
-        new HttpError(404, "Resource not found") :
-        null;
-  }
-
-
-  Object onActionFromLearnMore()
-  {
-    about.setLearn("LearnMore");
-
-    return about;
-  }
-
-  @Log
-  void onComplete()
-  {
-    logger.info("Complete call on Index page");
-  }
-
-  @Log
-  void onAjax()
-  {
-    logger.info("Ajax call on Index page");
-
-    ajaxResponseRenderer.addRender("middlezone", block);
-  }
-
-
-  public Date getCurrentTime()
-  {
-    return new Date();
-  }
-}
\ No newline at end of file
diff --git a/quickstart/filtered/archetype-resources/src/main/java/pages/Login.java b/quickstart/filtered/archetype-resources/src/main/java/pages/Login.java
deleted file mode 100644
index 2fa162d..0000000
--- a/quickstart/filtered/archetype-resources/src/main/java/pages/Login.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package ${package}.pages;
-
-import org.apache.tapestry5.alerts.AlertManager;
-import org.apache.tapestry5.annotations.InjectComponent;
-import org.apache.tapestry5.annotations.Property;
-import org.apache.tapestry5.corelib.components.Form;
-import org.apache.tapestry5.corelib.components.PasswordField;
-import org.apache.tapestry5.corelib.components.TextField;
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.slf4j.Logger;
-
-public class Login
-{
-  @Inject
-  private Logger logger;
-
-  @Inject
-  private AlertManager alertManager;
-
-  @InjectComponent
-  private Form login;
-  
-  @InjectComponent("email")
-  private TextField emailField;
-  
-  @InjectComponent("password")
-  private PasswordField passwordField;
-
-  @Property
-  private String email;
-
-  @Property
-  private String password;
-
-
-
-  void onValidateFromLogin()
-  {
-    if ( !email.equals("users@tapestry.apache.org"))
-      login.recordError(emailField, "Try with user: users@tapestry.apache.org");
-
-    if ( !password.equals("Tapestry5"))
-      login.recordError(passwordField, "Try with password: Tapestry5");
-  }
-
-  Object onSuccessFromLogin()
-  {
-    logger.info("Login successful!");
-    alertManager.success("Welcome aboard!");
-
-    return Index.class;
-  }
-
-  void onFailureFromLogin()
-  {
-    logger.warn("Login error!");
-    alertManager.error("I'm sorry but I can't log you in!");
-  }
-
-}
\ No newline at end of file
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/components/Layout.tml b/quickstart/filtered/archetype-resources/src/main/resources/components/Layout.tml
deleted file mode 100644
index cdd27ff..0000000
--- a/quickstart/filtered/archetype-resources/src/main/resources/components/Layout.tml
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
-        >
-<head>
-    <meta charset="utf-8"/>
-    <title>${D}{title}</title>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <meta name="description" content=""/>
-    <meta name="author" content=""/>
-    <!-- Fav and touch icons -->
-    <link rel="shortcut icon" href="${D}{asset:context:/favicon.ico}"/>
-</head>
-
-<body>
-
-<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
-    <div class="container">
-	    <div class="navbar-header">
-            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
-                <span class="sr-only">Toggle navigation</span>
-                <span class="icon-bar"></span>
-                <span class="icon-bar"></span>
-                <span class="icon-bar"></span>
-            </button>
-            <t:pagelink page="index" class="navbar-brand">app</t:pagelink>
-        </div>
-        <div class="navbar-collapse collapse">
-            <ul class="nav navbar-nav">
-                <t:loop source="pageNames" value="pageName">
-                    <t:any element="li" class="prop:classForPageName">
-                        <t:pagelink page="prop:pageName">${pageName}</t:pagelink>
-                    </t:any>
-                </t:loop>
-            </ul>
-            <span class="navbar-right">
-                <li>
-                    <t:pagelink page="login" class="btn btn-default navbar-btn">Sign in</t:pagelink>
-               	</li>
-            </span>
-
-        </div><!--/.nav-collapse -->
-    </div>
-</div>
-
-<div class="container">
-    <div class="row">
-        <div class="span12">
-            <t:alerts/>
-        </div>
-    </div>
-</div>
-
-<div class="container">
-
-    <t:body />
-
-    <hr />
-
-    <footer>
-        <p>&copy; Your Company 2015</p>
-    </footer>
-
-</div> <!-- /container -->
-
-</body>
-</html>
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/log4j.properties b/quickstart/filtered/archetype-resources/src/main/resources/log4j.properties
deleted file mode 100644
index 54d0f18..0000000
--- a/quickstart/filtered/archetype-resources/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,44 +0,0 @@
-# Default to info level output; this is very handy if you eventually use Hibernate as well.
-log4j.rootCategory=info, A1
-
-# A1 is set to be a ConsoleAppender.
-log4j.appender.A1=org.apache.log4j.ConsoleAppender
-
-# A1 uses PatternLayout.
-log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-log4j.appender.A1.layout.ConversionPattern=[%p] %c{2} %m%n
-
-# Service category names are the name of the defining module class
-# and then the service id.
-log4j.category.${package}.services.AppModule.TimingFilter=info
-
-# Outputs a list of pages, components and mixins at startup.
-log4j.category.org.apache.tapestry5.modules.TapestryModule.ComponentClassResolver=info
-
-# Outputs startup statistics; elapsed time to setup and initialize the registry, a list of
-# available services, and a launch banner that includes the Tapestry version number.
-log4j.category.org.apache.tapestry5.TapestryFilter=info
-
-
-# Turning on debug mode for a page's or component's transformer logger
-# will show all of the code changes that occur when the
-# class is loaded.
-
-# log4j.category.tapestry.transformer.${package}.pages.Index=debug
-
-# Turning on debug mode for a component's events logger will show all the events triggered on the
-# component, and which component methods are invoked as a result.
-
-# log4j.category.tapestry.events.${package}.pages.Index=debug
-
-# Turning on trace mode for a page's render logger provides extended information about every step
-# in rendering (this is not generally helpful).  Turning on debug mode will add a one-line
-# summary that includes the elapsed render time, which can be useful in tracking down
-# performance issues.
-
-# log4j.category.tapestry.render.${package}.pages.Index=debug
-
-# Turn on some verbose debugging about everything in the application. This is nice initially,
-# while getting everything set up.  You'll probably want to remove this once you are 
-# up and running, replacing it with more selective debugging output.
-log4j.category.${package}=debug
\ No newline at end of file
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/logback.xml b/quickstart/filtered/archetype-resources/src/main/resources/logback.xml
deleted file mode 100644
index 0870bf0..0000000
--- a/quickstart/filtered/archetype-resources/src/main/resources/logback.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<configuration>
-    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
-        <layout class="ch.qos.logback.classic.PatternLayout">
-            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
-        </layout>
-    </appender>
-
-    <logger name="${package}" level="TRACE"/>
-
-    <root level="info">
-        <appender-ref ref="STDOUT"/>
-    </root>
-</configuration>
\ No newline at end of file
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/pages/About.tml b/quickstart/filtered/archetype-resources/src/main/resources/pages/About.tml
deleted file mode 100644
index 1cbe73e..0000000
--- a/quickstart/filtered/archetype-resources/src/main/resources/pages/About.tml
+++ /dev/null
@@ -1,23 +0,0 @@
-<html t:type="layout" title="About ${artifactId}"
-      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
-      xmlns:p="tapestry:parameter">
-
-    <div class="row">
-        <div class="span12">
-            <p>About ${artifactId} application ...</p>
-        </div>
-    </div>
-
-    <t:if test="learn">
-        <div class="row">
-            <div class="span12">
-                <p>
-                    To learn more go to
-                    <a href="http://tapestry.apache.org">Tapestry home</a>
-                    and start typing...
-                </p>
-            </div>
-        </div>
-    </t:if>
-
-</html>
\ No newline at end of file
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/pages/Contact.tml b/quickstart/filtered/archetype-resources/src/main/resources/pages/Contact.tml
deleted file mode 100644
index 3ceda94..0000000
--- a/quickstart/filtered/archetype-resources/src/main/resources/pages/Contact.tml
+++ /dev/null
@@ -1,7 +0,0 @@
-<html t:type="layout" title="Contact ${groupId}"
-      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
-      xmlns:p="tapestry:parameter">
-
-    <p>Contact ${groupId} ...</p>
-
-</html>
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/pages/Error404.tml b/quickstart/filtered/archetype-resources/src/main/resources/pages/Error404.tml
deleted file mode 100644
index b7708bf..0000000
--- a/quickstart/filtered/archetype-resources/src/main/resources/pages/Error404.tml
+++ /dev/null
@@ -1,11 +0,0 @@
-<html t:type="layout" title="Not found ${artifactId}"
-      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
-      xmlns:p="tapestry:parameter">
-
-    <div class="row">
-        <div class="span12">
-            <h1>Requested page not found!</h1>
-        </div>
-    </div>
-
-</html>
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/pages/Index.tml b/quickstart/filtered/archetype-resources/src/main/resources/pages/Index.tml
deleted file mode 100644
index c670fcd..0000000
--- a/quickstart/filtered/archetype-resources/src/main/resources/pages/Index.tml
+++ /dev/null
@@ -1,46 +0,0 @@
-<html t:type="layout" title="${artifactId} Index"
-      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
-        >
-
-    <!-- Most of the page content, including <head>, <body>, etc. tags, comes from Layout.tml -->
-
-    <!-- Main hero unit for a primary marketing message or call to action -->
-    <div class="hero-unit">
-        <p>
-            <img src="${D}{asset:context:images/tapestry.png}"
-                 alt="${D}{message:greeting}" title="${D}{message:greeting}"/>
-        </p>
-        <h3>${D}{message:greeting}</h3>
-        <p>The current time is: <strong>${D}{currentTime}</strong></p>
-        <p>
-            This is a template for a simple marketing or informational website. It includes a large callout called
-            the hero unit and three supporting pieces of content. Use it as a starting point to create something
-            more unique.
-        </p>
-        <p><t:actionlink t:id="learnmore" class="btn btn-primary btn-large">Learn more &raquo;</t:actionlink></p>
-    </div>
-
-    <!-- Example row of columns -->
-    <div class="row">
-        <div class="span4">
-            <h2>Normal link</h2>
-            <p>Clink the bottom link and the page refresh with event <code>complete</code></p>
-            <p><t:eventlink event="complete" class="btn btn-default">Complete&raquo;</t:eventlink></p>
-        </div>
-        <t:zone t:id="middlezone" class="span4">
-
-        </t:zone>
-        <div class="span4">
-            <h2>Ajax link</h2>
-            <p>Click the bottom link to update just the middle column with Ajax call with event <code>ajax</code></p>
-            <p><t:eventlink event="ajax" zone="middlezone" class="btn btn-default">Ajax&raquo;</t:eventlink></p>
-        </div>
-    </div>
-
-    <t:block t:id="block">
-        <h2>Ajax updated</h2>
-        <p>I'v been updated through AJAX call</p>
-        <p>The current time is: <strong>${D}{currentTime}</strong></p>
-    </t:block>
-
-</html>
\ No newline at end of file
diff --git a/quickstart/src/main/resources-filtered/archetype-resources/build.gradle b/quickstart/src/main/resources-filtered/archetype-resources/build.gradle
new file mode 100644
index 0000000..f4d8748
--- /dev/null
+++ b/quickstart/src/main/resources-filtered/archetype-resources/build.gradle
@@ -0,0 +1,161 @@
+plugins {
+    id 'eclipse'
+    id 'idea'
+    id 'java'
+    id 'groovy'
+    id 'application'
+}
+
+description = "${artifactId} application"
+group = "${groupId}"
+version = "${version}"
+mainClassName = '${package}.App'
+
+sourceCompatibility = "1.8"
+targetCompatibility = "1.8"
+
+ext {
+    versions = [
+        tapestry: "@tapestryVersion@",
+        tapestryTestify: "@tapestryTestifyVersion@",
+        tapestryXpath: "@tapestryXpathVersion@",
+        geb: "@gebVersion@",
+        groovy: "@groovyVersion@",
+        htmlunitDriver: "@htmlunitDriverVersion@",
+        jackson: "@jacksonVersion@",
+        json: "@jsonVersion@",
+        selenium: "@seleniumVersion@",
+        servletApi: "@servletApiVersion@",
+        spock: "@spockVersion@",
+        springBoot: "@springBootVersion@",
+        yasson: "@yassonVersion@"
+    ]
+}
+
+repositories {
+    mavenCentral()
+    maven {
+      url 'https://repository.apache.org/content/repositories/staging/'
+    }
+}
+
+configurations {
+    provided
+    testUnitTapestryCompile.extendsFrom(testImplementation, provided)
+    testUnitTapestryRuntime.extendsFrom(testRuntimeOnly, provided)
+    testFunctionalTapestryCompile.extendsFrom(testImplementation, provided)
+    testFunctionalTapestryRuntime.extendsFrom(testRuntimeOnly, provided)
+}
+
+sourceSets {
+    main {
+        compileClasspath += configurations.provided
+        // To give the same path as IDEA has
+        // output.resourcesDir = 'build/production/${artifactId}'
+        // output.classesDir = 'build/production/${artifactId}'
+    }
+    test {
+        compileClasspath += configurations.provided
+        runtimeClasspath += configurations.provided
+        groovy {
+            exclude '**/tapestry/unit/**'
+            exclude '**/tapestry/functional/**'
+        }
+    }
+    testUnitTapestry {
+        groovy.srcDir file('src/test/groovy')
+        resources.srcDir file('src/test/resources')
+        compileClasspath += sourceSets.main.output + configurations.testRuntimeClasspath + configurations.provided
+        runtimeClasspath += output + compileClasspath + configurations.provided
+        groovy {
+            include '**/tapestry/unit/**'
+        }
+    }
+    testFunctionalTapestry {
+        groovy.srcDir file('src/test/groovy')
+        resources.srcDir file('src/test/resources')
+        compileClasspath += sourceSets.main.output + configurations.testRuntimeClasspath + configurations.provided
+        runtimeClasspath += output + compileClasspath + configurations.provided
+        groovy {
+            include '**/tapestry/functional/**'
+        }
+    }
+}
+
+dependencies {
+    implementation platform("org.springframework.boot:spring-boot-dependencies:${versions.springBoot}")
+
+    // Spring Boot
+    def excludeSpringBootStarterLogging = { exclude(group: 'org.springframework.boot', module: 'spring-boot-starter-logging') }
+
+    implementation("org.springframework.boot:spring-boot-starter", excludeSpringBootStarterLogging)
+    implementation("org.springframework.boot:spring-boot-starter-web", excludeSpringBootStarterLogging)
+    implementation("org.springframework.boot:spring-boot-starter-log4j2")
+
+    // Apache Tapestry
+    implementation("org.apache.tapestry:tapestry-core:${versions.tapestry}")
+
+    // CoffeeScript & Less support, plus resource minification
+    implementation("org.apache.tapestry:tapestry-webresources:${versions.tapestry}")
+
+    // Uncomment this to add support for spring, hibernate, bean validation and uploads
+    //implementation("org.apache.tapestry:tapestry-spring:$versions.tapestry")
+    //implementation("org.apache.tapestry:tapestry-hibernate:$versions.tapestry")
+    //implementation("org.apache.tapestry:tapestry-beanvalidator:$versions.tapestry")
+    //implementation("org.apache.tapestry:tapestry-upload:${tapestry}")
+
+    // Test
+    def excludeTestng = { exclude(group: 'org.testng'); }
+
+    testImplementation("org.springframework.boot:spring-boot-starter-test", excludeSpringBootStarterLogging)
+    testImplementation("org.spockframework:spock-core:${versions.spock}")
+    testImplementation("org.spockframework:spock-spring:${versions.spock}")
+    testImplementation("org.codehaus.groovy:groovy-all:${versions.groovy}", excludeTestng)
+
+    // Test Unit Tapestry
+    testUnitTapestryCompile("org.apache.tapestry:tapestry-test:${versions.tapestry}", excludeTestng)
+    testUnitTapestryCompile("net.sourceforge.tapestrytestify:tapestry-testify:${versions.tapestryTestify}", excludeTestng)
+    testUnitTapestryCompile("net.sourceforge.tapestryxpath:tapestry-xpath:${versions.tapestryXpath}", excludeTestng)
+
+    // Test Functional Tapestry
+    testFunctionalTapestryCompile("org.gebish:geb-spock:${versions.geb}")
+    testFunctionalTapestryCompile("org.seleniumhq.selenium:selenium-support:${versions.selenium}")
+    testFunctionalTapestryCompile("org.seleniumhq.selenium:htmlunit-driver:${versions.htmlunitDiver}")
+
+    // Miscellaneous
+    runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl")
+    runtimeOnly("org.eclipse:yasson:${versions.yasson}")
+    runtimeOnly("org.glassfish:javax.json:${versions.json}")
+    runtimeOnly("com.fasterxml.jackson.core:jackson-databind:${versions.jackson}")
+    runtimeOnly("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${versions.jackson}")
+
+    provided("javax.servlet:javax.servlet-api:${versions.servletApi}")
+}
+
+run {
+    systemProperty 'tapestry.execution-mode', System.getProperty('tapestry.execution-mode')
+}
+
+test {
+}
+
+task testUnitTapestry(type: Test) {
+    group = 'Verification'
+    description = 'Runs the tapestry unit tests.'
+    systemProperty 'tapestry.service-reloading-enabled', 'false'
+    systemProperty 'tapestry.execution-mode', 'development'
+    systemProperty 'geb.driver', 'htmlunit'
+    testClassesDirs = sourceSets.testUnitTapestry.output.classesDirs
+    classpath = project.sourceSets.testUnitTapestry.runtimeClasspath
+    include '**/*Spec*'
+}
+
+task testFunctionalTapestry(type: Test) {
+    group = 'Verification'
+    description = 'Runs the tapestry functional tests.'
+    systemProperty 'tapestry.service-reloading-enabled', 'false'
+    systemProperty 'tapestry.execution-mode', 'development'
+    systemProperty 'geb.driver', 'htmlunit'
+    testClassesDirs = sourceSets.testFunctionalTapestry.output.classesDirs
+    classpath = project.sourceSets.testFunctionalTapestry.runtimeClasspath
+}
diff --git a/quickstart/src/main/resources-filtered/archetype-resources/pom.xml b/quickstart/src/main/resources-filtered/archetype-resources/pom.xml
new file mode 100644
index 0000000..0a26174
--- /dev/null
+++ b/quickstart/src/main/resources-filtered/archetype-resources/pom.xml
@@ -0,0 +1,207 @@
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0">
+    #set( $D = '$' )
+    <modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.1.3.RELEASE</version>
+		<relativePath/>
+	</parent>
+    <groupId>${groupId}</groupId>
+    <artifactId>${artifactId}</artifactId>
+    <version>${version}</version>
+    <name>${artifactId} Tapestry 5 Application</name>
+	<properties>
+        <java.version>1.8</java.version>
+        <tapestry-version>@tapestryVersion@</tapestry-version>
+        <tapestry-testify-version>@tapestryTestifyVersion@</tapestry-testify-version>
+        <tapestry-xpath-version>@tapestryXpathVersion@</tapestry-xpath-version>
+        <jackson-version>@jacksonVersion@</jackson-version>
+        <geb-version>@gebVersion@</geb-version>
+        <htmlunit-driver-version>@htmlunitDriverVersion@</htmlunit-driver-version>
+        <json-version>@jsonVersion@</json-version>
+        <selenium-version>@seleniumVersion@</selenium-version>
+        <servlet-api-version>@servletApiVersion@</servlet-api-version>
+        <spock-version>@spockVersion@</spock-version>
+        <spring-boot-version>@springBootVersion@</spring-boot-version>
+        <yasson-version>@yassonVersion@</yasson-version>
+	</properties>
+    <repositories>
+        <repository>
+            <id>apache-staging</id>
+            <url>https://repository.apache.org/content/repositories/staging/</url>
+        </repository>
+    </repositories>
+    <dependencies>
+        <!-- Spring -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <!-- Apache Tapestry -->
+        <dependency>
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-core</artifactId>
+            <version>${D}{tapestry-version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <!-- CoffeeScript & Less support, plus resource minification -->
+        <dependency>
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-webresources</artifactId>
+            <version>${D}{tapestry-version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <!-- Uncomment this to add support for hibernate, bean validation and file uploads -->
+        <!--
+        <dependency>
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-hibernate</artifactId>
+            <version>${D}{tapestry-version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-beanvalidator</artifactId>
+            <version>${D}{tapestry-version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-upload</artifactId>
+            <version>${D}{tapestry-version}</version>
+            <scope>compile</scope>
+        </dependency>
+        -->
+        <!-- Unit Testing -->
+        <dependency>
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-test</artifactId>
+            <version>${D}{tapestry-version}</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.testng</groupId>
+                    <artifactId>testng</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>net.sourceforge.tapestrytestify</groupId>
+            <artifactId>tapestry-testify</artifactId>
+            <version>${D}{tapestry-testify-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.sourceforge.tapestryxpath</groupId>
+            <artifactId>tapestry-xpath</artifactId>
+            <version>${D}{tapestry-xpath-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.spockframework</groupId>
+            <artifactId>spock-core</artifactId>
+            <version>${D}{spock-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.spockframework</groupId>
+            <artifactId>spock-spring</artifactId>
+            <version>${D}{spock-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- Integration Testing -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.gebish</groupId>
+            <artifactId>geb-spock</artifactId>
+            <version>${D}{geb-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>selenium-support</artifactId>
+            <version>${D}{selenium-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>htmlunit-driver</artifactId>
+            <version>${D}{htmlunit-driver-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- Miscellaneous -->
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse</groupId>
+            <artifactId>yasson</artifactId>
+            <version>${D}{yasson-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish</groupId>
+            <artifactId>javax.json</artifactId>
+            <version>${D}{json-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${D}{jackson-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-yaml</artifactId>
+            <version>${D}{jackson-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>${D}{servlet-api-version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/quickstart/src/main/resources/META-INF/maven/archetype-metadata.xml b/quickstart/src/main/resources/META-INF/maven/archetype-metadata.xml
index a107b85..7239f18 100644
--- a/quickstart/src/main/resources/META-INF/maven/archetype-metadata.xml
+++ b/quickstart/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -1,88 +1,62 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <archetype-descriptor name="Tapestry 5 Quickstart Project">
     <fileSets>
-        <fileSet filtered="true" packaged="true">
-            <directory>src/main/java</directory>
-            <includes>
-                <include>**/*.java</include>
-            </includes>
-        </fileSet>
-
-        <!-- Currently just a placeholder. -->
-        <fileSet filtered="true" packaged="false">
-            <directory>src/test/java</directory>
-        </fileSet>
-
-        <fileSet filtered="true">
-            <directory>src/main/webapp</directory>
-            <excludes>
-                <exclude>*.ico</exclude>
-                <exclude>**/*.jpg</exclude>
-                <exclude>**/*.gif</exclude>
-                <exclude>**/*.png</exclude>
-                <exclude>**/*.js</exclude>
-                <exclude>**/*.css</exclude>
-            </excludes>
-        </fileSet>
-
-        <!-- Don't want to filter binary files. -->
-
-        <fileSet filtered="false">
-            <directory>src/main/webapp</directory>
-            <includes>
-                <include>*.ico</include>
-                <include>**/*.jpg</include>
-                <include>**/*.gif</include>
-                <include>**/*.png</include>
-                <include>**/*.js</include>
-                <include>**/*.css</include>
-            </includes>
-        </fileSet>
-
-        <!-- This needs to stay at the root. -->
-        <fileSet filtered="true" packaged="false">
-            <directory>src/main/resources</directory>
-            <includes>
-                <include>log4j.properties</include>
-            </includes>
-        </fileSet>
-
-        <!-- The rest should be packaged. -->
-        <fileSet filtered="true" packaged="true">
-            <directory>src/main/resources</directory>
-            <excludes>
-                <exclude>log4j.properties</exclude>
-            </excludes>
-        </fileSet>
-
-        <fileSet filtered="true" packaged="false">
-            <directory>src/test/resources</directory>
-        </fileSet>
-
-        <fileSet filtered="true" packaged="false">
-            <directory>src/test/conf</directory>
-        </fileSet>
-
-        <fileSet filtered="true" packaged="false">
-            <directory>src/site</directory>
-        </fileSet>
-
-        <!-- Now the Gradle stuff -->
-
         <fileSet filtered="true" packaged="false">
             <directory/>
             <includes>
                 <include>build.gradle</include>
             </includes>
         </fileSet>
-
         <fileSet filtered="false" packaged="false">
             <directory/>
             <includes>
-                <include>gradlew*</include>
-                <include>gradle/wrapper/*</include>
+                <include>.gitignore</include>
+                <include>gradlew</include>
+                <include>gradlew.bat</include>
+                <include>gradle/**</include>
+                <include>settings.gradle</include>
             </includes>
         </fileSet>
-
+        <!-- Source Code -->
+        <fileSet filtered="true" packaged="true">
+            <directory>src/main/java</directory>
+            <includes>
+                <include>**/*.java</include>
+            </includes>
+        </fileSet>
+        <!-- Resources -->
+        <fileSet filtered="true" packaged="false">
+            <directory>src/main/resources</directory>
+            <includes>
+                <include>log4j2.yml</include>
+                <include>application.yml</include>
+            </includes>
+        </fileSet>
+        <fileSet filtered="true" packaged="true">
+            <directory>src/main/resources</directory>
+            <includes>
+                <include>components/**</include>
+                <include>pages/**</include>
+            </includes>
+        </fileSet>
+        <fileSet filtered="false" packaged="false">
+            <directory>src/main/</directory>
+            <includes>
+                <include>webapp/**</include>
+            </includes>
+        </fileSet>
+        <!-- Test -->
+        <fileSet filtered="true" packaged="true">
+            <directory>src/test/groovy</directory>
+            <includes>
+                <include>**/*.groovy</include>
+            </includes>
+        </fileSet>
+        <fileSet filtered="false" packaged="false">
+            <directory>src/test/resources</directory>
+            <includes>
+                <include>**/*</include>
+            </includes>
+        </fileSet>
     </fileSets>
-</archetype-descriptor>
\ No newline at end of file
+</archetype-descriptor>
diff --git a/quickstart/src/main/resources/archetype-resources/.gitignore b/quickstart/src/main/resources/archetype-resources/.gitignore
new file mode 100644
index 0000000..f1dc26d
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/.gitignore
@@ -0,0 +1,40 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+#
+*~
+\#*
+.DS_Store
+
+.classpath
+.project
+.settings/
+*.ipr
+*.iml
+*.iws
+
+target/
+out/
+bin/
+build/
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/java/App.java b/quickstart/src/main/resources/archetype-resources/src/main/java/App.java
new file mode 100644
index 0000000..a382c5a
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/App.java
@@ -0,0 +1,25 @@
+package ${package};
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+@SpringBootApplication
+public class App extends SpringBootServletInitializer
+{
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(AppConfiguration.class);
+    }
+
+    public static void main(String[] args) throws Exception
+    {
+        SpringApplication application = new SpringApplication(App.class);
+        application.setApplicationContextClass(AnnotationConfigWebApplicationContext.class);
+        SpringApplication.run(App.class, args);
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/java/AppConfiguration.java b/quickstart/src/main/resources/archetype-resources/src/main/java/AppConfiguration.java
new file mode 100644
index 0000000..3b02a8d
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/AppConfiguration.java
@@ -0,0 +1,49 @@
+package ${package};
+
+import org.apache.tapestry5.TapestryFilter;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.server.ErrorPage;
+import org.springframework.boot.web.servlet.ServletContextInitializer;
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpStatus;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.SessionTrackingMode;
+import java.util.EnumSet;
+
+@Configuration
+@ComponentScan({ "${package}" })
+public class AppConfiguration
+{
+
+    @Bean
+    public ServletContextInitializer initializer()
+    {
+        return new ServletContextInitializer()
+        {
+            @Override
+            public void onStartup(ServletContext servletContext) throws ServletException {
+                servletContext.setInitParameter("tapestry.app-package", "${package}");
+                servletContext.setInitParameter("tapestry.development-modules", "${package}.services.DevelopmentModule");
+                servletContext.setInitParameter("tapestry.qa-modules", "com.foo.services.QaModule");
+                //servletContext.setInitParameter("tapestry.use-external-spring-context", "true");
+                servletContext.addFilter("app", TapestryFilter.class).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR), false, "/*");
+                //servletContext.addFilter("app", TapestrySpringFilter.class).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR), false, "/*");
+                servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));
+            }
+        };
+    }
+
+    @Bean
+    public ConfigurableServletWebServerFactory webServerFactory()
+    {
+        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error404"));
+        return factory;
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/java/components/Layout.java b/quickstart/src/main/resources/archetype-resources/src/main/java/components/Layout.java
new file mode 100644
index 0000000..f6df70c
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/components/Layout.java
@@ -0,0 +1,54 @@
+package ${package}.components;
+
+import org.apache.tapestry5.BindingConstants;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.annotations.Import;
+import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+
+import java.time.LocalDate;
+
+/**
+ * Layout component for pages of application test-project.
+ */
+@Import(module="bootstrap/collapse")
+public class Layout
+{
+    @Inject
+    private ComponentResources resources;
+
+    /**
+    * The page title, for the <title> element and the <h1> element.
+    */
+    @Property
+    @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL)
+    private String title;
+
+    @Property
+    private String pageName;
+
+    @Property
+    @Inject
+    @Symbol(SymbolConstants.APPLICATION_VERSION)
+    private String appVersion;
+
+    public String getClassForPageName()
+    {
+        return resources.getPageName().equalsIgnoreCase(pageName)
+            ? "active"
+            : null;
+    }
+
+    public String[] getPageNames()
+    {
+        return new String[]{"Index", "About"};
+    }
+
+    public int getYear()
+    {
+        return LocalDate.now().getYear();
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/java/pages/About.java b/quickstart/src/main/resources/archetype-resources/src/main/java/pages/About.java
new file mode 100644
index 0000000..067ec3a
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/pages/About.java
@@ -0,0 +1,17 @@
+package ${package}.pages;
+
+import org.apache.tapestry5.annotations.PageActivationContext;
+
+public class About
+{
+    @PageActivationContext
+    private String learn;
+
+    public String getLearn() {
+        return learn;
+    }
+
+    public void setLearn(String learn) {
+        this.learn = learn;
+    }
+}
diff --git a/quickstart/filtered/archetype-resources/src/main/java/pages/Error404.java b/quickstart/src/main/resources/archetype-resources/src/main/java/pages/Error404.java
similarity index 100%
rename from quickstart/filtered/archetype-resources/src/main/java/pages/Error404.java
rename to quickstart/src/main/resources/archetype-resources/src/main/java/pages/Error404.java
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/java/pages/Index.java b/quickstart/src/main/resources/archetype-resources/src/main/java/pages/Index.java
new file mode 100644
index 0000000..9680c36
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/pages/Index.java
@@ -0,0 +1,72 @@
+package ${package}.pages;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tapestry5.Block;
+import org.apache.tapestry5.EventContext;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.annotations.InjectPage;
+import org.apache.tapestry5.annotations.Log;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.services.HttpError;
+import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
+
+import java.time.ZonedDateTime;
+
+/**
+ * Start page of application ${artifactId}.
+ */
+public class Index
+{
+    private static final Logger logger = LogManager.getLogger(Index.class);
+
+    @Inject
+    private AjaxResponseRenderer ajaxResponseRenderer;
+
+    @Property
+    @Inject
+    @Symbol(SymbolConstants.TAPESTRY_VERSION)
+    private String tapestryVersion;
+
+    @InjectPage
+    private About about;
+
+    @Inject
+    private Block block;
+
+    // Handle call with an unwanted context
+    Object onActivate(EventContext eventContext)
+    {
+        return eventContext.getCount() > 0 ?
+            new HttpError(404, "Resource not found") :
+            null;
+    }
+
+    Object onActionFromLearnMore()
+    {
+        about.setLearn("LearnMore");
+
+        return about;
+    }
+
+    @Log
+    void onComplete()
+    {
+      logger.info("Complete call on Index page");
+    }
+
+    @Log
+    void onAjax()
+    {
+        logger.info("Ajax call on Index page");
+
+        ajaxResponseRenderer.addRender("middlezone", block);
+    }
+
+    public ZonedDateTime getCurrentTime()
+    {
+        return ZonedDateTime.now();
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/java/pages/Login.java b/quickstart/src/main/resources/archetype-resources/src/main/java/pages/Login.java
new file mode 100644
index 0000000..5b9f504
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/pages/Login.java
@@ -0,0 +1,56 @@
+package ${package}.pages;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tapestry5.alerts.AlertManager;
+import org.apache.tapestry5.annotations.InjectComponent;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.corelib.components.Form;
+import org.apache.tapestry5.corelib.components.PasswordField;
+import org.apache.tapestry5.corelib.components.TextField;
+import org.apache.tapestry5.ioc.annotations.Inject;
+
+public class Login
+{
+    private static final Logger logger = LogManager.getLogger(Login.class);
+
+    @Inject
+    private AlertManager alertManager;
+
+    @InjectComponent
+    private Form login;
+
+    @InjectComponent("email")
+    private TextField emailField;
+
+    @InjectComponent("password")
+    private PasswordField passwordField;
+
+    @Property
+    private String email;
+
+    @Property
+    private String password;
+
+    void onValidateFromLogin()
+    {
+        if (!email.equals("users@tapestry.apache.org"))
+            login.recordError(emailField, "Try with user: users@tapestry.apache.org");
+
+        if (!password.equals("Tapestry5"))
+            login.recordError(passwordField, "Try with password: Tapestry5");
+    }
+
+    Object onSuccessFromLogin()
+    {
+        logger.info("Login successful!");
+        alertManager.success("Welcome aboard!");
+        return Index.class;
+    }
+
+    void onFailureFromLogin()
+    {
+        logger.warn("Login error!");
+        alertManager.error("I'm sorry but I can't log you in!");
+    }
+}
diff --git a/quickstart/filtered/archetype-resources/src/main/java/services/AppModule.java b/quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java
similarity index 89%
rename from quickstart/filtered/archetype-resources/src/main/java/services/AppModule.java
rename to quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java
index dc19a51..a7e86d2 100644
--- a/quickstart/filtered/archetype-resources/src/main/java/services/AppModule.java
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java
@@ -1,8 +1,6 @@
 package ${package}.services;
 
-import java.io.IOException;
-
-import org.apache.tapestry5.*;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ioc.MappedConfiguration;
 import org.apache.tapestry5.ioc.OrderedConfiguration;
 import org.apache.tapestry5.ioc.ServiceBinder;
@@ -10,12 +8,15 @@
 import org.apache.tapestry5.ioc.annotations.Local;
 import org.apache.tapestry5.ioc.services.ApplicationDefaults;
 import org.apache.tapestry5.ioc.services.SymbolProvider;
-import org.apache.tapestry5.services.*;
-import org.apache.tapestry5.services.javascript.JavaScriptStack;
-import org.apache.tapestry5.services.javascript.StackExtension;
-import org.apache.tapestry5.services.javascript.StackExtensionType;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.RequestFilter;
+import org.apache.tapestry5.services.RequestHandler;
+import org.apache.tapestry5.services.Response;
 import org.slf4j.Logger;
 
+import java.io.IOException;
+import java.util.UUID;
+
 /**
  * This module is automatically included as part of the Tapestry IoC Registry, it's a good place to
  * configure and extend Tapestry, or to place your own service definitions.
@@ -32,8 +33,7 @@
         // invoking the constructor.
     }
 
-    public static void contributeFactoryDefaults(
-        MappedConfiguration<String, Object> configuration)
+    public static void contributeFactoryDefaults(MappedConfiguration<String, Object> configuration)
     {
         // The values defined here (as factory default overrides) are themselves
         // overridden with application defaults by DevelopmentModule and QaModule.
@@ -47,8 +47,7 @@
         configuration.override(SymbolConstants.PRODUCTION_MODE, false);
     }
 
-    public static void contributeApplicationDefaults(
-        MappedConfiguration<String, Object> configuration)
+    public static void contributeApplicationDefaults(MappedConfiguration<String, Object> configuration)
     {
         // Contributions to ApplicationDefaults will override any contributions to
         // FactoryDefaults (with the same key). Here we're restricting the supported
@@ -57,9 +56,9 @@
         // the first locale name is the default when there's no reasonable match).
         configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en");
 
-              // You should change the passphrase immediately; the HMAC passphrase is used to secure
+        // You should change the passphrase immediately; the HMAC passphrase is used to secure
         // the hidden field data stored in forms to encrypt and digitally sign client-side data.
-        configuration.add(SymbolConstants.HMAC_PASSPHRASE, "change this immediately");
+        configuration.add(SymbolConstants.HMAC_PASSPHRASE, "change this immediately-" + UUID.randomUUID());
     }
 
 	/**
@@ -129,8 +128,7 @@
      */
     @Contribute(RequestHandler.class)
     public void addTimingFilter(OrderedConfiguration<RequestFilter> configuration,
-     @Local
-     RequestFilter filter)
+        @Local RequestFilter filter)
     {
         // Each contribution to an ordered configuration has a name, When necessary, you may
         // set constraints to precisely control the invocation order of the contributed filter
diff --git a/quickstart/filtered/archetype-resources/src/main/java/services/DevelopmentModule.java b/quickstart/src/main/resources/archetype-resources/src/main/java/services/DevelopmentModule.java
similarity index 64%
rename from quickstart/filtered/archetype-resources/src/main/java/services/DevelopmentModule.java
rename to quickstart/src/main/resources/archetype-resources/src/main/java/services/DevelopmentModule.java
index 61dc38e..b80648d 100644
--- a/quickstart/filtered/archetype-resources/src/main/java/services/DevelopmentModule.java
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/services/DevelopmentModule.java
@@ -1,17 +1,7 @@
 package ${package}.services;
 
-import java.io.IOException;
-
-import org.apache.tapestry5.*;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ioc.MappedConfiguration;
-import org.apache.tapestry5.ioc.OrderedConfiguration;
-import org.apache.tapestry5.ioc.ServiceBinder;
-import org.apache.tapestry5.ioc.annotations.Local;
-import org.apache.tapestry5.services.Request;
-import org.apache.tapestry5.services.RequestFilter;
-import org.apache.tapestry5.services.RequestHandler;
-import org.apache.tapestry5.services.Response;
-import org.slf4j.Logger;
 
 /**
  * This module is automatically included as part of the Tapestry IoC Registry if <em>tapestry.execution-mode</em>
@@ -19,8 +9,7 @@
  */
 public class DevelopmentModule
 {
-    public static void contributeApplicationDefaults(
-            MappedConfiguration<String, Object> configuration)
+    public static void contributeApplicationDefaults(MappedConfiguration<String, Object> configuration)
     {
         // The factory default is true but during the early stages of an application
         // overriding to false is a good idea. In addition, this is often overridden
diff --git a/quickstart/filtered/archetype-resources/src/main/java/services/QaModule.java b/quickstart/src/main/resources/archetype-resources/src/main/java/services/QaModule.java
similarity index 71%
rename from quickstart/filtered/archetype-resources/src/main/java/services/QaModule.java
rename to quickstart/src/main/resources/archetype-resources/src/main/java/services/QaModule.java
index 9577f0e..35c19ff 100644
--- a/quickstart/filtered/archetype-resources/src/main/java/services/QaModule.java
+++ b/quickstart/src/main/resources/archetype-resources/src/main/java/services/QaModule.java
@@ -1,17 +1,10 @@
 package ${package}.services;
 
-import java.io.IOException;
-
-import org.apache.tapestry5.*;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.ioc.Configuration;
 import org.apache.tapestry5.ioc.MappedConfiguration;
-import org.apache.tapestry5.ioc.OrderedConfiguration;
 import org.apache.tapestry5.ioc.ServiceBinder;
-import org.apache.tapestry5.ioc.annotations.Local;
-import org.apache.tapestry5.services.Request;
-import org.apache.tapestry5.services.RequestFilter;
-import org.apache.tapestry5.services.RequestHandler;
-import org.apache.tapestry5.services.Response;
-import org.slf4j.Logger;
+import org.apache.tapestry5.services.LibraryMapping;
 
 /**
  * This module is automatically included as part of the Tapestry IoC Registry if <em>tapestry.execution-mode</em>
@@ -25,9 +18,7 @@
         // binder.bind(MyServiceMonitorInterface.class, MyServiceMonitorImpl.class);
     }
 
-
-    public static void contributeApplicationDefaults(
-            MappedConfiguration<String, Object> configuration)
+    public static void contributeApplicationDefaults(MappedConfiguration<String, Object> configuration)
     {
         // The factory default is true but during the early stages of an application
         // overriding to false is a good idea. In addition, this is often overridden
@@ -40,4 +31,9 @@
         // change, to force the browser to download new versions.
         configuration.add(SymbolConstants.APPLICATION_VERSION, "${version}-QA");
     }
+
+    public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
+    {
+        configuration.add(new LibraryMapping("test", "${package}"));
+    }
 }
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/resources/application.yml b/quickstart/src/main/resources/archetype-resources/src/main/resources/application.yml
new file mode 100644
index 0000000..d20dfcc
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/resources/application.yml
@@ -0,0 +1,3 @@
+server:
+    port: 8080
+
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/resources/components/Layout.tml b/quickstart/src/main/resources/archetype-resources/src/main/resources/components/Layout.tml
new file mode 100644
index 0000000..47f8052
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/resources/components/Layout.tml
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
+<head>
+    <meta charset="utf-8"/>
+    <title>${D}{title}</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+    <meta name="description" content=""/>
+    <meta name="author" content=""/>
+    <link rel="shortcut icon" href="${D}{asset:context:/favicon.ico}"/>
+</head>
+<body>
+
+<div class="container">
+    <div class="row">
+        <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
+            <div class="container">
+                <div class="navbar-header">
+                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
+                        <span class="sr-only">Toggle navigation</span>
+                        <span class="icon-bar"></span>
+                        <span class="icon-bar"></span>
+                        <span class="icon-bar"></span>
+                    </button>
+                    <t:pagelink page="index" class="navbar-brand">app</t:pagelink>
+                </div>
+                <div class="navbar-collapse collapse">
+                    <ul class="nav navbar-nav">
+                        <t:loop source="pageNames" value="pageName">
+                            <t:any element="li" class="prop:classForPageName">
+                                <t:pagelink page="prop:pageName">${D}{pageName}</t:pagelink>
+                            </t:any>
+                        </t:loop>
+                    </ul>
+                    <span class="navbar-right">
+                        <li>
+                            <t:pagelink page="login" class="btn btn-default navbar-btn">Sign in</t:pagelink>
+                        </li>
+                    </span>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="row">
+        <div class="span12">
+            <t:alerts/>
+        </div>
+    </div>
+    <div class="row">
+        <t:body />
+        <hr />
+        <footer>
+            <p>&copy; Your Company ${D}{year}</p>
+        </footer>
+    </div>
+</div>
+
+</body>
+</html>
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j2.yml b/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j2.yml
new file mode 100644
index 0000000..928efed
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/resources/log4j2.yml
@@ -0,0 +1,60 @@
+configuration:
+  status: warn
+
+  appenders:
+    console:
+      name: STDOUT
+      patternLayout:
+        Pattern: "%d{DEFAULT} [%-22thread] %-5level %60.60logger %msg%n"
+
+  loggers:
+    root:
+      level: info
+      appenderRef:
+        ref: STDOUT
+
+    logger:
+      # Outputs a list of pages, components and mixins at startup.
+      -
+        name: org.apache.tapestry5.modules.TapestryModule.ComponentClassResolver
+        level: info
+
+      # Outputs startup statistics; elapsed time to setup and initialize the registry, a list of
+      # available services, and a launch banner that includes the Tapestry version number.
+      -
+        name: org.apache.tapestry5.TapestryFilter
+        level: info
+
+      # Turning on debug mode for a page's or component's transformer logger
+      # will show all of the code changes that occur when the
+      # class is loaded.
+      #-
+      #   name: tapestry.transformer.${package}.pages.Index
+      #   level: debug
+
+      # Turning on debug mode for a component's events logger will show all the events triggered on the
+      # component, and which component methods are invoked as a result.
+      #-
+      #   name: tapestry.events.${package}.pages.Index
+      #   level: debug
+
+      # Turning on trace mode for a page's render logger provides extended information about every step
+      # in rendering (this is not generally helpful). Turning on debug mode will add a one-line
+      # summary that includes the elapsed render time, which can be useful in tracking down
+      # performance issues.
+      #-
+      #   name: tapestry.render.${package}.pages.Index
+      #   level: debug
+
+      # Service category names are the name of the defining module class
+      # and then the service id.
+      -
+        name: ${package}.services.AppModule.TimingFilter
+        level: info
+
+      # Turn on some verbose debugging about everything in the application. This is nice initially,
+      # while getting everything set up. You'll probably want to remove this once you are
+      # up and running, replacing it with more selective debugging output.
+      -
+        name: ${package}
+        level: debug
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/About.tml b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/About.tml
new file mode 100644
index 0000000..3906ebe
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/About.tml
@@ -0,0 +1,23 @@
+<html t:type="layout" title="About | ${artifactId}"
+      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
+      xmlns:p="tapestry:parameter">
+
+<div class="row">
+    <div class="span12">
+        <h1>About ${artifactId} application ...</h1>
+    </div>
+</div>
+
+<t:if test="learn">
+    <div class="row">
+        <div class="span12">
+            <p>
+                To learn more go to
+                <a href="https://tapestry.apache.org">Tapestry home</a>
+                and start typing...
+            </p>
+        </div>
+    </div>
+</t:if>
+
+</html>
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Error404.tml b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Error404.tml
new file mode 100644
index 0000000..670307e
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Error404.tml
@@ -0,0 +1,11 @@
+<html t:type="layout" title="Error404 Page Not Found | ${artifactId}"
+      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
+      xmlns:p="tapestry:parameter">
+
+<div class="row">
+    <div class="span12">
+        <h1>Error 404 - Requested page not found!</h1>
+    </div>
+</div>
+
+</html>
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/pages/Index.properties b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Index.properties
similarity index 100%
rename from quickstart/filtered/archetype-resources/src/main/resources/pages/Index.properties
rename to quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Index.properties
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Index.tml b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Index.tml
new file mode 100644
index 0000000..457d479
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Index.tml
@@ -0,0 +1,45 @@
+<html t:type="layout" title="Index | ${artifactId}"
+      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
+
+<!-- Most of the page content, including <head>, <body>, etc. tags, comes from Layout.tml -->
+
+<!-- Main hero unit for a primary marketing message or call to action -->
+<div class="row hero-unit">
+    <p>
+        <img src="${D}{asset:context:images/tapestry.png}" alt="${D}{message:greeting}" title="${D}{message:greeting}" width="550" height="230"/>
+    </p>
+    <h1>${D}{message:greeting}</h1>
+    <p>The current time is: <strong>${D}{currentTime}</strong></p>
+    <p>
+        This is a template for a simple marketing or informational website. It includes a large callout called
+        the hero unit and three supporting pieces of content. Use it as a starting point to create something
+        more unique.
+    </p>
+    <p><t:actionlink t:id="learnmore" class="btn btn-primary btn-large">Learn more &raquo;</t:actionlink></p>
+</div>
+
+<!-- Example row of columns -->
+<div class="row">
+    <div class="span4">
+        <h2>Normal link</h2>
+        <p>Clink the bottom link and the page refresh with event <code>complete</code></p>
+        <p><t:eventlink event="complete" class="btn btn-default">Complete&raquo;</t:eventlink></p>
+    </div>
+
+    <t:zone t:id="middlezone" class="span4">
+    </t:zone>
+
+    <div class="span4">
+        <h2>Ajax link</h2>
+        <p>Click the bottom link to update just the middle column with Ajax call with event <code>ajax</code></p>
+        <p><t:eventlink event="ajax" zone="middlezone" class="btn btn-default">Ajax&raquo;</t:eventlink></p>
+    </div>
+</div>
+
+<t:block t:id="block">
+    <h2>Ajax updated</h2>
+    <p>I'v been updated through AJAX call</p>
+    <p>The current time is: <strong>${D}{currentTime}</strong></p>
+</t:block>
+
+</html>
diff --git a/quickstart/filtered/archetype-resources/src/main/resources/pages/Login.tml b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Login.tml
similarity index 84%
rename from quickstart/filtered/archetype-resources/src/main/resources/pages/Login.tml
rename to quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Login.tml
index 7c52a16..9756fdc 100644
--- a/quickstart/filtered/archetype-resources/src/main/resources/pages/Login.tml
+++ b/quickstart/src/main/resources/archetype-resources/src/main/resources/pages/Login.tml
@@ -1,9 +1,9 @@
-<html t:type="layout" title="${artifactId} com.example"
+<html t:type="layout" title="Login | ${artifactId}"
       xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
       xmlns:p="tapestry:parameter">
 
 <div class="row">
-    <div class="span4 offset3">
+    <div class="col-md-6 col-md-offset-3">
         <t:form t:id="login">
             <h2>Please sign in</h2>
             <t:textfield t:id="email" class="input-block-level" validate="required" placeholder="Email address"/>
diff --git a/quickstart/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml b/quickstart/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644
index bdac553..0000000
--- a/quickstart/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
-    version="2.4">
-
-    <display-name>${artifactId} Tapestry 5 Application</display-name>
-    <context-param>
-        <!--
-        The only significant configuration for Tapestry 5, this informs Tapestry
-        of where to look for pages, components and mixins.
-        -->
-        <param-name>tapestry.app-package</param-name>
-        <param-value>${package}</param-value>
-    </context-param>
-
-    <!--
-    Specify some additional Modules for two different execution
-    modes: development and qa.
-    Remember that the default execution mode is production
-    -->
-    <context-param>
-        <param-name>tapestry.development-modules</param-name>
-        <param-value>
-            ${package}.services.DevelopmentModule
-        </param-value>
-    </context-param>
-    <context-param>
-        <param-name>tapestry.qa-modules</param-name>
-        <param-value>
-            ${package}.services.QaModule
-        </param-value>
-    </context-param>
-
-
-    <!-- Filter configuration -->
-    <filter>
-        <filter-name>app</filter-name>
-        <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>
-    </filter>
-
-    <filter-mapping>
-        <filter-name>app</filter-name>
-        <url-pattern>/*</url-pattern>
-        <dispatcher>REQUEST</dispatcher>
-        <dispatcher>ERROR</dispatcher>
-    </filter-mapping>
-
-    <error-page>
-        <error-code>404</error-code>
-        <location>/error404</location>
-    </error-page>
-
-</web-app>
\ No newline at end of file
diff --git a/quickstart/src/main/resources/archetype-resources/src/site/apt/index.apt b/quickstart/src/main/resources/archetype-resources/src/site/apt/index.apt
deleted file mode 100644
index 65a7a3c..0000000
--- a/quickstart/src/main/resources/archetype-resources/src/site/apt/index.apt
+++ /dev/null
@@ -1,9 +0,0 @@
- ----
- Module ${groupId}:${artifactId}
- ----
-
-${groupId}:${artifactId} Documentation
-
-  This is where you can start to document your module.
-
-  Create new files in the Maven APT format, and update the site.xml file to point to them.
diff --git a/quickstart/src/main/resources/archetype-resources/src/site/site.xml b/quickstart/src/main/resources/archetype-resources/src/site/site.xml
deleted file mode 100644
index e90b5be..0000000
--- a/quickstart/src/main/resources/archetype-resources/src/site/site.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<project name="Generated site for ${artifactId}">
-
-    <publishDate format="dd MMM yyyy"/>
-
-    <version/>
-
-    <body>
-
-        <menu name="${artifactId} Project">
-            <item name="About" href="index.html"/>
-        </menu>
-
-        <menu ref="reports"/>
-
-    </body>
-</project>
diff --git a/quickstart/src/main/resources/archetype-resources/src/test/conf/testng.xml b/quickstart/src/main/resources/archetype-resources/src/test/conf/testng.xml
deleted file mode 100644
index 4030b6e..0000000
--- a/quickstart/src/main/resources/archetype-resources/src/test/conf/testng.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
-<suite name="${artifactId} Application Test Suite" annotations="1.5">
-    <test name="Unit Tests">
-        <packages>
-            <package name="${package}"/>
-        </packages>
-    </test>
-</suite>
diff --git a/quickstart/src/main/resources/archetype-resources/src/test/conf/webdefault.xml b/quickstart/src/main/resources/archetype-resources/src/test/conf/webdefault.xml
deleted file mode 100644
index c587ac7..0000000
--- a/quickstart/src/main/resources/archetype-resources/src/test/conf/webdefault.xml
+++ /dev/null
@@ -1,278 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<web-app
-        xmlns="http://java.sun.com/xml/ns/j2ee"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
-        version="2.4">
-
-    <description>
-        Default web.xml file.
-        This file is applied to a Web application before it's own WEB_INF/web.xml file
-    </description>
-
-
-    <!-- ==================================================================== -->
-    <!-- Context params to control Session Cookies                            -->
-    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-    <!-- UNCOMMENT TO ACTIVATE
-    <context-param>
-      <param-name>org.mortbay.jetty.servlet.SessionDomain</param-name>
-      <param-value>127.0.0.1</param-value>
-    </context-param>
-
-    <context-param>
-      <param-name>org.mortbay.jetty.servlet.SessionPath</param-name>
-      <param-value>/</param-value>
-    </context-param>
-
-    <context-param>
-      <param-name>org.mortbay.jetty.servlet.MaxAge</param-name>
-      <param-value>-1</param-value>
-    </context-param>
-    -->
-
-
-    <!-- ==================================================================== -->
-    <!-- The default servlet.                                                 -->
-    <!-- This servlet, normally mapped to /, provides the handling for static -->
-    <!-- content, OPTIONS and TRACE methods for the context.                  -->
-    <!-- The following initParameters are supported:                          -->
-    <!--                                                                      -->
-    <!--   acceptRanges     If true, range requests and responses are         -->
-    <!--                    supported                                         -->
-    <!--                                                                      -->
-    <!--   dirAllowed       If true, directory listings are returned if no    -->
-    <!--                    welcome file is found. Else 403 Forbidden.        -->
-    <!--                                                                      -->
-    <!--   putAllowed       If true, the PUT method is allowed                -->
-    <!--                                                                      -->
-    <!--   delAllowed       If true, the DELETE method is allowed             -->
-    <!--                                                                      -->
-    <!--   redirectWelcome  If true, redirect welcome file requests           -->
-    <!--                    else use request dispatcher forwards              -->
-    <!--                                                                      -->
-    <!--   minGzipLength    If set to a positive integer, then static content -->
-    <!--                    larger than this will be served as gzip content   -->
-    <!--                    encoded if a matching resource is found ending    -->
-    <!--                    with ".gz"                                        -->
-    <!--                                                                      -->
-    <!--   resoureBase      Can be set to replace the context resource base   -->
-    <!--                                                                      -->
-    <!--   relativeResourceBase                                               -->
-    <!--                    Set with a pathname relative to the base of the   -->
-    <!--                    servlet context root. Useful for only serving     -->
-    <!--                    static content from only specific subdirectories. -->
-    <!--                                                                      -->
-    <!-- The MOVE method is allowed if PUT and DELETE are allowed             -->
-    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-    <servlet>
-        <servlet-name>default</servlet-name>
-        <servlet-class>org.mortbay.jetty.servlet.Default</servlet-class>
-        <init-param>
-            <param-name>acceptRanges</param-name>
-            <param-value>true</param-value>
-        </init-param>
-        <init-param>
-            <param-name>dirAllowed</param-name>
-            <param-value>true</param-value>
-        </init-param>
-        <init-param>
-            <param-name>putAllowed</param-name>
-            <param-value>false</param-value>
-        </init-param>
-        <init-param>
-            <param-name>delAllowed</param-name>
-            <param-value>false</param-value>
-        </init-param>
-        <init-param>
-            <param-name>redirectWelcome</param-name>
-            <param-value>false</param-value>
-        </init-param>
-        <init-param>
-            <param-name>minGzipLength</param-name>
-            <param-value>8192</param-value>
-        </init-param>
-        <load-on-startup>0</load-on-startup>
-    </servlet>
-
-
-    <servlet-mapping>
-        <servlet-name>default</servlet-name>
-        <url-pattern>/</url-pattern>
-    </servlet-mapping>
-
-    <!-- ==================================================================== -->
-    <session-config>
-        <session-timeout>30</session-timeout>
-    </session-config>
-
-
-    <!-- ==================================================================== -->
-    <welcome-file-list>
-        <welcome-file>index.html</welcome-file>
-        <welcome-file>index.htm</welcome-file>
-    </welcome-file-list>
-
-    <!-- ==================================================================== -->
-    <locale-encoding-mapping-list>
-        <locale-encoding-mapping>
-            <locale>ar</locale>
-            <encoding>ISO-8859-6</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>be</locale>
-            <encoding>ISO-8859-5</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>bg</locale>
-            <encoding>ISO-8859-5</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>ca</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>cs</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>da</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>de</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>el</locale>
-            <encoding>ISO-8859-7</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>en</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>es</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>et</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>fi</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>fr</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>hr</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>hu</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>is</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>it</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>iw</locale>
-            <encoding>ISO-8859-8</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>ja</locale>
-            <encoding>Shift_JIS</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>ko</locale>
-            <encoding>EUC-KR</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>lt</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>lv</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>mk</locale>
-            <encoding>ISO-8859-5</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>nl</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>no</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>pl</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>pt</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>ro</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>ru</locale>
-            <encoding>ISO-8859-5</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>sh</locale>
-            <encoding>ISO-8859-5</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>sk</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>sl</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>sq</locale>
-            <encoding>ISO-8859-2</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>sr</locale>
-            <encoding>ISO-8859-5</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>sv</locale>
-            <encoding>ISO-8859-1</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>tr</locale>
-            <encoding>ISO-8859-9</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>uk</locale>
-            <encoding>ISO-8859-5</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>zh</locale>
-            <encoding>GB2312</encoding>
-        </locale-encoding-mapping>
-        <locale-encoding-mapping>
-            <locale>zh_TW</locale>
-            <encoding>Big5</encoding>
-        </locale-encoding-mapping>
-    </locale-encoding-mapping-list>
-
-
-</web-app>
-
diff --git a/quickstart/src/main/resources/archetype-resources/src/test/groovy/IndexSpec.groovy b/quickstart/src/main/resources/archetype-resources/src/test/groovy/IndexSpec.groovy
new file mode 100644
index 0000000..f0419b8
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/test/groovy/IndexSpec.groovy
@@ -0,0 +1,15 @@
+package ${package}
+
+import spock.lang.Shared
+import spock.lang.Specification
+
+class CalculateSpec extends Specification {
+
+    def "calculate sum"() {
+        when:
+        def total = 1 + 2
+
+        then:
+        3 == total
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/functional/LoginSpec.groovy b/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/functional/LoginSpec.groovy
new file mode 100644
index 0000000..803fb4a
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/functional/LoginSpec.groovy
@@ -0,0 +1,60 @@
+package ${package}.geb
+
+import geb.Page
+import geb.spock.GebSpec
+
+import org.springframework.boot.test.context.SpringBootTest
+
+import ${package}.AppConfiguration
+
+class IndexPage extends Page {
+    static url = 'http://localhost:8080/'
+    static at = { title.startsWith('Index') }
+}
+
+class LoginPage extends Page {
+    static url = 'http://localhost:8080/login'
+    static at = { title.startsWith('Login') }
+    static content = {
+        email { $('#email') }
+        password { $('#password') }
+        submit { $("#login input[type=submit]") }
+    }
+}
+
+@SpringBootTest(classes = AppConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+class LoginSpec extends GebSpec {
+    def 'go to login'() {
+        when:
+        to LoginPage
+
+        then:
+        at LoginPage
+    }
+
+    def 'success login'() {
+        setup:
+        to LoginPage
+
+        when:
+        email().value "users@tapestry.apache.org"
+        password().value "Tapestry5"
+        submit().click()
+
+        then:
+        at IndexPage
+    }
+
+    def 'fail login'() {
+        setup:
+        to LoginPage
+
+        when:
+        email().value "users@tapestry.apache.org"
+        password().value "xxx"
+        submit().click()
+
+        then:
+        at LoginPage
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/unit/pages/LoginSpec.groovy b/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/unit/pages/LoginSpec.groovy
new file mode 100644
index 0000000..c2c6d5b
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/unit/pages/LoginSpec.groovy
@@ -0,0 +1,77 @@
+package ${package}.pages
+
+import com.formos.tapestry.testify.core.ForComponents
+import com.formos.tapestry.testify.core.TapestryTester
+import com.formos.tapestry.xpath.TapestryXPath
+
+import org.apache.tapestry5.alerts.AlertManager
+import org.apache.tapestry5.dom.Document
+import org.apache.tapestry5.dom.Element
+import org.apache.tapestry5.corelib.components.Form
+import org.apache.tapestry5.corelib.components.TextField
+import org.apache.tapestry5.corelib.components.PasswordField
+
+import static spock.mock.MockingApi.Mock
+import static spock.mock.MockingApi.Stub
+import spock.lang.Shared
+import spock.lang.Specification
+
+import ${package}.services.QaModule
+
+class LoginSpec extends Specification {
+
+    @Shared
+    private TapestryTester tester
+
+    @ForComponents
+    private AlertManager alertManager
+
+    def setupSpec() {
+        tester = new TapestryTester("${package}", "app", "src/main/webapp", QaModule.class)
+    }
+
+    def setup() {
+        tester.injectInto(this);
+        alertManager = Mock(AlertManager)
+        tester.collectForComponentsFrom(this);
+    }
+
+    def cleanup() {
+        tester.endTest()
+    }
+
+    def "login success"() {
+        given:
+        Document document = tester.renderPage("Login");
+        Element form = TapestryXPath.xpath("//form").selectSingleElement(document)
+
+        when:
+        def fields = [email: 'users@tapestry.apache.org', password: 'Tapestry5']
+        Document result = tester.submitForm(form, fields);
+
+        and:
+        String title = TapestryXPath.xpath("/html/head/title").selectSingleElement(result).getChildMarkup()
+
+        then:
+        title.startsWith("Index")
+        1 * alertManager.success(_)
+
+    }
+
+    def "login error"() {
+        given:
+        Document document = tester.renderPage("Login");
+        Element form = TapestryXPath.xpath("//form").selectSingleElement(document)
+
+        when:
+        def fields = [email: 'xxx', password: 'xxx']
+        Document result = tester.submitForm(form, fields);
+
+        and:
+        String title = TapestryXPath.xpath("/html/head/title").selectSingleElement(result).getChildMarkup()
+
+        then:
+        title.startsWith("Login")
+        1 * alertManager.error(_)
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/unit/pages/NavigationSpec.groovy b/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/unit/pages/NavigationSpec.groovy
new file mode 100644
index 0000000..bb766a4
--- /dev/null
+++ b/quickstart/src/main/resources/archetype-resources/src/test/groovy/tapestry/unit/pages/NavigationSpec.groovy
@@ -0,0 +1,41 @@
+package ${package}.pages
+
+import com.formos.tapestry.testify.core.ForComponents
+import com.formos.tapestry.testify.core.TapestryTester
+import com.formos.tapestry.xpath.TapestryXPath
+
+import org.apache.tapestry5.alerts.AlertManager
+import org.apache.tapestry5.dom.Document
+import org.apache.tapestry5.dom.Element
+import org.apache.tapestry5.corelib.components.Form
+import org.apache.tapestry5.corelib.components.TextField
+import org.apache.tapestry5.corelib.components.PasswordField
+
+import static spock.mock.MockingApi.Mock
+import static spock.mock.MockingApi.Stub
+import spock.lang.Shared
+import spock.lang.Specification
+
+import ${package}.services.QaModule
+
+class NavigationSpec extends Specification {
+
+    @Shared
+    private TapestryTester tester
+
+    def setupSpec() {
+        tester = new TapestryTester("${package}", "app", "src/main/webapp", QaModule.class)
+    }
+
+    def "go to #pageName"() {
+        when:
+        Document document = tester.renderPage(pageName)
+        String title = TapestryXPath.xpath("/html/head/title").selectSingleElement(document).getChildMarkup()
+
+        then:
+        title.startsWith(pageName)
+
+        where:
+        pageName << ["Index", "Login", "About", "Error404"]
+    }
+}
diff --git a/quickstart/src/main/resources/archetype-resources/src/test/java/PLACEHOLDER b/quickstart/src/main/resources/archetype-resources/src/test/java/PLACEHOLDER
deleted file mode 100644
index 62c163c..0000000
--- a/quickstart/src/main/resources/archetype-resources/src/test/java/PLACEHOLDER
+++ /dev/null
@@ -1 +0,0 @@
-This placeholder exists to ensure the directory is created. It may be deleted when real files are placed under src/test/java.
\ No newline at end of file