Monorepo structure
Nanahoshi uses a Bun workspaces + Turborepo monorepo with the following packages:Apps
apps/server
Hono HTTP server. Entry point that wires together API routers, authentication, BullMQ workers, and file downloads.
apps/web
TanStack Start/React frontend with file-based routing. Runs on port 3001 during development.
Packages
packages/api
Business logic: oRPC routers, services, repositories, BullMQ workers, and Elasticsearch client.
packages/auth
better-auth instance with email+password authentication and organizations plugin.
packages/db
Drizzle ORM schema and PostgreSQL client. Contains migration files and programmatic migration runner.
packages/env
Environment variable validation via
@t3-oss/env-core + Zod. Separate schemas for server and web.packages/config
Shared TypeScript and build configuration used by all workspaces.
Workspace configuration
The rootpackage.json defines workspace packages:
Workspace dependencies
Packages reference each other usingworkspace:* aliases:
Dependency catalog
Shared dependency versions are defined in the rootpackage.json under workspaces.catalog:
catalog::
Build system
Turborepo orchestrates builds across the monorepo.Development
Run all dev servers in parallel:turbo dev which:
- Starts
apps/serverin watch mode - Starts
apps/webin watch mode - Rebuilds dependent packages when their source changes
Production builds
Scoped commands
Run commands in specific workspaces using Turbo’s-F (filter) flag:
API layer
Nanahoshi uses oRPC for type-safe RPC procedures.Procedure builders
Base procedures are defined inpackages/api/src/index.ts:
publicProcedure— No authentication requiredprotectedProcedure— Requires authenticated session (throwsUNAUTHORIZEDotherwise)
Router composition
Routers are composed inpackages/api/src/routers/index.ts as appRouter. Each domain follows the layered pattern:
Request context
Context (packages/api/src/context.ts) extracts the better-auth session from request headers on every request.
Type safety
The frontend imports theAppRouter type from @nanahoshi-v2/api/routers/index, providing end-to-end type safety between server and client.
Server endpoints
The Hono app inapps/server mounts:
/rpc/*— oRPC RPC handler (used by the frontend)/api-reference/*— OpenAPI reference docs/api/auth/*— better-auth handler/admin/queues/— Bull Board dashboard for BullMQ queues/download/:uuid— Signed URL file download
Startup sequence
runMigrations()— Apply pending database migrationsfirstSeed()— Create default records if needed- Register BullMQ workers:
file.event.worker— Processes file add/delete eventsbook.index.worker— Indexes books into Elasticsearch
Frontend architecture
TanStack Start (SSR-capable) + TanStack Router (file-based routing). Route files live inapps/web/src/routes/. The auto-generated routeTree.gen.ts should not be edited manually.
oRPC client integration
The oRPC client is wired into TanStack Query viacreateTanstackQueryUtils in apps/web/src/utils/orpc.ts.
Use orpc.<router>.<procedure>.queryOptions(...) for queries in route loaders and components:
Route context
Route context provides{ orpc, queryClient }. Auth guards use beforeLoad to check session and redirect to /login.
Infrastructure
Located inpackages/api/src/infrastructure:
Queue
BullMQ queues (book-index, file-events) backed by Redis. Workers auto-scale concurrency based on CPU count.
Search
Elasticsearch client atinfrastructure/search/elasticsearch/search.client.ts.
- Index name:
${ELASTICSEARCH_INDEX_PREFIX}_books - Analyzer: Sudachi for Japanese text tokenization
Workers
Long-running BullMQ workers process background jobs:file.event.worker— Creates book records, triggers metadata enrichmentbook.index.worker— Indexes books into Elasticsearch for full-text search
Database
Drizzle ORM with PostgreSQL (groonga/pgroonga image for full-text search support).Schema organization
packages/db/src/schema/general.ts— App tables:book,book_metadata,library,library_path,user_library,author,series,publisher,collection,collection_book,liked_book,scanned_file,app_settingspackages/db/src/schema/auth.ts— better-auth tables (users, sessions, organizations)
Migrations
packages/db/src/migrate.ts— Programmatic migration runner, called on server startuppackages/db/src/migrations/— SQL migration files generated bydrizzle-kit generate
Schema change workflow
Key conventions
Package manager
Package manager
Use Bun (not npm/yarn). Commands:
bun add, bun install, bun run.Linter and formatter
Linter and formatter
Biome with tabs for indentation and double quotes for JS strings. Run
bun run check to auto-fix.Type safety
Type safety
oRPC provides end-to-end type safety. The frontend imports
AppRouter type from @nanahoshi-v2/api/routers/index.Environment variables
Environment variables
Server env validated in
packages/env/src/server.ts. Place variables in apps/server/.env.