Skip to main content

PostgreSQL Schema

PostgreSQL is the write database for all invoice data. Connection via pgx/v5 with pool, port 5433, 5-second query timeout.

Entity Relationship

Tables

invoices

Primary invoice records with status, amounts, and metadata.

ColumnTypeConstraintsDescription
idUUIDPK, DEFAULT gen_random_uuid()Primary key
invoice_numberSERIALAuto-increment number
display_numberVARCHAR(50)NOT NULLDisplay format (e.g., INV-1)
application_keyVARCHAR(20)NOT NULLClient application key
customer_keyVARCHAR(20)NOT NULLCustomer key
period_startDATENOT NULLBilling period start
period_endDATENOT NULLBilling period end
invoice_dateDATENOT NULL, DEFAULT CURRENT_DATEInvoice issue date
deal_typeVARCHAR(5)NOT NULL, CHECK (SUP/HR/FP)Deal type
currencyVARCHAR(5)NOT NULL, DEFAULT 'UZS'Currency code
base_amountDECIMAL(15,2)NOT NULLBase contract amount
overtime_hoursDECIMAL(8,2)DEFAULT 0Hours beyond limit
overtime_amountDECIMAL(15,2)DEFAULT 0Overtime charge
total_amountDECIMAL(15,2)NOT NULLFinal invoice total
total_hoursDECIMAL(8,2)DEFAULT 0Total billable hours
is_overtimeBOOLEANDEFAULT FALSEHas overtime flag
monthly_limit_hoursDECIMAL(8,2)Monthly hour limit from rate rules (stored at generation)
statusVARCHAR(20)NOT NULL, DEFAULT 'draft'Current status
approved_atTIMESTAMPTZApproval timestamp
approved_byVARCHAR(100)Approver identity
declined_atTIMESTAMPTZDecline timestamp
declined_byVARCHAR(100)Decliner identity
decline_reasonTEXTReason for declining
rejected_atTIMESTAMPTZRejection timestamp
rejected_byVARCHAR(100)Rejector identity
reject_reasonTEXTReason for rejecting
sent_atTIMESTAMPTZSent to client timestamp
paid_atTIMESTAMPTZPayment received timestamp
r2_storage_keyVARCHAR(500)Cloudflare R2 object key
r2_public_urlVARCHAR(500)Public PDF URL
planfact_shipment_idVARCHAR(100)PlanFact shipment ID
planfact_deal_idVARCHAR(100)PlanFact deal ID
didox_document_idVARCHAR(100)Didox document ID
didox_statusVARCHAR(50)Didox status
pdf_storage_pathVARCHAR(500)PDF file path
html_template_hashVARCHAR(64)SHA-256 of rendered HTML
pdf_dataBYTEAPDF binary data
show_task_listBOOLEANNOT NULL, DEFAULT TRUEShow individual task rows vs summary
show_tracked_timeBOOLEANNOT NULL, DEFAULT TRUEShow time column in table
show_task_pricingBOOLEANNOT NULL, DEFAULT FALSEShow price column per line item
show_overtimeBOOLEANNOT NULL, DEFAULT TRUEShow overtime row
legal_textTEXTPer-invoice legal text (overrides template default)
versionINTNOT NULL, DEFAULT 1Invoice version
created_atTIMESTAMPTZNOT NULL, DEFAULT NOW()Created timestamp
updated_atTIMESTAMPTZNOT NULL, DEFAULT NOW()Last update timestamp
created_byVARCHAR(100)Creator identity

Indexes:

  • idx_invoices_status — Filter by status
  • idx_invoices_application — Filter by application
  • idx_invoices_period — Filter by date range
  • idx_invoices_customer — Filter by customer

Unique constraint: (application_key, period_start, version)

Status check: status IN ('draft', 'needs_review', 'approved', 'declined', 'sent', 'accepted', 'rejected', 'paid')


invoice_line_items

Individual billable items on an invoice.

ColumnTypeConstraintsDescription
idUUIDPKPrimary key
invoice_idUUIDFK → invoices(id) ON DELETE CASCADEParent invoice
line_typeVARCHAR(20)NOT NULL, CHECKItem category
descriptionTEXTNOT NULLDisplay description
jira_keyVARCHAR(20)Jira issue key
jira_descTEXTJira issue description
time_secondsINTDEFAULT 0Raw time logged
billable_secondsINTDEFAULT 0After min billable rounding
unit_priceDECIMAL(15,2)Price per unit
quantityDECIMAL(8,2)DEFAULT 1Quantity (hours)
line_totalDECIMAL(15,2)Line item total
rate_tierVARCHAR(30)DEFAULT 'standard'Rate tier applied
rate_multiplierDECIMAL(5,2)DEFAULT 1.0Rate multiplier
sourceVARCHAR(10)NOT NULL, DEFAULT 'auto'auto or manual
is_auto_generatedBOOLEANNOT NULL, DEFAULT TRUEAuto-generated flag
original_descriptionTEXTPre-edit description
original_time_secondsINTPre-edit time
original_line_totalDECIMAL(15,2)Pre-edit total
linked_issue_keyVARCHAR(20)Linked issue key (e.g. SUP-* from Jira "duplicates" relation)
contributorsJSONBPer-person worklog breakdown
sort_orderINTNOT NULL, DEFAULT 0Display order
created_atTIMESTAMPTZNOT NULL, DEFAULT NOW()Created timestamp

