-
Notifications
You must be signed in to change notification settings - Fork 90
Description
Environment information
System:
OS: macOS 26.0
CPU: (12) arm64 Apple M2 Max
Memory: 1.37 GB / 96.00 GB
Shell: /bin/zsh
Binaries:
Node: 20.18.0 - ~/.nvm/versions/node/v20.18.0/bin/node
Yarn: undefined - undefined
npm: 11.4.0 - ~/.nvm/versions/node/v20.18.0/bin/npm
pnpm: undefined - undefined
NPM Packages:
@aws-amplify/auth-construct: 1.8.1
@aws-amplify/backend: 1.16.1
@aws-amplify/backend-ai: Not Found
@aws-amplify/backend-auth: 1.7.1
@aws-amplify/backend-cli: 1.8.0
@aws-amplify/backend-data: 1.6.1
@aws-amplify/backend-deployer: 2.1.3
@aws-amplify/backend-function: 1.14.1
@aws-amplify/backend-output-schemas: 1.7.0
@aws-amplify/backend-output-storage: 1.3.1
@aws-amplify/backend-secret: 1.4.0
@aws-amplify/backend-storage: 1.4.1
@aws-amplify/cli-core: 2.2.1
@aws-amplify/client-config: 1.8.0
@aws-amplify/data-construct: 1.16.3
@aws-amplify/data-schema: 1.21.1
@aws-amplify/deployed-backend-client: 1.8.0
@aws-amplify/form-generator: 1.2.4
@aws-amplify/model-generator: 1.2.0
@aws-amplify/platform-core: 1.10.0
@aws-amplify/plugin-types: 1.11.0
@aws-amplify/sandbox: 2.1.2
@aws-amplify/schema-generator: 1.4.0
@aws-cdk/toolkit-lib: 1.1.1
aws-amplify: 6.15.5
aws-cdk-lib: 2.204.0
typescript: 5.9.2
npm warn exec The following package was not found and will be installed: [email protected]
No AWS environment variables
No CDK environment variables
Data packages
[email protected] /Users/pavolkolencin/Documents/Coding/cedarcare/data-model
├─┬ @aws-amplify/[email protected]
│ └─┬ @aws-amplify/[email protected]
│ └── @aws-amplify/[email protected]
└─┬ @aws-amplify/[email protected]
└─┬ @aws-amplify/[email protected]
└── @aws-amplify/[email protected]
Description
Description
In Amplify Gen 1, it was possible to define one-way relationships safely.
For example:
type Patient @model {
id: ID!
clinicID: ID!
clinic: Clinic! @hasOne(fields: ["clinicID"])
}
type Clinic @model {
id: ID!
}
This allowed us to link a Patient → Clinic without automatically exposing Clinic → Patients.
This was critical for security and compliance, because sometimes the reverse edge leaks far too much data.
Problem in Gen 2
In Amplify Gen 2 with the TypeScript schema builder:
Patient: a.model({
id: a.string().required(),
clinicID: a.string().required(),
clinic: a.belongsTo('Clinic', 'clinicID'),
})
Clinic: a.model({
id: a.string().required(),
// forced inverse relation
patients: a.hasMany('Patient', 'clinicID'),
})
If you use belongsTo(), the compiler forces you to declare the inverse relation (hasMany).
This means Clinic will always expose a patients field, even if we don’t want clients to see it.
Unlike scalar/index fields, there is no .hidden() support for relation fields.
.authorization(() => []) doesn’t truly deny access — it inherits the parent model’s rules unless you explicitly block every group.
The result is that we are forced to expose clinic.patients, even in cases where that breaks our security model.
Why this is a Security Issue
In healthcare (HIPAA) and other sensitive domains, this is not just an annoyance:
We may want to allow Patient → Clinic (to know which clinic owns a patient) but never allow Clinic → Patients (to prevent enumeration of all patients in a clinic).
With Gen 2’s current behavior, the GraphQL schema always exposes the reverse list. Even if it resolves empty, the field itself is visible and queryable.
This leads to overexposure of data and complicates compliance audits.
In Gen 1, one-way modeling was possible and safe. In Gen 2, it is not.
Current Workarounds
Hack: define the inverse as hasOne instead of hasMany — the compiler is satisfied, but queries to it fail at runtime.
Manual FK modeling: avoid belongsTo entirely and just use a raw string foreign key (clinicID), resolving relations manually.
Custom resolver override: keep the inverse, but replace its resolver with one that always returns [].
All of these are fragile or add unnecessary boilerplate.
Suggested Solutions
Add support for .hidden() on relation fields, the same way we can hide scalars or index helpers.
Or provide an explicit API, e.g.:
a.belongsTo('Clinic', 'clinicID', { inverse: false })
Or a silent variant such as:
a.hasSilentMany('Patient', 'clinicID')
which satisfies schema validation but does not expose the field in GraphQL.
Summary
Gen 2 currently forces bidirectional modeling, which is a regression compared to Gen 1.
This leads to unnecessary data exposure and creates compliance risks.
We need a way to safely define one-way relations (Patient → Clinic) without exposing unwanted inverse fields (Clinic → Patients) in the schema.