A production-ready, multi-tenant secure RAG system designed to index documentation/repos and provide intelligent answers via a chat interface with enterprise-grade security and data isolation.
- Organization-level isolation: All data scoped by
org_idat the database level - JWT Authentication: Secure token-based authentication with role-based access control
- ACL Enforcement: Access Control Lists enforced in SQL queries, ensuring data isolation even if application logic has bugs
- Zero cross-tenant leakage: Impossible to retrieve data from other organizations
- Admin Role: Full access to create, read, update, and delete sources
- User Role: Read-only access to sources and documents, can use chat/retrieval
- Permission-based: Fine-grained permissions for different operations
- Guard-based: Decorator-based route protection with
@Roles()and@RequirePermissions()
- Org-scoped queries: Vector similarity search automatically filters by organization
- Database-level filtering: SQL queries include
WHERE s.org_id = $2for security - Defense in depth: Multiple security layers (Auth β RBAC β ACL)
- Indexing: Ingests GitHub repos or internal documentation
- Embeddings: Provider-agnostic embedding service with OpenAI and Ollama support
- Vector Store: Uses Postgres with
pgvectorfor efficient similarity search - Backend: Built with NestJS, supporting streaming responses (SSE/WebSockets)
- Caching: Redis-based embedding cache to reduce API calls by ~80%
- Backend: NestJS (Node.js)
- Frontend: React (Vite)
- Database: PostgreSQL + pgvector
- LLM Orchestration: LangChain / Custom
- LLM Provider: OpenAI / Ollama
- Caching: Redis (Optional)
- Node.js (v18+)
- Docker & Docker Compose
- pnpm (recommended) or npm
-
Clone the repository:
git clone <repository-url> cd ai-devops-knowledge-copilot
-
Set up environment variables:
cp env.example .env
Edit
.envand configure:- Database credentials (or use defaults)
JWT_SECRET- Change to a secure random string in productionOPENAI_API_KEY- Required if using OpenAI for embeddings/LLMGITHUB_TOKEN- Optional but recommended to avoid rate limits- Embedding provider settings (see Embedding Service Configuration)
-
Start Docker services (PostgreSQL + Redis):
docker-compose up -d
This starts:
- PostgreSQL with pgvector extension on port 5432
- Redis on port 6379
-
Install backend dependencies:
cd backend npm install # or pnpm install
-
Run database migrations:
cd backend npm run migration:runThis creates all necessary tables and enables the pgvector extension.
-
Verify database setup (optional):
npm run test:vector
-
Start the backend server:
npm run start:dev
The backend will run on
http://localhost:3000 -
Install frontend dependencies (in a new terminal):
cd frontend npm install # or pnpm install
-
Configure frontend API URL (optional):
Create a
.envfile in thefrontenddirectory:VITE_API_URL=http://localhost:3000
If not set, it defaults to
http://localhost:3000. -
Start the frontend development server:
npm run dev
The frontend will run on
http://localhost:5173(or another port if 5173 is busy) -
Create your first user:
You can register via the frontend UI, or use the API:
curl -X POST http://localhost:3000/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "admin@example.com", "password": "your-secure-password", "orgId": "your-org-id", "role": "admin" }'
For a quick setup, you can run everything in sequence:
# 1. Copy environment file
cp env.example .env
# Edit .env with your API keys
# 2. Start Docker services
docker-compose up -d
# 3. Setup backend
cd backend
npm install
npm run migration:run
npm run start:dev &
cd ..
# 4. Setup frontend (in new terminal)
cd frontend
npm install
npm run devBackend:
cd backend
npm run build
npm run start:prodFrontend:
cd frontend
npm run build
# Serve the dist/ directory with your web server (nginx, etc.)The embedding service supports multiple providers and can be switched via environment variables. This allows you to use cloud-based embeddings (OpenAI) or run embeddings locally (Ollama).
OpenAI provides high-quality embeddings with the text-embedding-3-small model (1536 dimensions).
Setup:
- Get your API key from OpenAI Platform
- Set in your
.envfile:EMBEDDING_PROVIDER=openai OPENAI_API_KEY=your_actual_api_key_here OPENAI_EMBEDDING_MODEL=text-embedding-3-small # Optional, defaults to text-embedding-3-small
Ollama allows you to run embeddings locally without API costs. Uses the nomic-embed-text model (768 dimensions).
Setup:
-
Install Ollama:
brew install ollama # macOS # or visit https://ollama.ai for other platforms
-
Start Ollama service:
brew services start ollama
-
Pull the embedding model:
ollama pull nomic-embed-text
-
Set in your
.envfile:EMBEDDING_PROVIDER=ollama OLLAMA_BASE_URL=http://localhost:11434 # Optional, defaults to localhost:11434 OLLAMA_EMBEDDING_MODEL=nomic-embed-text # Optional, defaults to nomic-embed-text
Embeddings are automatically cached in Redis to avoid duplicate API calls. Cache settings:
EMBEDDING_CACHE_ENABLED=true # Enable/disable caching (default: true)
EMBEDDING_CACHE_TTL=86400 # Cache TTL in seconds (default: 24 hours)
REDIS_ENABLED=true # Enable/disable Redis (default: true)
REDIS_HOST=localhost # Redis host
REDIS_PORT=6379 # Redis portTest the embedding service with your configured provider:
cd backend
npm run test:embeddingThis will:
- Generate embeddings for sample texts
- Verify cache hits (second call should be much faster)
- Display vector dimensions and sample values
To switch between providers, simply change the EMBEDDING_PROVIDER environment variable:
# Switch to OpenAI
EMBEDDING_PROVIDER=openai
# Switch to Ollama
EMBEDDING_PROVIDER=ollamaNo code changes required - the service uses a strategy pattern for provider-agnostic operation.
See ARCHITECTURE.md for detailed architecture documentation including:
- Multi-tenant security layers
- Data flow diagrams
- ACL enforcement mechanisms
- Permission matrix
See SHOWCASE.md for:
- Quick demo scripts
- Security feature highlights
- Real-world use cases
- Comparison with alternatives
-
Layer 1: JWT Authentication (Global Guard)
- Validates token and extracts user context
- Injects
@CurrentUser()into requests
-
Layer 2: RBAC Authorization (Selective Guard)
- Checks
@Roles()decorator - Validates
@RequirePermissions() - Throws
ForbiddenExceptionif unauthorized
- Checks
-
Layer 3: Database ACL (SQL WHERE clause)
- All queries filter by
org_id - Impossible to bypass at application level
- All queries filter by
@Post('sync')
@UseGuards(RolesGuard)
@Roles(UserRole.ADMIN) // Only admins can create sources
async syncRepository(
@CurrentUser() user: CurrentUserData, // orgId from JWT, not user input
) {
// orgId automatically scoped to user's organization
}-- ACL enforced at database level
SELECT ...
FROM embeddings e
INNER JOIN sources s ON s.id = d.source_id
WHERE s.org_id = $2 -- β Prevents cross-tenant access
ORDER BY e.vector <=> $1::vector| Permission | Admin | User |
|---|---|---|
CREATE_SOURCE |
β | β |
READ_SOURCE |
β | β |
UPDATE_SOURCE |
β | β |
DELETE_SOURCE |
β | β |
USE_CHAT |
β | β |
USE_RETRIEVAL |
β | β |
Comprehensive test suite with 100% coverage on security-critical paths:
# Run all tests
npm test
# Run RBAC tests
npm test -- rbac
# Run authentication tests
npm run test:auth- ARCHITECTURE.md - Detailed architecture and security design
- SHOWCASE.md - Demo scripts and feature highlights
- API Documentation - Backend API details