Skip to main content

Company Deletion

This guide covers how to delete companies, understanding soft delete behaviour, and the effects on users and data.


Overview​

What is Company Deletion?​

Shyfts uses soft deletion for companies:

AspectDescription
MethodSoft delete (sets is_active: false)
Data RetentionAll data preserved
ReversibilityCan be reactivated
User ImpactAll users lose access immediately

Why Soft Delete?​

ReasonBenefit
Data PreservationHistorical records maintained
ComplianceMeets data retention requirements
RecoveryAccidental deletions recoverable
Audit TrailComplete history preserved

Delete Company API​

Endpoint​

Endpoint: DELETE /api/companies/[companyId]

// Source: src/app/api/companies/[companyId]/route.ts:166-192
export async function DELETE(_request: NextRequest, { params }: RouteParams) {
try {
const resolvedParams = await params
const companyId = resolvedParams.companyId

const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()

if (!user) {
return ApiResponses.unauthorized()
}

// Check if user is system admin
if (getAuthRole(user) !== 'SYSTEM_ADMIN') {
return ApiResponses.forbidden('Forbidden - System Admin access required')
}

// Soft delete the company
const result = await companyDB.deleteCompany(companyId)

return ApiResponses.success({ message: 'Company deleted successfully', ...result.data })

} catch (error) {
return handleApiError(error)
}
}

Soft Delete Implementation​

// Source: src/lib/db/company.db.ts:212-223
export async function deleteCompany(id: string): Promise<{ data: CompanyComponentType, timing: { duration: number } }> {
const { result, timing } = await trackPerformance('deleteCompany', async () => {
const supabase = await createClient();
const { data: company, error } = await supabase
.from('companies')
.update({ is_active: false, updated_at: new Date().toISOString() })
.eq('id', id)
.select(`*,
industry_templates (*)`)
.single();

if (error) handleDBError(error);
// ... adapter conversion
});
}

Request Format​

// Delete company request
const deleteCompany = async (companyId: string) => {
const response = await fetch(`/api/companies/${companyId}`, {
method: 'DELETE'
})

if (!response.ok) {
throw new Error('Failed to delete company')
}

return response.json()
}

Response Format​

// Successful deletion response
{
success: true,
data: {
message: "Company deleted successfully",
id: "company-uuid",
name: "Example Practice",
is_active: false,
updated_at: "2025-01-14T10:30:00Z"
}
}

Deletion Effects​

Immediate Effects​

When a company is deleted (soft delete):

ComponentEffect
Company StatusSet to inactive
Company ManagersCannot login
Staff MembersCannot login
SchedulesFrozen, inaccessible
DataPreserved but inaccessible
API AccessBlocked

Data Preservation​

Data TypeStatusAccessibility
Company RecordPreservedSystem Admin only
Staff RecordsPreservedSystem Admin only
Shift HistoryPreservedNot accessible
Leave RecordsPreservedNot accessible
Time EntriesPreservedNot accessible
DocumentsPreservedNot accessible

Pre-Deletion Checklist​

Before Deleting​

Review these items before deletion:

ItemActionPriority
Active UsersCount and notifyHigh
Pending ShiftsReview future schedulesHigh
Leave RequestsProcess pending requestsMedium
Outstanding TimeApprove/reject entriesMedium
DocumentsExport if neededLow
ReportsGenerate final reportsLow

Pre-Deletion Report​

// Get pre-deletion summary
const getPreDeletionReport = async (companyId: string) => {
const [company, staffCount, pendingShifts, pendingLeave] = await Promise.all([
fetch(`/api/companies/${companyId}`).then(r => r.json()),
fetch(`/api/companies/${companyId}/staff/count`).then(r => r.json()),
fetch(`/api/companies/${companyId}/shifts?status=pending`).then(r => r.json()),
fetch(`/api/companies/${companyId}/leave?status=pending`).then(r => r.json())
])

return {
company: company.data,
totalStaff: staffCount.data.count,
pendingShifts: pendingShifts.data.length,
pendingLeave: pendingLeave.data.length
}
}

Deletion Process​

Step-by-Step​

1. Navigate to company details
2. Review pre-deletion checklist
3. Click "Delete Company" button
4. Review impact summary
5. Enter confirmation (company name)
6. Click "Confirm Delete"
7. Company soft deleted
8. Users notified

Confirmation Requirements​

RequirementPurpose
Enter Company NamePrevents accidental deletion
Review ImpactUnderstand consequences
Double ConfirmationExtra safety measure

Deletion Confirmation Modal​

Component Example​

