kennofizet/workpoint-backend

Workpoint Record backend for Laravel — record workpoint events with check rules, zone/server scoped via packages-core

Maintainers

Package info

github.com/kennofizet/point-backend

pkg:composer/kennofizet/workpoint-backend

Statistics

Installs: 10

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-03-31 13:23 UTC

This package is auto-updated.

Last update: 2026-03-31 13:23:59 UTC


README

Laravel package to record workpoints (points) for users with configurable rules. Zone-scoped via packages-core. Use the HasWorkpointRecords trait to record points and expose top ranking + rules APIs.

Requirements

  • PHP 8.2+, Laravel 12.x
  • kennofizet/packages-core-backend (zone scoping + API auth)

Install

composer require kennofizet/workpoint-backend
php artisan vendor:publish --tag=workpoint-config
php artisan vendor:publish --tag=workpoint-cases-config
php artisan vendor:publish --tag=workpoint-migrations
php artisan migrate

Note: workpoint-config publishes config/workpoint.php (and packages-core.php) only. config/workpoint_cases.php is on a separate tag (workpoint-cases-config) so your existing rules file is not overwritten when you run --tag=workpoint-config --force.

Optional .env (defaults are fine for most):

WORKPOINT_TABLE=workpoint_records
WORKPOINT_PERIOD_TOTALS_TABLE=workpoint_period_totals
WORKPOINT_ZONE_CASES_TABLE=workpoint_zone_cases
WORKPOINT_API_PREFIX=workpoint
WORKPOINT_USE_PERIOD_TOTALS_TABLE=true
WORKPOINT_HISTORY_PER_PAGE=30
WORKPOINT_ADMIN_MEMBERS_PER_PAGE=30

User display column comes from packages-core config:

  • packages-core.user_col_name (default: name)
  • packages-core.table_user (user table used by core)

Config

  • config/workpoint.php — Tables, API prefix, period totals, event/listeners, rules map.
  • config/workpoint_cases.php — Action keys (e.g. task_completed_on_time) with points, check, period, cap, descriptions (vi/en). Per-zone overrides stored in DB; defaults from this file.

Usage in code

1. Add trait to the model that earns points (e.g. User):

use Kennofizet\Workpoint\Traits\HasWorkpointRecords;

class User extends Authenticatable
{
    use HasWorkpointRecords;
}

2. Record workpoints (action key must exist in workpoint_cases.php):

$user->recordWorkpoint('app_first_visit_day');                    // no target
$user->recordWorkpoint('task_completed_on_time', $task);          // with target
$user->recordWorkpoint('task_accepted_sla', $task, ['sla' => 24]); // with payload

// Optional zone list (multi-zone record). Invalid/non-member zones are skipped silently.
$user->recordWorkpoint('task_completed_on_time', $task, [], [1, 2, 3]);

// Null zone list (or [null]) means: record across all zones that belong to this user.
$user->recordWorkpoint('app_first_visit_day', null, [], null);

Returns WorkpointRecord or null if skipped/disallowed.

workpoint_records and workpoint_period_totals now store user_id and all checks/queries use user_id as the primary key. subject_type/subject_id stay for polymorphic relation metadata only.

When request context has currentUserId, backend always uses that user first. If currentUserZoneId exists, it records only in that zone; otherwise it uses all zones of that current user. Only when currentUserId is null will backend use passed userId + zoneIds.

3. Check if a record already exists (by user_id; same action_key / target shape as when recording — does not re-run rule logic, only looks for a row):

use App\Constants\ProjectConstant;

if ($user->hasWorkpointRecord(ProjectConstant::$workpointCase['project_confirm_assign'], $project)) {
    // already has a workpoint row for this case + project in this zone
}

if ($user->hasWorkpointRecord('app_first_visit_day')) {
    // no-target case: matches rows with null target
}

// Optional: explicit zoneIds and/or userId
$user->hasWorkpointRecord('task_completed_on_time', $task, [1, 2], 123);

4. Get zone IDs that can record this action now (after membership filter + rule check):

// Returns only zone IDs where this action is currently allowed for this user.
$allowedZoneIds = $user->canWorkpointRecordZoneIds('task_completed_on_time', $task);

// Optional: limit candidate zones and/or force user id.
$allowedZoneIds = $user->canWorkpointRecordZoneIds(
    'task_completed_on_time',
    $task,
    [1, 2, 3], // optional candidate zones
    123        // optional user id override
);

canWorkpointRecordZoneIds() returns array<int, int>:

  • First filters zones to zones the user is a member of.
  • Then checks each zone with the configured rule (check) for that action key.
  • Returns only zones that pass the rule at call time.

API

All under {packages-core.api_prefix}/{workpoint.api_prefix}/ (e.g. api/knf/workpoint). Requires X-Knf-Token; zone from X-Knf-Zone-Id.

Method Endpoint Description
GET top?period=day|week|month|year&limit=10 Top users by points in period (zone-scoped).
GET rules?language=vi|en Merged rules (default + zone overrides). Returns rules, language, isManager.
POST rules/save Save one zone case override (manager). Zone from X-Knf-Zone-Id. Body: case_key, points, check, period?, cap?, descriptions?.
POST rules/reset Reset zone rules to default for the current zone (manager). Zone from X-Knf-Zone-Id; no body required.
GET history/me?period=day|week|month|year&cursor=&language=vi|en Current user: point log in period (cursor = last record id for “load more”), totals, ranks, today_by_rule, isManager.
GET history/user/{userId}?period=&cursor=&language= Same payload for one user (self always; others only if manager for zone / server).
GET admin/members?cursor= Manager only. Cursor-paginated users who have workpoints in the zone (next_cursor is base64 JSON).

History summary responses include today_by_rule: per rule, earned is points earned today; max_points is the max total points for that rule when the check is capped — for count_cap_per_period it is points × cap (cap = max awards per period); for first_time / first_time_per_period / first_time_per_target it is points (one award). max_points is null when unlimited (none or no cap on count rules).

Summary

Step Action
Install composer require kennofizet/workpoint-backend
Config php artisan vendor:publish --tag=workpoint-config
Cases config (optional first publish) php artisan vendor:publish --tag=workpoint-cases-config
Migrations php artisan vendor:publish --tag=workpoint-migrations then php artisan migrate
Model use HasWorkpointRecords;$model->recordWorkpoint(...), $model->hasWorkpointRecord($key, $target?), $model->canWorkpointRecordZoneIds($key, $target?)

More in config file comments (events, listeners, rules).