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 namedDocumentation 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.
qualitydoc_net.
Service and Port Overview
| Service | Container | Host Port | Internal Port | Technology |
|---|---|---|---|---|
| .NET MVC App | qualitydoc_app | 5001 | 5000 | ASP.NET Core MVC, EF Core, YARP |
| Node.js REST API | qualitydoc_node_api | 5000 | 5000 | Express 5, TypeScript, drizzle-orm |
| Search Microservice | qualitydoc_search | 3001 | 3001 | Node.js, Mongoose |
| PHP Portal | qualitydoc_php | 8080 | 80 | PHP 8, PDO |
| SQL Server 2022 | qualitydoc_sqlserver | 1433 | 1433 | SQL Server 2022 Express |
| PostgreSQL 16 | qualitydoc_postgres | 5432 | 5432 | PostgreSQL 16 Alpine |
| MongoDB 7 | qualitydoc_mongodb | 27017 | 27017 | MongoDB 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
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 Pattern | Forwarded To | Rewritten 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 theAuthorization: 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:
| Router | Prefix | Purpose |
|---|---|---|
healthRouter | /api/healthz | Health check endpoint |
authRouter | /api/auth | Login, token issuance, user management |
companiesRouter | /api/companies | Tenant/company management |
documentsRouter | /api/documents | Document CRUD and versioning |
searchRouter | /api/search | PostgreSQL token-based search |
webhooksRouter | /api/webhooks | Outbound webhook triggers |
modulesRouter | /api/modules | Per-company module flags |
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 toqualitydoc_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:
| Method | Path | Description |
|---|---|---|
GET | /health | Returns 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_auditdatabase): audit entries, queried via PDO usingpgsql:host=postgres;port=5432;dbname=qualitydoc_audit. - Search Microservice (
http://search-service:3001): document metadata queried viafile_get_contentswith a 5-second timeout. - .NET API (
http://qualitydoc-app:5000): portal login is delegated toPOST /api/auth/loginon the .NET app. The resulting JWT is stored in the PHP session and passed as aBearertoken on subsequent .NET API calls.
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 viaAppDbContext 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)
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 samequalitydoc_audit database:
-
Node.js API (drizzle-orm): The API creates and owns tables for
companies,users,documents,document_versions, andsearch_index. These are the tables the REST API reads from and writes to. -
PHP Portal (PDO): The portal queries
audit_entries, a table populated when the .NET application records compliance-relevant events.
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 thequalitydoc_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 thequalitydoc_net Docker bridge network, which is declared and created by docker-compose.infra.yml:
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 File | Creates Network | Joins Network |
|---|---|---|
docker-compose.infra.yml | ✅ Yes | — |
docker-compose.apps.yml | No | ✅ Yes (external) |
docker-compose.portal.yml | No | ✅ Yes (external) |
Document Approval Data Flow
When a document moves through the approval workflow, data propagates across all three databases:- 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). - Approved state reached → the .NET app calls the search microservice (
POSTtohttp://search-service:3001/api/...) with the document metadata. The search service writes a record to thedocument_metadatacollection in MongoDB. - 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. - 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.