= 100 ? 'completed' : 'active') : 'submitted';
$managerComment = $approvalState === 'approved' ? 'Auto-approved on submission by leadership role.' : null;
$stmt = db()->prepare(
'INSERT INTO okr_items (
organization_name,
organization_slug,
owner_name,
owner_email,
owner_role,
department_name,
period_name,
objective_title,
key_result_title,
description,
target_value,
current_value,
score_percent,
status,
approval_state,
manager_comment,
created_by_email
) VALUES (
:organization_name,
:organization_slug,
:owner_name,
:owner_email,
:owner_role,
:department_name,
:period_name,
:objective_title,
:key_result_title,
:description,
:target_value,
:current_value,
:score_percent,
:status,
:approval_state,
:manager_comment,
:created_by_email
)'
);
$stmt->execute([
':organization_name' => $user['organization_name'],
':organization_slug' => $user['organization_slug'],
':owner_name' => $user['name'],
':owner_email' => $user['email'],
':owner_role' => $user['role'],
':department_name' => $departmentName,
':period_name' => $periodName,
':objective_title' => $objectiveTitle,
':key_result_title' => $keyResultTitle,
':description' => $description !== '' ? $description : null,
':target_value' => $targetValue,
':current_value' => $currentValue,
':score_percent' => $scorePercent,
':status' => $status,
':approval_state' => $approvalState,
':manager_comment' => $managerComment,
':created_by_email' => $user['email'],
]);
okr_flash('success', 'Objective created and routed into the workflow.');
header('Location: index.php#my-okrs');
exit;
} catch (Throwable $exception) {
okr_flash('danger', $exception->getMessage());
header('Location: index.php#my-okrs');
exit;
}
}
$projectName = okr_app_name();
$projectDescription = okr_meta_description();
$projectImageUrl = env_value('PROJECT_IMAGE_URL');
$flash = okr_pull_flash();
$csrfToken = okr_csrf_token();
$scopeParams = okr_scope_params($user);
$scopeClause = okr_scope_clause();
$summaryStmt = db()->prepare(
'SELECT
COUNT(*) AS total_items,
SUM(approval_state = "pending_manager") AS pending_items,
SUM(approval_state = "approved") AS approved_items,
ROUND(COALESCE(AVG(score_percent), 0), 1) AS average_score,
SUM(status = "completed") AS completed_items
FROM okr_items
WHERE ' . $scopeClause
);
foreach ($scopeParams as $key => $value) {
$summaryStmt->bindValue($key, $value);
}
$summaryStmt->execute();
$summary = $summaryStmt->fetch() ?: ['total_items' => 0, 'pending_items' => 0, 'approved_items' => 0, 'average_score' => 0, 'completed_items' => 0];
$recentStmt = db()->prepare(
'SELECT id, organization_name, owner_name, owner_role, department_name, objective_title, score_percent, approval_state, updated_at
FROM okr_items
WHERE ' . $scopeClause . '
ORDER BY updated_at DESC
LIMIT 6'
);
foreach ($scopeParams as $key => $value) {
$recentStmt->bindValue($key, $value);
}
$recentStmt->execute();
$recentItems = $recentStmt->fetchAll();
$listStmt = db()->prepare(
'SELECT id, owner_name, owner_role, department_name, period_name, objective_title, key_result_title, score_percent, status, approval_state, updated_at
FROM okr_items
WHERE ' . $scopeClause . '
ORDER BY created_at DESC
LIMIT 24'
);
foreach ($scopeParams as $key => $value) {
$listStmt->bindValue($key, $value);
}
$listStmt->execute();
$okrItems = $listStmt->fetchAll();
$myStmt = db()->prepare(
'SELECT id, objective_title, key_result_title, score_percent, approval_state, updated_at
FROM okr_items
WHERE ' . $scopeClause . ' AND owner_email = :owner_email
ORDER BY created_at DESC
LIMIT 6'
);
foreach ($scopeParams as $key => $value) {
$myStmt->bindValue($key, $value);
}
$myStmt->bindValue(':owner_email', $user['email']);
$myStmt->execute();
$myItems = $myStmt->fetchAll();
$approvalInbox = [];
if (okr_is_approver($user['role'])) {
$approvalStmt = db()->prepare(
'SELECT id, owner_name, department_name, objective_title, key_result_title, score_percent, updated_at
FROM okr_items
WHERE ' . $scopeClause . ' AND approval_state = :approval_state
ORDER BY updated_at DESC
LIMIT 5'
);
foreach ($scopeParams as $key => $value) {
$approvalStmt->bindValue($key, $value);
}
$approvalStmt->bindValue(':approval_state', 'pending_manager');
$approvalStmt->execute();
$approvalInbox = $approvalStmt->fetchAll();
}
$departmentStmt = db()->prepare(
'SELECT department_name, COUNT(*) AS item_count, ROUND(COALESCE(AVG(score_percent), 0), 1) AS department_score
FROM okr_items
WHERE ' . $scopeClause . '
GROUP BY department_name
ORDER BY item_count DESC, department_name ASC
LIMIT 4'
);
foreach ($scopeParams as $key => $value) {
$departmentStmt->bindValue($key, $value);
}
$departmentStmt->execute();
$departmentRows = $departmentStmt->fetchAll();
$pendingCount = okr_notification_count($user);
$completionRate = ((int) ($summary['total_items'] ?? 0)) > 0 ? round(((int) ($summary['completed_items'] ?? 0) / (int) $summary['total_items']) * 100) : 0;
?>
= e($projectName) ?> · Workspace
Operational strategy workspace
Dashboard
First MVP delivery
A working OKR workflow for one tenant-aware organization at a time.
Create a personal objective, view organization-wide progress, and move items through manager review with auto-scored key results.
= e($flash['message']) ?>
Total OKRs
= e((string) ($summary['total_items'] ?? 0)) ?>
Scoped to = okr_is_super_admin() ? 'all organizations' : 'your organization' ?>
Pending approvals
= e((string) ($summary['pending_items'] ?? 0)) ?>
Queue for line-manager review
Approved items
= e((string) ($summary['approved_items'] ?? 0)) ?>
Includes leadership auto-approvals
Average score
= e((string) ($summary['average_score'] ?? 0)) ?>%
Calculated from key result progress
Corporate OKRs
Recent strategic objectives
A compact hierarchical view of the latest objectives and key results in scope.
Use the search field in the header to filter all table rows.
No OKRs yet
Create your first objective in the My OKRs section to populate the dashboard.
Department OKRs
Distribution by department
Department insights appear after your team creates records.
= e($departmentRow['department_name']) ?>
= e((string) $departmentRow['item_count']) ?> OKRs
Average score = e((string) $departmentRow['department_score']) ?>%
Staff OKRs
Workflow completion
= e((string) $completionRate) ?>% of in-scope objectives are completed.
My OKRs
Create a new objective
This thin slice covers create → confirmation → list → detail → approval.
All writes use PDO prepared statements.
Approval inbox
Items waiting for review
Only Manager, Director, CEO, Admin, and Super Admin roles can approve or reject submitted OKRs in this first release.
Inbox is clear
Pending approvals will appear here as staff submit new OKRs.
= e($pending['objective_title']) ?>
= e($pending['owner_name']) ?> · = e($pending['department_name']) ?>
= e((string) $pending['score_percent']) ?>%
Current score
Shared list
In-scope OKR records
Each record opens a detail page for approvals, comments, and score updates.
Showing up to 24 most recent records.
Your workspace is ready for the first OKR
Create one above to activate the dashboard, approval inbox, and analytics cards.
Owner
Department
Objective
Score
Status
Action
= e($item['owner_name']) ?>
= e($item['owner_role']) ?>
= e($item['department_name']) ?>
= e($item['period_name']) ?>
= e($item['objective_title']) ?>
= e($item['key_result_title']) ?>
= e((string) $item['score_percent']) ?>%
Updated = e(date('M j', strtotime((string) $item['updated_at']))) ?>
= e($item['approval_state']) ?>
= e($item['status']) ?>
Open
Personal queue
Your latest submissions
Quick access to your own items inside the current organization scope.
Create another
No personal OKRs created yet in this workspace.
Approval workload
= e((string) $pendingCount) ?> item(s) are currently waiting for a line manager or leadership decision.
This initial delivery uses lightweight refreshes and contextual alerts. Real-time comment streams and richer notifications can be layered onto the same workflow next.