Skip to content

Technology

Every technology used in Saha Doküman

Below are the technologies used in every layer of the application, with the versions that actually run and their role in Saha Doküman. Nothing was added to make the list longer.

Versions come from the project’s package records. They are the exact versions in use, and Docker images are pinned to an exact version too.

Backend

The API is a single deployable on .NET 10, written as Minimal APIs without controllers.

TechnologyVersionIts job in Saha Doküman
.NET / C#10 (SDK 10.0.300)All of the server side is written in C# on .NET 10, built with nullable reference checks and warnings treated as errors.
ASP.NET Core Minimal APIs10.0Every endpoint is a Minimal API declared in a single file per feature folder; no controllers are used.
Microsoft.AspNetCore.OpenApi10.0.13Generates the API contract as an OpenAPI 3.1 document; the web and mobile models are written against it.
Scalar.AspNetCore2.18.0Provides an interactive reference UI for trying the API in development (switched off in production).
JWT Bearer10.0.13Validates access tokens; refresh tokens rotate on every use. Roles are never put in the token, they are read from the permission engine on every request.
PasswordHasher10.0Passwords are stored as hashes made by ASP.NET Core’s PasswordHasher; no plain password is kept.
Rate limiting10.0Per-IP and per-user request limits on sign-in and other sensitive routes; brute-force attempts lock the account.
Entity Framework Core10.0.13The object-relational mapping layer for data access and schema migrations.
Npgsql EF Core provider10.0.3The PostgreSQL provider for EF Core; it uses PostgreSQL-specific types and indexes.
Markdig1.4.1Page content is stored as restricted Markdown; Markdig validates it on the syntax tree and turns it into plain text for search.
SkiaSharp4.153.1Every uploaded image is decoded and re-encoded: location and EXIF metadata are dropped, the size is limited and a thumbnail is made.
DocumentFormat.OpenXml3.5.1Imports Word files, extracts search text from Word, Excel and PowerPoint files, and reads the Excel user-import template.
PdfPig0.1.16Extracts search text from PDF files and keeps page numbers for citations. It runs in a separate child process to isolate broken PDFs.
Serilog4.3.1Writes structured log files; tokens, passwords and query-string values are masked before they reach the log.
MailKit4.18.1Sends the platform’s e-mail outbox over SMTP: the new company admin’s set-password link and subscription renewal reminders.
TimeProvider.NET 10All clock reads go through TimeProvider; tests control time with a fake clock and the database’s microsecond precision is respected.

Data and search

All content, ledgers and the search index live in PostgreSQL; no separate search server is needed.

TechnologyVersionIts job in Saha Doküman
PostgreSQL18.6The single data store for pages, versions, ledgers, the search index, knowledge chunks and the audit log; the cluster is created with Turkish (ICU tr-TR) collation.
tsvector + GINFull-text search uses GIN-indexed tsvector columns; the vector is built in C# from the same word rules as the query.
TurkishNormalizerNormalises Turkish and Arabic letters with an explicit, length-preserving table; search normalisation happens only on the server.
ArabicWordsResolves Arabic word forms (such as the definite article) so a search without the “ال” prefix still finds the word.
Advisory locksTransaction-level application locks serialise concurrent work such as publishing and indexing.
xmin concurrencyConcurrent edits are detected with PostgreSQL’s xmin column (optimistic concurrency) instead of silently overwriting.
Append-only ledgersPublishing events and contribution-check records are append-only; the runtime role’s database rights exclude update and delete.

AI and RAG

Semantic search runs locally; answer generation is optional and only uses permitted excerpts.

