imbytecat 7f4cfc8973 refactor: 跨边界导入改用 Node # subpath imports(package.json + drizzle SQL)
业务代码沿用 @/* (shadcn 等生态约定);仅"跳出 src/"的真实跨边界场景采用 Node 标准 #name:

- #package → ./package.json:替换 @/../package.json (2 处) 这种用 alias 跳出根目录的 hack
- #drizzle/*.sql → ./drizzle/*.sql:让 codegen 输出的 migrations.gen.ts 不再走 ../../../

效果:
- tsconfig.paths 与 vite.resolve.tsconfigPaths 维持,业务代码 0 改动
- 配置仅新增 package.json#imports 4 行
- Bun runtime / Vite 8 / TS bundler / 编译产物均原生支持

端到端验证:
- 编译二进制:CREATE TABLE 和 'fullstack-starter' 内嵌 ✓
- ./server migrate:应用嵌入式迁移成功 ✓
- ./server 运行:/health、/api/spec.json (title/version)、RPC create+list、OpenAPI create、Scalar /api/docs 全部 OK ✓
- bun run dev:Vite SSR <title>fullstack-starter</title> 注入 ✓
- fix/typecheck/test/build/compile 全绿
2026-04-25 15:15:20 +08:00

fullstack-starter

Opinionated single-binary fullstack starter. Bun + TanStack Start (React 19 SSR) + ORPC (contract-first) + Drizzle + PostgreSQL, deployed as one compiled executable.

Agent notes and non-obvious invariants live in AGENTS.md. Read it before making structural changes.

Quick start

cp .env.example .env
bun install
bun run db:push     # dev: sync schema without migration files
bun run dev         # http://localhost:3000

RPC endpoint: /api/rpc · OpenAPI docs: /api/docs · Spec: /api/spec.json · Liveness: /health.

Scripts

Command What it does
bun run dev Vite dev server on port 3000 (strict)
bun run build Build to .output/
bun run compile Single-binary out/server-<target> via bun build --compile
bun run cli <cmd> Run a CLI subcommand in source (serve, migrate)
bun run typecheck tsc --noEmit
bun run test bun test (colocated *.test.ts)
bun run fix Biome lint + format + organize imports
bun run db:push Dev-only schema sync (no migration files)
bun run db:generate Write SQL migrations to ./drizzle and regenerate migrations.gen.ts
bun run db:embed Regenerate src/server/db/migrations.gen.ts from ./drizzle (run if you hand-edit migrations)
bun run db:migrate Apply migrations locally via drizzle-kit (dev convenience)
bun run db:studio Drizzle Studio

Cross-compile: bun run compile:{linux,darwin,windows}[:arch].

Add a feature (e.g. post)

Contract-first, additive. Create or touch files in this order:

  1. src/server/db/schema/post.ts — define postTable, spread ...generatedFields.
  2. src/server/db/schema/index.tsexport * from './post'.
  3. src/server/api/contracts/post.contract.ts — derive Zod from the table via drizzle-zod.
  4. src/server/api/contracts/index.ts — add post to the contract object.
  5. src/server/api/routers/post.router.ts — implement os.post.*.handler(...).
  6. src/server/api/routers/index.ts — add post to the router object.
  7. src/client/queries/post.ts — export useInvalidatePosts (or finer-grained helpers) for affected list keys.
  8. src/routes/<page>.tsx — UI with useSuspenseQuery + loader ensureQueryData; call the helper from mutation onSuccess.
  9. bun run db:generate — emit SQL migrations to ./drizzle and embed them into src/server/db/migrations.gen.ts.

Deploy

Always migrate-then-serve. Migrations are embedded in the binary; the binary is the only artifact you ship.

./server migrate   # applies embedded migrations against $DATABASE_URL
./server           # starts HTTP server (default subcommand)

compose.yaml models the pattern with a one-shot migrate service that app depends on (service_completed_successfully). On Kubernetes: run ./server migrate as an initContainer or Helm pre-upgrade Job.

docker compose up --build
S
Description
No description provided
Readme 2.8 MiB
Languages
TypeScript 98.7%
Dockerfile 1%
JavaScript 0.2%