Catalyst / admin/Apex 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / Apex

public

Bid Management and Orchestration Tool with AI Capability

Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
Apex / Synapse-Apexv2 / backend / app / schemas / __init__.py 8016 B · main
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
from datetime import date, datetime
from decimal import Decimal

from pydantic import BaseModel, ConfigDict

# Email is a plain string: internal deployments commonly use special-use domains
# (e.g. .local) that RFC-strict validators reject, which would lock out the
# seeded administrator. Format is validated lightly at the UI layer.
EmailStr = str


class ORM(BaseModel):
    model_config = ConfigDict(from_attributes=True)


# --- auth ---
class LoginIn(BaseModel):
    email: EmailStr
    password: str
    otp: str | None = None


class TokenOut(BaseModel):
    access_token: str
    mfa_required: bool = False
    must_change_password: bool = False


class ChangePasswordIn(BaseModel):
    current_password: str
    new_password: str


class MfaEnrollOut(BaseModel):
    secret: str
    otpauth_uri: str
    qr_svg: str
    recovery_codes: list[str]


class MfaVerifyIn(BaseModel):
    otp: str


# --- users ---
class UserBase(BaseModel):
    email: EmailStr
    name: str
    roles: list[str] = []


class UserCreate(UserBase):
    password: str


class UserUpdate(BaseModel):
    name: str | None = None
    roles: list[str] | None = None
    is_active: bool | None = None
    password: str | None = None


class UserOut(ORM):
    id: int
    email: EmailStr
    name: str
    roles: list[str]
    mfa_enrolled: bool
    is_active: bool
    must_change_password: bool


# --- frameworks ---
class FrameworkIn(BaseModel):
    name: str
    description: str = ""
    controls: list = []
    active: bool = True


class FrameworkOut(ORM):
    id: int
    name: str
    description: str
    controls: list
    active: bool


# --- resource catalogue ---
class ResourceTypeIn(BaseModel):
    name: str
    role_family: str = ""
    skills: list[str] = []
    hourly_cost_rate: Decimal = Decimal("0")
    hourly_sell_rate: Decimal = Decimal("0")
    daily_cost_rate: Decimal = Decimal("0")
    daily_sell_rate: Decimal = Decimal("0")
    currency: str = "GBP"
    active: bool = True


class ResourceTypeOut(ORM):
    id: int
    name: str
    role_family: str
    skills: list
    hourly_cost_rate: Decimal
    hourly_sell_rate: Decimal
    daily_cost_rate: Decimal
    daily_sell_rate: Decimal
    currency: str
    active: bool


class LicenceIn(BaseModel):
    name: str
    vendor: str = ""
    unit: str = "per_endpoint"
    unit_cost: Decimal = Decimal("0")
    billing: str = "monthly"
    active: bool = True


class LicenceOut(ORM):
    id: int
    name: str
    vendor: str
    unit: str
    unit_cost: Decimal
    billing: str
    active: bool


class EffortRuleIn(BaseModel):
    name: str
    trigger: str
    endpoint_type: str | None = None
    per_qty: Decimal = Decimal("1")
    resource_type_id: int | None = None
    hours_recurring: Decimal = Decimal("0")
    hours_oneoff: Decimal = Decimal("0")
    active: bool = True


class EffortRuleOut(ORM):
    id: int
    name: str
    trigger: str
    endpoint_type: str | None
    per_qty: Decimal
    resource_type_id: int | None
    hours_recurring: Decimal
    hours_oneoff: Decimal
    active: bool


# --- capabilities ---
class CapabilityResponseOut(ORM):
    id: int
    framework_id: int | None
    response_text: str
    approved: bool
    model: str


class CapabilityOut(ORM):
    id: int
    name: str
    category: str
    description: str
    evidence: list
    status: str
    responses: list[CapabilityResponseOut] = []


class CapabilityUpdate(BaseModel):
    name: str | None = None
    category: str | None = None
    description: str | None = None
    status: str | None = None


# --- bids ---
class BidIn(BaseModel):
    ref: str | None = None
    title: str
    client: str = ""
    start_date: date
    submission_date: date
    frameworks: list[int] = []
    win_themes: str = ""
    opportunity_value: Decimal = Decimal("0")
    contract_duration_months: int = 12
    web_link: str = ""
    assistant_enabled: bool = False


