Certificates and compliance
concorbit issues formal trade compliance certificates directly from a job: Gas Safe CP12 landlord records, EICR electrical condition reports, PAT tests, legionella risk assessments, and several more. Each certificate produces a PDF stamped with the tenant's branding, the engineer's registration number, and a unique certificate number. The full history lives on a tenant-level compliance dashboard with expiry filtering.
Supported certificate types
Every certificate type ships with a dedicated, trade-specific PDF layout:
Gas Safe CP12 (Landlord): annual gas-safety record under the Gas Safety (Installation and Use) Regulations 1998. Payload captures the appliance list with CO readings, flue + ventilation test results, and warning-notice state.
CP1 (Commercial Gas Report): commercial variant of CP12 with heat-input (kW), commercial-use classification, and duty-holder fields.
EICR: Electrical Installation Condition Report (BS 7671). Installation type + earthing arrangement, a full circuit schedule with colour-coded observation codes (C1 / C2 / C3 / FI), summary recommendations.
Minor Electrical Works Certificate: single-circuit additions / alterations per BS 7671:2018+A2:2022. Work description + reason + circuit detail + formal declaration.
PAT Test Certificate: appliance schedule with asset ID, class, insulation resistance, earth continuity, pass/fail summary strip at the top.
Fire Extinguisher Service Record (BS 5306-3): extinguisher schedule with type badges (water / foam / CO2 / dry powder / wet chemical), pressure + pin-seal + hose checks, service-type tracking (annual / extended / discharge).
Legionella Risk Assessment (ACOP L8 / HSG274): overall risk-rating banner, asset register with stagnation + scale risk per location, action plan.
Emergency Light Test Certificate (BS 5266-1): 3-hour discharge test record, fitting schedule with mains / charge / discharge / pictogram checks, pass/fail summary.
Engineer registration numbers
Four registration-body fields live on each user and are encrypted at rest:
gas_safe_reg: Gas Safe Register ID (appears on CP12 / CP1 certificates)niceic_reg: NICEIC certificate number (appears on EICR / Minor Works)napit_reg: NAPIT registration (fallback for electrical certs)fgas_reg: F-Gas registration (for refrigerant handling)
Set these under Jobs > Settings > Technicians. Each technician card has four inline fields; blur to save. The correct registration number is auto-stamped onto the certificate based on its type.
Issuing a certificate
From any job's detail page, click + Issue certificate in the Certificates card. Pick the type, optionally set the customer signer name, and click Issue certificate. Behind the scenes:
A unique cert number is allocated under an advisory lock so concurrent issues don't collide (format:
CP12-0001,EICR-0001, etc.)The certificate row is created with the engineer's details copied from the job assignee
The type-specific Blade template renders the payload to HTML, WeasyPrint produces the PDF, the PDF is stored on the default Storage disk
The certificate appears in the card with a Download link
Template-specific fields (appliance list, circuit schedule) can be edited post-issue via the cert's payload; changes trigger a regeneration.
Compliance dashboard
/jobs/compliance shows every certificate issued by the tenant with:
Summary strip: total issued / expired / expiring in 30 days / expiring in 90 days
Filters: certificate type, engineer, expiry window (expired / 30d / 60d / 90d), free-text search on cert number or engineer name
Per-row download link
Expired certificates carry an Expired badge; within-30-days is Expiring; beyond that they're Valid. Expired certificates also render a large "EXPIRED" watermark on the PDF itself.
Expiry rules by type
| Type | Validity |
|---|---|
| CP12 (Landlord Gas Safety) | 12 months |
| CP1 (Commercial Gas Report) | 12 months |
| EICR | 60 months (domestic rental default; shorten in the payload if the installation type requires) |
| Minor Electrical Works | No expiry |
| PAT Test | 12 months |
| Fire Extinguisher Service | 12 months |
| Legionella Risk Assessment | 24 months |
| Emergency Light Test | 12 months |
The dashboard's summary counts are tenant-wide. Filter changes don't move them, so you always see the full picture.
Permissions
jobs.certificates.view: read the cert row, download the PDF, see the compliance dashboardjobs.certificates.issue: issue new certs, regenerate existing PDFsjobs.certificates.delete: remove a cert + its PDF
Field engineers typically need issue + view; office staff typically need view only; a senior dispatcher might carry delete for corrections.
Customer portal
Customers logged into the portal see a Certificates page listing every cert issued against a job linked to them or their company. Each row shows the cert type, number, issue + expiry date, status badge (Valid / Expiring soon / Expired) and a direct Download link. Cross-tenant / cross-customer access is blocked at the query level; customers only ever see certs for their own jobs.
Expiry reminders
A daily scheduled command (concorbit:check-certificate-expiry, runs 07:30) finds every cert where expires_at falls in exactly 30 days and queues a reminder email via the tenant's configured SMTP provider. The email uses the certificate.expiring system template, which tenants can customise under Email > Templates. Merge fields include cert_type_label, cert_number, expires_at_date, days_until_expiry, engineer_name, and portal_url (for a direct link into the customer portal).
A cert without a contact email on its job is silently skipped. onOneServer() in the scheduler prevents duplicate sends from a multi-worker fleet.
Renewal queue
Expiring certs don't auto-create a follow-up job; dispatchers decide when and who. The compliance dashboard's Renewal queue surfaces every cert that's either already expired or expiring within the next 60 days, with no renewal yet scheduled and no dismissal recorded.
Each queue row has two actions:
Schedule renewal: opens a wizard pre-filled with:
Job title:
Renewal: {cert type} — {customer}Suggested date: 2 weeks before expiry, or today + 3 days if already overdue
Customer + site address (copied from the original job, cannot be edited here; the job is created against the same customer)
Last engineer as preferred assignee
Priority: high if overdue, medium otherwise
Job type + required skills picker
Internal notes: auto-seeded with a reference to the source cert
Submitting creates a new Job via the standard
JobService::createflow, so all the usual activity logging, skill-match warnings, and auto-form-attachment fires. The resulting job's ID is stamped onrenewal_job_idso the cert drops out of the queue. A "Scheduled ↗" link appears in the Renewal column of the main history table, linking to the new job.Dismiss: opens a small modal with an optional reason field. Records
renewal_dismissed_at+renewal_dismissed_reasonon the cert so compliance audit retains why we didn't renew this one. The cert drops out of the queue but stays in the history table with a Dismissed indicator; click it to restore the cert to the queue (e.g. customer changes their mind).
Common dismiss reasons: customer switched provider, building sold, equipment decommissioned.
Not yet shipped
SMS expiry reminders (email-only for now;
jobs.sms_enabledflag remains dormant until an SMS provider is wired).