Upload API and UI
The upload endpoint is in RAG.Api/Program.cs:
The upload endpoint queues work instead of doing it
app.MapPost("/api/documents", async (HttpRequest request, RagDbContext dbContext, IObjectStorage storage, IOptions<RagOptions> options, CancellationToken cancellationToken) =>
{
var documentId = Guid.NewGuid();
var objectKey = $"{documentId:N}/{fileName}";
await storage.UploadAsync(objectKey, stream, contentType, cancellationToken);
return Results.Accepted($"/api/documents/{documentId}");
});The upload endpoint is in RAG.Api/Program.cs:
POST /api/documents
The endpoint:
- verifies that the request is multipart form data;
- requires a PDF or TXT file;
- enforces the configured upload limit;
- writes the original file to object storage;
- creates a
DocumentRecordwithPendingstatus; - returns
202 Accepted.
The API deliberately avoids doing extraction and embedding in the request. It queues work by creating a pending database row.
Production note: the upload limit protects the request body, but this sample still trusts the uploaded file enough to store it and later process it. A production system would usually add stronger content validation, malware scanning, tighter per-user quotas, and generic error responses instead of returning internal exception details. This project keeps the behavior simple because it is a learning project, not production software.
The UI in RAG.Api/wwwroot is intentionally plain:
index.html: structure for upload and chat.styles.css: layout and progress styling.app.js: calls the API, polls document status, renders answers and citations.
The UI polls GET /api/documents every few seconds. For large books, ingestion can take a while, so the worker updates:
progressStageprogressPercentprocessedChunkstotalChunks
Production note: polling is simple and works well for this local sample, but a production UI would usually subscribe to status updates instead. For example, the API could publish document progress events through SignalR, WebSockets, Server-Sent Events, or a message broker-backed notification service, and the browser could receive updates as they happen instead of repeatedly asking the API for the full document list.
This lets the UI show useful progress instead of leaving a book stuck at a vague Processing state.
Delete and Reindex Controls
The API now exposes document lifecycle controls in addition to upload and status polling:
DELETE /api/documents/{id}
POST /api/documents/{id}/reindexDocumentManagementService owns those operations. Deletion removes the metadata row, deletes the original object, and removes vector points for the document. Reindexing resets status and progress back to Pending so the worker can rebuild chunks and vectors from the original file.
This matters because RAG systems need maintenance workflows. Once chunking, extraction, prompts, embeddings, or generated artifacts change, users need a way to rebuild the derived index rather than upload the same document again.