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 is deliberately polyglot: it pairs each architectural concern with the technology best suited to handle it. The .NET MVC application provides a server-rendered approval UI backed by SQL Server. The Node.js REST API offers a JWT-authenticated, company-scoped interface backed by PostgreSQL. A lightweight Node.js search microservice indexes approved document metadata into MongoDB and answers full-text queries. A PHP portal reads audit data from PostgreSQL and calls the search service to surface a read-only reporting dashboard. All four application services and all three databases run in Docker containers on a shared bridge network named qualitydoc_net.

Service and Port Overview

ServiceContainerHost PortInternal PortTechnology
.NET MVC Appqualitydoc_app50015000ASP.NET Core MVC, EF Core, YARP
Node.js REST APIqualitydoc_node_api50005000Express 5, TypeScript, drizzle-orm
Search Microservicequalitydoc_search30013001Node.js, Mongoose
PHP Portalqualitydoc_php808080PHP 8, PDO
SQL Server 2022qualitydoc_sqlserver14331433SQL Server 2022 Express
PostgreSQL 16qualitydoc_postgres54325432PostgreSQL 16 Alpine
MongoDB 7qualitydoc_mongodb2701727017MongoDB 7

Application Services

.NET MVC Application (port 5001)

The .NET application is the primary interactive interface. It is an ASP.NET Core MVC app that handles document creation, editing, and the complete approval workflow through server-rendered views. Cookie-based authentication (CookieAuthenticationDefaults) manages browser sessions with an 8-hour sliding expiry. Unauthorized requests are redirected to /Auth/Login. Database connections: The .NET app connects to all three databases simultaneously:
  • SQL Server via AppDbContext (EF Core) — documents, users, document_approvals
  • PostgreSQL via AuditDbContext (EF Core) — audit entries written on every workflow transition
  • MongoDB via MongoDbContext (singleton) — flexible document metadata