Line types: support, monitoring, meeting, incident, task, overtime, incident_critical, off_hours, critical_off_hours


invoice_events

Audit log for all invoice lifecycle events.

ColumnTypeDescription
idUUIDPrimary key
invoice_idUUIDFK → invoices(id)
event_typeVARCHAR(30)Event type
from_statusVARCHAR(20)Previous status
to_statusVARCHAR(20)New status
actorVARCHAR(100)Who performed the action
metadataJSONBAdditional event data
created_atTIMESTAMPTZEvent timestamp

Event types: created, status_changed, regenerated, line_items_updated, invoice_updated, planfact_synced, planfact_sync_failed


invoice_edit_history

Tracks all user edits with before/after values.

ColumnTypeDescription
idUUIDPrimary key
invoice_idUUIDFK → invoices(id) ON DELETE CASCADE
line_item_idUUIDFK → invoice_line_items(id) ON DELETE SET NULL
edit_typeVARCHAR(20)Type of edit
field_nameVARCHAR(50)Which field was changed
old_valueTEXTValue before edit
new_valueTEXTValue after edit
edited_byVARCHAR(100)Who made the edit
edited_atTIMESTAMPTZEdit timestamp

Edit types: line_modified, line_added, line_removed, total_override, deal_amount_override


contract_rate_rules

Per-application billing rates and SLA multipliers.

ColumnTypeDefaultDescription
idUUIDPrimary key
application_keyVARCHAR(50)Application identifier
base_hourly_rateDECIMAL(15,2)Rate per hour
monthly_limit_hoursDECIMAL(10,2)SUP monthly limit
sla_tierVARCHAR(20)'standard'SLA tier name
coverage_typeVARCHAR(20)'business_hours'Coverage type
overtime_multiplierDECIMAL(5,2)1.0Overtime rate multiplier
p1_p3_multiplierDECIMAL(5,2)1.0Critical incident multiplier
off_hours_multiplierDECIMAL(5,2)1.0Off-hours multiplier
p1_p3_off_hours_multiplierDECIMAL(5,2)1.5Critical + off-hours
business_hours_startTIME09:00Business hours start
business_hours_endTIME18:00Business hours end
business_hours_tzVARCHAR(50)Asia/TashkentTimezone
weekend_daysINTEGER[]7Weekend day numbers
effective_fromDATECURRENT_DATERule start date
effective_toDATERule end date (null = current)

Unique constraint: (application_key, effective_from)


app_settings

Key-value configuration store with JSONB values.

ColumnTypeDescription
keyVARCHAR(100)PK — Setting name
valueJSONBSetting value
updated_atTIMESTAMPTZLast update
updated_byVARCHAR(100)Who updated

Seed keys: company, bank, planfact, didox, invoice_defaults, telegram, r2, calculator


client_invoice_config

Per-client invoice defaults, legal text template, and invoice numbering counter.

ColumnTypeConstraintsDescription
application_keyVARCHAR(20)PKClient application key
default_show_task_listBOOLEANNOT NULL, DEFAULT TRUEDefault: show task rows
default_show_tracked_timeBOOLEANNOT NULL, DEFAULT TRUEDefault: show time column
default_show_task_pricingBOOLEANNOT NULL, DEFAULT FALSEDefault: show pricing column
default_show_overtimeBOOLEANNOT NULL, DEFAULT TRUEDefault: show overtime row
default_legal_textTEXTLegal text template for this client
last_invoice_numberINTAtomic counter for per-client numbering
created_atTIMESTAMPTZNOT NULL, DEFAULT NOW()Created timestamp
updated_atTIMESTAMPTZNOT NULL, DEFAULT NOW()Last update timestamp

When an invoice is generated, the display toggle defaults and legal text are copied from this table. The last_invoice_number is atomically incremented using SELECT ... FOR UPDATE within the generation transaction to prevent concurrent collisions.


project_classifications

Classifies projects as billable, internal, or overhead.

ColumnTypeDescription
idUUIDPrimary key
project_labelVARCHAR(100)UNIQUE — Project label
classificationVARCHAR(20)billable / internal / overhead / excluded
notesVARCHAR(500)Optional notes

employee_exclusions

Employees excluded from billing.

ColumnTypeDescription
idUUIDPrimary key
account_idVARCHAR(100)UNIQUE — Jira account ID
exclusion_typeVARCHAR(20)overhead_only / excluded
reasonVARCHAR(500)Reason for exclusion

calculator_snapshots

Saved pricing calculator results.

ColumnTypeDescription
idUUIDPrimary key
application_keyVARCHAR(20)Application
snapshot_typeVARCHAR(20)client_margin / quote / what_if
input_paramsJSONBCalculator inputs
resultsJSONBCalculated results
created_byVARCHAR(100)Creator
created_atTIMESTAMPTZTimestamp