Files
itworx-knowledge-hub-Public/docs/08-database-schema.md
T

6.3 KiB

Database schema

This document defines the intended relational shape. EF Core migrations are the executable source once implemented. Names may be refined in M0/M1 through an ADR, but constraints and invariants must remain.

Conventions

  • PostgreSQL uuid primary keys generated by the application or database.
  • timestamptz for instants.
  • UTC application semantics.
  • lowercase snake_case database names.
  • explicit foreign keys and delete behavior.
  • citext or normalized columns for case-insensitive unique values.
  • jsonb only for versioned, non-core metadata and import diagnostics.
  • integer/bigint monotonic revision numbers where scoped.
  • byte/string concurrency token exposed as ETag.
  • no database credentials or secrets in data migrations.

Identity and workspace

installation

  • id singleton key
  • instance_id uuid unique
  • product_version
  • schema_version
  • primary_locale
  • time_zone
  • setup_completed_at
  • timestamps / concurrency version

users

Use ASP.NET Core Identity-compatible tables with application extensions:

  • display name
  • enabled state
  • last login
  • security stamp
  • created/updated timestamps

workspaces

  • id
  • name
  • normalized slug
  • settings version
  • timestamps
  • archived timestamp

Unique: normalized slug.

workspace_memberships

  • workspace/user composite uniqueness
  • role
  • timestamps

Constraint: valid role enum. Application invariant: final admin cannot be removed.

Knowledge tables

pages

Important columns:

id uuid primary key
workspace_id uuid not null
parent_page_id uuid null
sort_key text not null
title varchar(300) not null
normalized_title varchar(300) not null
slug varchar(320) not null
markdown text not null
document_type smallint not null
document_status smallint not null
current_revision bigint not null
content_hash char(64) not null
concurrency_version bigint not null
created_by / updated_by uuid
created_at / updated_at / published_at timestamptz
trashed_at / purge_after timestamptz null
search_vector tsvector generated or maintained

Indexes:

  • (workspace_id, parent_page_id, sort_key, id)
  • (workspace_id, slug)
  • (workspace_id, updated_at desc, id)
  • partial active-page indexes where trashed_at is null
  • GIN search_vector
  • GIN/GiST trigram on normalized title
  • optional path/ancestor closure only if measured need justifies it

Cycle prevention is primarily application-controlled and integration-tested. A recursive query validates moves transactionally.

page_revisions

Unique (page_id, revision_number). Store immutable snapshots and content hash.

Indexes:

  • page/revision descending
  • workspace/created timestamp
  • author/time where audit UI needs it

No cascade delete during ordinary content lifecycle.

drafts

Unique (workspace_id, user_id, draft_key). Draft content is private to the author.

Unique identity includes source page, occurrence key and source revision. Index target page for backlinks and unresolved text for maintenance.

page_relations

Unique (source_page_id, target_page_id, relation_type) unless multiple labels are explicitly supported.

tags / page_tags

  • normalized tag unique per workspace
  • composite join primary key
  • indexes for tag-filter search

favorites / recent_visits

Composite user/content uniqueness. Recent visits use upserted last-view time and bounded retention.

Attachments

attachment_blobs

Primary key is 64-character lowercase SHA-256.

Columns include:

  • length
  • detected media type
  • storage/preview/integrity states
  • created/verified timestamps
  • reference count cache only if transactionally maintained

attachment_references

Stable logical ID, workspace, blob hash, safe original filename and descriptive metadata.

attachment_usages

Polymorphic ownership must not use an unconstrained arbitrary string alone. Prefer separate nullable constrained columns or typed join tables for page/project update usage. The selected design requires an ADR.

Indexes support owner lookup and orphan discovery.

Projects

projects

Unique normalized project slug per workspace. Index lifecycle status and last update.

project_documents

Unique (project_id, page_id, role).

project_updates

Ordered by (occurred_at desc, id desc). Immutable content with correction/supersession links.

project_milestones

Unique name or sequence per project; stable sort key.

technology_tags / project_technology_tags

Normalized unique technology name per workspace.

Decisions and runbooks

decision_records

  • unique page profile
  • unique accepted decision number per project
  • self-referencing supersession constraints
  • indexes by project/status/date

runbook_profiles

  • unique page profile
  • risk/validation metadata
  • review/validation indexes

Imports

import_jobs

Unique source fingerprint plus invocation identity does not automatically prevent a new deliberate import, but idempotency keys prevent duplicate execution.

import_items

Unique (import_job_id, source_identity). Index target identities and status.

import_provenance

Links imported target rows to job/item. This table is the authoritative rollback scope.

Audit, jobs and outbox

audit_events

Append-only, indexed by workspace/time, actor/time, target/time and correlation ID. Partitioning is deferred until measured volume warrants it.

background_jobs

Durable state, lease owner/expiry, attempt count, schedule, progress and safe diagnostics.

outbox_messages

Index unprocessed (available_at, id). Retention after successful dispatch is configurable.

Search implementation

Use the PostgreSQL simple text-search configuration initially because documents mix Dutch, English, code, commands and product names. Maintain normalized searchable text from:

  • title;
  • stripped Markdown text;
  • tags;
  • selected structured metadata.

Use trigram matching for titles/slugs/tags and explicit ranking weights. Permission filters must be part of the query, not a post-filter after result selection.

Migration requirements

Every migration must:

  • be deterministic;
  • be tested from the previous released schema;
  • avoid silent data truncation;
  • include data backfill verification where needed;
  • document locks/expected duration for large tables;
  • have a tested application rollback strategy even when SQL downgrade is unsafe.