Repo layout
Monorepo with four runnable apps, shared types, and ops configs. No build system (Turbo/Nx) — each app has its own package.json and is independently buildable. Coordination is by convention.
Top level
ai-knowledge-base/
├── apps/
│ ├── web/ Next.js 15 frontend
│ ├── api/ Hono + Bun backend
│ ├── embedder/ Python FastAPI (embedding + reranker)
│ ├── worker/ Python BullMQ consumer
│ └── docs/ This documentation site
├── packages/
│ └── shared/ Shared TypeScript types
├── scripts/ Utility scripts (embed_chunks.py, etc.)
├── docker/
│ └── init.sql Postgres init (pgvector, RLS policies)
├── docker-compose.yml
├── AGENTS.md Rules for AI agents on this repo
└── README.md
apps/web
apps/web/
├── app/
│ ├── (dashboard)/
│ │ ├── layout.tsx Auth gate, sidebar, topbar wrapper
│ │ ├── page.tsx Home (/)
│ │ ├── projects/ /projects, /projects/[id]
│ │ ├── library/ /library
│ │ ├── admin/ /admin/* (full Admin cluster)
│ │ ├── engineer/ /engineer/* (LLM providers, workers, logs)
│ │ └── new/ /new (new thread picker)
│ ├── onboarding/
│ │ └── first-login/ Bootstrap wizard
│ ├── share/[token]/ Guest share page (no auth)
│ ├── login/
│ ├── globals.css Design tokens (source of truth)
│ └── layout.tsx Root HTML
├── features/ Feature-scoped components
│ ├── admin/ Admin sidebar, users, org, audit pages
│ ├── projects/ project-view, project-settings
│ ├── chat/ new-chat, chat-view
│ ├── library/ library-view, upload-modal, doc-detail
│ └── engineer/ Engineer sub-area
├── components/
│ ├── ui/ Shared primitives: Button, Tabs, StatCard…
│ ├── layout/ Topbar, Sidebar, PageLayout
│ └── org/ Org-specific: DepartmentPicker, GrantAccessModal…
├── lib/
│ ├── api.ts API client (auto-refresh JWT)
│ ├── auth.tsx React auth context
│ ├── hooks/ SWR hooks: useUsers, useDepartments, etc.
│ ├── types/ access.ts — mirrors backend types
│ └── mocks/ Mock data (dev-only, intentional)
├── middleware.ts Bootstrap redirect gate
└── package.json
UI rules are locked in AGENTS.md — see Admin layout pattern and Components.
apps/api
apps/api/
├── prisma/
│ ├── schema.prisma Single source of truth for DB
│ └── migrations/ Versioned SQL migrations
├── src/
│ ├── index.ts App bootstrap + route mounting
│ ├── db/
│ │ └── client.ts Prisma client singleton
│ ├── middleware/
│ │ ├── auth.ts authMiddleware + legacy adminOnly
│ │ ├── access.ts requireAuth, requirePlatformRole,
│ │ │ requireProjectAccess, requireBootstrapped
│ │ └── audit.ts Auto audit-log writer
│ ├── lib/
│ │ ├── access.ts resolveAccess() — 6-level priority
│ │ └── jwt.ts Token signing/verification
│ ├── routes/
│ │ ├── auth.ts /auth/login, /auth/refresh, /auth/me
│ │ ├── bootstrap.ts /bootstrap/status, /bootstrap/init
│ │ ├── users.ts /users CRUD + assign dept/role
│ │ ├── departments.ts /departments + members + grants
│ │ ├── groups.ts /groups CRUD under dept
│ │ ├── grants.ts /projects/:id/grants
│ │ ├── share-requests.ts Share workflow
│ │ ├── share-tokens.ts Token management
│ │ ├── audit-log.ts /audit-log query
│ │ ├── public-share.ts /share/:token (guest)
│ │ ├── projects.ts /projects CRUD
│ │ ├── documents.ts /documents upload + query
│ │ ├── chat.ts /chat/projects/:id POST (SSE stream)
│ │ ├── providers.ts /providers LLM config
│ │ └── memory.ts /memories project memory
│ ├── services/
│ │ ├── llm.ts Provider resolver + chat stream
│ │ ├── rag.ts Hybrid search + rerank
│ │ └── websearch.ts Tavily integration
│ └── types/
│ └── access.ts Shared enums (PlatformRole, etc.)
└── package.json
apps/embedder
Python FastAPI, sentence-transformers. Two endpoints:
POST /embed— multilingual-e5-small, 384-dim, needspassage:orquery:prefixPOST /rerank— BGE-reranker-v2-m3 cross-encoder
apps/worker
Python BullMQ consumer. Watches document-processing queue:
- Parse (PyMuPDF / python-docx / markdown / txt)
- Chunk (target ~400 tokens, 50 token overlap)
- Embed via embedder service
- Insert chunks with 384-dim vector + full-text tsvector
packages/shared
Minimal — just TypeScript types used by both web and api. Keep it tiny.
Conventions
- File naming:
kebab-case.tsfor files,PascalCasefor components - Feature-scoped components live in
apps/web/features/<feature>/ - Shared primitives live in
apps/web/components/ui/ - Never create a new primitive if an existing one covers the case — extend instead
- Never use native
<select>— always<Select>fromcomponents/ui/select.tsx - All top bars are
h-[52px]withflex items-center px-6 border-b border-line