Commit graph

201 commits

Author SHA1 Message Date
debac55a8a ci: enforce PR policy (tests-present + app type-check) and PR template
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>
2026-06-19 12:49:32 +05:30
859be8c8d0 Merge pull request 'fix: Suggestion - allow multiple statuses in the search for PO history' (#33) from claude/issue-31 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/33
2026-06-19 07:00:31 +00:00
b3e6f6181a Merge branch 'master' into claude/issue-31 2026-06-19 06:59:39 +00:00
7713601be7 Merge pull request 'fix: PO details: show all attachments, grouped by type' (#27) from claude/issue-10 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/27
2026-06-19 06:57:08 +00:00
f17df1ec6b docs: update design docs to the actual self-hosted architecture
The original design docs assumed Vercel + Supabase + GitHub Actions. Reality is a
single self-hosted pms1 server (Next.js under pm2, native PostgreSQL 16, Forgejo
Actions runner, Pangolin/Traefik tunnel).

- 02-architecture.md: CI/CD + Hosting rows, deployment diagram (section 10),
  CI/testing note, branch strategy, and secrets location.
- e2e-test-plan.md / e2e-test-framework.md: GitHub Actions -> Forgejo Actions.
- 03-open-questions.md: drop the Vercel-serverless aside.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:12:04 +05:30
e31014d45c docs: document the issue-to-deploy pipeline, staging, and test DB
- 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>
2026-06-19 12:07:55 +05:30
b472c149b4 feat(automation): lock staging to SSH tunnel + dev banner + desktop shortcut
- 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>
2026-06-19 11:59:25 +05:30
b592358db0 feat(app): env-gated banner (EnvBanner) for non-prod environments
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>
2026-06-19 11:56:34 +05:30
Claude (auto-fix)
e94c7f99a3 feat(history): allow filtering PO history by multiple statuses
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>
2026-06-19 11:53:42 +05:30
4da39fe5d1 fix(automation): apply master migrations to the test DB
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>
2026-06-19 11:51:59 +05:30
7daf3091bc feat(automation): staging-up.sh for pre-deploy smoke testing on pms1
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>
2026-06-19 11:40:06 +05:30
12e6d16061 feat(automation): test DB mirror + dev-server env for autofix verification
- automation/refresh-test-db.sh: daily pg_dump of prod (pelagia) into a throwaway
  mirror (pelagia_test) on pms1; cron at 03:30. ~10MB, refresh ~1s.
- Autofix clone ~/pelagia-autofix/App/.env points DATABASE_URL at pelagia_test in
  safe dev mode (no Resend/SSO secrets -> console email, local storage), port 3100.
- Fix prompt: Claude may run integration tests against the test DB and start a dev
  server on port 3100 ONLY; stop it by port (fuser -k 3100/tcp), never broad pkill
  (production also runs a next-server on 3000).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 04:49:15 +05:30
Claude (auto-fix)
4e6175153d fix(po): show all attachments grouped by type on PO details
All PO attachments are stored as PODocument rows whose lifecycle stage
(submission vs delivery) is encoded in the storageKey prefix. The PO
details screen previously listed them in a single flat "Attachments"
block, giving no indication of which were submission documents (invoice,
quotation) versus delivery receipts.

Add lib/attachments.ts to derive a user-facing group from the storageKey
prefix (submission / payment / delivery / other) and render each
non-empty group as a labelled subsection on the PO details screen, in
lifecycle order. Unknown prefixes fall back to an "Other" group so
nothing is ever hidden.

Fixes #10
2026-06-19 04:43:44 +05:30
3e711a171c feat(automation): port issue watcher to bash for pms1 (cron, 24/7)
- automation/claude-issue-watcher.sh: Linux port of the watcher (curl + jq +
  flock). Same triage + fix phases. On Linux the PS 5.1 encoding/array quirks
  don't apply, so it's simpler.
- Auth preflight: no-ops until Claude Code is signed in on the host (or an
  ANTHROPIC_API_KEY is set), so cron can be enabled before sign-in.
- Runs on pms1 under cron every 10 min; Windows scheduled task is disabled so the
  two machines don't race the Forgejo queue.
- .gitattributes pins *.sh to LF.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 04:32:06 +05:30
080dafb473 feat(automation): add triage phase to issue watcher
Portal issues now file with only the 'portal' label. The watcher runs two phases:
  1. Triage — Claude reads each untriaged 'portal' issue (analysis only), posts a
     requirements-breakdown comment, and routes it to 'claude-queue' (auto-fixable)
     or 'interactive' (needs human steering).
  2. Fix — unchanged; processes 'claude-queue' issues into PRs.

The triage breakdown is posted without the bot marker so the fix stage reads it
back as refined requirements.

PS 5.1 fixes found while validating:
  - Send API bodies as UTF-8 bytes (Invoke-RestMethod mangled non-ASCII, e.g. the
    em-dash in Claude's breakdown, so Forgejo rejected the JSON)
  - Build the labels array body by hand (ConvertTo-Json unwraps a single-element
    array to a scalar, which Forgejo rejects)
  - Triage output via two plain files (label + markdown) instead of one JSON blob
    (embedded-newline markdown broke ConvertFrom-Json)
  - Read triage files as UTF-8; additive label POST + a guard so Set-IssueLabels
    can never wipe an issue's labels

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 04:20:21 +05:30
23e5243442 Merge pull request 'fix: Allow attachments (incl. delivery receipt) at delivery confirmation' (#25) from claude/issue-9 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/25
2026-06-18 22:34:37 +00:00
64634ccb5e Merge branch 'master' into claude/issue-9 2026-06-18 22:34:18 +00:00
69901ba079 Merge pull request 'fix: Exported PO must include line item optional description' (#23) from claude/issue-8 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/23
2026-06-18 22:32:27 +00:00
Claude (auto-fix)
9adc93e54a fix(receipt): upsert Receipt record on repeat confirmations with notes
Partial-receipt flows call confirmReceipt multiple times. The nested
`create` on the Receipt relation threw a unique-constraint error on the
second call when both confirmations supplied notes, preventing any
delivery from completing and blocking attachment uploads.

Changed to `upsert` so subsequent confirmations update the existing
Receipt row's notes instead of failing.

Adds integration tests covering full receipt, partial receipt, the
upsert scenario (two confirmations each with notes), and permission guards.

Fixes #9
2026-06-19 04:01:26 +05:30
Claude (auto-fix)
d7be141589 fix(export): include optional line item description in PDF and XLSX exports
The POLineItem model has both a required `name` and an optional `description`
field. The export was only rendering `name` (with description as a fallback),
dropping the optional description entirely when a name was present.

- PDF: renders description in smaller italic text below the item name
- XLSX: appends description on a new line within the cell (wrapText enabled)
- Row height in XLSX now accounts for the extra line when description exists

Fixes #8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 03:43:49 +05:30
600f637de2 Merge pull request 'fix: Closed PO list filters are wrong for manager and submitter' (#21) from claude/issue-6 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/21
2026-06-18 22:10:25 +00:00
464475f62c Merge pull request 'fix: Approved POs should show approval date as the PO date (screen + export)' (#22) from claude/issue-5 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/22
2026-06-18 22:10:06 +00:00
Claude (auto-fix)
5d3b45a3a4 fix(po-detail): show approval date as PO date on detail screen
The PO date field was only displayed when a submitter explicitly set it.
For approved POs without an explicit date, the approval date is now shown.
Precedence: submitter-set poDate → approvedAt → createdAt (matches the
export route which already used this logic).

Fixes #5
2026-06-19 03:39:19 +05:30
Claude (auto-fix)
a37ca068c2 fix(my-orders): correct closed PO filters for manager and submitter
Managers and superusers were silently filtered to only their own
submitted POs because submitterId: userId was applied unconditionally.
Submitters were also shown MGR_APPROVED, SENT_FOR_PAYMENT,
PAID_DELIVERED and REJECTED orders alongside CLOSED ones.

Fix: managers/superusers see all CLOSED POs (no submitterId filter);
submitters see only their own CLOSED POs.

Fixes #6
2026-06-19 03:34:21 +05:30
b19ab695eb feat(automation): add manual run-watcher launcher for desktop shortcut
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 03:28:12 +05:30
5a7145e0cb Merge pull request 'fix: Add items to inventory on PO approval, not on closure' (#20) from claude/issue-7 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/20
2026-06-18 21:53:20 +00:00
06f8f91f1a Merge branch 'master' into claude/issue-7 2026-06-18 21:52:53 +00:00
Claude (auto-fix)
66f2e133b1 fix(inventory): add items to inventory on PO approval, not on closure
Moves the ItemInventory upsert from confirmReceipt (CLOSED) to approvePo
(MGR_APPROVED) so site inventory is visible as soon as a purchase order
is manager-approved, without waiting for full closure.

- approvePo: fetch lineItems, upsert ItemInventory per site PO line item
  that has a productId; revalidate the site admin path.
- confirmReceipt: remove the now-redundant inventory update block.
- Rename approvepo → approvePo for consistency (fixes import mismatch
  in the existing integration test file).
- Add three integration test cases covering: site PO inventory increment,
  line items without productId are skipped, vessel-only POs are untouched.

Fixes #7

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 03:15:56 +05:30
f3557aca97 fix(automation): feed issue comments to Claude; fix PS 5.1 array-unroll bug
- Get-IssueCommentsBlock includes human issue comments in Claude's prompt so
  scope/repro added as comments is acted on (requested for delivery-dropdown #19)
- Critical: capture Api responses to a variable before filtering. Piping the
  Api function's array output straight into Where-Object collapses all issues
  into one object in PS 5.1, so the watcher tried to process #12/#8/#7 at once
- Bot status comments now carry an ASCII <!-- ppms-bot --> marker and are
  filtered out (incl. legacy emoji comments via stable ASCII phrase match) so
  they are never fed back as human input; script kept ASCII-only for ANSI load
- Harden numeric sort/select on issue numbers

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 03:13:34 +05:30
feb6fb745a Merge pull request 'fix: Submitter can set an optional PO date (back/forward-datable)' (#16) from claude/issue-4 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/16
2026-06-18 21:08:10 +00:00
Claude (auto-fix)
25d1164d34 feat(po): allow submitter to set an optional PO date
Add an optional PO Date field to the create and edit PO forms.
Submitters can pick any date (back-dated or forward-dated). If left
blank, the exported PO document falls back to the approved date, then
to the creation date.

Changes:
- Prisma schema: add `poDate DateTime?` to PurchaseOrder
- Migration 20260616000000_add_po_date: ALTER TABLE to add the column
- createPoSchema: add optional `poDate` string field
- new-po-form, edit-po-form: add PO Date picker in Order Information
- create/edit actions: persist poDate to DB
- edit action resubmit snapshot: track poDate changes for manager diff
- po-detail: show PO Date in Order Details; include in resubmit diff banner
- export route: use poDate ?? approvedAt ?? createdAt as the date on
  the exported PDF/XLSX document
- validations.test: fix pre-existing costCentreRef→vesselId mismatch
  and add poDate test cases

Fixes #4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 13:06:12 +05:30
c7a20381f4 Merge branch 'master' of https://git.tunnel.pelagiamarine.com/shad0w/pelagia-portal 2026-06-15 12:01:07 +05:30
e1340b9d1e chore(perm): manager permissions fix 2 2026-06-15 12:00:49 +05:30
8d6ca69edf Merge branch 'master' of https://git.pelagiamarine.com/shad0w/pelagia-portal 2026-06-15 11:58:39 +05:30
0c384d4f86 Merge branch 'master' of https://git.pelagiamarine.com/shad0w/pelagia-portal 2026-06-15 11:51:05 +05:30
a88f27431e chore{perm}: Allow managers to confirm receipt 2026-06-15 11:49:14 +05:30
7a4dab4fe8 Merge pull request 'fix: Add CHANGELOG.md documenting the automated pipeline' (#2) from claude/issue-1 into master
Reviewed-on: https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/2
2026-06-11 11:36:07 +00:00
cc62a9ddf6 docs(automation): note Forgejo 10 broken-PR quirk and close/reopen fix
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:05:52 +05:30
21ead95506 Merge branch 'master' into claude/issue-1 2026-06-11 11:26:26 +00:00
2a9d4f08fa fix(automation): ASCII log prefix to avoid console encoding garble
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:50:02 +05:30
Claude (auto-fix)
d4be4ed0de docs: add CHANGELOG.md documenting the automated issue-to-deploy pipeline
Fixes #1
2026-06-11 16:41:52 +05:30
8b6d4e8ea6 feat(automation): issue-to-deploy pipeline — Report Issue button, Claude watcher, tag-triggered deploy
- Report Issue button in portal header files a Forgejo issue (portal + claude-queue labels)
- Windows scheduled watcher runs headless Claude Code on queued issues and opens a PR
- .forgejo/workflows/deploy.yml deploys v* release tags via the pms1 host runner (pm2 restart ppms)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:39:43 +05:30
4c6b9c670f chore(forgejo): add issue template 2026-06-11 16:04:22 +05:30
2a3fad3eb9 mockup(Reports): add graphs for reporting as mockup 2026-06-11 16:04:06 +05:30
add0f3c19c feat(payments): compulsory payment date when Accounts records payment
- New PurchaseOrder.paymentDate field (migration 20260531000002)
- Backfill: existing POs use paidAt, else the earliest payment action date
- Accounts must enter a payment date with the payment reference
- Date input pre-selected to today, max=today (no future dates)
- Validated server-side (required + not in future) in processPaymentSchema
- paymentDate stored on both full and partial payments; paidAt set from it
- Shown on PO detail (Payment Date) and payment history (prefers paymentDate)
- Integration tests updated; added future-date rejection test

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 08:59:25 +05:30
eb402e03ef fix(profile+vendors): profile reachable for all roles incl SSO; submitter vendor creation
Profile (fixes Safari/SSO no-password redirect):
- User lookup falls back to email when JWT id is stale (SSO users)
- generateDownloadUrl wrapped in try/catch so storage never crashes the page
- Signature gate now uses approve_po permission (approvers only)
- SSO/no-password users see a Set Password form (current-password field hidden)

Vendors:
- New create_vendor permission for all PO roles incl. submitters
- Submitters create UNVERIFIED vendors (no Vendor ID); simple form mode
- verifyVendor action + Verify menu item (manage_vendors)
- Vendors auto-verify when a PO closes with them (receipt confirm + import)
- Add Vendor button on /inventory/vendors

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 18:53:33 +05:30
b5a5097ab5 feat(sidebar): add Sites to Administration section for admin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 08:49:58 +05:30
025b932f70 feat(sidebar): no Purchasing section for admin; Cost Centres in Administration
PURCHASING_MGMT roles narrowed to MANAGER only, so the entire Purchasing
section disappears for ADMIN (they never needed the /inventory/ browse links).
Cost Centres (/admin/vessels) added to the top of ADMIN_ITEMS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 08:46:19 +05:30
2c912caedb fix(searchable-select): reposition portal on scroll/resize
Adds scroll (capture) and resize listeners so the fixed-position dropdown
tracks its trigger as the page scrolls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:49:49 +05:30
2057fc2d8d seed(prod): add 3 companies (PMS, HNR, DEI) with full GST/contact details
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:42:58 +05:30