Training & Placement
Data model
ER diagram
All screens
Cluster
Identity
Academic
Request
Evidence
Detail
Show fields
Entities only
−
100%
+
Fit
CLUSTER 1
Identity
CLUSTER 2
Academic
CLUSTER 3
Request
CLUSTER 4
Evidence
holds
1:N
scopes
1:N
signs in as
1:0..1
teaches
1:N
rules on
1:N
enrols
1:N
owns
1:N
populates
1:N
populates
1:N
populates
1:N
approves
1:N
declares
1:N
is taught as
1:N
dates
1:N
is mapped in
1:N
is judged in
1:N
pins version
1:N
requests
1:N
hosts
1:N
decided by
1:N
notifies
1:N
evidenced by
1:1
verified by
1:N
confirms
1:N
fans out to
1:N
writes
1:N
is verified via
1:N
records
1:N
users
2 idx
_id
Id<"users">
subject
string
email
string
displayName
string
status
active | inactive
createdAt
number
roleAssignments
2 idx
_id
Id<"roleAssignments">
userId
Id<"users">
role
enum · 5
scopeType
enum · 3
scopeId
string
grantedBy
Id<"users">
grantedAt
number
revokedAt?
number
departments
_id
Id<"departments">
name
string
school
string
code
string
rosterImports
_id
Id<"rosterImports">
uploadedBy
Id<"users">
fileName
string
fileHash
string · sha256
scopeSelector
string
status
enum · 3
rowCount
number
createdCount
number
updatedCount
number
deactivatedCount
number
createdAt
number
policies
_id
Id<"policies">
version
string
effectiveFrom
number
thresholds
Threshold[]
departmentId?
Id<"departments">
createdBy
Id<"users">
students
2 idx
_id
Id<"students">
userId?
Id<"users">
registrationNo
string · unique
name
string
programme
string
specialization
string
semester
number
section
string
departmentId
Id<"departments">
status
active | inactive
courses
1 idx
_id
Id<"courses">
code
string
title
string
credits
number
departmentId
Id<"departments">
semester
number
courseOutcomes
_id
Id<"courseOutcomes">
courseId
Id<"courses">
coId
CO1 … CO4
text
string
contactHours
number
teachingAssignments
2 idx
_id
Id<"teachingAssignments">
courseId
Id<"courses">
teacherUserId
Id<"users">
section
string
termId
Id<"terms">
terms
_id
Id<"terms">
name
string
startsOn
number
endsOn
number
isCurrent
boolean
nocRequests
3 idx
_id
Id<"nocRequests">
studentId
Id<"students">
stage
Stage · 10
blockers
Blocker[] · 5
companyId
Id<"companies">
role
string
startDate
number
endDate
number
mode
enum · 3
stipend
number
policyVersion
string
mappedPercent?
number
submittedAt
number
decidedAt?
number
fingerprint
string
companies
2 idx
_id
Id<"companies">
legalName
string
website
string
domain
string
status
enum · 3
registeredAt?
number
addedBy
Id<"users">
approvals
_id
Id<"approvals">
requestId
Id<"nocRequests">
approverUserId
Id<"users">
decision
enum · 3
reasons
RejectionReason[]
note
string
snapshotHash
string
decidedAt
number
notifications
_id
Id<"notifications">
requestId
Id<"nocRequests">
userId
Id<"users">
channel
enum · 3
event
string
sentAt
number
readAt?
number
offerLetters
Security note
_id
Id<"offerLetters">
requestId
Id<"nocRequests">
storageId
Id<"_storage">
mimeType
string
sizeBytes
number
sha256
string
uploadedAt
number
companyVerifications
_id
Id<"companyVerifications">
requestId
Id<"nocRequests">
companyId
Id<"companies">
contactName
string
hrEmail
string
channel
enum · 3
sentAt
number
respondedAt?
number
outcome
enum · 4
evidence
string
flags
string[]
verifiedBy
Id<"users">
mappingTasks
2 idx
_id
Id<"mappingTasks">
requestId
Id<"nocRequests">
courseId
Id<"courses">
teacherUserId
Id<"users">
status
enum · 6
dueAt
number
remindedAt?
number
mappingRulings
_id
Id<"mappingRulings">
taskId
Id<"mappingTasks">
coId
Id<"courseOutcomes">
coverage
enum · 3
note?
string
auditLog
_id
Id<"auditLog">
requestId
Id<"nocRequests">
actorUserId
Id<"users">
action
string
fromStage
Stage
toStage
Stage
reason
string
snapshotHash
string
prevHash
string
at
number
verificationTokens
_id
Id<"verificationTokens">
token
string · opaque
requestId
Id<"nocRequests">
purpose
enum · 2
expiresAt
number
revokedAt?
number
maxUses
number
usedCount
number
Security note — offerLetters
Convex ctx.storage.getUrl() returns a
PERMANENT, PUBLIC url with no expiry.
So an offer letter must be served only
through an authenticated httpAction —
never by handing the storage URL to a
browser.
−
100%
+
Fit
How to read