Startup seeding: On every startup, the application calls MigrateAsync() against SQL Server to apply any pending EF Core migrations. If the Users table is empty, it seeds five initial accounts (admin, gerente, revisor1, revisor2, editor) with BCrypt-hashed passwords. HTTP clients: The app registers a named HttpClient for the search service (http://search-service:3001 inside Docker) and an HttpClient<NodeApiAuthService> for communicating with the Node.js API. YARP reverse proxy: The .NET app embeds Microsoft YARP (Yet Another Reverse Proxy). Route and cluster configuration is loaded from appsettings.json:
Incoming Path PatternForwarded ToRewritten As
/node-api/{**catch-all}http://node-api:5000//api/{**catch-all}
/search/{**catch-all}http://search-service:3001//{**catch-all}
Because of the YARP proxy, a browser or API client pointed at the .NET app’s port (5001) can reach both the Node.js API and the search service without knowing their individual ports. In a production deployment where only port 5001 is exposed externally, all service traffic flows through this single entry point.

Node.js REST API (port 5000)

The Node.js API is a TypeScript Express 5 application that exposes a JSON REST interface. It is the programmatic entry point for integrations, CI pipelines, and the PHP portal’s authentication flow. Authentication: All protected routes require a JWT in the Authorization: Bearer <token> header. Tokens are issued by POST /api/auth/login and signed with the SESSION_SECRET environment variable. Tokens expire after 8 hours by default. Multi-tenancy: Every request is scoped to a company identified by the companySlug supplied at login. All queries are filtered by company_id, ensuring complete data isolation between tenants. Module-based access: The API supports per-company feature flags (MODULE_1, MODULE_2, MODULE_3) managed through the /api/modules router. Companies without a specific module flag enabled are denied access to that feature set. Route modules registered in src/routes/index.ts:
RouterPrefixPurpose
healthRouter/api/healthzHealth check endpoint
authRouter/api/authLogin, token issuance, user management
companiesRouter/api/companiesTenant/company management
documentsRouter/api/documentsDocument CRUD and versioning
searchRouter/api/searchPostgreSQL token-based search
webhooksRouter/api/webhooksOutbound webhook triggers
modulesRouter/api/modulesPer-company module flags
Persistence: The Node.js API uses drizzle-orm with the pg driver to read from and write to PostgreSQL. The DATABASE_URL environment variable (postgresql://qualitydoc:...@postgres:5432/qualitydoc_audit) points to the same PostgreSQL instance used by the PHP portal and the .NET app’s audit context.

Search Microservice (port 3001)

The search microservice is a lean Node.js service with a single responsibility: maintain and query the full-text document index in MongoDB. It uses Mongoose to connect to qualitydoc_meta on the MongoDB container. Startup: The service connects to MongoDB using credentials from environment variables (MONGO_HOST, MONGO_USER, MONGO_PASSWORD, MONGO_DB). If no credentials are provided (local development without Docker), it falls back to an unauthenticated connection string. Endpoints:
MethodPathDescription
GET/healthReturns MongoDB connection status and service name
*/api/*Search and document metadata routes (via searchRouter)
The .NET application calls the search microservice directly over the Docker network (http://search-service:3001) whenever a document is approved, pushing metadata to the MongoDB index. The YARP proxy additionally exposes the search service externally at /search/ on port 5001.

PHP Portal (port 8080)

The PHP portal is a read-only reporting dashboard. It does not have its own database schema — it reads from PostgreSQL and delegates search queries to the search microservice via HTTP. Data sources:
  • PostgreSQL (qualitydoc_audit database): audit entries, queried via PDO using pgsql:host=postgres;port=5432;dbname=qualitydoc_audit.
  • Search Microservice (http://search-service:3001): document metadata queried via file_get_contents with a 5-second timeout.
  • .NET API (http://qualitydoc-app:5000): portal login is delegated to POST /api/auth/login on the .NET app. The resulting JWT is stored in the PHP session and passed as a Bearer token on subsequent .NET API calls.
The portal displays document status using a seven-state badge map: Draft, UnderReview, PendingChanges, UnderSecondReview, Approved, Rejected, Obsolete.

Database Design

SQL Server 2022 (port 1433)

SQL Server is the source of truth for the .NET application. EF Core manages schema creation and migrations via AppDbContext and AuditDbContext. Key tables:
  • Documents — document records with title, type, department, and current status
  • Users — application user accounts with BCrypt-hashed passwords and role assignments
  • document_approvals — one row per workflow transition, recording who made the change and when
  • audit_logs — a secondary audit log written by the .NET app (distinct from the PostgreSQL audit table)
The SQL Server container uses a named volume (sqlserver_data) for persistence and exposes a health check that runs SELECT 1 via sqlcmd.

PostgreSQL 16 (port 5432)

PostgreSQL serves two independent consumers that happen to share the same qualitydoc_audit database:
  1. Node.js API (drizzle-orm): The API creates and owns tables for companies, users, documents, document_versions, and search_index. These are the tables the REST API reads from and writes to.
  2. PHP Portal (PDO): The portal queries audit_entries, a table populated when the .NET application records compliance-relevant events.
The PostgreSQL container uses a postgres:16-alpine image with a named volume (postgres_data) and a pg_isready health check.

MongoDB 7 (port 27017)

MongoDB stores flexible document metadata in the qualitydoc_meta database. The primary collection used by the search microservice is document_metadata, which holds indexed representations of approved documents for full-text querying. MongoDB was chosen here because document metadata schemas can vary across document types and companies, and because MongoDB’s text index operators fit the search microservice’s query patterns naturally. The MongoDB container is initialized with an init.js script (mounted at /docker-entrypoint-initdb.d/01_init.js) that configures the initial database and collections.

Docker Network and Compose Structure

All containers — databases and application services — share the qualitydoc_net Docker bridge network, which is declared and created by docker-compose.infra.yml:
networks:
  qualitydoc_net:
    name: qualitydoc_net
    driver: bridge
The other two compose files (docker-compose.apps.yml and docker-compose.portal.yml) declare the network as external: true, meaning they join it but do not attempt to create it. This means the infrastructure compose file must be started first.
Compose FileCreates NetworkJoins Network
docker-compose.infra.yml✅ Yes
docker-compose.apps.ymlNo✅ Yes (external)
docker-compose.portal.ymlNo✅ Yes (external)

Document Approval Data Flow

When a document moves through the approval workflow, data propagates across all three databases:
  1. User action in .NET UI → the .NET app writes the new document state to SQL Server (AppDbContext) and inserts an audit entry into PostgreSQL (AuditDbContext).
  2. Approved state reached → the .NET app calls the search microservice (POST to http://search-service:3001/api/...) with the document metadata. The search service writes a record to the document_metadata collection in MongoDB.
  3. PHP portal query → the portal reads audit entries from PostgreSQL and calls GET /api/... on the search service to retrieve document metadata for display. It does not query SQL Server directly.
  4. Node.js API → independently maintains its own document and version records in PostgreSQL, with its own approval and versioning logic scoped per company.
The Node.js API’s PostgreSQL tables and the .NET app’s SQL Server tables are independent stores. A document created through the Node.js API does not automatically appear in the .NET UI, and vice versa. The two stacks share the same physical PostgreSQL instance but use separate tables and schemas.

Docker Setup

Detailed Docker Compose configuration and deployment options.

Configuration

Environment variables, secrets, and per-service configuration reference.

Databases

Schema details, migration management, and backup strategies.

Build docs developers (and LLMs) love