Adds an `integration` job to PR checks: spins up a throwaway postgres:16
container on a random host port (isolated from prod / pelagia_test / staging),
applies migrations, dev-seeds, and runs `pnpm test:integration` (108 tests).
Container is always torn down via an EXIT trap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- resubmit: updatePo distinguishes intent "resubmit" (from EDITS_REQUESTED)
from "submit" (from DRAFT); test now sends "resubmit" (makePoForm widened).
- payment: MANAGER now holds process_payment, so the "wrong permission"
negative test uses TECHNICAL (which lacks it).
- vendor: provideVendorId rejects on a missing vendorId *code*; seeded
unverified vendors carry codes, so create a genuinely code-less vendor.
Full integration suite: 108/108 passing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The integration suite had rotted against the app. Systematic fixes:
- seed refs: MV Ocean Pride/Sea Breeze/TECH-OPS → current seed entities
- helper appendLineItem set lineItems[i].description; createPo now keys on
lineItems[i].name → zero line items. Fixed to .name.
- vendor gating: lifecycle setups (approval/payment/receipt) now attach the
seeded verified vendor before approval.
- cleanup: POAction has no onDelete:Cascade, so deletePo(sByTitle) now removes
POAction rows before the PO.
- import-api: fixture committed to tests/fixtures/Sample_PO.xlsx (was an
absolute path to a non-existent dir).
- products-search: code search assertion .every → .some (search spans fields).
11 failures remain (behavioral drift — separate commit).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
deploy.yml only triggers on v* tags; bare semver tags (0.2.0/0.2.1/0.2.2) silently
do not deploy. Clarify: push the v* tag specifically (not 'master --tags').
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Satisfies the contribution-policy test gate for the add/edit-page refactor.
Covers: createCompany returns the new id, code upper-casing, duplicate-code
rejection, updateCompany in-place edit, and manage_vessels_accounts gating.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Overhaul the manager dashboard "Total Approved Spend" stat card per the
reporter's request:
- Swap the DollarSign lucide icon for IndianRupee (rupee symbol).
- Render the amount in the Indian short scale (lakh/crore) via a new
`formatCompactINR` helper, e.g. ₹2 Cr, ₹49 L, ₹75 K, instead of the full
₹49,00,000.00.
`formatCompactINR` rounds to at most 2 decimals, trims trailing zeros, keeps
the ₹ prefix and sign. The DollarSign icon is retained for the Accounts
"Payment Queue Value" card; the precise `formatCurrency` is kept for tables.
Adds unit tests covering crore/lakh/thousand/sub-thousand, boundaries, zero,
string input, negatives and non-finite input.
Fixes#50
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The company form outgrew the modal once the branding (logo/stamp) section
was added. Add/edit now live on their own routes:
- /admin/companies/new
- /admin/companies/[id]/edit
- createCompany returns the new id and the create flow lands on the edit
page so logo/stamp can be uploaded immediately
- list "+ Add Company" is a link; row "Edit" navigates to the edit page
- branding is its own card on the edit page (independent uploads)
- list page no longer mints a presigned URL per company (moved to edit)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Companies can upload a logo and a stamp/seal (Admin → Companies → Edit →
Branding); both render on exported PDF and XLSX purchase orders. A fixed
brand-colour bar (#92D050, matching the sample PO) runs along the bottom of
every export.
- Company.logoKey / stampKey + migration
- buildCompanyAssetKey() deterministic storage keys (overwrite-in-place)
- uploadCompanyAsset / removeCompanyAsset server actions (≤4MB PNG/JPG/WebP,
manage_vessels_accounts gated)
- CompanyBrandingUploader in the company edit dialog with live previews
- Export route embeds logo (top-left), stamp (signatory block) and brand bar
in both ExcelJS and print-HTML paths
- Unit test (storage keys) + integration test (branding actions)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New .forgejo/workflows/staging.yml rebuilds ppms-staging to latest master on every
merge (push to master) on the host runner, so staging always mirrors the trunk;
concurrency-coalesced + workflow_dispatch. Also drops --update-env from staging-up.sh
(and unsets FORGEJO_*) so the runner's ephemeral token can't leak into ppms-staging.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The PO line-items Unit of Measure dropdown only offered hr/day among
time-based units. Add week, month and year so durations beyond days can
be selected, as requested. UOM_OPTIONS is the single source of truth and
`unit` is validated as a free-form string, so no schema/validation change
is needed.
Fixes#44
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The deploy job runs inside the Forgejo Actions runner, whose env includes an
ephemeral FORGEJO_TOKEN (per-job token, revoked when the job ends). 'pm2 restart
--update-env' injected it into ppms, where it shadowed the real PAT in .env
(Next.js won't override an already-set process.env var) — so the Report Issue
button 401'd once the job token expired. Plain restart keeps the daemon's clean env.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Triage now writes CLAUDE_TRIAGE_TYPE.txt (bug|feature) and the watcher applies the
matching label to every triaged issue (additive). Previously bug/feature labels were
never applied by the pipeline. Also shows the type in the triage comment.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Report Issue button (older deployed build) stamps claude-queue at creation, so
triage skipped those issues and they went straight to auto-fix (e.g. #37, a large
localization feature that should be interactive).
Triage now claims a portal issue until it carries a new `triaged` marker (or is
in progress/done) — claude-queue is no longer a skip reason. On routing to
interactive it strips the stray claude-queue; on claude-queue it adds triaged.
Manual queue still works for NON-portal issues (triage never claims those).
Resilient regardless of which button build is deployed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs: retire Docs/ to the project wiki
The design, architecture, and test docs under Docs/ have been migrated to the
Forgejo wiki (the living reference). Remove them here and leave a tombstone
Docs/README.md mapping each old file to its wiki page.
Also gitignore the nested wiki working clone (pelagia-portal.wiki/), which is a
separate repo checked out beside this one.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
Green-lights the test suite so the PR checks can enforce it:
- Fix the NextAuth v5 auth() mock typing across all integration tests (cast to a
simple async fn so mockResolvedValue accepts the session) — clears ~86 errors.
- Fix stale test values: intent 'resubmit'->'submit' / 'save'->'draft'; ParsedImportLine
.description -> .name; approvepo -> approvePo; add missing beforeEach/beforeAll imports.
- permissions: MANAGER *can* process_payment (intentional since e1340b9) — update the
stale assertion.
- po-import-parser: skip the Sample_PO.xlsx fixture tests when the file is absent (it
lives outside the repo); synthetic-workbook tests still cover the parser.
type-check is now 0 errors and unit tests pass (167 passed, 13 skipped). pr-checks.yml
flips type-check (whole project) and unit tests to HARD gates.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
All changes now land via PR. New .forgejo/workflows/pr-checks.yml runs on every PR
to master and (1) fails code PRs that lack a test change, (2) blocks new app-code type
errors. Unit tests are advisory until the baseline is green; lint is omitted (it needs
an interactive ESLint migration). PR template carries the docs/tests checklist.
Also makes the autofix watcher require a test (issue-12 style) + doc updates in every
fix, so its PRs satisfy the new gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reflects this iteration's domain/feature changes across the docs set:
- Cost centre = Vessel only (labelled 'Cost Centre'); costCentreRef/Site removed
- Companies (multi-company invoicing) on POs and exports
- 3-level 6-digit accounting-code hierarchy; leaf-only PO selection
- Structured PO numbers COMPANY/VESSEL/ID/FY (ids from 9000)
- Compulsory payment date; editable poDate; export date = approval date
- Submitter vendor creation (unverified until proven); verifyVendor
- Import PO -> CLOSED with auto vendor/product creation
- Inventory flag; inventory added at approval; partial pay/receipt states
- Microsoft Entra SSO (nullable passwordHash); profile reachable by all roles
- README: roles, domain concepts, db:seed:prod, migrate-before-serve callout
- CHANGELOG: Added/Changed/Fixed for the above
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- App/README.md: add FORGEJO_*/NEXT_PUBLIC_ENV_LABEL env vars and an
'Operations & Automation' section pointing to automation/README.md.
- App/CLAUDE.md: complete the env var list (AZURE_AD_*, FORGEJO_*, GST_SERVICE_URL,
NEXT_PUBLIC_ENV_LABEL) and note the prod-mirror test DB used by autofix/staging.
- .env.example: document NEXT_PUBLIC_ENV_LABEL.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The manager dashboard "Approved This Month" card only counted POs whose
current status is MGR_APPROVED, so approvals that had already moved on to
payment, delivery, or closure dropped out of the count. Managers could not
see what happened to the POs they approved this month.
- Count every PO whose `approvedAt` falls in the current month across all
post-approval statuses (MGR_APPROVED → ... → CLOSED). `approvedAt` is set
once at approval and persists, so it is the correct anchor.
- Introduce a shared `POST_APPROVAL_STATUSES` constant (includes the
previously-omitted PARTIALLY_CLOSED). This also fixes Total Approved Spend
and the vessel/monthly breakdowns, which were silently dropping
partially-received POs.
- Make the card a link into /history with an approval-date filter applied
(?approvedFrom=<startOfMonth>) so a click shows the full set with each PO's
current status, as requested.
- Add `approvedFrom`/`approvedTo` filtering to the history page, its filter
UI, and the reports export route so the deep-link and exports stay in sync.
Scope note: the count remains org-wide, consistent with every other card on
the manager dashboard.
Adds an integration test covering the moved-on case and the date window.
Fixes#32
- staging-up.sh binds the dev server to 127.0.0.1 (tunnel-only, no public access)
and sets NEXT_PUBLIC_ENV_LABEL so the 'INTERNAL DEV / STAGING - NOT PRODUCTION'
banner shows.
- staging-tunnel.cmd: Windows launcher that opens the SSH tunnel + browser
(wired to a desktop shortcut).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Renders a thin fixed banner only when NEXT_PUBLIC_ENV_LABEL is set; production
leaves it unset so nothing shows. Used to mark the staging instance.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The PO history page previously allowed only a single status filter. This
enhances it to accept multiple statuses that are OR-ed together (e.g.
Closed + Approved shows all POs in either state), as requested.
- Status filter is now a multi-select checkbox dropdown that serialises
selections as repeated `status` query params.
- History page and the reports export endpoint read all `status` values
and query with `status: { in: [...] }` (OR semantics).
- Single-status and no-status cases remain unchanged.
Verified OR-query semantics against the test DB and confirmed both routes
compile and respond. type-check passes for the changed files.
Fixes#31
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The test DB mirrors prod, which can be behind master, so the latest code 500s on
columns prod doesn't have yet (e.g. poDate from the optional-PO-date feature).
- staging-up.sh runs prisma migrate deploy after install.
- refresh-test-db.sh re-applies master migrations after each nightly data copy,
so the running staging/autofix DB stays at the schema of the code under test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings up pm2 'ppms-staging' on port 3200 from the latest master, against the
prod-mirror test DB in safe dev mode. Re-run to refresh to newer master.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>