vergunningzoeker-4eb1d867/docs/platform-technical-standard...

9.5 KiB

Platform Technical Standards

Revision: 2026-06-01

Every Druppie-created application follows these technical defaults. The Architect treats them as givens when writing docs/technical-design.md and only documents deviations.

The TD references this file by name and revision — it does not restate the defaults. See the user-facing functional defaults in platform-functional-standards.md.

1. Stack

Layer Default Notes
Frontend React 18 + Vite + TypeScript From druppie/templates/project/frontend/
Backend Python 3.11 + FastAPI From druppie/templates/project/app/
Database Postgres 15 One DB per project, no sharing
Runtime Docker Compose (dev) + the Druppie deploy pipeline (prod)
LLM access Druppie SDK (druppie_sdk.client) — never direct provider SDKs Provider swaps handled centrally
Module access Druppie SDK — module discovery + calls Do NOT reimplement capabilities that exist as modules

TDs do not restate this. They only call it out when they deviate.

2. Template is the starting point

Every app starts from druppie/templates/project/. The chat UI, session management, agent loop, and SDK wiring are already there. The TD assumes this scaffold exists and only describes:

  • New routes/components/endpoints added on top
  • Data model (the project's own tables)
  • Domain logic and business rules
  • External integrations specific to this project

The TD does not document: the chat panel, session list, keycloak wiring, agent framework, SDK setup — these are the template and do not change per project.

3. Modules before code

Before designing a capability from scratch, the Architect checks the module registry:

  • Text generation / reasoning → module-llm
  • Image / OCR / document vision → module-vision
  • Web search → module-web
  • File search inside a codebase → module-filesearch
  • ArchiMate / architecture reasoning → module-archimate
  • Shell / coding execution → module-coding
  • Document-heavy retrieval, knowledge-base search, citation-backed Q&A → app-local pgvector via app/rag.py helper (storage + semantic search) and module-llm embed tool (embeddings via SDK). Each app stores vectors in its own database for full data isolation.

If an existing module covers the capability, the TD references the module and the SDK call pattern — it does not design an alternative. Building a new capability is only valid if no matching module exists; the Architect notes this in the TD with a short justification.

4. Database & persistence

  • Postgres is the default. Reach for it whenever data needs to be queried, filtered, joined, or aggregated.
  • Use relational tables when you need to query inside the data. If a field is filtered, joined on, or aggregated — make it a proper column.
  • JSON / JSONB is fine when the data is only read back whole. If you store a blob, look it up by id, and hand it back to the caller as-is, there's no reason to normalise it. Common examples: opaque third-party payloads, rendered content, configuration snapshots.
  • Migrations are allowed. Use them when schema changes need to land in an existing environment without a reset.

Programming style — follow the Druppie core:

  • Summary / Detail domain modelsFooSummary for lists, FooDetail for single-item endpoints (see SessionSummary / SessionDetail). All domain types live in app/domain/ and are exported from app/domain/__init__.py.
  • One repository per aggregate. FooRepository owns all data access for Foo; repositories return domain models, not ORM rows.
  • Services compose repositories. Services hold business logic; they never touch the DB directly. Route handlers call services.

5. RAG defaults

For doc-heavy applications (knowledge bases, document search, citation-backed Q&A, large-document retrieval) the platform defaults are:

Topic Default
Vector storage App's own Postgres with pgvector (pgvector/pgvector:pg16 image). Use app/rag.py helper — never reimplement chunking or vector search from scratch.
Embeddings module-llm embed tool via the Druppie SDK (stateless, shared). Research recommends multilingual-e5-large-instruct (MIT, multilingual, CPU-feasible); module-llm config pins the active default.
Retrieval Semantic (cosine similarity) via rag.py search(). Hybrid (BM25 + dense) with RRF k=60 is a future upgrade — application-layer BM25 fusion until then.
BM25 analyzer Language-specific (to_tsvector('<corpus-language>', ...)) per field — application-layer
Chunking Recursive splitter, default chunk_size=2048 / chunk_overlap=256 characters (≈ 512 tokens, per the 2026 benchmarks in docs/RAG/rag-patterns.md)
Re-ranking BGE-reranker-v2-m3 self-hosted — application layer
Citation metadata source_name + source_page + source_section + chunk_id returned by every search result
Citation format Footnote style in formal Markdown output + anchor tags for interactive UI
Document extraction Caller-side; rag.py index_documents() accepts pre-extracted text + metadata
Data isolation Physical — each app owns its vectors in its own database. No shared vectorstore, no cross-app access.

Mandatory NFRs in the TD for any RAG component: retrieval latency, recall on a gold-set, faithfulness, citation precision, hallucination rate, freshness SLA, named content owner per domain, PII tagging before indexing, lineage per chunk. Use the LS / HS / Batch archetype defaults from the rag-patterns skill.

The TD does not restate these defaults. It only documents deviations and the trigger that justifies them.

For deeper guidance — chunking variants, advanced patterns (re-ranking, query rewriting, GraphRAG, agentic), NFR archetypes, anti-patterns — see the rag-patterns skill in the Druppie core.

6. API conventions

  • FastAPI routers under app/api/routes/.
  • Routes are thin: validate input, call a service, return a domain model. No business logic in route handlers.
  • Services under app/services/ contain the business logic.
  • Repositories under app/repositories/ own data access and return domain models, not ORM rows.
  • All domain types are Pydantic models in app/domain/, exported from app/domain/__init__.py.

7. Frontend conventions

  • TypeScript, strict mode on.
  • Pages under src/pages/, reusable components under src/components/.
  • API client under src/services/api.ts — all HTTP calls go through it.
  • Styling: Tailwind via the classes already set up in the template.
  • Chat UI: use the template's ChatPanel (from druppie/templates/project/frontend/src/components/chat/). Do not roll a new chat UI.

8. Testing

  • Backend: pytest. Integration tests target a real Postgres (via the template's docker-compose.yaml). Mocks only for external third-party APIs.
  • Frontend: Playwright for end-to-end. Unit tests only where logic is non-trivial — UI snapshots are usually not worth it.
  • The TD names the scenarios that need tests; test implementation details live in the repo, not the TD.

9. Security (technical)

  • Auth is handled by Druppie. Every app is deployed behind the Druppie platform, which already does Keycloak-based auth. Apps read the authenticated user from request headers; they do NOT implement their own login, token issuance, password storage, or role management.
  • Secrets come from env vars. No secrets in code, no secrets in the repo.
  • PII — if an app handles personal data, the Architect calls that out in the TD with retention + access-restriction notes. Everything else defaults to "authenticated Druppie user may access their own data."

The user-facing side of auth (no login screen, no role-admin UI) lives in the functional standards file.

10. Explicitly out of scope (for now)

The following are platform concerns and should NOT appear in individual project TDs:

  • Authentication & authorisation implementation. Handled by Druppie; apps trust headers.
  • Cost tracking / LLM-spend accounting. Will be a platform feature.
  • Audit logging of data access. Platform concern.
  • Rate limiting. Platform concern (handled at the ingress).
  • Multi-tenancy isolation beyond per-user data scoping. Single-tenant per app for now.
  • Backups / disaster recovery. Platform concern.

If a project has a genuine reason to do any of these itself (e.g. a compliance-driven exception), the Architect documents it as a platform- standard deviation with rationale.

11. Deployment

  • Each app ships a Dockerfile and a docker-compose.yaml in the same shape as the template.
  • Every service has a /health endpoint returning 200 when ready.
  • Startup uses the existing init pattern — see druppie/templates/project/docker-compose.yaml.
  • Prod deployment is via the Druppie deploy pipeline; the TD does not describe Kubernetes manifests or cloud infra.

12. Git

  • Conventional commits (feat:, fix:, refactor:, docs:, test:, chore:).
  • Feature branches off main; PRs back to main.
  • One logical change per commit.
  • Every PR description states the why, not just the what.

13. Referencing this file in the TD

Every technical-design.md starts with a Platform standards line linking back here with the revision the TD was written against:

Platform standards: conforms to docs/platform-technical-standards.md rev 2026-06-01. Only deviations are documented below.