// Delete confirmation modal
const DeleteConfirmModal = ({ company, onConfirm, onCancel }) => {
const [confirmName, setConfirmName] = useState('')
const [loading, setLoading] = useState(false)

const isConfirmed = confirmName.toLowerCase() === company.name.toLowerCase()

const handleDelete = async () => {
if (!isConfirmed) return

setLoading(true)
try {
await onConfirm()
} finally {
setLoading(false)
}
}

return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="card-glass p-6 max-w-md w-full mx-4">
<h2 className="text-xl font-semibold text-red-400 mb-4">
Delete Company
</h2>

<div className="space-y-4">
<p className="text-secondary-text">
This will immediately block access for all {company.staffCount} users.
</p>

<div className="bg-red-500/10 border border-red-500/20 rounded p-3">
<p className="text-sm text-red-300">
<strong>Warning:</strong> All company managers and staff will be
unable to login. This action can be reversed by reactivating the company.
</p>
</div>

<div>
<label className="block text-sm font-medium mb-2">
Type <strong>{company.name}</strong> to confirm
</label>
<input
type="text"
value={confirmName}
onChange={(e) => setConfirmName(e.target.value)}
className="form-input w-full"
placeholder="Enter company name"
/>
</div>

<div className="flex gap-3 pt-2">
<button
onClick={onCancel}
className="form-button secondary flex-1"
disabled={loading}
>
Cancel
</button>
<button
onClick={handleDelete}
disabled={!isConfirmed || loading}
className="form-button danger flex-1"
>
{loading ? 'Deleting...' : 'Delete Company'}
</button>
</div>
</div>
</div>
</div>
)
}

Recovery Options​

Reactivating Deleted Companies​

Since deletion is soft, companies can be reactivated:

// Reactivate a deleted company
const reactivateCompany = async (companyId: string) => {
const response = await fetch(`/api/companies/${companyId}/toggle-status`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ active: true })
})

return response.json()
}

Recovery Process​

1. Navigate to Admin Portal
2. View inactive companies filter
3. Select the deleted company
4. Click "Reactivate Company"
5. Confirm reactivation
6. Company and users regain access

Recovery Limitations​

LimitationDescription
Time LimitNo hard limit (data preserved indefinitely)
Data IntegrityAll original data restored
User AccountsAll accounts restored
PermissionsOriginal permissions restored

Permanent Deletion​

Hard Delete (Future Feature)​

Not Currently Available

Permanent deletion is not currently implemented. All deletions are soft deletes that can be reversed.

When Permanent Delete May Be Needed​

ScenarioReason
GDPR RequestData subject right to erasure
ComplianceRegulatory requirement
StorageLong-term inactive data cleanup

Data Subject Requests​

For GDPR erasure requests:

  1. Document Request - Record the formal request
  2. Verify Identity - Confirm requester identity
  3. Assess Scope - Determine what data to erase
  4. Contact Support - Manual database intervention required
  5. Confirm Deletion - Provide confirmation to requester

Audit Trail​

Deletion Logging​

All deletions are logged:

// Deletion activity log entry
{
action: 'company_deleted',
company_id: 'company-uuid',
created_by: 'system-admin-uuid',
details: {
company_name: 'Example Practice',
staff_count: 15,
manager_count: 2,
reason: 'Contract terminated'
},
created_at: '2025-01-14T10:30:00Z',
ip_address: '192.168.1.1'
}

Viewing Deletion History​

// Get deletion history
const getDeletionHistory = async () => {
const { data } = await supabase
.from('system_activity_logs')
.select('*')
.eq('action', 'company_deleted')
.order('created_at', { ascending: false })

return data
}

User Notifications​

Notification Flow​

When a company is deleted:

RecipientNotificationMethod
Company ManagersAccount suspendedEmail (if configured)
Staff MembersAccess revokedEmail (if configured)
System AdminsDeletion confirmedDashboard notification

Notification Template​

// Deletion notification content
{
subject: "Your Shyfts Account Has Been Suspended",
body: `
Dear {firstName},

Your company ({companyName}) account on Shyfts has been suspended.
You will no longer be able to access the platform.

If you believe this is an error, please contact your administrator.

Regards,
Shyfts Team
`
}

Best Practices​

Before Deletion​

PracticeDescription
Export DataGenerate reports for records
Notify UsersGive advance warning when possible
Process PendingHandle outstanding requests
Document ReasonRecord why company was deleted

After Deletion​

PracticeDescription
Verify Access BlockedConfirm users cannot login
Update RecordsNote deletion in external systems
Retain DocumentationKeep deletion records
Monitor Recovery RequestsWatch for reactivation needs

Troubleshooting​

Common Issues​

IssueCauseSolution
Deletion failedNetwork errorRetry operation
Users still have accessCache delayWait 5 minutes
Company not foundInvalid IDVerify company exists
Forbidden errorNot System AdminCheck permissions

Error Messages​

ErrorMeaningAction
"Company not found"Invalid company IDVerify company exists
"Forbidden"Not authorisedLogin as System Admin
"Database error"Server issueContact support
"Deletion in progress"Already processingWait and retry

API Reference Summary​

Delete Endpoint​

PropertyValue
MethodDELETE
Endpoint/api/companies/[companyId]
AuthenticationRequired
Role RequiredSYSTEM_ADMIN
Soft DeleteYes (sets is_active = false)

Response Codes​

CodeMeaning
200Successfully deleted
401Not authenticated
403Not authorised (not System Admin)
404Company not found
500Server error


Source Files:

  • src/app/api/companies/[companyId]/route.ts - Company delete API
  • src/lib/db/company.db.ts - Soft delete implementation
  • src/types/database.types.ts - Database type definitions