Part 6 of 10 · MaidsMe Pro

Why No Profile Went Public Until a Human Approved It

Most platforms race content live, sign up, post, visible in seconds. MaidsMe does the opposite on purpose, a worker completes a profile and nothing becomes public until the admin approves it. Deliberate friction. This post is the approval workflow as built, and the argument for why slower was safer here.

The lifecycle from post one becomes concrete in the admin screen. Submitted profiles arrive as pending_approval, and the admin’s list shows them first with three actions, approve, reject, or approve but keep hidden. Each action is a capability-checked, nonce-checked status change:

public function handle_profile_action() {
    if (!current_user_can('manage_options')) { wp_die('Not allowed'); }
    if (!wp_verify_nonce($_POST['mm_nonce'], 'mm_profile_action')) { wp_die('Security check failed'); }

    $profile_id = absint($_POST['profile_id']);
    $action     = sanitize_key($_POST['profile_action']);

    $map = array(
        'approve' => 'approved_visible',
        'hide'    => 'approved_hidden',
        'reject'  => 'rejected',
        'suspend' => 'suspended',
    );
    if (!isset($map[$action])) { wp_die('Unknown action'); }

    $wpdb->update($this->table_profiles,
        array('status' => $map[$action], 'reviewed_at' => current_time('mysql')),
        array('id' => $profile_id)
    );
    $this->log_status_change($profile_id, $map[$action]);
}

Details worth stealing from that handler. current_user_can comes before everything, approval is an admin power and the check is the door. The action names map through a whitelist array, so a crafted request cannot invent a status, unknown input dies rather than writes. And every change is logged to a status history table with who and when, because on a platform responsible for vulnerable people, why is this profile hidden must always have an answer.

Why accept the friction at all? Because every profile here is a person offering to work inside someone’s home, and the failure cases are not spam, they are exploitation, fake profiles harvesting inquiries, stolen photos, listings that endanger the person listed. A human reading each profile before it exists publicly is the cheapest effective filter for all of those at once. The approve-but-hidden state earns its place too, a worker travels or pauses, the admin unlists them without destroying an approved profile, and relists with one click. Friction, in this design, is not a missing optimisation. It is the feature.

A few things people ask me about this

Does manual approval scale? To a point, and that point is further than founders fear. One admin reviews dozens of profiles daily in minutes each. When volume truly outgrows one person, the answer is more reviewers with the same logged workflow, not removing the gate.

Why whitelist actions in an array? So the request can only choose among statuses you defined. Writing $_POST values into a status column directly lets an attacker invent states your queries never anticipated.

Next

Profiles are made of fields, and hardcoding fields for every profession would have frozen the platform in its first week. The form builder the admin can shape is the next post.

Leave a Reply

Your email address will not be published. Required fields are marked *