Tech Debt
A running register of known shortcuts, dormant code paths, and design/implementation mismatches that we've consciously accepted for now. The goal is visibility: each item records what, why it matters, and a suggested direction — not a commitment to fix on any timeline.
Add new items at the top of the "Open" list with a short, honest description. Move resolved items to "Resolved" with the commit/PR that closed them.
Open
TD-4 · Crewing recruitment vetting gates only partially enforced
What. The 7-stage pipeline (Implementation Spec §5.1)
now enforces C5 (≥1 reference before leaving COMPETENCY_AND_REFERENCES) and a
partial C3 (an expired mandatory document for the seat's rank blocks
verifyDocuments). Two gaps remain:
- C3 "missing required document" is not hard-enforced in the pipeline. Seafarer
documents are collected on the crew profile after onboarding (Phase 4a), so a
candidate usually has none on file mid-pipeline; a presence check would stall the
funnel. Presence is enforced post-onboarding in the verification queue (§8.11).
Once careers intake (A2) uploads documents pre-onboarding, tighten
verifyDocumentsto require every mandatorydocTypeto be present. - C4 experience check is deferred:
Requisitionhas no min-experience criteria field (see A2 AC1). When it lands, compare the candidate'sExperienceRecordtotal against it inverifyDocumentsand flag a shortfall.
Touch points. App/app/(portal)/crewing/applications/actions.ts
(advanceStage, verifyDocuments); App/prisma/schema.prisma (Requisition
min-experience, future).
TD-3 · Inventory increments are not reversed when a PO is cancelled
What. Approving a PO with a siteId increments ItemInventory
(approvals/[id]/actions.ts). The cancel feature (#53) intentionally does not
reverse that increment, so a cancelled approved PO can leave stale stock behind.
Why it matters. Low impact today — inventory writes almost never fire (see TD-1) and the surface is feature-flagged off — but it becomes a correctness bug the moment inventory-on-approval is brought live.
Suggested direction. When inventory goes live, cancelPo should decrement the same
ItemInventory quantities for line items with a productId, guarding against
double-reversal and negative stock. Tracked as Forgejo issue #55; deferred per the
#53 answers.
Touch points. app/(portal)/po/[id]/actions.ts (cancelPo),
app/(portal)/approvals/[id]/actions.ts (the increment), lib/feature-flags.ts.
TD-1 · Inventory-on-approval is dormant in production
What. Approving a PO is meant to add its ordered items to the delivery
site's stock (ItemInventory, keyed by (productId, siteId)). In production the
write almost never fires, and it isn't governed by the inventory feature flag.
Why it matters.
- POs are raised against a Vessel (cost centre), and PO forms set
vesselId, neversiteId. Theif (po.siteId)guard inapprovePo()is therefore almost always false → no inventory is written. Inventory screens render (the flag defaults on) but stay empty. - The
ItemInventoryupsert is not gated byNEXT_PUBLIC_INVENTORY_ENABLED— the flag only hides UI. So "inventory off" would still mutate data if a PO ever did carry asiteId. - Line items are counted only when they already have a
productId, but products are linked/created at payment, not approval — so hand-typed items would be skipped even with a site. - Root cause: inventory is modelled per Site, but POs are per Vessel, and nothing maps a PO to a Site.
Suggested direction. Decide one: (a) give POs a Site (vessel→home-site link
or an explicit delivery-site field) and link products at approval; or (b) gate
the write on the flag / remove it and set NEXT_PUBLIC_INVENTORY_ENABLED=false
in prod to hide the empty screens. Full write-up:
Inventory on Approval.
Touch points. app/(portal)/approvals/[id]/actions.ts (the upsert),
lib/feature-flags.ts, PurchaseOrder.siteId, payments/actions.ts
(syncProductCatalog).
TD-2 · Migrations are not coupled to the build
What. pnpm build runs prisma generate (TypeScript client) but not
prisma migrate deploy. Shipping code whose client expects a new column before
the DB has it throws P2022 … column does not exist at runtime.
Why it matters. This already caused a production incident (the paymentDate
column). The deploy workflow (.forgejo/workflows/deploy.yml) does run
migrate deploy, but manual deploys can skip it.
Suggested direction. Treat "apply migrations before the new build serves
traffic" as the invariant. Options: fold prisma migrate deploy into the
start/release script, or add a pre-deploy check that fails if migrations are
pending. Documented in the App README.md.
Touch points. App/package.json scripts, .forgejo/workflows/deploy.yml,
App/README.md.
Resolved
None yet.
Pelagia Portal (PPMS)
Overview
Build & Run
System
Product
- Feature Catalogue
- Pages and Navigation
- Workflows
- Purchase Orders
- Vendors and GST Lookup
- Inventory and Catalogue
- Inventory on Approval
- Notifications
- File Storage
- Design System
Planned
Quality
Ops
Engineering
Pelagia Portal (PPMS) — internal purchase-order management. Self-hosted on pms1, live at pms.pelagiamarine.com. This wiki tracks the shipped product; authoritative sources are the repo code, App/CLAUDE.md, Docs/, and CHANGELOG.md.