Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/juescoryisus/QualityDocD/llms.txt

Use this file to discover all available pages before exploring further.

QualityDocD deliberately stores data in three different database engines, a pattern known as polyglot persistence. This is not complexity for its own sake — each engine was chosen because it is genuinely better suited to its workload than any single-database alternative. SQL Server 2022 is the authoritative system of record for all transactional document data. PostgreSQL 16 stores structured audit trails and serves the multi-tenant Node.js API, where Drizzle ORM manages the schema. MongoDB 7 holds denormalized document metadata with a full-text index, enabling sub-millisecond search queries that would be expensive to run against a normalized relational schema. When a document changes state, each of these three stores is updated in sequence, with SQL Server always written first.

SQL Server 2022 — Primary Application Store

SQL Server is the single source of truth for the .NET MVC application. All business logic in DocumentService.cs reads and writes SQL Server via Entity Framework Core using the AppDbContext. Transactions, referential integrity, and cascading deletes are enforced at the database level. Schema changes are tracked through EF Core migrations stored in QualityDocD/Migrations/SqlServer/.
The Documents table is the heart of the system. Every field in the Document class maps to a column here, with Status stored as a string via EF Core’s HasConversion<string>() configuration. Document codes follow the QD-XXXX format generated at creation time.
ColumnTypeNotes
IdintPrimary key, auto-increment
CodestringUnique; format QD-0001, QD-0042, etc.
TitlestringRequired
DescriptionstringRequired
CategorystringUsed for filtering and compliance grouping
StandardstringQuality standard reference (e.g. ISO 9001)
VersionintIncrements when a file attachment is replaced; starts at 1
StatusstringStored as string enum: Draft, UnderReview, PendingChanges, UnderSecondReview, Approved, Rejected, Obsolete
StoredFileNamestringGuid-based filename on disk under wwwroot/uploads/
OriginalFileNamestringOriginal filename as uploaded by the user
FileExtensionstringNormalized lowercase extension (e.g. .pdf)
ContentTypestringMIME type
FileSizeByteslongFile size in bytes
TagsstringComma-separated tag string
IsPublicboolWhether the document is visible without authentication
MongoMetadataIdstring?MongoDB ObjectId of the mirrored DocumentMeta document
CreatedAtDateTimeUTC timestamp set on creation
UpdatedAtDateTime?UTC timestamp set on every update
ApprovedAtDateTime?Set when Status transitions to Approved
RejectedAtDateTime?Set when Status transitions to Rejected
ExpiresAtDateTime?Optional expiry date for the document
CreatedByUserIdint (FK)References Users.Id with DeleteBehavior.Restrict

PostgreSQL 16 — Audit Store and Node.js API

PostgreSQL serves two distinct consumers and hosts two logically separate sets of tables within the same server. The .NET application writes audit entries to PostgreSQL via EF Core’s AuditDbContext. The Node.js API owns its own tables, managed entirely by Drizzle ORM with schema definitions in node-api/schema/. Migrations for each consumer are stored separately: EF Core migrations in QualityDocD/Migrations/AuditDb/ and Drizzle schema in node-api/schema/.
The AuditDbContext manages three tables on the PostgreSQL side of the .NET application. These tables provide a compliance-grade audit trail separated from the primary transactional database.audit_entries — Cross-database mirror of every document state change
ColumnTypeNotes
IdintPrimary key
DocumentIdintReferences the SQL Server document ID (not a FK — cross-db reference)
DocumentCodestringDenormalized QD-XXXX code for query convenience
DocumentTitlestring?Denormalized title
UserIdint?References the SQL Server user ID
Usernamestring?Denormalized username
ActionstringE.g. "Created", "StatusChange", "Approved", "Rejected"
OldValuestring?Previous state
NewValuestring?New state
IpAddressstring?Remote IP address
CreatedAtDateTimeUTC timestamp; indexed for range queries
compliance_records — Aggregated compliance snapshot
ColumnTypeNotes
Category + StandardstringComposite unique index
Approved / Draft / UnderReview / Obsolete / TotalintDocument counts per status group
LastUpdatedDateTimeWhen the aggregate was last refreshed
access_logs — Per-document view and download tracking
ColumnTypeNotes
DocumentIdintWhich document was accessed
Usernamestring?Who accessed it
IpAddressstring?From where
ActionstringDefault "view"
AccessedAtDateTimeIndexed timestamp
The .NET AuditDbContext writes are wrapped in a try/catch block that silently swallows failures: /* PostgreSQL no disponible — continúa sin bloquear */. This is an intentional design decision — a PostgreSQL outage must never block a document state change in SQL Server. Audit entries may be lost during a PostgreSQL outage, so monitoring PostgreSQL availability is essential for compliance workflows.

