Editing Companies
This guide covers how to view and update company details, including contact information, settings, and configuration options.
Overview
What Can Be Edited?
System Admins can update most company information:
| Category | Editable Fields | Non-Editable |
|---|---|---|
| Identity | Name | Subdomain |
| Contact | Email, Phone | - |
| Address | Address, City, Postal Code | - |
| Branding | Logo URL | - |
| Settings | Full-Time Hours | Industry Template |
| Status | Is Active | Created At |
Why Some Fields Are Locked
Subdomain and Industry Template are locked after creation because:
- Subdomain affects URLs and authentication routing
- Industry Template defines roles, rooms, and terminology
- Changing these would break existing integrations
Accessing Company Details
View Company
- Navigate to Admin Portal
- Click Companies in the sidebar
- Click on a company name or View button
- Company details are displayed
Company Details API
Endpoint: GET /api/companies/[companyId]
// Source: src/app/api/companies/[companyId]/route.ts:19-126
// Fetches company with related data
const { data } = await adminClient
.from('companies')
.select(`*,
industry_templates (*)`)
.eq('id', companyId)
.single()
// Also retrieves:
// - Staff count
// - Manager count
// - Opening hours
Response Structure
// Company details response
{
success: true,
data: {
// Identity
id: "company-uuid",
name: "Example Practice",
subdomain: "example-practice",
// Contact
email: "contact@example.com",
phone: "+44 20 7946 0958",
// Address
address: "123 High Street",
city: "London",
postalCode: "SW1A 1AA",
// Settings
industryTemplateId: "template-uuid",
fullTimeHoursPerWeek: 37.5,
logoUrl: null,
isActive: true,
// Timestamps
createdAt: "2025-01-01T00:00:00Z",
updatedAt: "2025-01-14T10:30:00Z",
// Counts
staffCount: 15,
managerCount: 2,
// Related
industryTemplate: {
id: "template-uuid",
name: "gp_practice",
displayName: "GP Practice",
terminology: { /* ... */ }
},
openingHours: { /* ... */ }
}
}
Updating Company Information
Update Company API
Endpoint: PUT /api/companies/[companyId]
// Source: src/app/api/companies/[companyId]/route.ts:128-164
export async function PUT(request: NextRequest, { params }: RouteParams) {
// Requires System Admin role
if (getAuthRole(user) !== 'SYSTEM_ADMIN') {
return ApiResponses.forbidden('Forbidden - System Admin access required')
}
const body = await request.json()
const validationResult = parseWithErrors(updateCompanySchema, body)
if (!validationResult.success) {
return ApiResponses.badRequest('Validation failed', validationResult.errors)
}
const result = await companyDB.updateCompany(
companyId,
validationResult.data
)
return ApiResponses.success(result.data, { timing: result.timing.duration })
}
Validation Schema
// Source: src/lib/validation/company.schemas.ts:97-116
export const updateCompanySchema = z.object({
name: z.string()
.min(2, 'Company name must be at least 2 characters')
.max(100, 'Company name must not exceed 100 characters')
.trim()
.optional(),
email: emailSchema.optional().nullable(),
phone: phoneSchema,
address: addressSchema,
city: citySchema,
postal_code: z.string()
.regex(postalCodeRegex, 'Invalid UK postal code format')
.optional()
.nullable(),
logo_url: z.string()
.url('Invalid logo URL')
.optional()
.nullable(),
is_active: z.boolean().optional()
})
Request Format
// Update company request
const updateCompany = async (companyId: string, updates: CompanyUpdate) => {
const response = await fetch(`/api/companies/${companyId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
})
return response.json()
}
// Example usage
await updateCompany('company-uuid', {
name: 'Updated Practice Name',
email: 'newemail@practice.com',
phone: '+44 20 7946 1234',
address: '456 New Street',
city: 'Manchester',
postal_code: 'M1 1AA'
})
Editable Fields
Company Name
| Property | Value |
|---|---|
| Field | name |
| Type | String |
| Min Length | 2 characters |
| Max Length | 100 characters |
| Required | No (for updates) |
// Update company name
await updateCompany(companyId, {
name: 'New Practice Name'
})
Contact Information
Email
| Property | Value |
|---|---|
| Field | email |
| Type | String (email format) |
| Max Length | 255 characters |
| Required | No |
// Update email
await updateCompany(companyId, {
email: 'contact@newdomain.com'
})
Phone
| Property | Value |
|---|---|
| Field | phone |
| Type | String |
| Format | International phone format |
| Max Length | 30 characters |
| Required | No |
// Valid phone formats
'+44 20 7946 0958'
'020 7946 0958'
'+1 555 123 4567'
Address Fields
Street Address
| Property | Value |
|---|---|
| Field | address |
| Type | String |
| Max Length | 200 characters |
| Required | No |
City
| Property | Value |
|---|---|
| Field | city |
| Type | String |
| Min Length | 2 characters |
| Max Length | 100 characters |
| Required | No |
Postal Code
| Property | Value |
|---|---|
| Field | postal_code |
| Type | String |
| Format | UK postal code |
| Required | No |
// Valid UK postal codes
'SW1A 1AA'
'M1 1AA'
'EC1A 1BB'
'W1A 0AX'
Branding
Logo URL
| Property | Value |
|---|---|
| Field | logo_url |
| Type | String (URL) |
| Required | No |
// Update logo
await updateCompany(companyId, {
logo_url: 'https://example.com/logo.png'
})
Database Schema
Companies Table
// Source: src/types/database.types.ts:262-320
companies: {
Row: {
address: string | null
city: string | null
created_at: string | null
email: string | null
full_time_hours_per_week: number | null
id: string
industry_template_id: string | null
is_active: boolean | null
logo_url: string | null
name: string
phone: string | null
postal_code: string | null
subdomain: string
updated_at: string | null
}
Update: {
address?: string | null
city?: string | null
email?: string | null
full_time_hours_per_week?: number | null
is_active?: boolean | null
logo_url?: string | null
name?: string
phone?: string | null
postal_code?: string | null
}
}
Update Workflow
Step-by-Step Process
1. Navigate to company details
2. Click "Edit Company" button
3. Modify desired fields
4. Review changes
5. Click "Save Changes"
6. Confirmation displayed
UI Components
// Company edit form
const CompanyEditForm = ({ company, onSave }) => {
const [formData, setFormData] = useState({
name: company.name,
email: company.email || '',
phone: company.phone || '',
address: company.address || '',
city: company.city || '',
postal_code: company.postalCode || ''
})
const [saving, setSaving] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setSaving(true)
try {
await onSave(formData)
// Show success toast
} catch (error) {
// Show error toast
} finally {
setSaving(false)
}
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
{/* Form fields */}
<button type="submit" disabled={saving}>
{saving ? 'Saving...' : 'Save Changes'}
</button>
</form>
)
}
Validation Rules
Field Validation
| Field | Rules |
|---|---|
| Name | 2-100 chars, trimmed |
| Valid email format, max 255 chars | |
| Phone | International format, max 30 chars |
| Address | Max 200 chars |
| City | 2-100 chars |
| Postal Code | UK format (e.g., SW1A 1AA) |
| Logo URL | Valid URL format |
Validation Patterns
// Source: src/lib/validation/company.schemas.ts:11-17
// Phone regex
const phoneRegex = /^\+?[1-9][\d\s\-().]{0,20}$/
// Postal code regex (UK format)
const postalCodeRegex = /^[A-Z]{1,2}\d[A-Z\d]?\s?\d[A-Z]{2}$/i
Error Handling
// Validation error response
{
success: false,
error: "Validation failed",
details: {
name: ["Company name must be at least 2 characters"],
postal_code: ["Invalid UK postal code format"],
email: ["Invalid email format"]
}
}
Best Practices
Do's and Don'ts
| Do | Don't |
|---|---|
| Verify changes before saving | Make changes without review |
| Keep contact info current | Leave outdated information |
| Use official company email | Use personal email addresses |
| Maintain accurate address | Skip address updates |
| Upload proper logo format | Use low-quality images |
Update Considerations
- Notify Company Manager - Inform of significant changes
- Verify Contact Details - Ensure accuracy of updates
- Update Consistently - Keep all records synchronised
- Document Changes - Note reason for updates
Audit Trail
Change Logging
All company updates are logged:
// Activity log entry
{
action: 'company_updated',
company_id: 'company-uuid',
manager_id: 'system-admin-uuid',
details: {
fields_updated: ['name', 'email'],
old_values: { name: 'Old Name', email: 'old@email.com' },
new_values: { name: 'New Name', email: 'new@email.com' }
},
created_at: '2025-01-14T10:30:00Z',
ip_address: '192.168.1.1'
}
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Validation failed | Invalid field format | Check field requirements |
| Update failed | Network error | Retry the operation |
| Forbidden error | Insufficient permissions | Verify System Admin role |
| Company not found | Invalid company ID | Check company exists |
Error Messages
| Error | Meaning | Action |
|---|---|---|
| "Company name must be at least 2 characters" | Name too short | Use longer name |
| "Invalid UK postal code format" | Wrong postcode | Use format like SW1A 1AA |
| "Invalid email format" | Bad email | Check email syntax |
| "Forbidden - System Admin access required" | Not authorised | Login as System Admin |
Related Documentation
- Creating Companies - Create new companies
- Company Status - Activate/deactivate
- Company Deletion - Remove companies
- Industry Templates - Template configuration
Source Files:
src/app/api/companies/[companyId]/route.ts- Company API endpointsrc/lib/validation/company.schemas.ts- Validation schemassrc/lib/db/company.ts- Database operationssrc/types/database.types.ts- Database type definitions