Skip to content

User Account Service (UAS) Docs

Target host: doc.g3nretailstack.com (VitePress → S3/CloudFront with post-deploy invalidation). Service is implemented and deployed; this doc mirrors the live handlers.

Overview

  • Class: Core microservice. Direct Lambda for most ops; public API Gateway only for /uas/stat.
  • Data: DynamoDB uas_main single-table; GSIs for email uniqueness, account ref, payment ordering. Events to EventBridge uas-events; change logs to S3 via Firehose.
  • Runtime: Node.js 24, ARM64; argon2 native module pinned at 0.40.3 and bundled via CDK command hooks (npm_config_platform=linux npm_config_arch=arm64 npm install argon2@0.40.3) so Lambdas ship with the correct binary. Responses/events carry build metadata and stats. orgcode is opaque passthrough only. cccode is validated/canonicalized on the public /uas/stat API Gateway surface (body/header mismatch → 400); direct Lambda actions treat cccode as passthrough only. Bearer session_guid tokens are treated as secrets and are not emitted in response stats or tenant events/audits.

Surfaces

  • Public API: POST https://api.g3nretailstack.com/uas/stat → user snapshot. Payload { email, passcode, include_payment_history?, actor? } (email inputs canonicalized: trim + lowercase; optional passthrough accepted: orgcode, cccode; cccode may also be provided via x-cccode header and must match ^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$; body/header mismatch → 400).
  • Direct Lambda (CLI/SDK): actions userCreate, userGet/userSnapshot, userStatusSet, email (emailAdd/list/setPrimary/issueToken/confirmToken/doom), passcode (passcodeSet/reset), payment methods (pmCreate/list/setStatus/promote/demote/doom/vacateToken).
  • CLI (in-repo cli/bin/g3n.js): mirrors direct actions with --profile required.
  • Optimistic concurrency: for any state-changing action on an existing user record, caller must provide expected_revision matching the current record revision (from stat/userGet). Missing → 428 expected-revision-required; mismatch → 409 conflict with error.details.{provided_revision,current_revision,current_record}.

Response envelope

json
{
  "success": true,
  "data": {},
  "build": { "build_major": "MONDAY", "build_minor": "<epoch>", "build_id": "MONDAY-<epoch>" },
  "revision": "...",
	  "stats": {
	    "call": "...",
	    "service": "uas",
	    "request_id": "...",
	    "timestamp_utc": "...",
	    "latency_ms": 12,
	    "ddb_calls": 3,
	    "actor": "...",
	    "user_guid": "...",
	    "orgcode": "...",
	    "cccode": "..."
	  }
}

Domain rules (summary)

  • User FSM: unverified→verified/suspended; doomed is terminal; primary email must be verified for verified status.
  • Emails: last token wins; primary cannot be doomed; doomed TTL 31d.
  • Passcodes: Argon2id, 8+ chars upper/lower/number/special; no reuse within 90d.
  • Payment methods: statuses pending/active/suspended/doomed; uniqueness on processor+token_type+token; ordering active>pending>suspended>doomed; status_history required.
  • Eventing: emit success/failure events; change logs to versioned S3 (1y).

Publishing notes

  • Build static docs with VitePress (npm run docs:build) → S3 bucket behind CloudFront doc.g3nretailstack.com; invalidate CloudFront after publish.
  • Keep external-facing protocol doc synced at uservice/uas/mcp/PROTOCOL.md for mcp.g3nretailstack.com.
  • Contract test hook: npm run test:uas exercises the deployed Lambdas directly (see QA.md for latest run).