offdataai
Public Sector & Nonprofit · data model template

Citizen Services 311 & Permits data model

Third-normal-form mirror of a 311 / permitting source system. Each operational table becomes its own entity with a warehouse surrogate key plus the genuine business key (Open311 service_request_id, permit_application_id, inspection_id, violation_id, feedback_id). Citizen PII (name, email, address, phone) is masked under FOIA / GDPR records-retention rules; lat/long is preserved at request grain for spatial reporting on caseload and SLA performance.

Normalized replica of a municipal citizen-services platform: Open311 service requests (type, location, description, status lifecycle), permit applications and inspections, code-enforcement violations, and post-resolution citizen satisfaction feedback. Reference data (agency, service catalog, channel, status, priority, inspection type, permit type) is held in slow-changing lookup tables and joined to the transactional intake, permits/inspections, compliance and feedback subject areas. It is a normalized (3NF) relational model that mirrors the source system, suited to operational databases and to landing source data faithfully.

3NFPublic Sector & NonprofitFOIAGDPR
14
tables
116
columns
18
relationships
11
PII columns

Opening the template creates a project with the ERD, platform-native DDL, a dbt project and documentation already generated (recommended platform: PostgreSQL). Edit it in plain English or on the canvas, then ship it to any supported warehouse.

Subject areas

master_dataintakepermits_inspectionscompliancefeedback

Design decisions

  • Open311 service-request lifecycle modeled with status-update history

    Open311 represents a service request as a single record whose status evolves; splitting service_request_update into its own entity preserves the full lifecycle (open → in-progress → closed/cancelled/rejected) so SLA breach and reopen-rate reporting can replay every transition.

  • Permit → inspection lifecycle kept as parent/child entities

    A permit application typically requires one or more inspections of different disciplines (building, electrical, plumbing, ...); modeling permit_inspection as a child of permit_application with an inspection_type lookup mirrors how permitting systems store the schedule of visits and their pass/fail outcomes.

  • Citizen as the single party across SR, permits and feedback

    The same citizen can file a service request, apply for a permit and submit satisfaction feedback; keeping a single citizen entity referenced by all three subject areas avoids duplicating PII and lets analytics stitch one resident's journey across the portfolio.

  • Spatial reporting captured at request grain

    Latitude and longitude are stored on service_request itself (not promoted to a separate location dimension) so heat-map and district rollups can group requests geographically without an extra join — matching Open311's location_lat / location_long fields.

  • FOIA / records-retention framing for PII

    Citizen name, address, phone, email and free-text feedback are subject to FOIA disclosure rules and GDPR records-retention; classifying these as PII with partial masking ensures responsive records can be produced without leaking unrelated PII in extracts.

Tables in the Citizen Services 311 & Permits model

Every table with its grain, columns, types and keys. PK marks a primary key, BK a business key and PII a column classified as personal data, which gets a masking strategy by default.

Tables (7)

citizen

Grain: one row per registered or anonymous citizen

Citizen party — single record across SR, permit and feedback subject areas.

ColumnTypeKeys
citizen_keybigintPK
citizen_idvarcharBK
first_namevarcharPII
last_namevarcharPII
emailvarcharPII
phonevarcharPII
mailing_addressvarcharPII
preferred_languagevarchar
is_anonymousboolean
registration_datedate

service_request

Grain: one row per Open311 service request (service_request_id)

Open311 service request — the canonical citizen-reported case.

ColumnTypeKeys
service_request_keybigintPK
citizen_keybigint
agency_keybigint
service_type_keybigint
channel_keybigint
status_keybigint
priority_keybigint
service_request_idvarcharBK
reported_attimestamp
location_latitudedecimal
location_longitudedecimal
incident_addressvarcharPII
district_councilvarchar
descriptionvarchar
parent_service_request_keybigint
expected_resolution_datedate
closed_attimestamp
resolution_minutesinteger

service_request_update

Grain: one row per status update on a service request

Status-update history — replays the lifecycle of a service request.

ColumnTypeKeys
service_request_update_keybigintPK
service_request_keybigint
status_keybigint
update_idvarcharBK
updated_attimestamp
updated_byvarcharPII
update_notevarchar
channel_usedvarchar

permit_application

Grain: one row per permit application

Permit application — the lifecycle record from submission through issuance.

ColumnTypeKeys
permit_application_keybigintPK
citizen_keybigint
agency_keybigint
permit_type_keybigint
permit_application_idvarcharBK
applied_attimestamp
expected_issue_datedate
issued_attimestamp
expired_attimestamp
total_feedecimal
paid_amountdecimal
currencyvarchar
application_statusvarchar
project_addressvarcharPII