class BidOut(ORM):
    id: int
    ref: str
    title: str
    client: str
    start_date: date
    submission_date: date
    state: str
    frameworks: list
    win_themes: str
    opportunity_value: Decimal
    contract_duration_months: int
    web_link: str
    assistant_enabled: bool
    version: int
    created_at: datetime


class RequirementIn(BaseModel):
    ref: str = ""
    type: str = "question"
    question_text: str = ""
    limits: str = ""
    weighting: str = ""
    word_limit: int | None = None
    mandatory: bool = False
    source: str = ""


class RequirementOut(ORM):
    id: int
    bid_id: int
    ref: str
    type: str
    question_text: str
    limits: str
    weighting: str
    word_limit: int | None
    mandatory: bool
    source: str
    status: str


class ResponseOut(ORM):
    id: int
    requirement_id: int
    draft_text: str
    final_text: str
    status: str
    capabilities_used: list
    gaps: str
    model_meta: dict


class ResponseUpdate(BaseModel):
    final_text: str | None = None
    status: str | None = None


class PlanTaskOut(ORM):
    id: int
    name: str
    kind: str
    requirement_id: int | None
    owner_user_id: int | None
    planned_hours: Decimal
    actual_hours: Decimal
    start: date | None
    due: date | None
    status: str


class PlanTaskUpdate(BaseModel):
    owner_user_id: int | None = None
    planned_hours: Decimal | None = None
    actual_hours: Decimal | None = None
    due: date | None = None
    status: str | None = None


# --- cost / pricing ---
class CostInputs(BaseModel):
    endpoints: dict = {}
    term_months: int = 12
    scope: dict = {}
    non_people: list = []


class NonPeopleCostIn(BaseModel):
    description: str
    monthly: Decimal = Decimal("0")
    oneoff: Decimal = Decimal("0")


class CostLineOut(ORM):
    id: int
    group: str
    description: str
    resource_type_id: int | None
    qty: Decimal
    hours: Decimal
    rate_snapshot: Decimal
    monthly: Decimal
    oneoff: Decimal
    overridden: bool


class CostLineUpdate(BaseModel):
    description: str | None = None
    qty: Decimal | None = None
    hours: Decimal | None = None
    rate_snapshot: Decimal | None = None
    monthly: Decimal | None = None
    oneoff: Decimal | None = None


class PricingIn(BaseModel):
    name: str = "Base case"
    risk_pct: Decimal = Decimal("0")
    mgmt_pct: Decimal = Decimal("0")
    margin_pct: Decimal = Decimal("0")


class PricingOut(ORM):
    id: int
    name: str
    risk_pct: Decimal
    mgmt_pct: Decimal
    margin_pct: Decimal
    computed: dict
    justification_text: str
    selected: bool


class StateChangeIn(BaseModel):
    state: str


# --- assistant ---
class AssistantSuggestionOut(ORM):
    id: int
    bid_id: int
    response_id: int | None
    kind: str
    target_ref: str
    advice: list
    proposed_text: str
    guardrail: dict
    status: str
    model: str
    created_at: datetime


# --- Answer Library ---
class AnswerEntryOut(ORM):
    id: int
    question: str
    answer: str
    summary: str
    category: str
    tags: list
    frameworks: list
    source_type: str
    source_bid_id: int | None
    source_response_id: int | None
    client: str
    outcome: str
    status: str
    is_master: bool
    quality_score: int | None
    reuse_count: int
    word_count: int
    created_at: datetime
    updated_at: datetime


class AnswerEntryIn(BaseModel):
    question: str
    answer: str
    summary: str = ""
    category: str = ""
    tags: list[str] = []
    frameworks: list[int] = []


class AnswerEntryUpdate(BaseModel):
    question: str | None = None
    answer: str | None = None
    summary: str | None = None
    category: str | None = None
    tags: list[str] | None = None
    frameworks: list[int] | None = None
    status: str | None = None
    quality_score: int | None = None


class ReuseIn(BaseModel):
    bid_id: int | None = None
    response_id: int | None = None
    action: str = "inserted"  # inserted|adapted|copied


class AnswerSearchOut(BaseModel):
    total: int
    items: list[AnswerEntryOut]