Live Demo
- Open the public GitHub Pages demo
- Scope: credential-free demonstration with synthetic data.
Kkuldanji converts internal documents into a structured 6-section handover document and supports follow-up Q&A via retrieval (vector + semantic search).
This repo explores a document-to-handover workflow with a security-conscious web stack and an explicit split between:
- review-only fallback/demo mode
- local BYO LLM mode
- cloud-connected Azure mode when configuration is complete
Core capabilities:
- Document ingestion (PDF/DOCX/TXT/images/code)
- LLM-based preprocessing into structured JSON chunks
- Retrieval on Azure AI Search (embeddings + semantic ranking)
- Generation/Q&A on Azure OpenAI
- Handover completeness gate that blocks review-ready export when owner/timeline/risk/reference coverage is incomplete
- Practical web security basics (JWT, refresh tokens, CSRF, security headers)
Status: working prototype for explicit development/test environments. Authentication is a local demo implementation, not production identity.
Security boundary: AUTH_BACKEND=demo-local uses bundled users, self-issued JWT role claims, and process-local refresh/CSRF/rate-limit state. staging and production intentionally fail during startup even when a strong JWT_SECRET is present. Do not expose this backend to untrusted users or customer documents until external identity, server-authoritative tenant roles, shared security state, and document-level authorization are implemented.
System Overview
A document-handover assistant that turns messy operational files into cited Q&A, controlled workflows, and safer support handoffs.
| Area | Details |
|---|---|
| Users | Support teams, onboarding teams, internal operations groups, and document-heavy service organizations. |
| Technical path | Validate the demo, README, architecture notes, and quality gate before deeper workflow review. |
| System scope | Retrieval-backed Q&A, document workflow controls, web security boundaries, and a hosted prototype surface. |
| Operating boundary | Private files and customer documents must stay inside approved storage; the repository should remain a prototype and pattern library. |
| Evaluation path | Use the README quick start and repository tests to verify upload, retrieval, citation, and workflow behavior. |
Evaluation Path
- Start here: Compare review-only fallback, local BYO LLM, and Azure-connected mode before testing upload.
- Local demo: Run
make backend-runandmake frontend-dev, then openhttp://localhost:5173. - Checks: Run
make verify; it compiles the backend, runs backend tests, and verifies the frontend.
Technical Notes
- Technical guide summarizes the system scope, first files to inspect, verification commands, and known boundaries.
- Quality notes lists the local checks, CI surface, and release expectations for this repository.
- Enterprise readiness notes outlines security, data, operations, integration, and handoff expectations.
When to use this repo
- Use honeypot when the architecture question is document ingestion → retrieval → editable handover workflow with explicit auth and runtime-mode switching.
- Use Upstage-DocuAgent when the stronger story is document-to-learning delivery and LMS packaging.
- Use secure-xl2hwp-local when the stronger story is strict local/high-trust document transformation without cloud dependencies.
This repo is the best place to review the three execution postures side by side:
- review-only demo fallback,
- local BYO LLM mode,
- cloud-connected Azure mode.
Project layout
- Primary runtime: the document-to-handover workflow lives in
app/,frontend/, and the FastAPI services. - Packaging experiments: Railway, Vercel, Electron, and desktop build files are optional delivery paths for the same workflow.
- Related repos:
Upstage-DocuAgent,enterprise-llm-adoption-kit,secure-xl2hwp-local
Scope
- System architecture design (end-to-end flow + component boundaries)
- Backend implementation (FastAPI ingestion/status, extraction routing, blob/search integration)
- RAG quality improvement support (schema-first chunking + retrieval tuning)
Problem
Handover documents are often:
- Time-consuming to write and review
- Inconsistent in structure across teams
- Missing key details (owners, timelines, risks, references)
Kkuldanji aims to reduce that overhead by extracting structured information from uploaded documents and generating an editable handover template, with retrieval-backed Q&A for follow-ups.
Key Features
- Upload multiple files (PDF/DOCX/TXT/images/code)
- Async processing pipeline with progress tracking
- LLM preprocessing to structured JSON chunks (optimized for indexing/search)
- Retrieval-backed chat using top-k relevant chunks
- "Generate report" flow producing a 6-section handover JSON that the UI renders/edit
- Optional Electron packaging for desktop usage
Architecture
┌───────────────────────────────────────────────────────────────┐
│ Frontend (React + Vite + TypeScript) │
│ - Upload sidebar │
│ - Handover editor (6 sections) │
│ - Chat/Q&A │
└───────────────────────────────┬───────────────────────────────┘
│ HTTP (JWT + CSRF header)
┌───────────────────────────────▼───────────────────────────────┐
│ Backend (FastAPI) │
│ - app/routers/auth.py (login/refresh/me) │
│ - app/routers/upload.py (async ingest + status) │
│ - app/routers/chat.py (analyze + chat) │
│ - app/security.py (JWT/CSRF/rate-limit helpers) │
│ - app/services/* (blob/doc/search/llm) │
└───────────────────────────────┬───────────────────────────────┘
│
┌───────────────────────────────▼───────────────────────────────┐
│ Cloud Services (optional for local demo) │
│ - Azure Blob Storage (raw + processed JSON) │
│ - Azure Document Intelligence (OCR / PDF pipeline) │
│ - Azure AI Search (vector + semantic search) │
│ - Azure OpenAI (generation + embeddings) │
│ - Google Gemini (preprocessing) │
└───────────────────────────────────────────────────────────────┘
LLM Strategy
This project uses "model role separation" to reduce failure modes and cost:
- Preprocess (long text -> structured JSON chunks)
- Provider: Google Gemini (OpenAI-compatible endpoint)
- Goal: robust JSON extraction for long inputs (up to 50,000 chars in this prototype)
- Output: chunk list with metadata fields (
fileName,parentSummary,chunkSummary,tags,relatedSection, ...)
- Retrieval + Q&A / Report generation
- Provider: Azure OpenAI (configurable deployment)
- Goal: higher answer quality and consistent schema output
- Optional local provider override (BYO LLM)
- Provider: any OpenAI-compatible endpoint (for example, Ollama local)
- Goal: run real LLM inference in local demo without cloud keys
- Scope: per-request override via headers from the frontend BYO LLM panel
Configuration is controlled by proto.env:
GEMINI_MODEL(preprocess)AZURE_OPENAI_CHAT_DEPLOYMENT(generate report, chat)AZURE_OPENAI_EMBEDDING_DEPLOYMENT(embeddings for retrieval)
Directory Structure
.
├── app/
│ ├── main.py # FastAPI entrypoint, CORS, security headers
│ ├── config.py # loads proto.env, optional Key Vault helper
│ ├── security.py # JWT/refresh/CSRF/rate-limit helpers (demo-grade)
│ ├── routers/
│ │ ├── auth.py # /api/auth/*
│ │ ├── upload.py # /api/upload/*
│ │ └── chat.py # /api/analyze, /api/chat
│ └── services/
│ ├── openai_service.py # Azure OpenAI + Gemini calls
│ ├── search_service.py # Azure AI Search index/create/search
│ ├── blob_service.py # Azure Blob (raw/processed)
│ ├── document_service.py # text extraction (DOCX local + Azure DI)
│ └── prompts.py # JSON extraction prompts
├── frontend/
│ ├── App.tsx
│ ├── services/ # auth + API calls
│ ├── components/ # UI
│ └── electron/ # optional desktop packaging
├── proto.env.example # local env template (copy to proto.env)
├── docs/ops/RUNBOOK.md
└── .github/workflows/ci.yml
Prerequisites
- Python 3.11+
- Node.js 18+
1) Backend
Demo mode (no cloud keys):
- You can run the full UI end-to-end without Azure/Gemini credentials.
- Copy
proto.env.exampletoproto.env; startup requires explicitENVIRONMENT=developmentorENVIRONMENT=test. - Keep
APP_MODE=demo,AUTH_BACKEND=demo-local, andSECURITY_STATE_BACKEND=memoryfor the supported local walkthrough. - Demo mode supports:
txt,md, code files, anddocxuploads (PDF/images require live mode). - Upload preprocessing is deterministic by default in demo mode (stable/faster local flow).
- To force user LLM preprocessing during upload, set
DEMO_LLM_PREPROCESS=true.
Live mode (Azure/OpenAI/Search/Gemini): APP_MODE=live connects cloud document services while retaining the same demo-only authentication boundary. It is an integration evaluation mode, not a production deployment profile. Even locally, it requires an explicit 32-byte-or-longer JWT_SECRET and overrides for all three HONEYPOT_DEMO_*_PASSWORD values.
Create proto.env before either mode:
cp proto.env.example proto.env
Install and run:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e ".[dev]"
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
Backend endpoints:
- Health:
GET http://localhost:8000/api/health - Runtime brief:
GET http://localhost:8000/api/runtime-brief - Runtime scorecard:
GET http://localhost:8000/api/runtime-scorecard - Swagger:
http://localhost:8000/docs
2) Frontend
cd frontend
npm ci
## export VITE_GISCUS_CATEGORY_ID="DIC_kwxxxx"
npm run dev
Open:
http://localhost:5173
3) Optional: Ollama local demo path (no cloud key)
Run Ollama locally:
ollama pull llama3.2
ollama serve
Then in the web UI:
- Open
BYO LLMpanel - Click
Ollama 빠른 연결 - Keep API key empty (local mode supports no-key override)
- Run upload/analyze/chat as usual
Default local endpoint:
http://127.0.0.1:11434/v1
Demo Accounts
Bundled users and passwords exist only to keep the explicit local demo reproducible. Override the HONEYPOT_DEMO_*_PASSWORD values when needed, but do not publish or deploy these accounts. Changing their passwords does not make the authentication model production-capable.
Runtime notes
- The primary runtime is the FastAPI backend in
app/plus the React/Vite client infrontend/. frontend/dist/is the static build export; editable source lives underfrontend/src/.frontend/electron/is optional desktop packaging.- If OpenAI is configured, it runs as BYOK or operator-only refresh -- no public arbitrary-upload endpoint.
Evaluation Path
GET /api/health— confirm demo/BYO/Azure posture firstGET /api/runtime-brief— inspect auth, retrieval, and configuration modeGET /api/runtime-scorecard— confirm route pressure and security posture- Login to the frontend and walk one upload → analyze → handover pass
GET /api/approval-matrix— inspect handover completeness before trusting export-readiness claims
API
All state-changing requests must include:
Authorization: Bearer <access_token>X-CSRF-Token: <csrf_token>
Read endpoints that expose indexed/document metadata also require:
Authorization: Bearer <access_token>
Auth
POST /api/auth/login- body:
{ "email": "...", "password": "..." } POST /api/auth/refresh- body:
{ "refresh_token": "..." } GET /api/auth/mePOST /api/auth/validate-token
Upload
POST /api/upload(multipart)- fields:
file, optionalindex_name - constraints:
- file extension must be one of:
txt,text,md,pdf,docx,py,js,java,c,cpp,h,cs,ts,tsx,html,css,json - size limit:
MAX_UPLOAD_BYTES(default 20MB) index_nameformat: lowercase letters/numbers/-/_, 2-63 charsGET /api/upload/status/{task_id}(owner/admin only)
Status and schema endpoints
GET /api/health- runtime status, ops contract, review links
GET /api/meta- trust boundary, staged evidence, runtime posture
GET /api/runtime-brief- runtime contract for auth mode, retrieval mode, and configuration status
GET /api/runtime-scorecard- compact route pressure, alert count, and security posture snapshot
GET /api/approval-matrix- role coverage, blocked sections, and handover readiness gate
GET /api/schema/handover- handover export contract (
honeypot-handover-v1)
The frontend renders the same status board on the login screen and main workspace.
Key implementation files
app/main.py-- FastAPI entrypoint and middlewareapp/service_meta.py-- runtime brief and status buildersapp/runtime_scorecard.py-- runtime scorecard contractapp/routers/ops.py-- route diagnostics and runtime infofrontend/components/ServiceReadinessBoard.tsx-- readiness board component
GET /api/upload/documents(optional query:index_name)GET /api/upload/indexesGET /api/upload/stats(optional query:index_name)