TechnologyVersionIts job in Saha Doküman
Ollama0.35.1Runs the embedding model locally on the server; it sits on the internal network only and has no published port.
bge-m31024 dim.A multilingual embedding model (Turkish included) that produces a 1024-dimension vector for every knowledge chunk.
Microsoft.Extensions.AI10.10.0An abstraction for the embedding generator: Ollama in production, a deterministic fake in tests.
OllamaSharp5.5.0The client that connects the Microsoft.Extensions.AI abstraction to the local Ollama server.
System.Numerics.Tensors10.0.13SIMD-accelerated dot products and norms for the in-memory vector index; the permission filter is applied before scoring.
Hybrid retrieval + RRFThe top 40 results from vector and full-text search are merged with Reciprocal Rank Fusion (RRF); rule chunks get a small boost.
Anthropic C# SDK12.58.0The official C# SDK used to produce the assistant’s answers through the Claude API as a stream; error types and retries are typed.
claude-sonnet-5-5default modelThe default model is claude-sonnet-5-5; model and effort level are set in configuration, and the API key is read only from configuration or the secret store.
Citations + prompt cachingExcerpts are sent as document blocks with citations enabled, so each statement links to its source block; the system prompt is cached.
ModelContextProtocol.AspNetCore2.2.0A read-only MCP server at /mcp built with the official MCP C# SDK, with the tools search_documentation, get_page and list_rules.
Retrieval APIPOST /api/rag/retrieve for external systems: returns chunks with text, citation URL, block id, version and full provenance.
Personal access tokensPersonal access tokens with a scope, an expiry and revocation; only a hash is stored and every call acts with its owner’s permissions.

Web

The web interface of the application, built with types generated from the API contract.

TechnologyVersionIts job in Saha Doküman
React19.3.1The web interface is written with React 19 function components and hooks.
TypeScript5.9.3The web project is written in strict TypeScript; the API types are generated from the contract.
Vite8.3.4The build tool and dev server of the web app; it proxies the API locally.
Tailwind CSS4.3.3The interface is styled with Tailwind 4; logical utility classes keep the layout right-to-left ready for Arabic.
React Router7.18.4Page routing in the web app.
TanStack Query5.104.3Caches server state (lists, pages, permissions) and handles refetching and cancellation.
openapi-fetch0.17.0A small, type-safe client that calls the API with the OpenAPI types.
openapi-typescript7.13.0Generates the TypeScript types from the docs/openapi.json contract; the build fails when the contract changes.
TipTap + @tiptap/markdown3.32.0The rich-text engine of the block editor; it reads and writes content as Markdown.
react-markdown + remark-gfm10.1.0 / 4.0.1Displays content safely (raw HTML is never accepted); GFM tables and task lists are supported.
dnd-kit6.3.1 / 10.0.0Reorders blocks with drag and drop.
lucide-react1.59.0The icon set of the interface.
sonner2.0.8Shows feedback such as “saved” or “submitted” as toast notifications.
diff9.0.0Computes the difference between two versions in the version history.

Mobile

One code base for Android and iOS; it also runs on the web, for smoke tests.

TechnologyVersionIts job in Saha Doküman
Flutter / Dart3.41.9 / 3.11Builds the Android and iOS app from one code base (Flutter 3.41, Dart 3.11).
flutter_riverpod3.3.2State management with Notifier, AsyncNotifier and Provider; no code generation.
go_router17.5.0Declarative page routing of the mobile app.
dio5.11.1The single HTTP client, with an auth interceptor that refreshes the token in a single flight.
flutter_secure_storage11.2.0Keeps the session tokens in the operating system’s secure store (Keychain / Keystore).
flutter_markdown_plus1.0.12Shows page content as Markdown behind a single AppMarkdown widget.
image_picker / file_picker1.2.4 / 13.1.0Photo and file selection; uploads are sent as bytes (MultipartFile.fromBytes).
url_launcher6.3.3Opens link blocks and external addresses in the browser.
flutter_localizations + intl0.20.2Localisation and date/number formats for the Turkish, Arabic (right-to-left) and English interface.
shared_preferences2.5.6Keeps non-secret user preferences.

Infrastructure and operations

sahadoc.com runs on a single Linux server with Docker; companies get their own database and service container.

TechnologyVersionIts job in Saha Doküman
Docker + ComposeThe production stack is defined with Docker Compose: PostgreSQL, Ollama and the API are separate containers; the database and Ollama sit on the internal network only.
nginx1.24Terminates TLS and redirects www to the apex domain; it writes the X-Forwarded headers itself, and its access log leaves out the query string and the Authorization header.
Let's EncryptFree TLS certificates; a wildcard certificate for the company subdomains is issued with DNS validation.
Multi-tenant hostingIn the SaaS each company runs with its own database, file folder and dependency container; keys derived per company make one company’s token useless at another.
Backup + restoreThe database and the files are backed up together, and the restore script keeps them together.
Verification jobsJobs that verify the ledger chain and file integrity; in the SaaS they loop over every company database.
Structured logsStructured, daily-rolling log files with secrets removed; container logs are size-limited.

Quality

