25 KiB
CSV Template Specification
Source task: plans/task-d.7.1.md
All supported CSV imports must run in two phases:
- Preview: parse, validate, resolve references, detect duplicates, and produce an import report.
- Commit: upsert in a transaction where database-only writes are involved.
CSV imports must not bypass feature/foundation services once those services exist. Where current seed logic only exists in scripts, D.7.2+ should extract reusable server services first.
Supported Templates
organizations.csv
Purpose: create tenant organizations.
Target: organizations.
Seed type: organization.
Required columns: organization_code, organization_name, slug, created_by_email.
Optional columns: tax_id, default_currency, phone, email, address, logo_url, plan, status.
Generated columns: id, created_at, updated_at.
Validation rules: slug lowercase and unique; organization_code uppercase; created_by_email must resolve to a user.
Relationship resolution: created_by_email -> users.id.
Duplicate detection: existing organization by slug.
Upsert key: slug.
Import order: 02.
organization_code,organization_name,slug,created_by_email,tax_id,default_currency,status
ALLA,ALLA Public Company Limited,alla,admin@example.com,0107558000393,THB,active
Error examples: duplicate slug with conflicting name; missing creator user; invalid lowercase/uppercase format.
users.csv
Purpose: create setup-managed users.
Target: users through auth/user service.
Seed type: organization.
Required columns: email, name, system_role.
Optional columns: password, active_organization_code, image_url, reset_password.
Generated columns: id, password_hash, created_at, updated_at.
Validation rules: email format; system_role in super_admin,user; password required for new credential users unless invitation flow exists.
Relationship resolution: active_organization_code -> organizations.slug or setup organization_code.
Duplicate detection: existing user by email.
Upsert key: email.
Import order: 01.
email,name,system_role,password,active_organization_code,reset_password
admin@example.com,System Administrator,super_admin,ChangeMe123!,ALLA,true
Error examples: invalid email; unsupported system role; existing user without reset permission.
memberships.csv
Purpose: grant app-level organization access.
Target: memberships.
Seed type: organization.
Required columns: organization_code, user_email, membership_role, business_role.
Optional columns: permissions, branch_scope_codes, product_type_scope_codes.
Generated columns: id, timestamps.
Validation rules: membership_role in admin,user; business_role should be a known CRM role fallback code; scope codes must resolve when provided.
Relationship resolution: organization, user, branch options, product type options.
Duplicate detection: existing membership by organization_id + user_id.
Upsert key: organization_code + user_email.
Import order: 03.
organization_code,user_email,membership_role,business_role,permissions,branch_scope_codes,product_type_scope_codes
ALLA,admin@example.com,admin,crm_admin,crm.dashboard.read|crm.role.read,head_office,crane|dockdoor
Error examples: unknown user; unknown organization; invalid branch/product type code.
crm-role-assignments.csv
Purpose: assign CRM role profiles and CRM scopes.
Target: crm_user_role_assignments.
Seed type: organization.
Required columns: organization_code, user_email, crm_role_code, is_primary, branch_scope_mode, product_type_scope_mode.
Optional columns: branch_codes, product_type_codes, is_active.
Generated columns: id, assigned_at, timestamps.
Validation rules: role profile must exist; scope mode in all,selected,none,inherit; selected modes require matching codes.
Relationship resolution: user, organization, role profile, branch options, product type options.
Duplicate detection: existing assignment by organization_id + user_id + role_profile_id.
Upsert key: organization_code + user_email + crm_role_code.
Import order: 05.
organization_code,user_email,crm_role_code,is_primary,branch_scope_mode,branch_codes,product_type_scope_mode,product_type_codes,is_active
ALLA,admin@example.com,crm_admin,true,all,,all,,true
Error examples: selected scope without codes; role profile missing; multiple primary rows for one user unless explicit replacement mode.
master-options.csv
Purpose: import governed option rows.
Target: ms_options.
Seed type: foundation.
Required columns: organization_code, category, code, label.
Optional columns: value, parent_category, parent_code, sort_order, is_active, metadata_json.
Generated columns: id, timestamps.
Validation rules: category/code non-empty; parent resolves in same organization when provided; metadata must be valid JSON.
Relationship resolution: organization, optional parent option.
Duplicate detection: existing option by organization_id + category + code.
Upsert key: organization_code + category + code.
Import order: 06.
organization_code,category,code,label,value,parent_category,parent_code,sort_order,is_active,metadata_json
ALLA,crm_customer_group,industrial,Industrial,industrial,,,1,true,{}
Error examples: invalid JSON; missing parent option; duplicate category/code in same CSV with conflicting labels.
branches.csv
Purpose: typed convenience template for branch options.
Target: ms_options with category=crm_branch.
Seed type: organization.
Required columns: organization_code, branch_code, branch_name.
Optional columns: prefix, address, tax_id, phone, email, sort_order, is_active.
Generated columns: id, category, timestamps.
Validation rules: branch code unique per organization; code lowercase snake_case recommended; metadata fields serialized into option metadata.
Relationship resolution: organization.
Duplicate detection: existing crm_branch option by code.
Upsert key: organization_code + branch_code.
Import order: 07.
organization_code,branch_code,branch_name,prefix,address,tax_id,sort_order,is_active
ALLA,head_office,Head Office,HO,99/9 Rama IX Road,0107558000393,1,true
Error examples: duplicate branch code; invalid organization; malformed metadata.
product-types.csv
Purpose: typed convenience template for product type options.
Target: ms_options with category=crm_product_type.
Seed type: organization.
Required columns: organization_code, product_type_code, product_type_name.
Optional columns: document_prefix, sort_order, is_active, metadata_json.
Generated columns: id, category, timestamps.
Validation rules: product type code unique per organization; document_prefix uppercase recommended.
Relationship resolution: organization.
Duplicate detection: existing crm_product_type option by code.
Upsert key: organization_code + product_type_code.
Import order: 08.
organization_code,product_type_code,product_type_name,document_prefix,sort_order,is_active
ALLA,crane,Crane,CR,1,true
Error examples: duplicate product type code; invalid JSON metadata; unsupported inactive default product type for document sequence.
document-sequences.csv
Purpose: configure document numbering.
Target: document_sequences.
Seed type: foundation.
Required columns: organization_code, document_type, prefix, period.
Optional columns: branch_code, product_type_code, current_number, padding_length, format, reset_policy, is_active.
Generated columns: id, timestamps.
Validation rules: document type supported by sequence foundation; branch/product type resolve or default to generic scope; current number non-negative integer.
Relationship resolution: organization, branch option, product type option.
Duplicate detection: organization_id + branch_id + product_type + document_type + period.
Upsert key: same as duplicate detection.
Import order: 14.
organization_code,branch_code,product_type_code,document_type,prefix,period,current_number,padding_length,format,reset_policy,is_active
ALLA,head_office,crane,quotation,QT-HO-CR-,2607,0,3,{prefix}{period}-{running},period,true
Error examples: unknown branch; unknown product type; malformed format missing {running}.
approval-workflows.csv
Purpose: configure approval workflow headers.
Target: crm_approval_workflows.
Seed type: foundation.
Required columns: organization_code, workflow_code, workflow_name, entity_type.
Optional columns: description, is_system, is_active.
Generated columns: id, timestamps.
Validation rules: workflow code unique per organization; entity type supported, currently quotation.
Relationship resolution: organization.
Duplicate detection: organization_id + workflow_code.
Upsert key: organization_code + workflow_code.
Import order: 15.
organization_code,workflow_code,workflow_name,entity_type,description,is_system,is_active
ALLA,quotation_standard,Quotation Standard Approval,quotation,Default quotation approval,false,true
Error examples: duplicate workflow code; unsupported entity type.
approval-steps.csv
Purpose: configure workflow steps.
Target: crm_approval_steps.
Seed type: foundation.
Required columns: organization_code, workflow_code, step_number, role_code, role_name.
Optional columns: approval_mode, is_required, sla_hours, calendar_mode, timeout_action.
Generated columns: id, timestamps.
Validation rules: workflow resolves; step number positive integer; role code known to CRM role profiles or approved workflow roles.
Relationship resolution: organization, approval workflow.
Duplicate detection: workflow_id + step_number.
Upsert key: organization_code + workflow_code + step_number.
Import order: 16.
organization_code,workflow_code,step_number,role_code,role_name,approval_mode,is_required,sla_hours,calendar_mode,timeout_action
ALLA,quotation_standard,1,sales_manager,Sales Manager,sequential,true,24,calendar_days,none
Error examples: missing workflow; duplicate step number; invalid SLA value.
approval-matrix.csv
Purpose: map approval workflows to entity/scope/amount.
Target: crm_approval_matrices.
Seed type: foundation.
Required columns: organization_code, entity_type, workflow_code, priority, is_default.
Optional columns: branch_code, product_type_code, min_amount, max_amount, currency, is_active, description.
Generated columns: id, timestamps.
Validation rules: workflow resolves; branch/product optional; amount range valid; at most one default per target policy unless replacement mode.
Relationship resolution: organization, workflow, branch option, product type option.
Duplicate detection: default matrix by organization + entity_type + is_default or scoped matrix by full scope/amount tuple.
Upsert key: organization_code + entity_type + workflow_code + priority + scope.
Import order: 17.
organization_code,entity_type,workflow_code,branch_code,product_type_code,min_amount,max_amount,currency,priority,is_default,is_active,description
ALLA,quotation,quotation_standard,head_office,crane,0,5000000,THB,100,true,true,Default crane approval
Error examples: max less than min; missing workflow; unresolved currency option.
customers.csv
Purpose: import CRM customers.
Target: crm_customers.
Seed type: business.
Required columns: organization_code, customer_code, customer_name, customer_type, customer_status, created_by_email.
Optional columns: branch_code, abbr, tax_id, address, province, district, sub_district, postal_code, country, phone, fax, email, website, lead_channel, customer_group, customer_sub_group, owner_user_email, notes, is_active.
Generated columns: id, timestamps, owner assignment timestamps if owner provided.
Validation rules: code unique per organization; option references resolve; email format when provided.
Relationship resolution: organization, branch, owner user, creator user, master options.
Duplicate detection: organization_id + customer_code.
Upsert key: organization_code + customer_code.
Import order: 30.
organization_code,customer_code,customer_name,customer_type,customer_status,owner_user_email,created_by_email,branch_code,customer_group,email,phone
ALLA,CUS-001,Siam Manufacturing,company,active,sales.crane.uat@alla.local,admin@example.com,head_office,industrial,contact@siam.example,02-000-1000
Error examples: unresolved owner; invalid customer group/sub-group relationship; duplicate customer code.
contacts.csv
Purpose: import customer contacts.
Target: crm_customer_contacts.
Seed type: business.
Required columns: organization_code, customer_code, contact_name, created_by_email.
Optional columns: position, department, phone, mobile, email, is_primary, notes, is_active.
Generated columns: id, timestamps.
Validation rules: customer resolves; email format; one primary contact warning when multiple rows set primary.
Relationship resolution: organization, customer, creator user.
Duplicate detection: organization + customer + email when email exists, otherwise customer + contact name.
Upsert key: organization_code + customer_code + email/contact_name.
Import order: 32.
organization_code,customer_code,contact_name,email,mobile,position,is_primary,created_by_email
ALLA,CUS-001,Anan Sales,anan@siam.example,081-000-0001,Procurement Manager,true,admin@example.com
Error examples: missing customer; duplicate primary contact warning; invalid email.
contact-shares.csv
Purpose: import contact sharing grants.
Target: crm_contact_shares.
Seed type: business.
Required columns: organization_code, customer_code, contact_email, shared_to_user_email, shared_by_user_email.
Optional columns: remark, is_active.
Generated columns: id, shared_at, timestamps.
Validation rules: contact resolves; users resolve; cannot share to user outside organization membership.
Relationship resolution: organization, customer, contact, users.
Duplicate detection: organization_id + contact_id + shared_to_user_id.
Upsert key: same as duplicate detection.
Import order: 33.
organization_code,customer_code,contact_email,shared_to_user_email,shared_by_user_email,remark,is_active
ALLA,CUS-001,anan@siam.example,sales.dockdoor.uat@alla.local,admin@example.com,Shared for joint account coverage,true
Error examples: contact not found; target user has no membership; self-share warning.
leads.csv
Purpose: import marketing-owned leads.
Target: crm_leads.
Seed type: business.
Required columns: organization_code, lead_code, status, created_by_email.
Optional columns: branch_code, customer_code, contact_email, description, project_name, project_location, lead_channel, product_type_code, priority, estimated_value, awareness_code, followup_status, lost_reason, outcome, owner_marketing_user_email, assigned_sales_owner_email, assignment_remark.
Generated columns: id, assignment timestamps when assigned, timestamps.
Validation rules: status/priority/product type resolve; customer/contact relationship valid; estimated value numeric.
Relationship resolution: organization, branch, customer, contact, users, master options.
Duplicate detection: organization_id + lead_code.
Upsert key: organization_code + lead_code.
Import order: 34.
organization_code,lead_code,status,created_by_email,customer_code,contact_email,branch_code,product_type_code,priority,project_name,owner_marketing_user_email,assigned_sales_owner_email
ALLA,LD-001,assigned,mk.uat@alla.local,CUS-001,anan@siam.example,head_office,crane,high,Warehouse Crane,mk.uat@alla.local,sales.crane.uat@alla.local
Error examples: contact does not belong to customer; unresolved status option; assignee outside organization.
opportunities.csv
Purpose: import sales opportunities.
Target: crm_opportunities.
Seed type: business.
Required columns: organization_code, opportunity_code, customer_code, title, product_type_code, status, priority, created_by_email, updated_by_email.
Optional columns: lead_code, contact_email, branch_code, description, requirement, project_name, project_location, outcome_status, lead_channel, estimated_value, chance_percent, expected_close_date, competitor, source, notes, is_hot_project, pipeline_stage, assigned_to_user_email.
Generated columns: id, assignment timestamps when assigned, lifecycle timestamps where appropriate.
Validation rules: product/status/priority resolve; percent 0-100; dates ISO YYYY-MM-DD; lead optional.
Relationship resolution: organization, lead, customer, contact, users, options.
Duplicate detection: organization_id + opportunity_code.
Upsert key: organization_code + opportunity_code.
Import order: 36.
organization_code,opportunity_code,customer_code,title,product_type_code,status,priority,created_by_email,updated_by_email,branch_code,contact_email,lead_code,chance_percent,assigned_to_user_email
ALLA,OP-001,CUS-001,Warehouse Crane Expansion,crane,negotiation,high,sales.crane.uat@alla.local,sales.crane.uat@alla.local,head_office,anan@siam.example,LD-001,70,sales.crane.uat@alla.local
Error examples: chance percent outside range; unresolved lead; contact/customer mismatch.
opportunity-parties.csv
Purpose: import opportunity project parties.
Target: crm_opportunity_customers.
Seed type: business.
Required columns: organization_code, opportunity_code, customer_code, role_code.
Optional columns: remark.
Generated columns: id, timestamps.
Validation rules: opportunity/customer resolve; project party role resolves.
Relationship resolution: opportunity, customer, role option.
Duplicate detection: opportunity_id + customer_id + role.
Upsert key: same as duplicate detection.
Import order: 37.
organization_code,opportunity_code,customer_code,role_code,remark
ALLA,OP-001,CUS-001,end_customer,Primary project owner
Error examples: unknown role; opportunity not found; duplicate role/customer row.
quotations.csv
Purpose: import quotation headers.
Target: crm_quotations.
Seed type: business.
Required columns: organization_code, quotation_code, customer_code, quotation_date, quotation_type, status, currency, subtotal, total_amount, created_by_email, updated_by_email.
Optional columns: opportunity_code, contact_email, branch_code, valid_until, project_name, project_location, attention, reference, notes, revision, parent_quotation_code, revision_remark, exchange_rate, discount, discount_type, tax_rate, tax_amount, chance_percent, is_hot_project, competitor, salesman_email, is_sent, sent_at, sent_via.
Generated columns: id, timestamps, approval/snapshot/artifact fields remain runtime generated.
Validation rules: status/currency/type resolve; amounts numeric; parent quotation resolves for revision imports.
Relationship resolution: organization, opportunity, customer, contact, branch, options, users.
Duplicate detection: organization_id + quotation_code.
Upsert key: organization_code + quotation_code.
Import order: 40.
organization_code,quotation_code,customer_code,quotation_date,quotation_type,status,currency,subtotal,total_amount,created_by_email,updated_by_email,opportunity_code,branch_code,salesman_email
ALLA,QT-HO-CR-2607-001,CUS-001,2026-07-02,crane,draft,THB,1000000,1070000,sales.crane.uat@alla.local,sales.crane.uat@alla.local,OP-001,head_office,sales.crane.uat@alla.local
Error examples: parent revision missing; total mismatch warning; approved/runtime fields supplied.
quotation-items.csv
Purpose: import quotation line items.
Target: crm_quotation_items.
Seed type: business.
Required columns: organization_code, quotation_code, item_number, product_type_code, description, quantity, unit_price, total_price.
Optional columns: unit, discount, discount_type, tax_rate, notes, sort_order.
Generated columns: id, timestamps.
Validation rules: numeric amount fields; product type resolves; quotation resolves.
Relationship resolution: quotation, product type, unit, discount type.
Duplicate detection: quotation_id + item_number.
Upsert key: organization_code + quotation_code + item_number.
Import order: 41.
organization_code,quotation_code,item_number,product_type_code,description,quantity,unit,unit_price,discount,discount_type,tax_rate,total_price,sort_order
ALLA,QT-HO-CR-2607-001,1,crane,Crane installation package,1,set,1000000,0,,7,1000000,1
Error examples: missing quotation; invalid item number; total calculation warning.
quotation-parties.csv
Purpose: import quotation project parties.
Target: crm_quotation_customers.
Seed type: business.
Required columns: organization_code, quotation_code, customer_code, role_code.
Optional columns: is_primary, remark.
Generated columns: id, timestamps.
Validation rules: quotation/customer resolve; role resolves; one primary warning per role as applicable.
Relationship resolution: quotation, customer, project party role option.
Duplicate detection: quotation_id + customer_id + role.
Upsert key: same as duplicate detection.
Import order: 42.
organization_code,quotation_code,customer_code,role_code,is_primary,remark
ALLA,QT-HO-CR-2607-001,CUS-001,end_customer,true,Primary quotation customer
Error examples: missing quotation; unknown project party role; duplicate primary warning.
quotation-topics.csv
Purpose: import quotation topic headers.
Target: crm_quotation_topics.
Seed type: business.
Required columns: organization_code, quotation_code, topic_key, topic_type, title.
Optional columns: sort_order.
Generated columns: id, timestamps.
Validation rules: quotation resolves; topic type resolves; topic key unique per quotation CSV batch.
Relationship resolution: quotation, topic type option.
Duplicate detection: quotation_id + topic_key.
Upsert key: organization_code + quotation_code + topic_key.
Import order: 43.
organization_code,quotation_code,topic_key,topic_type,title,sort_order
ALLA,QT-HO-CR-2607-001,scope-main,scope,Scope of Work,1
Error examples: topic type missing; duplicate topic key.
quotation-topic-items.csv
Purpose: import quotation topic rows.
Target: crm_quotation_topic_items.
Seed type: business.
Required columns: organization_code, quotation_code, topic_key, content.
Optional columns: sort_order.
Generated columns: id, timestamps.
Validation rules: topic key resolves from imported or existing topic; content required.
Relationship resolution: quotation topic.
Duplicate detection: topic_id + sort_order + content.
Upsert key: organization_code + quotation_code + topic_key + sort_order.
Import order: 44.
organization_code,quotation_code,topic_key,content,sort_order
ALLA,QT-HO-CR-2607-001,scope-main,Supply and install one overhead crane system,1
Error examples: missing topic; empty content; duplicate sort order warning.
Unsupported or Deferred Templates
departments.csv
Status: unsupported pending schema. No first-class department table was identified. Do not map this to ad hoc options without an ADR.
department_code,department_name
SALES,Sales
teams.csv
Status: unsupported pending schema. Team scope limitations are documented; no first-class team graph exists.
team_code,team_name
SALES-CRANE,Crane Sales Team
warehouses.csv
Status: unsupported pending schema. No warehouse table was identified.
warehouse_code,warehouse_name
MAIN,Main Warehouse
sites.csv
Status: unsupported pending schema. Project/customer site is currently represented by text fields such as project_location, not a reusable site entity.
site_code,site_name,address
BKK-HQ,Bangkok HQ,99/9 Rama IX Road
services.csv
Status: unsupported pending schema. Service catalog does not currently exist as first-class CRM data.
service_code,service_name
INSTALL,Installation Service
price-books.csv
Status: unsupported pending schema. Current quotation items are not backed by a price-book foundation.
price_book_code,product_or_service_code,currency,unit_price
STD-THB,INSTALL,THB,10000
tax-rates.csv
Status: unsupported pending schema. Tax rate currently lives as numeric fields on quotation/item rows.
tax_code,tax_name,tax_rate
VAT7,VAT 7%,7
attachments.csv
Status: deferred. Attachment metadata exists, but binary upload/storage import is not safe as a generic CSV-only flow.
entity_type,entity_code,file_path,description
quotation,QT-HO-CR-2607-001,./files/spec.pdf,Customer specification
email-settings.csv
Status: unsupported pending schema. Email configuration appears environment/provider driven; verification can check readiness but CSV import should not persist secrets without a secure configuration design.
provider,host,port,from_address
smtp,smtp.example.com,587,no-reply@example.com