diff --git a/app/routes/_auth/auth.$provider.callback.test.ts b/app/routes/_auth/auth.$provider/callback.test.ts
similarity index 99%
rename from app/routes/_auth/auth.$provider.callback.test.ts
rename to app/routes/_auth/auth.$provider/callback.test.ts
index 84b2cc0fa..10346eb5f 100644
--- a/app/routes/_auth/auth.$provider.callback.test.ts
+++ b/app/routes/_auth/auth.$provider/callback.test.ts
@@ -14,7 +14,7 @@ import { insertGitHubUser, deleteGitHubUsers } from '#tests/mocks/github.ts'
import { server } from '#tests/mocks/index.ts'
import { consoleError } from '#tests/setup/setup-test-env.ts'
import { BASE_URL, convertSetCookieToCookie } from '#tests/utils.ts'
-import { loader } from './auth.$provider.callback.ts'
+import { loader } from './callback.ts'
const ROUTE_PATH = '/auth/github/callback'
const PARAMS = { provider: 'github' }
diff --git a/app/routes/_auth/auth.$provider.callback.ts b/app/routes/_auth/auth.$provider/callback.ts
similarity index 95%
rename from app/routes/_auth/auth.$provider.callback.ts
rename to app/routes/_auth/auth.$provider/callback.ts
index cc124ac85..e95b01c42 100644
--- a/app/routes/_auth/auth.$provider.callback.ts
+++ b/app/routes/_auth/auth.$provider/callback.ts
@@ -21,10 +21,10 @@ import {
redirectWithToast,
} from '#app/utils/toast.server.ts'
import { verifySessionStorage } from '#app/utils/verification.server.ts'
-import { type Route } from './+types/auth.$provider.callback.ts'
-import { handleNewSession } from './login.server.ts'
-import { onboardingEmailSessionKey } from './onboarding.tsx'
-import { prefilledProfileKey, providerIdKey } from './onboarding_.$provider.tsx'
+import { handleNewSession } from '../login.server.ts'
+import { prefilledProfileKey, providerIdKey } from '../onboarding/$provider.tsx'
+import { onboardingEmailSessionKey } from '../onboarding/index.tsx'
+import { type Route } from './+types/callback.ts'
const destroyRedirectTo = { 'set-cookie': destroyRedirectToHeader }
diff --git a/app/routes/_auth/auth_.$provider.ts b/app/routes/_auth/auth.$provider/index.ts
similarity index 95%
rename from app/routes/_auth/auth_.$provider.ts
rename to app/routes/_auth/auth.$provider/index.ts
index b604005e6..b4842b0f6 100644
--- a/app/routes/_auth/auth_.$provider.ts
+++ b/app/routes/_auth/auth.$provider/index.ts
@@ -4,7 +4,7 @@ import { handleMockAction } from '#app/utils/connections.server.ts'
import { ProviderNameSchema } from '#app/utils/connections.tsx'
import { getReferrerRoute } from '#app/utils/misc.tsx'
import { getRedirectCookieHeader } from '#app/utils/redirect-cookie.server.ts'
-import { type Route } from './+types/auth_.$provider.ts'
+import { type Route } from './+types/index.ts'
export async function loader() {
return redirect('/login')
diff --git a/app/routes/_auth/onboarding_.$provider.server.ts b/app/routes/_auth/onboarding/$provider.server.ts
similarity index 83%
rename from app/routes/_auth/onboarding_.$provider.server.ts
rename to app/routes/_auth/onboarding/$provider.server.ts
index 502ef8078..e6f373eca 100644
--- a/app/routes/_auth/onboarding_.$provider.server.ts
+++ b/app/routes/_auth/onboarding/$provider.server.ts
@@ -1,8 +1,8 @@
import { invariant } from '@epic-web/invariant'
import { redirect } from 'react-router'
import { verifySessionStorage } from '#app/utils/verification.server.ts'
-import { onboardingEmailSessionKey } from './onboarding.tsx'
-import { type VerifyFunctionArgs } from './verify.server.ts'
+import { type VerifyFunctionArgs } from '../verify.server.ts'
+import { onboardingEmailSessionKey } from './index.tsx'
export async function handleVerification({ submission }: VerifyFunctionArgs) {
invariant(
diff --git a/app/routes/_auth/onboarding_.$provider.tsx b/app/routes/_auth/onboarding/$provider.tsx
similarity index 98%
rename from app/routes/_auth/onboarding_.$provider.tsx
rename to app/routes/_auth/onboarding/$provider.tsx
index 65aeafa00..850ae95dc 100644
--- a/app/routes/_auth/onboarding_.$provider.tsx
+++ b/app/routes/_auth/onboarding/$provider.tsx
@@ -29,8 +29,8 @@ import { authSessionStorage } from '#app/utils/session.server.ts'
import { redirectWithToast } from '#app/utils/toast.server.ts'
import { NameSchema, UsernameSchema } from '#app/utils/user-validation.ts'
import { verifySessionStorage } from '#app/utils/verification.server.ts'
-import { type Route } from './+types/onboarding_.$provider.ts'
-import { onboardingEmailSessionKey } from './onboarding'
+import { type Route } from './+types/$provider.ts'
+import { onboardingEmailSessionKey } from './index.tsx'
export const providerIdKey = 'providerId'
export const prefilledProfileKey = 'prefilledProfile'
diff --git a/app/routes/_auth/onboarding.server.ts b/app/routes/_auth/onboarding/index.server.ts
similarity index 83%
rename from app/routes/_auth/onboarding.server.ts
rename to app/routes/_auth/onboarding/index.server.ts
index 502ef8078..e6f373eca 100644
--- a/app/routes/_auth/onboarding.server.ts
+++ b/app/routes/_auth/onboarding/index.server.ts
@@ -1,8 +1,8 @@
import { invariant } from '@epic-web/invariant'
import { redirect } from 'react-router'
import { verifySessionStorage } from '#app/utils/verification.server.ts'
-import { onboardingEmailSessionKey } from './onboarding.tsx'
-import { type VerifyFunctionArgs } from './verify.server.ts'
+import { type VerifyFunctionArgs } from '../verify.server.ts'
+import { onboardingEmailSessionKey } from './index.tsx'
export async function handleVerification({ submission }: VerifyFunctionArgs) {
invariant(
diff --git a/app/routes/_auth/onboarding.tsx b/app/routes/_auth/onboarding/index.tsx
similarity index 99%
rename from app/routes/_auth/onboarding.tsx
rename to app/routes/_auth/onboarding/index.tsx
index a9d05a8e6..bf1afa022 100644
--- a/app/routes/_auth/onboarding.tsx
+++ b/app/routes/_auth/onboarding/index.tsx
@@ -24,7 +24,7 @@ import {
UsernameSchema,
} from '#app/utils/user-validation.ts'
import { verifySessionStorage } from '#app/utils/verification.server.ts'
-import { type Route } from './+types/onboarding.ts'
+import { type Route } from './+types/index.ts'
export const onboardingEmailSessionKey = 'onboardingEmail'
diff --git a/app/routes/_auth/verify.server.ts b/app/routes/_auth/verify.server.ts
index 8ec85f59d..9e9264201 100644
--- a/app/routes/_auth/verify.server.ts
+++ b/app/routes/_auth/verify.server.ts
@@ -14,7 +14,7 @@ import {
handleVerification as handleLoginTwoFactorVerification,
shouldRequestTwoFA,
} from './login.server.ts'
-import { handleVerification as handleOnboardingVerification } from './onboarding.server.ts'
+import { handleVerification as handleOnboardingVerification } from './onboarding/index.server.ts'
import { handleVerification as handleResetPasswordVerification } from './reset-password.server.ts'
import {
VerifySchema,
diff --git a/app/routes/admin/cache.tsx b/app/routes/admin/cache/index.tsx
similarity index 99%
rename from app/routes/admin/cache.tsx
rename to app/routes/admin/cache/index.tsx
index 04150fb48..4c6efc276 100644
--- a/app/routes/admin/cache.tsx
+++ b/app/routes/admin/cache/index.tsx
@@ -25,7 +25,7 @@ import {
} from '#app/utils/litefs.server.ts'
import { useDebounce, useDoubleCheck } from '#app/utils/misc.tsx'
import { requireUserWithRole } from '#app/utils/permissions.server.ts'
-import { type Route } from './+types/cache.ts'
+import { type Route } from './+types/index.ts'
export const handle: SEOHandle = {
getSitemapEntries: () => null,
diff --git a/app/routes/admin/cache_.lru.$cacheKey.ts b/app/routes/admin/cache/lru.$cacheKey.ts
similarity index 93%
rename from app/routes/admin/cache_.lru.$cacheKey.ts
rename to app/routes/admin/cache/lru.$cacheKey.ts
index 7534705a1..ca5e35297 100644
--- a/app/routes/admin/cache_.lru.$cacheKey.ts
+++ b/app/routes/admin/cache/lru.$cacheKey.ts
@@ -6,7 +6,7 @@ import {
ensureInstance,
} from '#app/utils/litefs.server.ts'
import { requireUserWithRole } from '#app/utils/permissions.server.ts'
-import { type Route } from './+types/cache_.lru.$cacheKey.ts'
+import { type Route } from './+types/lru.$cacheKey.ts'
export async function loader({ request, params }: Route.LoaderArgs) {
await requireUserWithRole(request, 'admin')
diff --git a/app/routes/admin/cache_.sqlite.$cacheKey.ts b/app/routes/admin/cache/sqlite.$cacheKey.ts
similarity index 93%
rename from app/routes/admin/cache_.sqlite.$cacheKey.ts
rename to app/routes/admin/cache/sqlite.$cacheKey.ts
index 9aeb3e047..32c498b85 100644
--- a/app/routes/admin/cache_.sqlite.$cacheKey.ts
+++ b/app/routes/admin/cache/sqlite.$cacheKey.ts
@@ -6,7 +6,7 @@ import {
ensureInstance,
} from '#app/utils/litefs.server.ts'
import { requireUserWithRole } from '#app/utils/permissions.server.ts'
-import { type Route } from './+types/cache_.sqlite.$cacheKey.ts'
+import { type Route } from './+types/sqlite.$cacheKey.ts'
export async function loader({ request, params }: Route.LoaderArgs) {
await requireUserWithRole(request, 'admin')
diff --git a/app/routes/admin/cache_.sqlite.server.ts b/app/routes/admin/cache/sqlite.server.ts
similarity index 96%
rename from app/routes/admin/cache_.sqlite.server.ts
rename to app/routes/admin/cache/sqlite.server.ts
index 04746fc15..b90dd9f75 100644
--- a/app/routes/admin/cache_.sqlite.server.ts
+++ b/app/routes/admin/cache/sqlite.server.ts
@@ -5,7 +5,7 @@ import {
getInstanceInfo,
getInternalInstanceDomain,
} from '#app/utils/litefs.server'
-import { type Route } from './+types/cache_.sqlite.ts'
+import { type Route } from './+types/sqlite.ts'
export async function updatePrimaryCacheValue({
key,
diff --git a/app/routes/admin/cache/sqlite.tsx b/app/routes/admin/cache/sqlite.tsx
new file mode 100644
index 000000000..44d490291
--- /dev/null
+++ b/app/routes/admin/cache/sqlite.tsx
@@ -0,0 +1 @@
+export { action } from './sqlite.server.ts'
diff --git a/app/routes/admin/cache_.sqlite.tsx b/app/routes/admin/cache_.sqlite.tsx
deleted file mode 100644
index e46989117..000000000
--- a/app/routes/admin/cache_.sqlite.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { action } from './cache_.sqlite.server.ts'
diff --git a/app/routes/users/$username_/index.test.tsx b/app/routes/users/$username/index.test.tsx
similarity index 100%
rename from app/routes/users/$username_/index.test.tsx
rename to app/routes/users/$username/index.test.tsx
diff --git a/app/routes/users/$username_/index.tsx b/app/routes/users/$username/index.tsx
similarity index 100%
rename from app/routes/users/$username_/index.tsx
rename to app/routes/users/$username/index.tsx
diff --git a/app/routes/users/$username_/notes/$noteId.tsx b/app/routes/users/$username/notes/$noteId.tsx
similarity index 99%
rename from app/routes/users/$username_/notes/$noteId.tsx
rename to app/routes/users/$username/notes/$noteId.tsx
index 768ddd888..f72186624 100644
--- a/app/routes/users/$username_/notes/$noteId.tsx
+++ b/app/routes/users/$username/notes/$noteId.tsx
@@ -205,7 +205,7 @@ export function DeleteNote({
export const meta: Route.MetaFunction = ({ data, params, matches }) => {
const notesMatch = matches.find(
- (m) => m?.id === 'routes/users/$username_/notes',
+ (m) => m?.id === 'routes/users/$username/notes',
) as { data: NotesRoute.ComponentProps['loaderData'] } | undefined
const displayName = notesMatch?.data?.owner.name ?? params.username
diff --git a/app/routes/users/$username_/notes/$noteId_.edit.tsx b/app/routes/users/$username/notes/$noteId_.edit.tsx
similarity index 100%
rename from app/routes/users/$username_/notes/$noteId_.edit.tsx
rename to app/routes/users/$username/notes/$noteId_.edit.tsx
diff --git a/app/routes/users/$username_/notes/+shared/note-editor.server.tsx b/app/routes/users/$username/notes/+shared/note-editor.server.tsx
similarity index 100%
rename from app/routes/users/$username_/notes/+shared/note-editor.server.tsx
rename to app/routes/users/$username/notes/+shared/note-editor.server.tsx
diff --git a/app/routes/users/$username_/notes/+shared/note-editor.tsx b/app/routes/users/$username/notes/+shared/note-editor.tsx
similarity index 100%
rename from app/routes/users/$username_/notes/+shared/note-editor.tsx
rename to app/routes/users/$username/notes/+shared/note-editor.tsx
diff --git a/app/routes/users/$username_/notes/_layout.tsx b/app/routes/users/$username/notes/_layout.tsx
similarity index 100%
rename from app/routes/users/$username_/notes/_layout.tsx
rename to app/routes/users/$username/notes/_layout.tsx
diff --git a/app/routes/users/$username_/notes/index.tsx b/app/routes/users/$username/notes/index.tsx
similarity index 93%
rename from app/routes/users/$username_/notes/index.tsx
rename to app/routes/users/$username/notes/index.tsx
index 8b238caaa..9ea8b7de7 100644
--- a/app/routes/users/$username_/notes/index.tsx
+++ b/app/routes/users/$username/notes/index.tsx
@@ -11,7 +11,7 @@ export default function NotesIndexRoute() {
export const meta: Route.MetaFunction = ({ params, matches }) => {
const notesMatch = matches.find(
- (m) => m?.id === 'routes/users/$username_/notes',
+ (m) => m?.id === 'routes/users/$username/notes',
) as { data: NotesRoute.ComponentProps['loaderData'] }
const displayName = notesMatch?.data?.owner.name ?? params.username
diff --git a/app/routes/users/$username_/notes/new.tsx b/app/routes/users/$username/notes/new.tsx
similarity index 100%
rename from app/routes/users/$username_/notes/new.tsx
rename to app/routes/users/$username/notes/new.tsx
diff --git a/app/utils/cache.server.ts b/app/utils/cache.server.ts
index 5eb6105da..6e26fb93e 100644
--- a/app/utils/cache.server.ts
+++ b/app/utils/cache.server.ts
@@ -15,7 +15,7 @@ import {
import { remember } from '@epic-web/remember'
import { LRUCache } from 'lru-cache'
import { z } from 'zod'
-import { updatePrimaryCacheValue } from '#app/routes/admin/cache_.sqlite.server.ts'
+import { updatePrimaryCacheValue } from '#app/routes/admin/cache/sqlite.server.ts'
import { getInstanceInfo, getInstanceInfoSync } from './litefs.server.ts'
import { cachifiedTimingReporter, type Timings } from './timing.server.ts'
diff --git a/docs/routing.md b/docs/routing.md
index 749112ccf..2ceb3febc 100644
--- a/docs/routing.md
+++ b/docs/routing.md
@@ -17,38 +17,41 @@ of the Epic Stack routes at the time of this writing:
```
app/routes
├── $.tsx
+├── me.tsx
├── _auth
-│ ├── auth.$provider.callback.ts
-│ ├── auth_.$provider.ts
│ ├── forgot-password.tsx
│ ├── login.tsx
│ ├── logout.tsx
-│ ├── onboarding.tsx
-│ ├── onboarding_.$provider.tsx
│ ├── reset-password.tsx
│ ├── signup.tsx
│ ├── verify.tsx
+│ ├── auth.$provider
+│ │ ├── callback.ts
+│ │ └── index.ts
+│ ├── onboarding
+│ │ ├── $provider.tsx
+│ │ └── index.tsx
│ └── webauthn
│ ├── authentication.ts
│ └── registration.ts
├── _marketing
-│ ├── +logos
-│ │ ├── logos.ts
-│ │ └── ...
│ ├── about.tsx
│ ├── index.tsx
│ ├── privacy.tsx
│ ├── support.tsx
-│ └── tos.tsx
+│ ├── tos.tsx
+│ └── +logos
+│ ├── logos.ts
+│ └── ...
├── _seo
│ ├── robots[.]txt.ts
│ └── sitemap[.]xml.ts
├── admin
-│ ├── cache.tsx
-│ ├── cache_.lru.$cacheKey.ts
-│ ├── cache_.sqlite.$cacheKey.ts
-│ └── cache_.sqlite.tsx
-├── me.tsx
+│ └── cache
+│ ├── index.tsx
+│ ├── lru.$cacheKey.ts
+│ ├── sqlite.$cacheKey.ts
+│ └── sqlite.tsx
├── resources
│ ├── download-user-data.tsx
│ ├── healthcheck.tsx
@@ -70,17 +73,17 @@ app/routes
│ ├── index.tsx
│ └── verify.tsx
└── users
- ├── $username_
- │ ├── index.tsx
- │ └── notes
- │ ├── $noteId.tsx
- │ ├── $noteId_.edit.tsx
- │ ├── _layout.tsx
- │ ├── index.tsx
- │ └── new.tsx
- └── index.tsx
+ ├── index.tsx
+ └── $username
+ ├── index.tsx
+ └── notes
+ ├── $noteId.tsx
+ ├── $noteId_.edit.tsx
+ ├── _layout.tsx
+ ├── index.tsx
+ └── new.tsx
-13 directories, 49 files
+17 directories, 72 files
```
```tsx
@@ -89,17 +92,21 @@ app/routes
+
-
-
+
@@ -118,13 +125,13 @@ app/routes
-
+
-
-
+
+
-
+
-
-
+
+