permit_inspection

Grain: one row per inspection scheduled against a permit

Inspection scheduled against a permit application — captures permit→inspection lifecycle.

ColumnTypeKeys
permit_inspection_keybigintPK
permit_application_keybigint
inspection_type_keybigint
inspection_idvarcharBK
scheduled_datedate
performed_datedate
inspector_namevarcharPII
inspection_resultvarchar
follow_up_requiredsmallint
notesvarchar
parent_inspection_keybigint

code_violation

Grain: one row per code-enforcement citation

Code-enforcement citation arising from a service request.

ColumnTypeKeys
code_violation_keybigintPK
service_request_keybigint
agency_keybigint
violation_idvarcharBK
citation_numbervarchar
violation_codevarchar
violation_descriptionvarchar
issued_datedate
fine_amountdecimal
paid_amountdecimal
currencyvarchar
violation_statusvarchar
cited_partyvarcharPII

citizen_satisfaction

Grain: one row per satisfaction feedback submission

Post-resolution citizen satisfaction feedback tied back to the originating SR.

ColumnTypeKeys
citizen_satisfaction_keybigintPK
service_request_keybigint
citizen_keybigint
channel_keybigint
feedback_idvarcharBK
submitted_attimestamp
satisfaction_scoresmallint
would_recommendsmallint
feedback_textvarcharPII

Lookup tables (7)

agency

Grain: one row per municipal agency / department

Municipal agency responsible for handling service requests and permits.

ColumnTypeKeys
agency_keybigintPK
agency_idvarcharBK
agency_namevarchar
departmentvarchar
jurisdictionvarchar

service_type

Grain: one row per Open311 service type

Open311 service catalog — the set of request types citizens can report.

ColumnTypeKeys
service_type_keybigintPK
service_codevarcharBK
service_namevarchar
service_categoryvarchar
jurisdictionvarchar

channel

Grain: one row per intake channel

Origination channel through which a request, update or feedback was submitted.

ColumnTypeKeys
channel_keybigintPK
channel_idvarcharBK
channel_namevarchar
is_digitalboolean

status

Grain: one row per service-request lifecycle status

Open311 service-request lifecycle status values.

ColumnTypeKeys
status_keybigintPK
status_idvarcharBK
status_namevarchar
is_terminalboolean
is_openboolean

inspection_type

Grain: one row per inspection type

Catalog of inspection disciplines performed against permitted projects.

ColumnTypeKeys
inspection_type_keybigintPK
inspection_type_idvarcharBK
descriptionvarchar
requires_followupboolean

permit_type

Grain: one row per permit type

Permit catalog — the set of permits citizens / businesses can apply for.

ColumnTypeKeys
permit_type_keybigintPK
permit_type_idvarcharBK
permit_namevarchar
fee_amountdecimal
requires_inspectionboolean

priority

Grain: one row per service-request priority tier

Priority tier with associated SLA response and resolution targets.

ColumnTypeKeys
priority_keybigintPK
priority_idvarcharBK
priority_namevarchar
sla_response_hoursinteger
sla_resolution_hoursinteger

Relationships

Each relationship is a foreign key on the first table referencing the second.

  • service_request.citizen_key → citizen (many-to-one)
  • service_request.agency_key → agency (many-to-one)
  • service_request.service_type_key → service_type (many-to-one)
  • service_request.channel_key → channel (many-to-one)
  • service_request.status_key → status (many-to-one)
  • service_request.priority_key → priority (many-to-one)
  • service_request_update.service_request_key → service_request (many-to-one)
  • service_request_update.status_key → status (many-to-one)
  • permit_application.citizen_key → citizen (many-to-one)
  • permit_application.agency_key → agency (many-to-one)
  • permit_application.permit_type_key → permit_type (many-to-one)
  • permit_inspection.permit_application_key → permit_application (many-to-one)
  • permit_inspection.inspection_type_key → inspection_type (many-to-one)
  • code_violation.service_request_key → service_request (many-to-one)
  • code_violation.agency_key → agency (many-to-one)
  • citizen_satisfaction.service_request_key → service_request (many-to-one)
  • citizen_satisfaction.citizen_key → citizen (many-to-one)
  • citizen_satisfaction.channel_key → channel (many-to-one)

Related templates

All templates →
Start for $1

From requirements to AI-ready context, in one platform.

Describe your business in a conversation, start from a template or connect your own database. Your first model is ready in minutes.

Get startedBook a demo

Plans from $1/month · cancel any time