Search by

rayzenai / project-management-app

kiran1991

PMOPM — project & task tracking workspace (Laravel + Inertia + Svelte) with a JSON API for companion clients and external systems.

Package info

github.com/rayzenai/project-management-app

Type:project

pkg:composer/rayzenai/project-management-app

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 1

v1.0.0 2026-07-27 09:27 UTC

This package is auto-updated.

Last update: 2026-10-29 06:09:45 UTC


README

Project & task tracking workspace for PMOPM (Office of the Prime Minister and Council of Ministers) — projects → tasks → subtasks, assignments, notes, contacts, teams, members, activity log, notifications, and the 100-point plan tracker — with a JSON API for the companion mobile client and for any other system that needs to read or manage tasks.

This is a standalone application. Everything (models, services, controllers, authorization, Svelte UI, migrations) lives in this repo; it no longer depends on the retired rayzenai/project-management Composer package.

Tech stack

  • Backend: Laravel 13, PHP 8.5, Sanctum (API token auth)
  • Frontend: Inertia.js + Svelte 5, Tailwind CSS v4, Vite
  • Testing: Pest (tests/Feature/Workspace/** covers the domain, tests/Feature/Workspace/Api/** the JSON API)
  • Quality: Laravel Pint, PHPStan/Larastan (level 7), ESLint + Prettier + svelte-check

Requirements

  • PHP 8.5
  • Composer 2
  • Node 22 + npm
  • PostgreSQL — task search uses a pg_trgm migration; the migration no-ops on other drivers (the test suite runs on SQLite) but you lose fuzzy search
  • Redis — cache, sessions, and the queue
  • Docker (optional) — only to run the deployment image locally via ./dock.sh

Quick start

git clone git@github.com:rayzenai/project-management-app.git pmopm
cd pmopm
composer setup

composer setup runs composer install, copies .env.example to .env, generates the app key, runs migrations, and installs + builds the frontend.

Manual equivalent:

composer install
cp .env.example .env
php artisan key:generate
createdb pmopm            # then set DB_* / REDIS_* in .env
php artisan migrate
php artisan db:seed       # creates the PM_SUPER_ADMINS logins
php artisan db:seed --class=SdocProjectsSeeder   # SDOC and its projects (safe to rerun)
npm install
npm run build             # or: npm run dev

Serve with php artisan serve, or composer dev (server + queue listener + Vite, concurrently).

Configuration

Variable Purpose
PM_SUPER_ADMINS Comma-separated emails granted the manage-workspace gate (full super-admin access)
PM_SUPER_ADMIN_PASSWORD Default password used by WorkspaceSuperadminSeeder
PM_TRASH_TTL_DAYS Days a soft-deleted record survives before workspace:prune-trashed removes it (default 30)
PM_REMINDERS_RUN_AT Time of day workspace:send-deadline-reminders runs (default 08:00)

Config files worth knowing:

  • config/project-management.php — task status workflow, super-admins, trash TTL, reminder cadence.
  • config/government.php — the 100-point plan metadata (categories, deadline types, oath date) that drives the plan tracker and task category labels.
  • config/themes.php — the system / light / dark token sets for web and mobile appearance settings.

Using the app

  • / redirects to /workspace.
  • Web (Inertia) — /workspace/*, session auth, branded login at /workspace/login.
  • JSON API — /api/v1/*, Sanctum bearer auth. Full reference in docs/api.md.

Letting another system manage tasks

Mint a token for a service account and call the JSON API with it — no login flow needed:

php artisan workspace:api-token bot@example.com --name=crm-sync [--expires-days=90] [--revoke]

See docs/api.md → Integrating another system.

Console commands

Command Purpose
workspace:api-token Issue / revoke an API token for an external system
workspace:prune-trashed [--pretend] Force-delete soft-deleted rows past the trash TTL (scheduled daily)
workspace:send-deadline-reminders [--pretend] Heads-up / due-today / overdue notifications (scheduled daily at PM_REMINDERS_RUN_AT)

Organizations and roles

The workspace is multi-tenant. Each office or ministry is an organization; its teams, projects and people are invisible to every other organization.

Role Who Can
Super-admin emails in PM_SUPER_ADMINS, in no organization manage organizations and everything in them; make a team cross-organization; make someone an office admin
Office admin a person marked office admin create teams and people in their organization, choose team leaders, see all of it
Team leader leader on a team add people to the team by searching (their organization, or anyone for a cross-organization team), see the team's live progress page and Gantt chart
Member everyone else see their teams, teammates and those teams' projects

New organizations: super-admin opens Organizations, creates one, then adds its office admin from Team (Add person, choose the organization, tick Office admin). The migration that introduced organizations put existing data into one organization named after APP_NAME.

Architecture

Request flow, mirrored across the web and API surfaces:

Route → Controller (thin) → FormRequest::authorize() → Service (returns ServiceResult) → JsonResource

Read CLAUDE.md for the full guide (authorization model, domain model, theming layer, conventions).

Testing & quality

composer test          # config:clear + pint check + phpstan + Pest
php artisan test       # Pest only
composer lint          # Pint (fixes)
composer types:check   # PHPStan
npm run lint           # ESLint (fixes)
npm run format         # Prettier (fixes)
npm run types:check    # svelte-check
composer ci:check      # everything CI runs

CI

GitHub Actions run on every push/PR:

  • .github/workflows/lint.yml — Pint + frontend lint/format
  • .github/workflows/tests.yml — Pest, PHPStan, and the asset build

Docker & deployment

Dockerfile is the deployment artifact, built by Dokploy straight from a git clone. Three stages: Composer vendor → asset build (PHP + Node 22, because the wayfinder Vite plugin shells out to php artisan wayfinder:generate during vite build) → serversideup/php:8.5-fpm-nginx serving on port 8080. AUTORUN_ENABLED=true makes the container run migrate --force, storage:link, and optimize at boot.

Run that exact image locally against your own Postgres and Redis:

./dock.sh build          # build the image and start it on http://localhost:8101
./dock.sh logs           # follow container logs
./dock.sh artisan migrate:status
./dock.sh shell
./dock.sh down

The original PMOPM instance ran as three Dokploy applications off this one image on a separate server (202.45.146.44): pmopm-api (image default, runs migrations via AUTORUN), pmopm-scheduler and pmopm-queue. Its GitHub push webhooks still exist. Workers need AUTORUN_ENABLED=false (so they don't race the web app's migrations) and a disabled Swarm healthcheck (they don't run nginx). See ~/rayzen/DOKPLOY.md §4 for the full playbook.

Production: SDOC instance (https://tasks.sdoc.gov.np)

Production runs on the SDOC VM's own Dokploy (private 10.5.23.138, VPN only; dashboard via ~/rayzen/sdoc/open_dokploy.sh), project tasks / production. It replaced the Kaneo trial (since deleted) on 27 Oct 2026.

Service Notes
tasks-web (esMcfCXzNzINE0Z8bATg1) This Dockerfile, main over HTTPS (public repo), port 8080, domain tasks.sdoc.gov.np with Let's Encrypt
tasks-scheduler (gXpBWLno7vIpZgTwq4p9z) php artisan schedule:work, AUTORUN_ENABLED=false, healthcheck NONE
tasks-postgres PostgreSQL 18.6, database/user tasks
tasks-redis Redis 8.2, password, 128 MB volatile-lru, AOF

No queue worker: nothing is queued, so QUEUE_CONNECTION=sync. Mail uses SDOC's SMTP account (no-reply@sdoc.gov.np). The production env is in Dokploy and in the gitignored, owner-only .env.sdoc, which also holds the seeded super-admin password. The app always runs on Nepal time (Asia/Kathmandu, fixed in config/app.php and the pgsql connection), so the reminders fire at PM_REMINDERS_RUN_AT Nepal time.

GitHub webhooks cannot reach the panel, so deploys are manual. Both scripts need the SDOC VPN and read the VM's credentials from the sibling ../sdoc checkout (ssh.txt, dokploy-access.txt):

git push origin main     # Dokploy builds origin/main, not this checkout
./deploy.sh              # web (migrates at boot), then scheduler; waits for build, rollout and /up
./deploy.sh web          # one service
./dump_tasks.sh          # production DB → dumps/tasks-<timestamp>.dump (gitignored)
./dump_tasks.sh --restore-latest   # replace the local .env database with the last dump