MongoDB 7 — Full-Text Metadata Store

MongoDB stores a denormalized snapshot of every document’s metadata in the document_metadata collection inside the qualitydoc_meta database. This collection is the backend for both the search microservice (called by DocumentService.SearchAsync() via HTTP) and the Node.js API. The MongoDbContext creates all required indexes at startup using EnsureIndexes(), including a weighted full-text index.
Each document in SQL Server has a corresponding DocumentMeta document in MongoDB. The MongoMetadataId field in the SQL Server Documents table stores the MongoDB ObjectId string to link the two records.
FieldBSON ElementTypeNotes
Id_idObjectIdMongoDB primary key
DocumentIddocumentIdintUnique index; mirrors SQL Server Id
CodecodestringUnique index; mirrors QD-XXXX format
TitletitlestringIncluded in full-text index (weight: 10)
DescriptiondescriptionstringIncluded in full-text index (weight: 1)
CategorycategorystringAscending index
StandardstandardstringQuality standard reference; has a weight entry in the index Weights document but is not included in the Text() key spec and is not indexed for full-text search
Tagstagsstring[]Ascending index; included in full-text index (weight: 5)
FileExtensionfileExtensionstringExtension filter in search queries
StatusstatusstringE.g. "Draft", "Approved"
IsPublicisPublicboolPublic visibility flag
CreatedAtcreatedAtDateTimeUTC creation timestamp
UpdatedAtupdatedAtDateTimeUTC last-sync timestamp
When the search microservice is unavailable, DocumentService.SearchAsync() automatically falls back to a SQL Server LIKE query using Title.Contains(), Description.Contains(), Code.Contains(), and Tags.Contains(). Results are capped at 50 documents. This fallback is logged at the Warning level: "Search service no disponible: {Message}. Usando SQL Server.".

Data Consistency: The Dual-Write Pattern

QualityDocD uses a synchronous-then-async dual-write pattern. SQL Server is always written first within the main transaction. After the SQL Server save succeeds, the service writes to PostgreSQL audit and syncs to MongoDB (via HTTP POST to the search microservice). Neither of these secondary writes is part of a distributed transaction.
1

SQL Server write (synchronous, authoritative)

_sql.SaveChangesAsync() commits the document state change and creates an AuditLog row in SQL Server. This is the only write that can cause the HTTP request to fail — if it throws, no secondary writes are attempted.
2

PostgreSQL audit write (async, non-blocking)

SyncPgAuditAsync() writes an AuditEntry row to PostgreSQL. This is wrapped in a try/catch that logs a warning and continues on failure. The SQL Server AuditLog serves as the fallback if this write is lost.
3

MongoDB sync (async, non-blocking)

SyncSearchServiceAsync() sends an HTTP POST to the Node.js search service, which upserts the DocumentMeta document in MongoDB. Failure is logged at Warning level and does not affect the HTTP response. Search results may be stale by one event in the rare case of a sync failure.
HTTP Request


SQL Server ──────────────────── Source of Truth (must succeed)

    ├──► PostgreSQL audit_entries ── Non-blocking, best-effort

    └──► MongoDB document_metadata ─ Non-blocking via HTTP to Search Service
Because the secondary writes are not transactional with the SQL Server write, it is possible for PostgreSQL or MongoDB to be temporarily out of sync with SQL Server after a partial failure. In practice, SQL Server’s AuditLogs table and Documents table are always consistent with each other. If you observe discrepancies in search results or audit reports, the SQL Server data is the authoritative source.

Build docs developers (and LLMs) love