Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8f6890d
feat: turborepo + cloudflare
dotnize Feb 4, 2026
e4f89ae
Merge branch 'main' into next
dotnize Feb 4, 2026
a0314c6
chore: temp readme
dotnize Feb 4, 2026
0b78db0
update readme
dotnize Feb 4, 2026
dfdffc5
chore: remove migrations
dotnize Feb 4, 2026
7846db3
rename template
dotnize Feb 4, 2026
fff481d
update readme
dotnize Feb 4, 2026
2c124c3
update readme
dotnize Feb 4, 2026
cbc7578
chore: update middleware comments
dotnize Feb 5, 2026
7962a96
add worker & vite types to app tsconfig
dotnize Feb 5, 2026
48f5ef6
merge main
dotnize Feb 5, 2026
68d0ad1
bump deps
dotnize Feb 5, 2026
6cb42ae
update readme
dotnize Feb 5, 2026
0f3f7a9
add default inter custom font
dotnize Feb 5, 2026
f9ee24d
chore: oxlint + oxfmt (#51)
dotnize Feb 6, 2026
7feb4b9
bump deps
dotnize Feb 8, 2026
dbce23c
bump deps
dotnize Feb 8, 2026
9f5ac9f
update comments for hooks
dotnize Feb 8, 2026
a6c3a4b
add nanoid dependency
dotnize Feb 8, 2026
3ae5e9d
cleanup
dotnize Feb 8, 2026
d6c31aa
update schema & components
dotnize Feb 9, 2026
d151428
add github to default social providers
dotnize Feb 9, 2026
a6f7ccb
chore: upgrade dependencies
dotnize Feb 11, 2026
d0e0c06
bump dependencies
dotnize Feb 13, 2026
da2cf70
remove cloudflare & switch back to nitro v3
dotnize Feb 13, 2026
b2c31e5
update readme
dotnize Feb 13, 2026
8ca74e8
rename /dashboard to /app
dotnize Feb 13, 2026
49dddf8
update readme
dotnize Feb 13, 2026
0256be3
update readme
dotnize Feb 13, 2026
0f5cf3d
update readme
dotnize Feb 14, 2026
6c315ce
update readme
dotnize Feb 14, 2026
1261c97
add AGENTS.md
dotnize Feb 15, 2026
37e06b5
update dependencies
dotnize Feb 15, 2026
27d42c1
AGENTS.md: clarify data fetching pattern for tanstack query
dotnize Feb 15, 2026
e5e997d
update tanstack patterns
dotnize Feb 15, 2026
0d6e080
bump dependencies
dotnize Feb 15, 2026
b8ca699
update deps
dotnize Feb 16, 2026
a9e2e16
update deps
dotnize Feb 17, 2026
73022e8
disable prettier & eslint in vscode
dotnize Feb 17, 2026
1485c61
update vscode settings
dotnize Feb 17, 2026
593863a
import protection
dotnize Feb 18, 2026
3069470
explicit port to 3000
dotnize Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .agents/auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Auth Conventions

## Auth Architecture

- Better Auth config lives in `packages/auth/src/auth.ts`.
- Auth utilities are centralized in `packages/auth/src/tanstack/*`.
- In components, prefer shared auth hooks (`useAuth`, `useAuthSuspense`) from `packages/auth/src/tanstack/hooks.ts`. These reuse the same auth data as the route loader.
- For route loaders under `_auth`, prefer loader context user over duplicate auth fetches.

## Route Guards

- Protected route layout is `apps/web/src/routes/_auth/route.tsx`.
- It enforces auth in `beforeLoad` using `ensureQueryData(authQueryOptions())`.
- It returns `{ user }`, which is available to all child route loaders via router context.
- Guest-only route layout is `apps/web/src/routes/_guest/route.tsx`.
- It redirects authenticated users away from login/signup routes.

## Server Functions and Mutations

- Server functions can be called from both server and client code.
- Server call: executed directly on the server.
- Client call: treated as RPC and executed through an HTTP API request.
- Treat protected server functions like protected API routes from a security perspective.
- If a server function requires auth, always apply `authMiddleware` from `packages/auth/src/tanstack/middleware.ts`. This applies even when called from an auth-protected route (`routes/_auth/**`).
- Route-level `beforeLoad` guards protect route navigation/rendering, but they do not replace server-function authorization.
- When auth is required, middleware-provided user context is the source of truth.
86 changes: 86 additions & 0 deletions .agents/tanstack-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<!-- based on https://github.com/TanStack/tanstack.com/blob/main/.claude/tanstack-patterns.md -->

# TanStack Patterns

## Route Group Conventions

- Protected routes live under `apps/web/src/routes/_auth/**`, enforced by `beforeLoad` in the `_auth` layout (`apps/web/src/routes/_auth/route.tsx`).
- Guest-only routes live under `apps/web/src/routes/_guest/**`, enforced by `beforeLoad` in the `_guest` layout (`apps/web/src/routes/_guest/route.tsx`).
- Auth-specific route guard behavior and middleware rules are documented in `.agents/auth.md`.

## Data Fetching

Route loaders are isomorphic; they run on both server and client. They cannot directly access server-only APIs.

```typescript
// Bad: direct server API access
loader: async () => {
const todos = await fs.readFile("todos.json");
return { todos };
};
```

```typescript
// Good (minimal/valid): call a server function from the loader
loader: async () => {
const todos = await $getTodos({ data: {} });
return { todos };
};
```

Instead of directly calling server functions in loaders, prefer wrapping in TanStack Query for better caching and reusability.

```typescript
loader: async ({ context }) => {
// Best/Preferred: For read/data-fetching server functions, wrap in TanStack Query
const todos = await context.queryClient.ensureQueryData(todosQueryOptions());
return { todos };
};

// lib/todos/queries.ts
export const todosQueryOptions = () =>
queryOptions({
queryKey: ["todos"],
queryFn: ({ signal }) => $getTodos({ signal }), // TanStack Query calls the server function
});
```

## Environment Shaking

TanStack Start strips any code not referenced by a `createServerFn` handler from the client build.

- Server-only code (database, fs) is automatically excluded from client bundles
- Only code inside `createServerFn` handlers goes to server bundles
- Code outside handlers is included in both bundles

## Importing Server Functions

Server functions wrapped in `createServerFn` can be imported statically. Never use dynamic imports for server-only code in components. Prefix server function names with `$` (e.g. `$getUser`) for easier identification.

```typescript
// Bad: dynamic import causes bundler issues
const rolesQuery = useQuery({
queryFn: async () => {
const { $listRoles } = await import("~/utils/roles.server");
return $listRoles({ data: {} });
},
});

// Good: static import
import { $listRoles } from "~/utils/roles.server";

const rolesQuery = useQuery({
queryFn: async () => $listRoles({ data: {} }),
});
```

## Server-Only Import Rules

1. `createServerFn` wrappers can be imported statically anywhere
2. Direct server-only code (database clients, fs) must only be imported:
- Inside `createServerFn` handlers
- In `*.server.ts` files

## Auth-specific Patterns

- See `.agents/auth.md` for auth middleware usage, route guards, and session/cookie patterns.
47 changes: 47 additions & 0 deletions .agents/typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!-- based on https://github.com/TanStack/tanstack.com/blob/main/.claude/typescript.md -->

# TypeScript Conventions

## Avoid Type Casting

Never cast types unless absolutely necessary. This includes:

- Manual generic type parameters (e.g., `<Type>`)
- Type assertions using `as`
- Type assertions using `satisfies`

## Prefer Type Inference

Infer types by going up the logical chain:

1. **Schema validation** as source of truth (e.g. Zod)
2. **Type inference** from function return types, API responses
3. **Fix at source** (schema, API definition, function signature) rather than casting at point of use

```typescript
// Bad
const result = api.getData() as MyType;
const value = getValue<MyType>();

// Good
const result = api.getData(); // Type inferred from return type
const value = getValue(); // Type inferred from implementation
```

## Generic Type Parameter Naming

All generic type parameters must be prefixed with `T`.

```typescript
// Bad
function withCapability<Args extends unknown[], R>(
handler: (user: AuthUser, ...args: Args) => R,
) { ... }

// Good
function withCapability<TArgs extends unknown[], TReturn>(
handler: (user: AuthUser, ...args: TArgs) => TReturn,
) { ... }
```

Common names: `T`, `TArgs`, `TReturn`, `TData`, `TError`, `TKey`, `TValue`
18 changes: 18 additions & 0 deletions .agents/workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Workflow

## Build Commands

- `pnpm build`: Only for build/bundler issues or verifying production output
- `pnpm lint`: Type-checking & type-aware linting
- `pnpm dev` runs indefinitely in watch mode
- `pnpm db` for Drizzle Kit commands (e.g. `pnpm db generate` to generate a migration)

Don't build after every change. If lint passes; assume changes work.

## Testing

No testing framework is currently set up. Prefer lint checks for now.

## Formatting

Oxfmt is configured for consistent code formatting via `pnpm format`. It runs automatically on commit via Husky pre-commit hooks, so manual formatting is not necessary.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
max_line_length = 90
max_line_length = 100
49 changes: 32 additions & 17 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
node_modules
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# Ignore lockfiles we don't use
# package-lock.json
# yarn.lock
# pnpm-lock.yaml
# bun.lock
# Dependencies
node_modules
.pnp
.pnp.js

.DS_Store
.cache
# Local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Testing
coverage

# Turbo
.turbo

.data
# Build Outputs
out/
build
dist
.nitro
.vercel
.output
.wrangler
.netlify
dist
/build/
/api/
/server/build
/public/build

.tanstack
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Misc
.DS_Store
*.pem
.cache
.tanstack
worker-configuration.d.ts
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pnpm exec lint-staged
36 changes: 36 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"tabWidth": 2,
"semi": true,
"printWidth": 100,
"singleQuote": false,
"endOfLine": "lf",
"trailingComma": "all",
"experimentalSortImports": {},
"experimentalTailwindcss": {
"stylesheet": "./packages/ui/styles/base.css",
"attributes": ["class", "className"],
"functions": ["clsx", "cn", "cva", "tw"]
},
"ignorePatterns": [
"pnpm-lock.yaml",
"package-lock.json",
"yarn.lock",
"bun.lock",
"pnpm-workspace.yaml",
"routeTree.gen.ts",
".tanstack-start/",
".tanstack/",
"drizzle/",
"migrations/",
".drizzle/",
".turbo",
".cache",
"worker-configuration.d.ts",
".vercel",
".output",
".wrangler",
".netlify",
"dist"
]
}
48 changes: 48 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "react", "react-perf", "jsx-a11y"],
"env": {
"builtin": true,
"node": true,
"browser": true
},
"jsPlugins": [
"eslint-plugin-turbo",
// Plugins with "/" in name have to be aliased for now
// Issue: https://github.com/oxc-project/oxc/issues/14557
{
"name": "eslint-tanstack-router",
"specifier": "@tanstack/eslint-plugin-router"
},
{
"name": "eslint-tanstack-query",
"specifier": "@tanstack/eslint-plugin-query"
}
],
"rules": {
"no-deprecated": "warn",
"typescript/no-floating-promises": "off",
"typescript/no-misused-spread": "off",

"turbo/no-undeclared-env-vars": "warn",

"eslint-tanstack-router/create-route-property-order": "warn",
"eslint-tanstack-query/exhaustive-deps": "warn",
"eslint-tanstack-query/stable-query-client": "warn",
"eslint-tanstack-query/no-rest-destructuring": "warn",
"eslint-tanstack-query/no-unstable-deps": "warn",
"eslint-tanstack-query/infinite-query-property-order": "warn",
"eslint-tanstack-query/no-void-query-fn": "warn",
"eslint-tanstack-query/mutation-property-order": "warn"
},
"ignorePatterns": [
"dist",
".wrangler",
".vercel",
".netlify",
".output",
"build/",
"worker-configuration.d.ts",
"scripts/"
]
}
18 changes: 0 additions & 18 deletions .prettierignore

This file was deleted.

9 changes: 0 additions & 9 deletions .prettierrc

This file was deleted.

6 changes: 1 addition & 5 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss"
]
"recommendations": ["oxc.oxc-vscode", "bradlc.vscode-tailwindcss"]
}
Loading