# SaaS VOC Server Independent backend template for the domestic ecommerce VOC product. The first case workspace is Demashi on JD. This repository does not connect to the cross-border production database and does not contain any Fmode, Parse, PostgreSQL, or supplier credential. ## Current state Completed on 2026-07-23: - Independent Git repository and Node.js 22 / TypeScript service baseline. - Independent PostgreSQL schema with workspace, source, product, metric, relation, review, import, and sync-job tables. - Independent Parse Server application configuration on the same dedicated database. - Strict startup validation for every required credential. - `GET /health` database readiness check. - `POST /api/domestic-voc/sync` idempotent manual-sync queue entry. - `GET /api/domestic-voc/jobs/:id` sync-job status. - `GET /api/domestic-voc/snapshot` response compatible with the frontend `DomesticDataset` interface. - Server-side Fmode gateway client with timeout, retry, and credential redaction behavior. - Deterministic identities for products, relations, reviews, and daily sync requests. - Bounded batch importer for the normalized Demashi dataset. - Database-free local demo runtime for frontend integration before infrastructure is provisioned. The current case import resolves to 2,817 operating products, 9,717 daily metrics, 40 relations, and 38 internal `relation_stub` records required to preserve foreign keys. Stub records are excluded from the frontend product list and are never presented as collected product facts. The worker calls JD product-detail and review paths only through the company `/api/voc-e-commerce` gateway. It never sends a browser request to a supplier endpoint and never returns raw gateway errors or credentials. ## Architecture ```text Saas-voc frontend -> saas-voc-server -> dedicated Parse application -> dedicated PostgreSQL database (voc schema) -> sync queue -> existing /api/voc-e-commerce gateway ``` The browser only calls this service. `FMODE_API_KEY` is used in the server-side `Authorization` header and is never returned to the browser or included in a request URL. Registered JD gateway contracts: ```text GET /api/voc-e-commerce/jd/get-item-detail/v1?itemId={productId} GET /api/voc-e-commerce/jd/get-item-comments/v1?itemId={productId}&page={page} ``` The first worker run defaults to one review page. `JD_REVIEW_MAX_PAGES` can raise the bounded limit after quota and response validation. ## Runtime Use Node.js 22.13 or newer within the Node 22 release line. The repository intentionally pins Node 22 because Parse Server publishes explicit supported runtime ranges. Required configuration is listed in `.env.example`. Empty secrets are rejected before the HTTP server starts. Generate independent random values for `PARSE_MASTER_KEY` and `PARSE_MAINTENANCE_KEY`; do not reuse any value from `moshengqi-server` or `future-server`. `DATABASE_URL` is the least-privilege runtime connection. `MIGRATION_DATABASE_URL` is the schema-owner connection used only by `npm run migrate`; it falls back to `DATABASE_URL` for local development. ### Local frontend integration without a database The local demo runtime has no PostgreSQL, Parse, or gateway credential dependency. From this repository run: ```powershell npm ci npm run start:local ``` It loads `../../Saas-voc/src/assets/data/demashi-summary.json` by default and listens on `http://127.0.0.1:4400`. Override the source only when the repositories are stored elsewhere: ```powershell $env:LOCAL_DATASET_PATH = 'E:\path\to\demashi-summary.json' npm run start:local ``` Local demo `sync` requests create queryable in-memory completion records that validate whether requested products exist in the packaged dataset. They do not collect external data or persist anything. Production collection and persistence remain in `npm run dev`. ### Database-backed runtime Local database: ```powershell $env:POSTGRES_PASSWORD = '' docker compose up -d postgres ``` The compose database listens only on `127.0.0.1:54329`. A local `DATABASE_URL` therefore uses database `saas_voc` on port `54329`. Install, migrate, and run: ```powershell npm ci npm run migrate npm run dev ``` Import the current normalized case after migration: ```powershell npm run import:dataset -- "E:\workspace\Saas-voc\src\assets\data\demashi-summary.json" ``` Default local API address: ```text http://127.0.0.1:4400 ``` ## API Queue a JD product and review sync: ```http POST /api/domestic-voc/sync Idempotency-Key: optional-client-key Content-Type: application/json { "workspaceId": "demashi", "platform": "jd", "productIds": ["11266507445"], "scopes": ["product", "reviews"] } ``` When `Idempotency-Key` is absent, the service derives a stable key from workspace, platform, products, scopes, and UTC date. The same daily request returns the same job. Read status and frontend data: ```text GET /api/domestic-voc/jobs/{jobId} GET /api/domestic-voc/snapshot?workspaceId=demashi&platform=jd ``` An empty database returns a valid empty dataset. It does not invent reviews, ratings, sentiment, pain points, or AI output. ## Database rules - Runtime identities are enforced by composite unique constraints, not by check-then-insert logic. - Import and sync writers must use `INSERT ... ON CONFLICT` in batches. - Foreign-key columns and common workspace/date filters are indexed. - Workers claim jobs with `FOR UPDATE SKIP LOCKED`. - External HTTP requests must run outside database transactions. - Production deployments must use a pooled, least-privilege runtime role. Migration credentials should be separate from runtime credentials. - The HTTP server never runs DDL automatically; migrations are an explicit deployment step. ## Security status `parse-server@9.10.0` replaces the initially evaluated v8 line, removing all high and critical audit findings. A `ws@8.21.0` override is retained because Parse currently pins an older vulnerable patch. The remaining audit findings are moderate transitive dependencies in Parse push/Firebase and redirect support; push and LiveQuery are not configured in this template. Re-run `npm audit --omit=dev` before each deployment and do not use `npm audit fix --force`, which currently proposes an unsafe Parse downgrade. ## Verification ```powershell npm run build npm test npm audit --omit=dev ``` Current result: - TypeScript build: passed. - Unit, adapter, worker, local-demo, and HTTP contract tests: 20 passed. - Production dependency audit: 0 critical, 0 high, 13 moderate. - Company gateway health: HTTP 200 on 2026-07-23. - Credentialed live JD product-detail request: passed through the company gateway for product `11266507445`; the adapter extracted the product id, title, and brand from the live double-`data` envelope. - Credentialed live JD review request: authenticated successfully and returned an empty first page with next-page metadata. A non-empty review sample is still required before review evidence can be accepted. - The live credential was process-only: it was not written to an environment file, source file, fixture, log, or Git history. No supplier endpoint was contacted directly. - PostgreSQL integration: pending a newly provisioned database; the cross-border production database is intentionally excluded. See `TASKS.md` for the implementation sequence and acceptance boundary.