Program creation and editing — frontend integration¶
This guide covers the v2 company and superadmin program creation flows, general program editing, and program auction-settings editing. It includes configurable Dichit hosting, required branch ownership, and the validation rules for externally hosted auctions.
The auction contracts are development-only: clients must explicitly send a hosting choice when creating an auction-based program. There is no compatibility fallback that treats a missing choice as Dichit hosting.
1. Hosting and form visibility¶
bid controls winner selection; isAuctionHostedOnDichit controls where the auction runs. These are separate choices.
| Bid type | Hosting choice | Dichit-specific sections |
|---|---|---|
LOT | Omit hosting or send false; true is rejected | Hide |
AUCTION | Explicit true or false required at creation | Show only for true |
AUCTION_AND_LOT | Explicit true or false required at creation | Show only for true |
For externally hosted auctions, hide these sections and omit their keys from both create and edit requests:
| Section | Request fields |
|---|---|
| Has Prebid and dependent options | hasPrebid, prebidMutabilityPolicy, prebidDocumentRequired, prebidDocumentTemplateVersionId |
| Auction automation triggers | autoStart, approvalRequired, autoOpenPrebid, autoRevealPrebids, autoDeclareWinner |
| Advanced auction details | auctionBidMode, auctionClosingMode, auctionDurationSeconds, auctionExtensionSeconds, auctionFirstCallSeconds, auctionSecondCallSeconds, auctionThirdCallSeconds, subscriberJoinGraceSeconds, auctionJoiningRule, allowStaffOfflineBids |
| Optional Dichit preset selector | auctionPresetId |
Do not send null, false, 0, or empty strings as substitutes for hidden fields. Omission is sufficient. Supplied fields still undergo normal type, range, dependency, and ownership validation; valid supplied settings are stored as dormant configuration, not rejected simply because hosting is external.
On edits, omitted values are retained. Turning hosting off does not erase the saved prebid settings, triggers, preset, or advanced configuration. They can be used again if hosting is enabled later. Creating a fresh program without these fields leaves its existing defaults in place (hasPrebid: false, prebidDocumentRequired: false, and unset optional auction overrides).
hasFirstCycleAuction is not a Dichit-only option: it describes whether the first cycle is auction-eligible. Keep it in the creation payload where required below, including external hosting. General program fields, money fields, and allowedSecurities are not removed by the hosting choice.
Recommended UI state:
type Bid = 'LOT' | 'AUCTION' | 'AUCTION_AND_LOT';
type HostingChoice = 'DICHIT' | 'EXTERNAL' | null;
function showDichitSections(bid: Bid, hosting: HostingChoice): boolean {
return bid !== 'LOT' && hosting === 'DICHIT';
}
function hostingPayload(
bid: Bid,
hosting: HostingChoice
): {
isAuctionHostedOnDichit: boolean;
} {
if (bid === 'LOT') return { isAuctionHostedOnDichit: false };
if (hosting === null) throw new Error('Select where the auction is hosted.');
return { isAuctionHostedOnDichit: hosting === 'DICHIT' };
}
Keep “not selected” distinct from false. Do not use a truthiness check to validate the hosting choice. Validate only visible sections in the form and build requests from an allowlist of fields, not the entire form state.
2. Endpoints, authorization, and responses¶
Send Authorization: Bearer <access-token> and JSON bodies. Company routes use the authenticated company; do not send companyId in those bodies. Admin routes require SUPERADMIN; admin creation step 1 requires the target companyId. Both company and admin creation step 1 require a branchId returned by the branch API. The branch must belong to the target company, be active, have an operational address, and not be archived/deleted. All path IDs and template/preset/branch IDs must be valid CUID2 strings returned by the API.
| Operation | Company | Superadmin |
|---|---|---|
| Create new, step 1 | POST /v2/companies/programs/new/steps/1 | POST /v2/admin/programs/new/steps/1 |
| Create new, step 2 | POST /v2/companies/programs/new/:programId/steps/2 | POST /v2/admin/programs/new/:programId/steps/2 |
| Import existing, step 1 | POST /v2/companies/programs/existing/steps/1 | POST /v2/admin/programs/existing/steps/1 |
| Import existing, steps 2–5 | POST /v2/companies/programs/existing/:programId/steps/:step | POST /v2/admin/programs/existing/:programId/steps/:step |
| Edit general program fields | PATCH /v2/companies/me/programs/:programId | PATCH /v2/admin/programs/:programId |
| Read/edit auction settings | GET/PATCH /v2/companies/programs/:programId/settings | GET/PATCH /v2/admin/programs/:programId/settings |
| Transfer eligible draft | POST /v2/companies/programs/:programId/transfer | Not exposed |
Creation steps 1 and 2 and general PATCH return HTTP 200 with data.programId. Existing-program step 1 also returns mayBeCompletedCycles. The common response envelope is { status, code, message, data, error }. For example, a successful step 2 response has this shape:
{
"status": "success",
"code": 200,
"message": "Additional details have been added.",
"data": { "programId": "tz4a98xxat96iws9zmbrgj3a" },
"error": null
}
Messages can differ by endpoint; do not branch on the success message. Creation step 2 requires a non-deleted INCOMPLETE program with approval status UNDER_REVIEW; the existing-program flow additionally requires preStarted. New-program step 2 submits the company program (APPLIED), or drafts an admin-created program (DRAFTED), so subsequent edits use PATCH, not step 2. Existing programs remain incomplete through steps 2–4 and finalize at step 5.
3. Shared value conventions¶
| Value | Contract |
|---|---|
| Money/commission | Send decimal strings, e.g. "100000", "5.5". Do not send currency symbols, separators, or empty strings. See the decimal validation caveat in section 11. |
| Booleans | JSON true / false, not strings. Only fields explicitly marked nullable accept null. |
| Dates | Send consistent ISO date strings, preferably YYYY-MM-DD for date-only controls. The backend parses dates and applies calendar-day bounds. Handle backend date errors even if local validation passes. |
frequency | MONTHLY, BI_MONTHLY, QUARTERLY, WEEKLY, BI_WEEKLY |
durationType | DAYS, WEEKS, MONTHS, YEARS |
bid | LOT, AUCTION, AUCTION_AND_LOT |
| Counts | Send JSON numbers. Use integers for slots, divisions, durations, and completed cycles; some routes currently validate only numeric minima. |
| Optional fields | Omit untouched fields. Do not rely on unknown fields being stored or on a GET object being a valid PATCH body. |
4. Creation step 1: all fields and cross-field validation¶
Every field listed as present in a flow is required unless stated otherwise. Both company and admin flows require branchId; admin also adds companyId.
| Field | New program | Existing-program import |
|---|---|---|
branchId | Required CUID2 | Required CUID2 |
name | String, length ≥ 1 | Same |
chitId | String, length ≥ 1 | Same |
totalAmount | Decimal, declared minimum 0 | Same |
subscriptionAmount | Decimal, declared minimum 0 | Same |
minimumBidAmount | Decimal, declared minimum 0 | Same |
frequency | Supported enum | Same |
totalSlots | Number ≥ 0 | Integer ≥ 0 |
availableSlots | Number ≥ 0 | Not part of this step |
durationValue | Number ≥ 1 | Integer ≥ 1 |
durationType | Supported enum | Same |
divisions | Number ≥ 1 | Integer ≥ 1 |
startDate | Today or later | Today or earlier |
lastDateOfSubmission | Today or later | Not part of this step |
lastAuctionDate | Not part of this step | Today or earlier |
companyId | Admin only, required CUID2 | Admin only, required CUID2 |
Cross-field checks:
branchIdmust identify a program-ready branch in the selected company.- Company employees need program-creation access within the selected branch.
- Both flows:
subscriptionAmount <= totalAmountandminimumBidAmount <= totalAmount. - New:
availableSlots <= totalSlotsandlastDateOfSubmission <= startDate. - Existing:
subscriptionAmount <= minimumBidAmountandstartDate <= lastAuctionDate. - New creation does not impose the existing flow's lower bound on
minimumBidAmountrelative to the subscription. General editing does check that lower bound when either participating money field changes.
Trim user-entered names and identifiers in the UI; the program string validators check length but do not themselves reject whitespace-only values.
5. Creation step 2: all fields and conditional requirements¶
5.1 General and prebid fields¶
| Field | Validation and requirement |
|---|---|
foremanCommission | Required decimal; declared range 0–100. New-program validators explicitly enforce this range. |
delayFineAmount | Required decimal; declared minimum 0. Existing-program step 2 also enforces delayFineAmount <= subscriptionAmount. |
bid | Required enum. |
isAuctionHostedOnDichit | Required boolean for both auction bid types. For LOT, omit or send false; true fails. Never nullable. |
description | Required string, length ≥ 1. |
hasFirstCycleAuction | Required boolean for new company/admin programs and admin existing-program step 2. Not accepted by company existing-program step 2. Must be false for LOT. See section 11 for the admin-import limitation. |
completedCycles | Existing programs only: required integer ≥ 1, no greater than the server-calculated possible cycles from the program's start date and frequency. |
acceptedTermsAndConditions | Company step 2 only: required literal true. Omit for admin. |
hasPrebid | Optional for explicitly external auction programs. Otherwise required boolean; for LOT, send false. Not nullable here. |
prebidDocumentRequired | Optional for explicitly external auction programs. Otherwise required boolean; for LOT, send false. Not nullable here. |
prebidMutabilityPolicy | IMMUTABLE_CANCEL_ONLY or MUTABLE_UNTIL_CLOSE. Optional in new programs. Required in existing-program step 2 unless hosting is explicitly external, including the current existing-LOT contract. Not nullable here. |
prebidDocumentTemplateVersionId | Optional CUID2, not nullable at creation. Must satisfy template ownership/status checks below. |
auctionPresetId | Optional CUID2 or null; must refer to a global preset or a preset owned by the program's company. |
allowedSecurities | Optional array of strings, each 1–50 characters. Codes must exist and be visible to the program's company. Empty array is accepted. Not nullable. |
Prebid and selection dependencies still apply to supplied fields:
LOTrejectshasPrebid: true,hasFirstCycleAuction: true,prebidDocumentRequired: true, a prebid template ID, or a non-null auction preset ID.- A required prebid document or a supplied template ID requires
hasPrebid: truein the creation request. OmittedhasPrebiddoes not imply enabled prebid. - With
hasPrebid: false,autoOpenPrebid: trueandautoRevealPrebids: trueare rejected. - A template version must belong to an active company-owned
PREBIDtemplate for this company and bePUBLISHED. A missing/foreign/wrong-purpose template returns 404; an inactive/unpublished template returns 400. prebidDocumentRequired: truedoes not itself require an explicit template version ID; the system can resolve its default template.- Omitted advanced settings and automation flags are allowed for Dichit-hosted programs too; their effective values come from the configuration layers.
5.2 Automation and advanced-field validation¶
All fields in this table are optional in creation and general PATCH. For external hosting, omit the entire group. “Nullable” in this table applies to creation/general PATCH; settings PATCH has additional nullable fields (section 8).
| Field | Accepted value | Nullable |
|---|---|---|
autoStart | Boolean | Yes |
approvalRequired | Boolean | Yes |
autoOpenPrebid | Boolean; cannot be true with explicitly disabled prebid | Yes |
autoRevealPrebids | Boolean; cannot be true with explicitly disabled prebid | Yes |
autoDeclareWinner | Boolean | Yes |
auctionBidMode | DISCOUNT_INCREASING, TOTAL_VALUE_DECREASING | No |
auctionClosingMode | DURATION_MODE, CALL_MODE | No |
auctionDurationSeconds | Integer ≥ 1 | Yes |
auctionExtensionSeconds | Integer ≥ 0; 0 disables extension | Yes |
auctionFirstCallSeconds | Integer ≥ 0 | Yes |
auctionSecondCallSeconds | Integer ≥ 0 | Yes |
auctionThirdCallSeconds | Integer ≥ 0 | Yes |
subscriberJoinGraceSeconds | Integer ≥ 0 | Yes |
auctionJoiningRule | BEFORE_START, GRACE_PERIOD, ANYTIME | No |
allowStaffOfflineBids | Boolean | Yes |
There is no separate autoExtension request key. Use auctionExtensionSeconds. All timing fields are seconds. Convert them to milliseconds only when constructing client-side timers.
5.3 Minimal external payloads¶
Company new-program step 2:
{
"foremanCommission": "5",
"delayFineAmount": "50",
"bid": "AUCTION",
"isAuctionHostedOnDichit": false,
"hasFirstCycleAuction": false,
"description": "Auction conducted outside Dichit",
"acceptedTermsAndConditions": true
}
Company existing-program step 2:
{
"foremanCommission": "5",
"delayFineAmount": "50",
"bid": "AUCTION_AND_LOT",
"isAuctionHostedOnDichit": false,
"completedCycles": 1,
"description": "Existing program with externally conducted auctions",
"acceptedTermsAndConditions": true
}
For admin new creation, remove acceptedTermsAndConditions. For admin existing creation, remove it and add hasFirstCycleAuction: false.
For Dichit-hosted creation, send isAuctionHostedOnDichit: true, hasPrebid, and prebidDocumentRequired; existing creation also requires prebidMutabilityPolicy. Add the optional advanced/automation fields only when the user chooses explicit overrides.
For new LOT creation, use bid: "LOT", hasFirstCycleAuction: false, hasPrebid: false, and prebidDocumentRequired: false; omit hosting or send false. Existing LOT creation additionally requires its policy enum and completedCycles under the current contract.
6. Existing-program creation steps 3–5¶
These import historical participation, payments, and winners. They remain required by the existing workflow regardless of auction hosting. Company and admin routes use the same body validators. Each requires the target program to be non-deleted, preStarted, INCOMPLETE, and UNDER_REVIEW, with company ownership checked on company routes.
| Step | Body | Validation |
|---|---|---|
| 3: Subscribers | { subscribers: [{ name, mobileNumber, countryCode?, email? }] } | Required array, maximum 250 entries; no array minimum in this validator. |
| 4: Payments | { cycles: [{ cycleId, subscribers: [{ subscriberId, enrolledSubscriberId, isPaid }] }] } | Required arrays; IDs are CUID2; isPaid is a required boolean. No array minimum/maximum here. |
| 5: Winners | { cycles: [{ cycleId, winners: [{ division, amount, subscriberId, enrolledSubscriberId }] }] } | Required arrays; CUID2 IDs; division is an integer ≥ 1; amount is a decimal with declared minimum 0. No array minimum/maximum here. |
Subscriber fields:
name: required; trimmed, Unicode-normalized, 1–100 characters; at least one letter; letters, combining marks, spaces, hyphens/dashes, apostrophes and periods allowed; no digits, repeated spaces, or repeated basic punctuation.mobileNumber: required string; normalized; resulting value must be+followed by 10–15 digits. Prefer sending normalized international numbers.countryCode: optional uppercase ISO alpha-2 enum; defaults toIN.email: optional valid email ornull; defaults tonull.
Repeated mobile numbers are handled by the import flow to support multiple enrollments; do not assume every repeated mobile is rejected. Step 3 creates the historical cycles based on the stored completed-cycle count. Use IDs returned by the existing-program detail endpoints for subsequent requests; client-provided ID syntax alone is not proof of membership. Do not infer winner count, division uniqueness, or amount ceilings from the array validators.
GET .../existing/:programId/steps/4 and /steps/5 provide the selection data. Their query contract supports pagination (default true), pageNumber (integer ≥ 1, default 1), and pageSize (integer 1–100, default 10). Step 5 finishes the import: company programs become APPLIED, admin programs become DRAFTED.
7. General program editing: complete PATCH validation¶
Load the basic form with GET /v2/companies/me/programs/:programId or GET /v2/admin/programs/:programId, and load the matching settings GET for hosting and resolved auction configuration. Wait for both before initializing hosting-dependent controls; a loading or missing value is not an external hosting selection. Keep the last fetched state separate from the editable form so PATCH contains only intentional changes.
Use the general PATCH endpoints for bid type, basic information, dates, financial fields, first-cycle eligibility, and preset assignment. All fields are optional; at least one recognized field must remain after validation. Omitted fields retain their stored values, subject to the explicit LOT and prebid-off normalization below.
7.1 Field rules¶
| Field | Company PATCH | Admin PATCH |
|---|---|---|
name | String, length ≥ 1 | String, 1–255 characters |
chitId | String, no minimum length | String, 1–100 characters |
description | String, length ≥ 1 | String, 1–2000 characters |
totalAmount, subscriptionAmount, minimumBidAmount, delayFineAmount | Decimal, declared minimum 0 | Same |
foremanCommission | Decimal, declared 0–100 | Same |
durationValue, divisions | Number ≥ 1 | Same |
durationType, frequency, bid | Respective enum | Same |
totalSlots, availableSlots | Number ≥ 1 | Number ≥ 0 |
completedCycles | Number ≥ 1 | Number ≥ 0 |
startDate | Valid date; business constraints below | Same |
lastDateOfSubmission | Today or later | Same |
lastAuctionDate | Today or earlier | Same |
images | Array of nonempty strings | Not accepted by this admin validator |
hasFirstCycleAuction, hasPrebid, prebidDocumentRequired, isAuctionHostedOnDichit | Boolean, not nullable | Same |
prebidMutabilityPolicy | Policy enum, not nullable | Same |
prebidDocumentTemplateVersionId, auctionPresetId | CUID2 or null | Same |
allowedSecurities | Array of 1–50-character strings; visible existing security codes | Same |
| Automation and advanced fields | Section 5.2 | Section 5.2 |
7.2 Cross-field and state restrictions¶
- Company generic PATCH rejects an
APPROVEDprogram. Admin generic PATCH does not have that approval-status restriction. Use settings PATCH for permitted ongoing auction-setting/hosting changes. - Company ownership and non-deleted existence are checked before mutation; another company's program is treated as not found.
- Validate changes against the merged stored state plus the PATCH, not only pairs of fields present in the request.
- When relevant financial fields change:
subscriptionAmount <= totalAmount,subscriptionAmount <= minimumBidAmount <= totalAmount, anddelayFineAmount <= subscriptionAmount. - Changed
startDate: existing (preStarted) programs cannot use a future date; non-prestarted programs cannot use a past date. - For non-prestarted programs, changed slots must maintain
availableSlots <= totalSlots; changed submission/start dates must maintainlastDateOfSubmission <= startDate. Admin also checks the slot relationship when both slot fields are supplied. See section 11 for zero-value caveats. - Existing-program start/last-auction date editing has a pre-existing reversed comparison; see section 11 rather than copying the creation rule blindly.
- Supplied template/preset/security IDs follow the ownership and existence rules in section 5. General PATCH checks supplied prebid-only triggers against the patched
hasPrebidor, when omitted, the stored program value. - If effective prebid is disabled, generic PATCH clears the required-document flag and template pin. To merely choose external hosting, omit
hasPrebidand the other dormant settings; do not sendhasPrebid: falseas a side effect.
7.3 Hosting/bid transitions¶
| Transition | Required payload / effect |
|---|---|
| Existing auction program, unchanged hosting | Omit hosting and all unchanged settings. |
| Dichit → external | Send { "isAuctionHostedOnDichit": false }; omit Dichit settings to preserve them. Active-auction blocking still applies. |
| External → Dichit | Send { "isAuctionHostedOnDichit": true }. Existing/default settings are reused; PATCH does not require resending creation fields. Review them in the UI before enabling. |
LOT → AUCTION or AUCTION_AND_LOT | Send bid and an explicit hosting boolean. No prebid/advanced details are required for the external choice. |
Auction → LOT | Send { "bid": "LOT" }. Backend sets hosting, first-cycle auction, prebid and required document to false; clears template and preset. Do not send hosting true. |
AUCTION ↔ AUCTION_AND_LOT | Hosting remains unchanged when omitted. |
Changing to LOT has different cleanup semantics from keeping an auction-based bid type and switching its hosting to external.
Example general edit that needs no auction sections:
8. Program settings GET/PATCH¶
Use settings GET as the authoritative source for the current hosting boolean. It is returned at data.isAuctionHostedOnDichit, not inside settings or triggerPolicy. Do not assume the general program GET serializer exposes it.
Settings GET and successful settings PATCH return:
programId,programName,isAuctionHostedOnDichit.presetId(or null),prebidDocumentRequired,prebidDocument(or null).settings: effective prebid and advanced auction configuration.triggerPolicy: effective values for the five automation flags.allowedSecurities: string array.provenance: supplying layer for the effective configuration fields.
These settings are still returned when hosting is external; they are dormant, not evidence that a Dichit auction is active. Hosting itself is an explicit program choice, not an inherited/provenance field.
Settings PATCH is flat, not { settings: {...} }. All recognized fields are optional; at least one is required. It accepts the section 5.2 fields plus hasPrebid, prebidMutabilityPolicy, allowedSecurities, prebidDocumentRequired, prebidDocumentTemplateVersionId, and isAuctionHostedOnDichit. It does not accept bid, hasFirstCycleAuction, basic program fields, or auctionPresetId; use general PATCH for those.
Differences from creation/general PATCH:
| Fields | Settings PATCH semantics |
|---|---|
hasPrebid, prebidMutabilityPolicy, auctionBidMode, auctionClosingMode, auctionJoiningRule | Nullable in addition to their normal types; null removes the program override. |
Numeric advanced settings, allowStaffOfflineBids, automation flags | Nullable; null removes the program override. Numeric bounds still apply when set. |
isAuctionHostedOnDichit, prebidDocumentRequired | Optional non-nullable booleans. |
prebidDocumentTemplateVersionId | Optional CUID2 or null; null removes the pin so default-template resolution can apply. |
allowedSecurities | Optional array, not nullable; use an empty array to remove the explicit whitelist. |
Settings PATCH validates same-patch contradictions: hasPrebid: false with autoOpenPrebid: true or autoRevealPrebids: true fails. It does not impose creation's requirement to send prebid/document fields, and does not require a new hosting choice when the flag is unchanged. It rejects hosting true for a stored LOT program; bid changes belong to general PATCH.
Minimal hosting edit, usable on either company's or admin's settings endpoint:
Do not serialize resolved GET settings back wholesale: doing so pins inherited values as program overrides. Send only intentional changes. On external hosting, omit the hidden groups even if they remain populated in form memory.
For layer precedence, presets, provenance, and complete settings response details, see Auction settings and policy.
9. Hosting changes and existing cycles¶
Disabling hosting is rejected with HTTP 400 while a Dichit auction is in any of these states: PENDING, SCHEDULED, READY, LIVE, PAUSED. ENDED, COMPLETE, and CANCELLED are terminal for this check and do not block it.
A hosting change can assign the nearest eligible unassigned cycle, preferring ACTIVE over UPCOMING. Ended cycles, cycles with a declared winner, and first-cycle-ineligible cycles are not candidates. An eligible cycle is assigned DICHIT with one auction or EXTERNAL without a Dichit auction. Assigned cycles are immutable: changing the program does not convert an already-external cycle to Dichit or rewrite existing Dichit history.
The client must not create a second auction to compensate for a hosting change, assume every cycle changed host, or treat program hosting as a historical per-cycle value. Refresh settings, cycle details, and auction queries after a successful change. The internal auctionHost field is not a new guaranteed public cycle-response field.
10. Errors and frontend acceptance checklist¶
Handle errors through the existing API envelope; show field validation details when available and a form-level message for lifecycle/ownership/state errors.
| HTTP status | Relevant cases | UI response |
|---|---|---|
| 400 | Missing creation fields, missing auction hosting choice, invalid values, contradictory prebid flags, active auction blocks disabling, approved company general edit | Retain form state; show validation/server message; do not mark saved. |
| 401 / 403 | Authentication or role failure | Follow the application's existing authentication/access handling. |
| 404 | Missing/deleted/out-of-company program, inaccessible preset/template, creation program not in the required state | Stop mutation; refresh/navigate as appropriate without assuming the record belongs to this company. |
Suggested copy for blocked disabling: “This program has an active Dichit auction. Finish or cancel it before switching to external hosting.” Do not automatically cancel auctions as part of a form save.
Frontend checks:
- New and existing creation work for both auction bid types with external hosting and no prebid/automation/advanced fields.
- The hosting question cannot be left unanswered for auction-based creation; explicit external (
false) is accepted. - Switching to Dichit displays the sections and enforces creation's required prebid fields without making optional overrides mandatory.
- External edit submits only changed general fields/hosting. Hidden values do not become null or false; re-enabling restores saved settings.
LOTcreation andLOTtransitions follow their own rules rather than the external-auction rules.- Company/admin and new/existing differences above are reflected in the form.
- Failed saves do not leave optimistic hosting state committed. Refetch on successful save; a timeout must not trigger ad hoc auction creation.
- Client-side numeric/date validation and backend errors are both handled.
11. Existing validation caveats (not changed by hosting support)¶
These are observed implementation differences, not new product requirements:
- The shared
decimalSchemahelper currently calls.refine()without keeping the returned schemas. Its declared min/max bounds are therefore not reliably enforced by that helper. New-program step 2 explicitly checks commission 0–100; cross-field money comparisons are separately enforced as described above. Enforce nonnegative amounts and commission 0–100 in the UI, but do not interpret acceptance of an out-of-range value as supported behavior. - Existing-program creation enforces
startDate <= lastAuctionDate, but the general-edit helper currently rejectsstartDate < lastAuctionDatewhen one of those dates changes. This is an existing backend inconsistency. Surface the server error; do not silently reverse user dates to satisfy it. - Admin existing-program step 2 requires
hasFirstCycleAuction, but the shared existing-program step-2 writer does not persist that field. Keep sending the required boolean for that route; do not present it as a newly supported historical first-cycle override. - New-program creation and generic PATCH use
number().min(...)rather than integer validation for several count fields. Some stored-state slot checks also use truthiness, so zero-value admin edits are not uniformly checked. The UI should use integer counts and always enforce available ≤ total. - The route date schemas capture their today-bound when initialized. Around day changes or differing client/server time zones, server validation can differ from the browser's local today. Preserve and show backend errors.
This change intentionally does not alter these unrelated validation behaviors. The field tables describe the expected form constraints; the caveats distinguish them from enforcement gaps in the current backend.
12. Implementation reference¶
The behavior is covered by the creation-hosting validator matrix, company/admin creation and edit API tests, creation command tests, and program-settings API tests. Relevant source files (repository-relative paths):
src/interfaces/http/routes/v2/companies/programs/new/create-new-validators.tssrc/interfaces/http/routes/v2/companies/programs/existing/create-existing-validator.tssrc/interfaces/http/routes/v2/admin/programs/new/create-new-validators.tssrc/interfaces/http/routes/v2/admin/programs/existing/create-existing-validators.tssrc/interfaces/http/routes/v2/companies/me/programs/[programId]/program-id-validators.tssrc/interfaces/http/routes/v2/admin/programs/[programId]/program-id-validators.tssrc/interfaces/http/routes/common/program-auction-settings/program-auction-settings-validators.tssrc/application/use-cases/programs/v2/commands/update-program/update-program-by-company-command-helper.ts
No new database migration is required for making the Dichit-only creation fields optional on external hosting. Deploy this contract before the frontend begins omitting those formerly required fields.