بنقرة واحدة
skill-api
Skill to create new features in the API that has context on our data model and business logic.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Skill to create new features in the API that has context on our data model and business logic.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
How OpenTelemetry tracing works in the managed-care-review API and how to add to it — resolver spans, dedicated/background spans, recording trace errors, and the Datadog trace-analytics monitors those spans feed. Read when instrumenting code with spans, recording errors on a trace, wiring a Lambda's tracer, or writing/changing a Datadog monitor in infra/datadog.
Skill for working in the Cypress E2E workspace, including test structure, custom commands, direct API seeding, fixture loading, GraphQL intercepts, and LaunchDarkly flag handling.
| name | skill-api |
| description | Skill to create new features in the API that has context on our data model and business logic. |
Reference for any agent building or modifying contract/rate features in the services/app-api/ portion of the managed-care-review codebase. The supporting files in references/ describe what the data layer actually does — including the non-obvious dynamics that aren't visible from reading any single file.
Read the relevant reference files when the task involves:
services/app-api/src/postgres/questionResponse/ or services/app-api/src/resolvers/questionResponse/services/app-api/src/postgres/contractAndRates/, services/app-api/src/postgres/questionResponse/, services/app-api/src/postgres/prismaHelpers.ts, services/app-api/src/domain-models/contractAndRates/, or services/app-api/src/resolvers/{contract,rate,questionResponse}/ directoriesContractTable, RateTable, ContractQuestion, RateQuestion, UpdateInfoTable, SubmissionPackageJoinTable, or DraftRateJoinTableIf the task only involves UI/frontend without touching the data layer, you probably don't need these references.
| If the task touches… | Read |
|---|---|
| Anything contract/rate-shaped (start here) | references/01-storage-schema.md + references/02-domain-types.md |
Reading data via findContractWithHistory / findRateWithHistory; building a new query path; understanding packageSubmissions shape | references/03-parse-pipeline.md |
| Creating a new draft contract or rate; editing form data on a draft; reconciling rates on a draft | references/04-insert-and-update.md |
| Submit, unlock, or resubmit (any state-flip operation) | references/05-submit-unlock-resubmit.md |
Adding or changing questionResponse store/resolver logic; reasoning about lock-vs-stale-state behavior on ContractQuestion / RateQuestion | Read this SKILL.md for the row-lock rules, then inspect services/app-api/src/postgres/questionResponse/ directly because there is no dedicated reference file yet |
| Anything involving rates that span multiple contracts (linking, parent reassignment, withdraw rate fallout) | references/06-linked-rates.md |
| Withdraw contract specifically | references/07-withdraw.md |
Working out what status a contract or rate ends up in; computing parent contract; resolving cause on packageSubmissions; recursion in domain types | references/08-derived-state.md |
| Undo unlock, reversed revisions, active-draft rules, linked-rate cleanup | references/09-undo-unlock.md |
| Contract/rate data overrides, override mutations, parser merge behavior, adding new overridable fields | references/10-revision-overrides.md + docs/technical-design/contract-and-rate-data-override.md |
For broad multi-area features (e.g. a new "undo unlock contract" mutation): read 01, 02, 05, and 08 first; pull in 06 and 07 if rates cross contract boundaries.
submitInfoID / unlockInfoID on a row.submitInfo/unlockInfo pair, plus the latest *ActionTable row, plus a few special-case rules.submitContract, unlockContract, fetchRate, createContractQuestion. These handle auth, user-input validation, orchestration, store writes/reads, and error formatting for client-initiated operations.Rate, Contract, RateRevision, ContractQuestion, GenericDocument, DocumentZipPackage in services/app-api/src/resolvers/configureResolvers.ts. These run when GraphQL resolves selected fields on already-fetched objects. They usually compute derived fields (webURL, state, initiallySubmittedAt, packageSubmissions, downloadURL, round) or do secondary lookups, but they are not top-level workflow entrypoints.UpdateInfoTable event row per submit-or-unlock; shared across the contract and every child rate touched in that transaction. This is what lets the parser later detect "these were submitted/unlocked together."SubmissionPackageJoinTable is the immutable snapshot of contract↔rate at submit time, joining specific contract revision + specific rate revision + position. DraftRateJoinTable is the working set on a contract that's currently in draft, joining parent tables only.updateDraftContract are full replaces, not merges. Omitted fields are nulled (nullify) or emptied (emptify). Child collections (documents, contacts) are delete-and-recreate, so row IDs are not stable across updates.ContractTable, RateTable, ContractQuestion, or RateQuestion should default to runTransactionWithRowLock. Use services/app-api/src/postgres/prismaHelpers.ts and pass the table + row id so concurrent writes to the same record serialize before the store performs additional reads or writes.ContractQuestion or RateQuestion row or appends related responses based on current question state, default to runTransactionWithRowLock and validate deleted/current status after the lock is acquired.09-undo-unlock.md if you touch undoUnlockInfo, active-draft logic, or linked-rate cleanup.10-revision-overrides.md and docs/technical-design/contract-and-rate-data-override.md before touching override mutations, override tables, parser merge behavior, document override lookup, or unlock/submit behavior for overridden data.OVERRIDE applies payload, CLEAR_OVERRIDE clears scalar field override state, and nullable op columns mean no instruction.documentSha256 as the sparse merge key, use documentID to disambiguate duplicate base docs, and remember override-added documents expose the override row id as GenericDocument.id.ContractTable.sharedRateRevisions / RateRevisionTable.contractsWithSharedRateRevision (the SharedRateRevisions M:N) — not marked deprecated in the schema source, but confirmed deprecated 2026-05-04.HealthPlanPackageTable / HealthPlanRevisionTable (proto legacy) — marked deprecated Boolean @default(true).Without... Zod schema (e.g. contractWithoutDraftRatesSchema) is the one-level recursion break. It exists so a contract can embed rates and a rate can embed contracts without infinite recursion. The include shape mirrors this with includeContractWithoutDraftRates / includeRateWithoutDraftContracts.DRAFT_PARENT_PLACEHOLDER ('DRAFT_PARENT_REPLACE_ME'): a never-submitted rate has no real parent, so the parser returns this placeholder; the outer parser patches it from draftContracts[0].id.ContractRevisionTable.relatedSubmisions (one s) vs RateRevisionTable.relatedSubmissions (correct). Both are valid relation names; code uses each side's spelling.Use this model when changing lastActionDate, submissionHistoryHelpers, fetchSubmissionHistory, submit/unlock/withdraw flows, override flows, or Q&A writes.
Core rule: lastActionDate should move when submitted-visible data changes for CMS users, or when a visible review, Q&A, or status action happens. Draft-only form edits should not move CMS-facing freshness unless the action itself is visible, such as an unlock.
For contracts, submitted-visible data means the latest submitted contract package: contract form data plus submitted rate data attached to that package. For rates, submitted-visible data means the latest submitted rate revision plus submitted contract relationship changes, rate overrides, rate Q&A, and rate review/status actions.
Write lastActionDate at the lowest-level store/transaction function that writes the user-visible action row or submission event to the database. Do not rely on a resolver or broad orchestration wrapper to recalculate it later. Examples: submit freshness belongs in submitContractAndOrRates, review freshness belongs where the review action row is appended, override freshness belongs where the override row is created, and Q&A freshness belongs where the question/response/action row is created.
When one workflow writes multiple actions in one transaction, ordering matters: intermediate submit/unlock writes may happen first, but the final visible action should overwrite lastActionDate. For example, withdraw and undo-withdraw flows can submit/unlock first, then write a review/status action that becomes the stored freshness date.
Contract lastActionDate should update for:
UNDER_REVIEW, NOT_SUBJECT_TO_REVIEW, MARK_AS_APPROVED, WITHDRAW, reverse approve, and undo-withdraw restored review actions.Contract lastActionDate should not update for:
Rate lastActionDate should update for:
UNDER_REVIEW, WITHDRAW, undo-withdraw restored actions, and future rate review actions if added.Rate lastActionDate should not update for:
buildContractSubmissionHistory returns contract-level submitted history:
CONTRACT_SUBMISSION, UNLOCK, LINKED_RATE_UPDATE, contract OVERRIDE, and contract review actions.RATE_LINK and RATE_UNLINK by design. From the contract perspective, submitted link/unlink changes are captured by the contract's own submit/resubmit. Separate link/unlink entries would duplicate contract submission history and are brittle for draft-only relationship changes.buildRateSubmissionHistory returns rate-level submitted history:
RATE_SUBMISSION, UNLOCK, RATE_LINK, RATE_UNLINK, rate OVERRIDE, and rate review actions.buildQuestionResponseHistory returns scoped Q&A actions:
CONTRACT_QUESTION, CONTRACT_QUESTION_RESPONSE, and contract question/response delete/restore action types.RATE_QUESTION, RATE_QUESTION_RESPONSE, and rate question/response delete/restore action types.buildCompleteHistory merges already-built histories and sorts newest-first. If two actions have the same JS millisecond, actionTypeSortRank breaks ties so later lifecycle actions such as overrides or review/status actions sort above submit, and submit sorts above unlock. Keep this tie-breaker in mind when adding action types that can share a DB transaction timestamp.
History builders are best-effort readers over parsed domain data. They should not block fetching a contract/rate because history shape is imperfect; for example, ambiguous missing previous package data is logged/skipped rather than throwing.
fetchSubmissionHistory is the heavier explicit history query. The resolver should stay thin: check OAuth/read permissions, fetch the contract enough to enforce state/CMS/Admin access, then call findSubmissionHistoryByContractID for the assembled history and map the result to GraphQL. Keep the expensive history assembly in the store layer so resolver tests exercise the same data-building path other callers can reuse.
findSubmissionHistoryByContractID merges contract submission history, contract Q&A history, and selected rate-owned history filtered to windows where the rate was attached to the contract in submitted package history. This windowing matters because a linked rate can be linked, delinked, and relinked; rate actions only belong in contract history when CMS users could see that rate through the contract's latest submitted package.
For contract history, derive attached-rate windows from the contract's own packageSubmissions, not from rate-wide package history. The contract package timeline is the source of truth for when a given rate was submitted as part of that contract. Rate package history can include parent submits and other linked contracts that are not relationship changes for this contract.
Do not merge buildRateSubmissionHistory wholesale into contract fetchSubmissionHistory. Contract history should include attached-window-filtered rate overrides and rate Q&A because those can change CMS-visible submitted data without a contract submit. It should not include raw rate RATE_SUBMISSION, RATE_LINK, RATE_UNLINK, UNLOCK, or rate review/status entries from the rate builder; those are either represented by the contract package timeline or are not contract-scoped enough for this view.
Important edge cases:
LINKED_RATE_UPDATE, and B lastActionDate should update to that parent submit timestamp.lastActionDate and appear in explicit submission history while R is attached.updateRelatedContractsLastActionDateByRateID resolves contracts from the rate's latest submitted package snapshot. It is appropriate for rate-visible changes that happen outside a contract submit, such as rate overrides and rate Q&A. It intentionally ignores draft-only links and previously removed links. It throws if no currently related submitted contracts exist, so callers should only use it when at least one related contract is expected.
submitContractAndOrRates also updates related contracts when a submitted rate was already attached to those contracts in their previous submitted package. This keeps lastActionDate aligned with the LINKED_RATE_UPDATE history entry. Group these writes with contract freshness writes; rate freshness writes are separate and should only update rates whose own rate history changed.
lastActionDate is the stored CMS/Admin freshness date. CMS/Admin users do not see draft-only edits, so lastUpdatedForDisplay uses lastActionDate when present and falls back to updatedAt. State users can see draft changes, so display/index formatting considers the latest of lastActionDate and draftRevision.updatedAt.
indexContracts should use the stored lastActionDate for CMS/Admin filtering/sorting when the use-stored-contract-action-dates flag is on rather than recalculating full history for every indexed contract. The legacy flag-off updatedWithin path uses calculated display freshness and is incomplete compared with lastActionDate; keep compatibility fixes minimal and avoid treating it as canonical submission history.
When adding a new action, status transition, override path, Q&A path, submit-like workflow, or relationship change, explicitly answer these questions in code review:
Is this action visible to CMS users?
lastActionDate.lastActionDate.Which record's freshness moves?
ContractTable.lastActionDate.RateTable.lastActionDate.lastActionDate when the rate is attached to those contracts in submitted package history.lastActionDate when the submitted relationship for the rate changes.Where should the write happen?
lastActionDate in the lowest-level store/transaction function that writes the action row or submission event.createdAt / updatedAt) instead of creating a separate timestamp when possible.Which history builder should emit the action?
buildContractSubmissionHistory.buildRateSubmissionHistory.buildQuestionResponseHistory.fetchSubmissionHistory, not in a lightweight field resolver.Does fetchSubmissionHistory need relationship-window filtering?
Do GraphQL enums/types need updates?
What tests prove freshness and history stay aligned?
lastActionDate equals the timestamp of the newest relevant history entry.Does indexing/display behavior still hold?
lastActionDate is enough for indexContracts and lastUpdatedForDisplay.| Mutation | Who can do it | Source of rule |
|---|---|---|
insertDraftContract / insertDraftRate / updateDraftContract / updateDraftContractRates | State user matching the contract's stateCode | Resolver |
submitContract (initial submit + resubmit) | State user matching the contract's stateCode | Resolver |
unlockContract | CMS user (hasCMSPermissions) | Resolver |
unlockRate | CMS user (hasCMSPermissions), inactive standalone-rate path | Resolver |
withdrawContract / withdrawRate | CMS user | Resolver |
overrideContractData / overrideRateData | Admin user only | Resolver + store status checks |
Edit a rate's form data via UPDATE | Only the rate's parent contract | Postgres + resolver enforce parentContractID === contract.id |
Link to a rate via LINK | Any contract (target must not be DRAFT or WITHDRAWN) | Resolver |
OAuth canWrite (or canOauthWrite) is required on every write. State-vs-CMS checks are layered on top.
| Concern | Path |
|---|---|
| Schema | services/app-api/prisma/schema.prisma |
| Domain model index | services/app-api/src/domain-models/contractAndRates/index.ts |
| Base Zod shapes | services/app-api/src/domain-models/contractAndRates/baseContractRateTypes.ts |
| Full Zod shapes | contractTypes.ts, rateTypes.ts (same dir) |
packageSubmissions schemas | packageSubmissions.ts (same dir) |
| Revision schemas | revisionTypes.ts (same dir) |
| Status schemas | statusType.ts (same dir) |
UpdateInfoType | updateInfoType.ts (same dir) |
| Submission history domain types | services/app-api/src/domain-models/contractAndRates/submissionHistoryTypes.ts |
| Find entry points | services/app-api/src/postgres/contractAndRates/findContractWithHistory.ts, findRateWithHistory.ts |
| Full include shapes | prismaFullContractRateHelpers.ts (same dir) |
| Without-draft includes | prismaSubmittedContractHelpers.ts, prismaSubmittedRateHelpers.ts |
| Parsers | parseContractWithHistory.ts, parseRateWithHistory.ts |
| Override write paths | services/app-api/src/resolvers/contract/overrideContractData.ts, services/app-api/src/resolvers/rate/overrideRateData.ts, services/app-api/src/postgres/contractAndRates/overrideContractData.ts, services/app-api/src/postgres/contractAndRates/overrideRateData.ts |
| Override merge and validation helpers | services/app-api/src/postgres/prismaOverrideMergeHelpers.ts |
| Status helpers, parent-id, formData converters | prismaSharedContractRateHelpers.ts |
| Insert (create new) | insertContract.ts, insertRate.ts |
| Update draft form data | updateDraftContract.ts, updateDraftRate.ts, updateDraftContractRates.ts, updateDraftContractWithRates.ts |
| Domain↔Prisma form-data adaptors | prismaContractRateAdaptors.ts |
nullify / emptify helpers | services/app-api/src/postgres/prismaDomainAdaptors.ts |
| Submit resolver | services/app-api/src/resolvers/contract/submitContract.ts |
| Submit postgres outer | services/app-api/src/postgres/contractAndRates/submitContract.ts |
| Submit core engine | submitContractAndOrRates.ts (same dir) |
| Submission history builders | services/app-api/src/postgres/submissionHistoryHelpers.ts |
| Full submission history store reader | services/app-api/src/postgres/contractAndRates/findSubmissionHistoryByContractID.ts |
| Full submission history resolver | services/app-api/src/resolvers/contract/fetchSubmissionHistory.ts |
| lastActionDate helpers | services/app-api/src/postgres/updateLastActionDateHelpers.ts |
| Resolver registration map (top-level + object-field resolvers) | services/app-api/src/resolvers/configureResolvers.ts |
| Unlock resolver | services/app-api/src/resolvers/contract/unlockContract.ts |
| Unlock postgres (contract) | services/app-api/src/postgres/contractAndRates/unlockContract.ts |
| Unlock postgres (rate engine) | unlockRate.ts (same dir) |
| Standalone unlock rate resolver | services/app-api/src/resolvers/rate/unlockRate.ts (standalone-rate scaffold; not expected to match unlockContract parity while rates submit with contracts only) |
| Withdraw rate resolver | services/app-api/src/resolvers/rate/withdrawRate.ts |
| Withdraw rate postgres | services/app-api/src/postgres/contractAndRates/withdrawRate.ts |
| Withdraw contract resolver | services/app-api/src/resolvers/contract/withdrawContract.ts |
| Withdraw contract postgres | services/app-api/src/postgres/contractAndRates/withdrawContract.ts |
| Parent reassignment | reassignParentContract.ts (same dir) |
| Parent picker / new-parent selection | getNewParentContract in prismaSharedContractRateHelpers.ts |
Cause derivation (*WithCause) | services/app-api/src/resolvers/contract/contractResolver.ts, services/app-api/src/resolvers/rate/rateResolver.ts |
| Other status mutations | sibling files in same dir (approveContract.ts, reverseApproveContract.ts, undoWithdrawContract.ts, etc.) |
The repo's docs/ directory has broader architecture and conventions docs that complement this skill. Most relevant for API work:
docs/architectural-decision-records/023-seperate-contract-rates-tables-postgres.md — the ADR that established the two-tier contract/rate schema this skill describesdocs/technical-design/contract-and-rate-data-override.md — canonical design for contract/rate override storage, operation semantics, read-time merge behavior, write validation, document overrides, and submission lifecycle behaviordocs/technical-design/graphql-resovler-design.md — resolver layer conventions (error formatting, structure, audit trails)docs/technical-design/dependency-injection-pattern.md — how the Store is injected into resolversdocs/architectural-decision-records/011-typescript-error-handling.md + 012-custom-error-types.md — the result/error pattern used throughout the postgres helpersdocs/technical-design/creating-and-testing-endpoints.md — end-to-end checklist for a new resolverdocs/technical-design/error-handling.md — errorUtils.ts, GraphQLError codes, common error shapesdocs/technical-design/testing-approach.md — integration vs. unit testing conventionsdocs/technical-design/howto-migrations.md — Prisma migration workflowdocs/technical-design/contract-rate-types-naming.md — contract/rate type naming (heads-up: file truncates mid-section in the current repo state)docs/technical-design/naming-conventions.md — broader naming guidedocs/architectural-decision-records/026-oauth-machine-to-machine-authentication.md, docs/technical-design/oauth.md, docs/technical-design/api-jwt-security.md, docs/technical-design/third_party_api_access.mddocs/architectural-decision-records/016-launchdarkly-server-side-flags.md, docs/technical-design/launch-darkly-implementation.md, docs/technical-design/launch-darkly-testing-approach.md (heads-up: Jest references are stale; project uses Vitest)docs/technical-design/file-upload.mddocs/architectural-decision-records/017-application-observability.md, docs/technical-design/monitoring.mddocs/Technologies.md (heads-up: may say React 18; project is on React 19 as of 2026-05)docs/Configuration.md, docs/technical-design/howto-access-deployment-database.md, docs/technical-design/howto-update-state-programs.mddocs/technical-design/database-diagram.mdHealthPlanPackage design, since superseded by the contract/rate tables this skill describessubmitInfo/unlockInfo on the latest revision, adding a new revision, or appending an action row.services/app-api/src/resolvers/configureResolvers.ts first if you're unsure which kind you're looking at.
ContractTable, RateTable, ContractQuestion, or RateQuestion, default to runTransactionWithRowLock. Only skip it when last-write-wins behavior is intentional and acceptable for that path.packageSubmissions and cause impact (reference 08) if the change involves an UpdateInfoTable event. The change may append entries to the package history from both contract and rate perspectives.lastActionDate at the lowest-level DB write, update the relevant history builder/query, and add tests proving newest history aligns with stored freshness.sharedRateRevisions in any new design — deprecated.DRAFT_PARENT_PLACEHOLDER if the change involves draft rates without a submitted parent yet — the placeholder needs the outer parser to patch.migration.sql files.localhost:5432). If a task requires prisma migrate, prisma db push, prisma migrate reset, or similar DB-connected Prisma commands, the human user should run them in their own shell and provide the results back for review.BEGIN; / COMMIT; transaction block.