Permissions and privacy are verified both by tests and by an adversarial audit.

TechnologyVersionIts job in Saha Doküman
xUnit v22.9.3The backend test framework (v2).
Shouldly4.3.0Readable assertions; FluentAssertions and Moq are deliberately not used.
NSubstitute6.2.0Substitutes dependencies in unit tests.
Respawn7.0.0Quickly resets the database between integration tests; every test collection has its own database.
ASP.NET Core test host10.0.13Tests the API end to end, in memory against a real PostgreSQL.
FakeTimeProvider10.11.0Tests time-dependent behaviour (reminders, session lifetimes) deterministically.
Persona x endpoint matrixA persona × endpoint table for every endpoint: an unauthorised person must get 404, and every new endpoint is added to the table.
OpenAPI snapshot + JSON samplesThe OpenAPI document is a snapshot test; JSON samples feed the client tests; the contract is changed deliberately.
Vitest5.0.5The web test runner.
Testing Library (React)16.3.3Tests components the way a user sees them.
MSW3.0.3Mocks the API at the network level in web tests.
flutter_test + mocktail1.0.5Mobile unit and widget tests; models are tested against the docs/samples JSON files.
Red-team auditEvery leak channel (search, files, notifications, assistant, API, MCP) is probed with unauthorised personas, and revocation scenarios are tested.

The journey of a request

When a user searches or asks the assistant a question, this happens, in order.

  1. Client

    The web or mobile app (or an external tool over MCP) sends an HTTPS request.

  2. nginx

    TLS ends here; the client address and scheme headers are written reliably.

  3. Identity and limits

    The token is validated, the rate limit is applied and the company is determined (from the subdomain in the SaaS).

  4. Permission

    The permission engine says what the user may see; everything not visible is a 404.

  5. Data and search

    Full-text and vector candidates are fetched from PostgreSQL and filtered by permission.

  6. AI (optional)

    The selected permitted excerpts are checked again; if enabled, Claude writes the answer with sources.

  7. Response

    The result returns to the client with its source information, never cached by an intermediate layer.

  1. Clients

    • Web app — React 19
    • Mobile app — Flutter · Android / iOS
    • External AI — MCP · access token
  2. One Saha Doküman application

    • Saha Doküman API — .NET 10 · permission engine
    • Assistant (RAG) — hybrid search + re-check
    • Embedding worker — in the background
  3. Data and AI

    • PostgreSQL 18 — content · versions · ledger · knowledge chunks + vectors
    • Ollama · bge-m3 — local embeddings
    • Claude API — Anthropic · optional

The journey of a piece of information

From the moment someone writes it to the moment someone finds it: every step has an owner, and four checkpoints stand on the way.

  1. Add

    • Draft

      Written in the web or mobile app, from a template, or imported from Word.

    • Contribution check

      Language review and similar-information check. If the information already exists, you see it first.

      Before saving

  2. Approve

    • Change request

      The contribution goes to the department admin with its note.

    • Approval

      The admin reviews it, corrects it if needed, and approves or rejects it.

      Before publishing

  3. Publish

    • One publishing service

      The new version is written together with who added it and who published it.

    • Ledger

      Append-only and linked by a chain of hashes: the record cannot be rewritten.

  4. Index

    • Search index

      Updated at once, ready for search in Turkish, Arabic and English.

    • Knowledge chunks

      Sections, rules, tables and file pages become short excerpts that keep their source.

    • Local embeddings

      Vectors are computed on the server with Ollama; the text does not leave.

  5. Find and answer

    • Search

      Only pages you may see; hidden ones do not show, not even as a count.

      Permission filter

    • Assistant

      Semantic and full-text results are merged; if the company enabled it, only permitted excerpts go to Claude and the answer cites them.

      Checked again

    • Other AI tools

      Through MCP with a personal access token, under the same permissions.

      Checked again

Four checkpoints on the way

  1. Before savingEvery addition and change passes a contribution check.
  2. Before publishingA contributor’s change is published only after an admin approves it.
  3. Permission filterEvery result and every excerpt is filtered by the user’s permissions.
  4. Checked againEach excerpt is checked once more before it leaves for AI.

A technical question?

Let us go through the architecture, the installation and the security audit together.

Go to your company

Enter your company code and we will take you to your company’s Saha Doküman address.

If you do not know the code, ask your company’s administrator.