Skip to content

Delete Organization

Method

REST method is adopted.

HTTP Method

DELETE: Delete an organization (soft delete)

Naming Convention

To unify naming of query parameters and nodes and improve readability, snake_case is used for URIs and nodes in JSON during requests.

Request and Response

Headers

Meta information is set in HTTP headers rather than in the response body.

Request Headers

  • Authorization: Bearer <access_token>
  • Content-Type: application/json

Response Headers

  • Content-Type: application/json

Delete Organization

URI

Path parameter type is integer.

/api/v1/organizations/{organization_id}

Path Parameters

Name Type Description
organization_id integer Required. Must be a positive integer identifying the organization.

Response (200 OK)

Response is JSON. The organization record is soft-deleted: deletedAt and deletedBy are populated while the row remains in the database.

{
  "id": 1,
  "name": "Example Organization",
  "createdAt": 1640995200000,
  "updatedAt": 1641081600000,
  "createdBy": "1111-aaaa-2222-bbbb",
  "updatedBy": "1111-aaaa-2222-bbbb",
  "deletedAt": 1641168000000,
  "deletedBy": "3333-cccc-4444-dddd"
}

Authentication

Authentication is performed using JSON Web Tokens (JWT) issued by Amazon Cognito. A valid Bearer token is required in the Authorization header.

Exception Handling

Exception handling status codes are as follows.

Description Status Code Status Name
Missing or invalid token 401 Unauthorized
Organization not found 404 Not Found
Organization already deleted (conflict) 409 Conflict
Internal server error 500 Internal Server Error

Process Flow

Sequence Diagram

sequenceDiagram
    participant Client
    participant Middleware as Protected Route Middleware
    participant API as Hono Router
    participant Service as Organization Service
    participant Repository as Organization Repository
    participant Cognito as AWS Cognito
    participant DB as PostgreSQL Database

    Client->>Middleware: DELETE /api/v1/organizations/{organization_id}
    Middleware->>Middleware: Extract Bearer token
    Middleware->>Middleware: Verify JWT & session

    alt Token Valid
        Middleware-->>API: Auth info (sub, adminId)
        API->>Service: remove(id, adminId)
        Service->>Repository: findOneById(id)
        Repository->>DB: SELECT FROM organizations WHERE id = ?

        alt Organization Not Found
            DB-->>Repository: null
            Repository-->>Service: null
            Service-->>API: throw NotFoundError
            API-->>Client: 404 Not Found
        else Organization Already Deleted
            DB-->>Repository: Organization with deletedAt
            Repository-->>Service: Organization (soft-deleted)
            Service-->>API: throw ConflictError
            API-->>Client: 409 Conflict
        else Organization Found
            DB-->>Repository: Organization record
            Repository-->>Service: Organization (active)
            Service->>Repository: findAllUsersByOrgId(orgId)
            Repository->>DB: SELECT FROM users WHERE org_id = ?
            DB-->>Repository: User list

            loop For each user in organization
                Service->>Cognito: deleteCognitoUser(user.cognitoSub)
                Cognito-->>Service: User deleted
                Service->>Repository: deleteUser(userId)
                Repository->>DB: DELETE FROM users WHERE id = ?
                DB-->>Repository: User deleted
            end

            Service->>Repository: findAllProjectsByOrgId(orgId)
            Repository->>DB: SELECT FROM projects WHERE org_id = ?
            DB-->>Repository: Project list

            loop For each project in organization
                Service->>Repository: deleteProject(projectId)
                Repository->>DB: DELETE FROM projects WHERE id = ?
                DB-->>Repository: Project deleted
            end

            Service->>Repository: softDeleteOrg(orgId, adminId)
            Repository->>DB: UPDATE organizations SET deleted_at, deleted_by WHERE id = ?
            DB-->>Repository: Organization soft-deleted
            Repository-->>Service: Deleted organization
            Service-->>API: Organization data with deletedAt
            API-->>Client: 200 OK { id, name, deletedAt, deletedBy, ... }
        end
    else Token Invalid
        Middleware-->>Client: 401 Unauthorized
    end

Routes Layer

API routing is performed here. The protectedRoute middleware validates the JWT token and session before the handler executes. The handler extracts the organization_id path parameter and delegates to the organization service.

Source: apps/admin/src/routes/v1/organization.ts

Services Layer

This section describes business logic. It retrieves the organization by ID and verifies it exists and is not already soft-deleted. It then cascade-deletes all users belonging to the organization (removing each from AWS Cognito and the database) and all projects belonging to the organization. Finally, it soft-deletes the organization itself by populating deletedAt and deletedBy.

Source: apps/admin/src/services/organization.ts

Repositories Layer

This section describes access to databases and external services. It performs lookups for the organization, its users, and its projects. It also handles user deletion from the database, project deletion, and the soft-delete update on the organization record.

Source: apps/admin/src/repositories/organization.ts

Security

  • Token validated by protectedRoute middleware before handler execution
  • Session existence verified via verifySession
  • Path parameter validated as positive integer to prevent injection
  • Cascade deletion ensures no orphaned users or projects remain after organization deletion
  • AWS Cognito users are explicitly removed to prevent orphaned authentication identities