From vivreal-workflow
Vivreal Portal shared engineering standards — the non-negotiable conventions every Vivreal bug/feature workflow agent reads before working. Use when an agent or command says to consult "shared-standards" or "_shared-standards", or when a task touches Vivreal proxy routes, multi-tenancy (active_ctx/dbKey/groupID), CSRF, hydration/SSR, Lambda infra, MongoDB queries, or testing rules. Carries the ${VIVREAL_REPOS} path-resolution preamble and the lazy-reading trigger map.
How this skill is triggered — by the user, by Claude, or both
Slash command
/vivreal-workflow:shared-standardsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> NOTE: This skill is the relocated form of the portal's `.claude/agents/_shared-standards.md`.
NOTE: This skill is the relocated form of the portal's
.claude/agents/_shared-standards.md. Workflow agents and commands that historically read.claude/agents/_shared-standards.mdnow resolve it through this skill, so it works from any repo. Content below is verbatim.
This workflow uses two placeholder env vars that every agent must resolve before reading cross-repo or ecosystem files. They are NOT shell expansions you literally execute — they are placeholders this section tells you how to resolve.
${VIVREAL_REPOS} — root containing all Vivreal reposDefault convention: all Vivreal repos are sibling directories under one parent. From the project root (where this repo lives), the parent is ...
Resolution rule:
VIVREAL_REPOS is set, use it$(cd .. && pwd)${VIVREAL_REPOS}/Vivreal_Portal_Mobile/CLAUDE.md existsExample resolution in Bash (use this in agent commands):
VIVREAL_REPOS="${VIVREAL_REPOS:-$(cd .. && pwd)}"
cat "$VIVREAL_REPOS/VR_CMS_API/CLAUDE.md"
docs/ecosystem/Cross-repo ecosystem docs (architecture, debugging guides, Lambda inventory, etc.) live in this repo at docs/ecosystem/. No env var resolution needed — they're version-controlled and always available.
${VIVREAL_REPOS}/... in this doc or any agent promptResolve it before reading. Never paste the literal placeholder into a Read or Bash command — substitute the actual path. Ecosystem docs are at docs/ecosystem/ (no resolution needed).
~/.bashrc, ~/.zshrc, or your shell profile. Example: export VIVREAL_REPOS="$HOME/repos"Role agents (coordinator, researcher, architect, coder, tester, reviewer, documenter, designer, vuln, growth, sentry): do NOT eager-read this file. The path-resolution preamble above is the only mandatory read. Read sections of this file ONLY when your task touches one of the trigger areas below.
System experts (main-api, secure-api, cms-api, event-handler, client-stack, portal): do NOT load this file at all by default. You may consult a specific section if your findings explicitly need to align with portal-side conventions (rare).
| If the task touches… | Read these sections |
|---|---|
src/app/api/proxy/* (any portal proxy route) | "The three-tier API rule" + "Proxy route factory" |
active_ctx, dbKey, groupID, multi-tenant routing | "Auth & multi-tenancy" |
| MongoDB queries, indexes, write concerns | "Optimization principles" + read docs/ecosystem/mongo_queries.md |
useAuth() in app layout, hydration, SSR | "Hydration & SSR rules" |
| Lambda env vars, function names, CloudFormation | "AWS Lambda & Infrastructure Reference" + read docs/ecosystem/aws-lambda-inventory.md |
| CSP, cookies, CSRF, security headers | "Security non-negotiables" |
| Any test files — e2e, unit, or backend (writing OR editing) | "Testing rules" + "Backend testing conventions" |
Integration manifests (src/data/manifests/) | "Conventions you'll see" |
| Removing cross-repo code (consumer → producer) | "Cross-stack removal ordering" |
| Anything not listed above | Skip this file. CLAUDE.md is sufficient. |
If a task obviously spans multiple trigger areas, read each relevant section once. Do not eager-load adjacent sections.
This file is read by every bug-fix subagent BEFORE doing any work. It encodes the non-negotiable rules. If anything here conflicts with the project CLAUDE.md, CLAUDE.md wins.
src/app/api/proxy/* run on edge runtimedbKey| Context | Tool |
|---|---|
Authenticated proxy routes (/app/api/proxy/*) | createAuthAxios() from @/lib/api/axiosInstance |
Public main API (NEXT_PUBLIC_MAIN_API) | publicAxios from @/lib/api/axiosInstance |
| S3 presigned, service worker, AuthContext login | Native fetch() |
NEVER use native fetch() for proxy routes. Any 401/419 from a proxy route MUST redirect to login — only createAuthAxios does this automatically.
Errors from axios calls: use getApiError(err, fallback) from @/lib/api/auth/helpers — extracts the backend's error.response.data.error before falling back.
createProxyHandler() factory in src/app/api/proxy/_helpers/ (see src/app/api/proxy/ — count them when it matters; CLAUDE.md's route table is the reference)active_ctx via verifyCtxEdge()injectCtxParams(), filterParams(), cleanSearchParam()active_ctx JWT contains: groupID, dbKey, bucketname, exp{ _id: groupID }. NEVER groupName.dbKey, served from general_shared (free/basic/pro) or pro_plusdbKey from active_ctx directly| Field | Source | Value example | Used for |
|---|---|---|---|
dbKey | deriveDbKey(group) in contextCookieFns.js | general_shared, pro_plus, or slugified groupName (enterprise) | Database routing — dynamicDb[dbKey] selects the tenant MongoDB database. This is the key query param passed to CMS API. |
group.key | Stored on the group document in mainDb | thecomedycollective | S3 bucket naming — bucket is vivreal-{group.key}. Also used for display/URL slugs. NOT the database key. |
bucketname | ${group.type}-${group.key} | collection-thecomedycollective | S3 object path prefix — used in media upload/retrieval paths. |
deriveDbKey() logic (defined in VR_Secure_API/src/userAndAuth/services/contextCookieFns.js):
free/basic/pro → 'general_shared'
proplus → 'pro_plus'
enterprise → slugify(group.groupName)
fallback → group.database (legacy)
Where dbKey is set in active_ctx:
profileSwitch.js:17 — const dbKey = deriveDbKey(foundGroup)updateDefaultProfile.js:37 — samecreateGroup.js:192 / joinGroup.js:57 — same mapping inlineThe databaseDict pattern you'll see in backend code (e.g., oauthCallback.js:157-162) is the SAME tier→DB mapping as deriveDbKey(). When you see databaseDict[group.tier], that IS the correct dbKey — do NOT "fix" it to group.key.
vivreal-db-explorer:db-schema — Use to inspect Mongoose schema, indexes, and sample docs for any collection. Invoke during research before reasoning about data shape.vivreal-db-explorer:db-query — Safe MongoDB queries with built-in dbKey routing and multi-tenant safety guards. ALWAYS prefer this over raw mcp__mongodb__find. It handles general_shared/pro_plus routing automatically._id fields require {"$oid": "..."} syntax, groupID on tenant objects is a string (not ObjectId), collectionObj.refID is a string.src/lib/csrf/)src/proxy.ts on auth endpoints (10 attempts / 15 min / IP)next.config.ts — don't break themsecure: true forced in productiondangerouslySetInnerHTML user contentany (use unknown and narrow)as casts without an inline comment explaining whyPascalCase components, camelCase fns/vars, kebab-case files, UPPER_SNAKE_CASE constants$in or aggregate pipelines)useMemo/useCallback only when there's a measurable problemuseAuth() in app layout MUST use useHydrated() guardDate.now() / Math.random() in initial render pathforce-dynamic preserved on dashboard routes'use client' only for interactivitye2e/. Import from e2e/fixtures/global-setup or e2e/fixtures/auth-setup. NEVER import from @playwright/test directly.e2e/fixtures/api-mocks.ts before adding (don't trust any hardcoded count — check the file).__reactProps on elements before clicking. Use pressSequentially() for stubborn controlled inputs.page.route() does NOT intercept server-side fetches in Next.js server components. See e2e/TESTING.md "Critical Patterns & Gotchas".toBe→toContain, exact→anything(), deleting a check) or align new code to a buggy expectation just to go green — the reviewer treats that as test-tampering and FAILs the pass..only, no sleep(), use waitFor().GET /api/proxy/get-mediacdnUrl() for site assetsEvery Vivreal repo has a CLAUDE.md at its root with conventions, patterns, and gotchas. ALWAYS read the relevant one(s) before researching, planning, or coding in that area.
| Repo | Path | Purpose |
|---|---|---|
| Portal (this repo) | ${VIVREAL_REPOS}/Vivreal_Portal_Mobile/CLAUDE.md | Frontend Next.js portal |
| VR_Main_API | ${VIVREAL_REPOS}/VR_Main_API/CLAUDE.md | 1 monolithic Lambda — auth, signup, email, Slack/Discord, Stripe products |
| VR_Secure_API | ${VIVREAL_REPOS}/VR_Secure_API/CLAUDE.md | 6 Lambdas — group, billing, sites, profile, OAuth init |
| VR_CMS_API | ${VIVREAL_REPOS}/VR_CMS_API/CLAUDE.md | 5 Lambdas — collections, integrations, media, audit, versioning |
| VR_Client_API | ${VIVREAL_REPOS}/VR_Client_API/CLAUDE.md | Public content delivery (read-only with publishDate filter) |
| VR_Client_Auth | ${VIVREAL_REPOS}/VR_Client_Auth/CLAUDE.md | TOKEN authorizer for VR_Client_API (Serverless Framework, not SAM) |
| Vivreal_Templates | ${VIVREAL_REPOS}/Vivreal_Templates/CLAUDE.md | Storefront templates (main + per-customer branches; NO ecommerce/showcase template branches — see inbox bug #91) |
| VR-MCP-Server | ${VIVREAL_REPOS}/VR-MCP-Server/CLAUDE.md | MCP server with ~40 CMS tools (TypeScript, OAuth 2.1) |
| VR_OnCall_Agent | ${VIVREAL_REPOS}/VR_OnCall_Agent/CLAUDE.md | On-call agent |
| VR_OnCall_Webhook | ${VIVREAL_REPOS}/VR_OnCall_Webhook/CLAUDE.md | On-call webhook receiver |
| Vivreal_EventHandler | ${VIVREAL_REPOS}/Vivreal_EventHandler/CLAUDE.md | Step Functions site deployment pipeline |
| Vivreal_Docs | ${VIVREAL_REPOS}/Vivreal_Docs\ | Public docs site (Next.js, content under content/) |
| Vivreal-Schemas | ${VIVREAL_REPOS}/Vivreal-Schemas\ | Shared Mongoose schemas package |
| Vivreal-Tier-Quotas | ${VIVREAL_REPOS}/Vivreal-Tier-Quotas\ | Shared @hillbombcreations/tier-quotas package |
All backends: Express + serverless-express, JavaScript (not TS), Mongoose, Pino, X-Ray, AWS SAM (except VR_Client_Auth = Serverless Framework).
Full inventory: docs/ecosystem/aws-lambda-inventory.md — READ THIS when debugging Lambda config issues, env var mismatches, deployment failures, or cross-function communication. It maps every Lambda function name → repo → CloudFormation fragment → env vars → stack.
| API | Prod Lambdas | Has WebSocket | Deploy Trigger |
|---|---|---|---|
| VR_Secure_API | 8 (6 domain + agent + webhook-delivery) | 4 of 8 | Push to main/dogfood |
| VR_CMS_API | 5 | All 5 | Push to main/dogfood |
| VR_Main_API | 2 (express + email consumer) | 1 of 2 | Push to main/dogfood |
| VR_Client_API | 1 | No | Push to main |
| VR_Client_Auth | 1 (Node 18, Serverless Framework) | No | Push to main |
| EventHandler | 10 (Step Functions pipeline) | No | Push to main |
| Stack | Repo Location | Workflow |
|---|---|---|
vivreal-websocket | VR_Secure_API/websocket/ | .github/workflows/websocket.yml |
Vivreal-Media-CDN | VR_Secure_API/cloudformation/media-cdn.yaml | .github/workflows/media-cdn.yml |
hb-api-secrets)All backend Lambdas resolve env vars from hb-api-secrets at deploy time via {{resolve:secretsmanager:hb-api-secrets:SecretString:KEY}}. Key categories: Database (CLUSTER_URL), Auth (CLIENT_ID, USERPOOL_ID), Stripe, WebSocket (WS_ENDPOINT, WS_TABLE), OAuth (6 providers), Encryption, CDN/Media, Push notifications (VAPID), Agent (Anthropic + GitHub App), Comms (Slack/Discord/SES).
CREATE_UPDATE_COL_GROUPS_FUNCTION_NAME, GET_COLLECTION_INFO_FUNCTION_NAME, UPDATE_SITE_ENV_VARS_LAMBDA are env vars pointing to other LambdasWS_ENDPOINT + WS_TABLEdocs/ecosystem/)Cross-repo ecosystem docs checked into this repo. Richer than per-repo CLAUDE.md files for ecosystem-wide questions. ALWAYS check the relevant ones during research before grepping blindly.
| File | When to read |
|---|---|
docs/ecosystem/ARCHITECTURE.md | Overall system architecture, service boundaries |
docs/ecosystem/FRONTEND_APPLICATION.md | Portal frontend structure, patterns, conventions |
docs/ecosystem/BACKEND_APIS.md | All backend API surface, endpoint inventory |
docs/ecosystem/CLIENT_API_AND_AUTH.md | Public content delivery API + authorizer |
docs/ecosystem/DATABASE.md | MongoDB schemas, multi-tenant routing, indexes |
docs/ecosystem/mongo_queries.md | Common query patterns, dbKey routing examples |
docs/ecosystem/CROSS_API_DEBUGGING_GUIDE.md | How to trace bugs across the 3 backend services |
docs/ecosystem/AI_AGENT_SYSTEM.md | Agent system vision and design |
docs/ecosystem/SITE_CREATION_PIPELINE.md | EventHandler Step Functions flow |
docs/ecosystem/PRICING_AND_COSTS.md | Tier quotas, pricing, overage rates |
docs/ecosystem/aws-ses-email-guide.md | SES email integration |
docs/ecosystem/aws-lambda-inventory.md | Full Lambda inventory — function names, env vars, stacks, CloudFormation fragments, Secrets Manager keys, WebSocket config |
docs/ecosystem/insights_architecture.md | Cross-cutting architecture insights |
docs/ecosystem/multi-agent-workflow.md | CloudWatch log group inventory by Lambda |
Updating ecosystem docs: If during a bug fix you discover ecosystem knowledge that is wrong or missing, the documenter is authorized to propose an update via Edit. Cite the bug slug so the change is traceable. Never wholesale rewrite — make targeted edits.
When justifying technical decisions, reference these public standards. The reviewer will demand evidence-based justification, and "industry best practice" without a citation does not count.
Security
AWS
mcp__awslabs_aws-documentation-mcp-server__*) to fetch up-to-date docsWeb platform
Frameworks
Code review and engineering
Performance and reliability
MongoDB
OAuth and identity
When making a non-trivial decision, the architect/coder MUST cite the relevant standard. The reviewer MUST verify citations exist for non-obvious choices.
Client.tsx (interactive) / Loader.tsx (skeleton) / Dialog.tsx (modals)(app) protected, (public) unauthenticated/app set in next.config.ts — affects links and API routesProviders/index.tsx useEffect from siteDatasrc/lib/cookies/onboarding.ts)src/data/manifests/ drive the integration UI — never hardcode integration logicfile:line.$in, bulk operations).force-dynamic where set. Add cache only with explicit reason.explain(). Avoid full collection scans.docs/ecosystem/ docs and the relevant repo CLAUDE.md before forming hypotheses. They contain knowledge that grep cannot surface.The portal uses Playwright e2e + e2e/fixtures (see the spec files in e2e/ or run npx playwright test --list for the current count). Backends are NOT Playwright. Don't confuse them.
| Layer | Framework | Pattern | Coverage gate |
|---|---|---|---|
| Portal frontend | Playwright | e2e/**/*.spec.ts via e2e/fixtures | none |
| VR_Main_API | Mocha + Chai + Sinon + NYC | test/**/*.test.js | 100% on npm test |
| VR_Secure_API | Mocha + Chai + Sinon + NYC | test/**/*.test.js | 100% on npm test |
| VR_CMS_API | Mocha + Chai + Sinon + NYC | test/**/*.test.js | 100% on npm test |
| VR_Client_API | Mocha + Chai + Sinon | test/**/*.test.js | (varies) |
| VR_Client_Auth | Minimal / none | — | — |
Backend test conventions (read each repo's test/CLAUDE.md or test/claude.md first):
test/helpers/loadWithMocks.jsnpm run test:unit (no coverage gate, faster) or npm test (with NYC 100% gate)test/test.js is legacy and NOT in the active glob — don't add tests thereBackend test commands quick ref:
# in any backend repo
npm run test:unit # Mocha only, fast feedback
npm test # Mocha + NYC coverage gate (CI parity)
npm test -- --grep "name" # Run a single test by name
These skills are available via the Skill tool and SHOULD be invoked when relevant:
| Skill | When to use |
|---|---|
vivreal-fullstack:fullstack | Bug spans portal → proxy → backend → DB. Scaffolds an end-to-end checklist across the stack with all the layers required. Use as a starting checklist for cross-repo bug fixes. |
vivreal-fullstack:fullstack-context | Auto-loads cross-repo context when researching backend endpoints. Researcher should rely on the auto-trigger. |
vivreal-db-explorer:db-query | Safe MongoDB queries with built-in dbKey routing, safety guards, multi-tenant boundaries. ALWAYS prefer this over raw mcp__mongodb__find calls. |
vivreal-db-explorer:db-schema | Pulls Mongoose schema, indexes, sample doc for any collection. Use during research to understand data shape before reasoning about queries. |
vivreal-proxy-factory:proxy-route | Generate a new factory-based proxy route. Use when adding a new proxy route is part of the fix. |
superpowers:systematic-debugging | Use when the bug's root cause is unclear after initial research. |
superpowers:test-driven-development | Use when writing the test FIRST is the right move (e.g. fix has multiple possible implementations and the test pins behavior). |
code-review:code-review | Optional secondary review pass — coordinator may use this in addition to reviewer if a fix is high-risk. |
When a fix REMOVES code that crosses repos (shared package + backend + frontend), plan the work in the REVERSE of addition order. New features ship producer → consumer (shared package first so downstream can import); removals ship consumer → producer (frontend/backend stop importing, THEN the shared package deletes the symbols). Any other order leaves an intermediate commit where a live consumer still imports a deleted symbol, breaking downstream builds.
Researcher and architect default to the addition order out of habit — flag the inversion explicitly when the bug is a removal, not an addition.
Shared sheet, dialog, drawer, and card components MUST NOT fall back to JSON.stringify(obj) (or any raw object dump) as developer-facing UI when a render-prop is omitted. These dev-only fallbacks ship to production the moment a new caller forgets the prop, and they look like a bug to users.
Pick one:
typeof/instanceof (never as), and hides internal metadata keys (_id, __v, timestamps) into a footer block.The architect should flag any review that introduces an Optional render-prop with a JSON.stringify fallback.
Skill invocation rule: When an agent needs functionality covered by a skill, it should invoke the skill via the Skill tool rather than reimplementing. The reviewer will flag any agent that bypassed an applicable skill.
A PreToolUse hook checks if files being written are inside src/app/api/proxy/ and blocks non-factory proxy routes. This hook sometimes interferes with Write calls to OTHER directories (like docs/) — the hook runs, outputs its analysis, and the Write silently fails even though the hook approved. When this happens:
cat > path << 'EOF' ... EOF.py script file first, then execute itpython3 -c "open(path,'w').write('placeholder')", then Read the file, then use the Write tool (which requires a prior Read)Bash heredocs (<< 'EOF') break when the content contains:
"""...""" inside a heredoc)unexpected EOF errorsFix: For large multi-line content with potential quote issues, write a Python script to a temp file first, then execute it. Or use the Write tool after a Read.
Subagents (researcher, architect, etc.) sometimes claim they wrote a file but did NOT actually write it. The coordinator MUST verify every artifact exists after each agent dispatch:
ls -la "path/to/expected/file.md"
If the file is missing, the coordinator should write it from the agent's returned output rather than re-dispatching.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub hillbombcreations/vivreal-skills --plugin vivreal-workflow