10 KiB
04. Unified Domain Model And Config Contracts
1) Objectives
This target model turns the Monaco flow into strict, reusable contracts while preserving the current pipeline infrastructure.
Goals:
- Minimize schema churn where current models are already correct.
- Remove ambiguity for jury identity, assignment policy, round bundles, mentoring promotion, and final lock.
- Keep customization through explicit policy layers, not ad hoc conditionals.
2) Proposed Domain Additions
2.1 Stage Purpose Contract
Add To Stage
purposeKey(enum/string, required after migration)
Proposed purpose enum values:
submission_r1_intakeeligibility_filterjury1_evaluationsubmission_r2_intakejury2_evaluationjury3_live_finalsfinal_confirmationresults_publicationaward_evaluationaward_results
Rule:
StageTyperemains coarse technical type.purposeKeycontrols business behavior and policy validation.
2.2 Jury As First-Class Entity
New Jury
Fields:
id,programId,purposeKey,code,displayLabel,kind(MAIN,AWARD),isActive
Examples:
code=main-semifinal,displayLabel=Technical Semi-Final Jurycode=main-finalist,displayLabel=Grand Jurycode=award-blue-innovation,displayLabel=Blue Innovation Prize Jury
New JuryMembership
Fields:
juryId,userId,roleInJury(CHAIR,MEMBER),activeFrom,activeTo,status
New JuryStageBinding
Fields:
juryId,stageId,isPrimary,permissionsJson
Use:
- controls which juries are allowed to evaluate/vote in each stage
- allows overlap across juries and awards
2.3 Assignment Policy Contract
New AssignmentPolicy (stage + jury scoped)
Fields:
stageIdjuryIdrequiredReviewsdefaultCapdefaultCapMode(HARD,SOFT)softBuffer(default 10, configurable)categoryBiasPolicyJson(startup/concept mix preference weights; non-deterministic)overflowPolicy(manual_queue,expand_pool,reduce_reviews)isActive
New JudgePolicyOverride
Fields:
assignmentPolicyIduserIdcap,capMode,softBufferstartupBiasWeight,conceptBiasWeightbiasDisclosureAcceptedAt(onboarding acknowledgement that bias is suggestive only)source(ADMIN_SET,JUDGE_ONBOARDING)
New AssignmentIntent
Purpose:
- records desired assignments created before assignment materialization (e.g., from member invite page)
Fields:
stageId,juryId,userId,projectId,intentSource,status
New AssignmentException
Purpose:
- explicit record for manual over-cap assignments
Fields:
assignmentId,policyId,exceptionType,reasonCode,reasonText,approvedBy
2.4 Submission Round Bundle Contract
New SubmissionRound
Fields:
id,stageId,roundKey,name,openAt,closeAt,latePolicy,lateGraceHours,editabilityPolicy
Evolve FileRequirement
Add:
submissionRoundId(nullable transitional, required after migration)slotKey(stable requirement slot identifier)
Evolve ProjectFile
Add:
submissionRoundIdsubmissionSlotKeysourceType(DIRECT_UPLOAD,MENTOR_PROMOTION,ADMIN_REPLACEMENT)sourceReferenceId(e.g., mentor file id)isOfficial
New SubmissionBundleState
Fields:
projectId,submissionRoundId,status(DRAFT,SUBMITTED,LOCKED),lockedAt,lockedBy
2.5 Mentoring Collaboration + Promotion
New MentorWorkspaceFile
Fields:
projectId,mentorId(nullable for team upload), file storage metadata, visibility, status
New MentorWorkspaceComment
Fields:
workspaceFileId,authorId,threadKey,content, timestamps
New SubmissionPromotionEvent
Fields:
projectId,workspaceFileId,targetSubmissionRoundId,targetSlotKeypromotedById,promotedAtresultProjectFileIdapprovalState(if mentor/admin approvals required)
Invariant:
- promotion always creates immutable provenance link from mentoring artifact to official submission slot.
- promotion authority is limited to team lead and admin.
2.6 Special Award Governance Contract
Extend SpecialAward
Add:
participationMode(SEPARATE_POOL,DUAL_TRACK)routingBehavior(PULL_FROM_MAIN,KEEP_IN_MAIN)routingConfirmationMode(AUTO,ADMIN_CONFIRMED) // Monaco default:ADMIN_CONFIRMEDfor pull-outrequiresDedicatedJury(bool)winnerDecisionMode(JURY_CONFIRMATION,SINGLE_JUDGE_DECIDES)singleJudgeUserId(nullable, required whenwinnerDecisionMode=SINGLE_JUDGE_DECIDES)winnerCandidateSource(ELIGIBILITY_REMAINING_POOL,CUSTOM_SHORTLIST) // Monaco single-judge awards use eligibility remaining poolsubmissionRequirementMode(REUSE_MAIN,CUSTOM)
New AwardStageBinding
Fields:
awardId,filterStageId,evaluationStageId,resultStageId
2.7 Final Confirmation Contract
New FinalConfirmationSession
Fields:
stageId(final confirmation stage)status(OPEN,PENDING_ADMIN_APPROVAL,FINALIZED,CANCELLED)decisionRule(UNANIMOUS,SUPERMAJORITY,SIMPLE_MAJORITY,SINGLE_JUDGE_DECIDES)quorumPolicy(ACTIVE_MEMBERS_ONLY,ALLOW_REPLACEMENT)requiredApprovalsCount(resolved from active quorum after absence/replacement decisions)scope(CATEGORY,AWARD)isAdminOverridden(bool)overrideReasonCode,overrideReasonText,overriddenByAdminId,overriddenAtfinalizedByAdminId,finalizedAt
New FinalConfirmationParticipant
Fields:
sessionId,juryMemberIdstatus(REQUIRED,ABSENT_EXCUSED,REPLACED,REPLACEMENT_ACTIVE)replacedByJuryMemberId(nullable)absenceReasonCode,absenceReasonTextupdatedByAdminId,updatedAt
New FinalConfirmationVote
Fields:
sessionId,juryMemberId,projectId/category/awardScope,decision,comment
New ResultLock
Fields:
sessionId,programId,lockVersion,lockedAt,lockedBy,snapshotJson
New ResultUnlockEvent
Fields:
resultLockId,programIdunlockedBySuperAdminId,unlockedAtreasonCode,reasonTextrelockVersion(nullable until relock)
Invariant:
- once
ResultLockis created, winner outputs are immutable except via explicit super-admin unlock workflow with mandatory audit reason.
3) Policy Precedence Model
Order of precedence (highest to lowest):
- Explicit admin override action (with reason)
- Per-user override policy (e.g., judge cap override)
- Stage+jury policy
- Program-level default policy
- System default
All runtime evaluators must return:
- resolved value
- source layer
- explanation payload for audit/debug UI
4) Access Contract (Role + Context)
Replace scattered checks with resolveAccess(user, context) where context includes:
programIdtrackIdstageIdstagePurposeKeyjuryId(if applicable)projectId(if applicable)submissionRoundId(if applicable)
Returns typed permissions:
canViewProjectcanUploadSubmissionSlotcanViewPreviousRoundDocscanAssignProjectscanVoteLivecanConfirmFinalWinners- etc.
5) Assignment Engine Contract
Input:
- projects eligible in stage
- jury members bound to stage
- resolved per-judge policy (cap mode, cap, buffer, category-bias preference)
- required reviews
- COI and availability constraints
Required behavior:
- satisfy hard-cap constraints strictly
- satisfy soft-cap targets before using buffer
- apply startup/concept distribution as a soft scoring bias (never a strict blocker)
- when all soft-cap members hit cap+buffer, place remainder in manual queue
- never silently drop unassigned projects
Output:
- assignment set
- unassigned queue with explicit reasons
- policy-compliance summary
6) Document Contract
For every stage with submission behavior:
- active
SubmissionRoundmust exist - all required slots represented by
FileRequirement.slotKey - applicant write rights only for active round if open
- previous round slots read-only in applicant scope
- judges see current + previous according to stage policy
- admins full mutate rights with replacement provenance
7) Invite + Onboarding Contract
7.1 Admin Member Invite
- Invitations create
User+ optionalJuryMembership. - Jury selection uses program-defined custom jury labels, while binding to explicit stage-purpose contracts.
- Pre-assignment supports both modes:
- intent-first mode via
AssignmentIntent(default recommended) - direct assignment mode via
Assignment(explicitly enabled and policy-validated)
- intent-first mode via
7.2 Team Invite
- Team lead invites create/attach
TeamMember - invite token acceptance path remains, but post-accept routing resolves to proper applicant/team context
7.3 Accept Invite Routing
After acceptance:
- if user has jury memberships pending onboarding -> jury onboarding journey
- if mentor -> mentor onboarding
- if applicant team member only -> applicant team dashboard
8) Event/Audit Contract
Every significant workflow event emits:
- business event type (
assignment.generated,final_confirmation.finalized, etc.) - actor
- entity scope
- policy snapshot
- before/after state where relevant
Override events must include:
- reason code
- reason text
- impacted policy key
- reviewer chain (if applicable)
9) API Contract Evolution (Router-Level)
9.1 Keep and Evolve
- Keep existing routers (
pipeline,stage,assignment,evaluation,file,mentor,live-voting,decision,user, etc.) - Add new endpoints for purpose/policy/jury/final confirmation and deprecate ambiguous patterns progressively
9.2 New Endpoint Families
jury.*: CRUD memberships/bindingsassignmentPolicy.*: configure and inspect effective policysubmissionRound.*: lifecycle and bundle statementorWorkspace.*: files/comments/promotionfinalConfirmation.*: create/collect/finalize lock, handle quorum fallback, and manage juror replacement/absenceresultUnlock.*: super-admin unlock/relock workflow with audit captureaccess.*: debug effective permissions (admin-only)
10) Migration Safety Rules
- Additive migrations first.
- Backfill
purposeKeyand policy references from existing configs. - Dual-read / single-write transition windows where needed.
- Feature flags for critical runtime path switches.
- No silent behavior changes in production without compatibility mode.
11) End State
A coherent operating model where all functions, pages, and APIs are consistent with Monaco flow and each key behavior is explainable, testable, and auditable.