A route's routes array holds nested routes, whose paths are joined to the parent's: notes/ inside the book route becomes /books/:id(\d+)/notes/ and inherits id. Relative links resolve against the current URL, so <a href="notes/"> on /books/3/ opens /books/3/notes/, while href="/notes/" looks for a root route.
The default route is the one a view loads first: data-url="/" in app.f7 matches path: '/'. alias gives a route extra paths, and redirect takes a URL, or a function that calls resolve(url) or reject(). The 404 route is just the last entry, path: '(.*)', which matches anything; placed earlier, it would swallow every route after it. The console shows which route four URLs matched:
app.off('routeChange routeChanged'); // silence the logging handlers
const router = app.views.main.router;
for (const url of ['/home/', '/latest/', '/books/99/', '/books/abc/']) {
router.navigate(url);
await new Promise((done) => setTimeout(done, 700));
console.log(`${url} => ${router.url} matched ${router.currentRoute.route.path}`);
}/home/ => /home/ matched /
book.f7 props={"id":"4"} query={}
/latest/ => /books/4/ matched /books/:id(\d+)/
book.f7 props={"id":"99"} query={}
/books/99/ => /books/99/ matched /books/:id(\d+)/
/books/abc/ => /books/abc/ matched (.*)The alias kept its own URL; the redirect replaced /latest/ before matching, so it never entered history; and abc failed the digits pattern, so the 404 route caught it.