name: CI/CD - ERP Core Monorepo

on:
  pull_request:
    branches:
      - production
    types:
      - closed

jobs:
  backend-build-and-deploy:
    name: Build & Deploy ERP Core Backend
    runs-on: linux
    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout code
        run: |
          git clone \
            --depth 1 \
            --branch production \
            https://oauth2:${{ secrets.ERPCORE }}@gitea.hexdive.com/New_REP_SYSTEM/ERP-core.git \
            .

      - name: Restore backend
        run: dotnet restore Backend/ERPCore.sln

      - name: Publish backend
        run: |
          rm -rf /tmp/erpcore-deploy
          mkdir -p /tmp/erpcore-deploy
          dotnet publish Backend/ERPCore/ERPCore.csproj \
            -c Release \
            -r linux-x64 \
            --self-contained true \
            -o /tmp/erpcore-deploy

      - name: Stop backend service
        run: systemctl stop erpcore.service

      - name: Copy backend to deploy folder
        run: |
          mkdir -p /home/erp/core/publish
          rm -rf /home/erp/core/publish/*
          cp -r /tmp/erpcore-deploy/* /home/erp/core/publish/

      - name: Fix backend ownership and permissions
        run: |
          chown -R erpuser:erpuser /home/erp/core/publish
          find /home/erp/core/publish -type d -exec chmod 755 {} +
          find /home/erp/core/publish -type f -exec chmod 644 {} +
          chmod +x /home/erp/core/publish/ERPCore

      - name: Restart backend service
        run: systemctl restart erpcore.service

      - name: Verify backend
        run: |
          systemctl is-active erpcore.service && echo "Backend service running" || echo "Backend service failed"

  frontend-build-and-deploy:
    name: Build & Deploy ERP Core Frontend
    runs-on: linux
    needs: backend-build-and-deploy
    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout code
        run: |
          git clone \
            --depth 1 \
            --branch Production \
            https://oauth2:${{ secrets.ERPCORE }}@gitea.hexdive.com/New_REP_SYSTEM/ERP-core.git \
            .

      - name: Build frontend Docker image
        run: docker build -t erpcore-frontend:latest Frontend/erp-system

      - name: Stop & remove existing frontend container
        run: |
          docker stop erpcore-frontend 2>/dev/null || true
          docker rm erpcore-frontend 2>/dev/null || true

      - name: Start frontend container
        run: |
          docker run -d \
            --name erpcore-frontend \
            -p 6702:6702 \
            --add-host=host.docker.internal:host-gateway \
            -e BACKEND_ORIGIN=http://host.docker.internal:6701 \
            --restart unless-stopped \
            --memory="512m" \
            --cpus="1.0" \
            --cap-drop ALL \
            --security-opt no-new-privileges \
            erpcore-frontend:latest

      - name: Remove old frontend images
        run: docker image prune -f

      - name: Verify frontend
        run: |
          docker ps --filter name=erpcore-frontend --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" \
            | grep erpcore-frontend && echo "Frontend container running" || echo "Frontend container failed"
This commit is contained in:
Kalana B. Thilakarathna
2026-09-17 13:59:05 +05:30
parent 93f2f1bd3b
commit 03d01d4c4e
61 changed files with 2195 additions and 1245 deletions
@@ -684,15 +684,33 @@ appsettings.Development.json
---
## Open Items (must resolve before coding the relevant phase)
## Open Items
### Resolved during implementation
| # | Item | Resolution |
|---|---|---|
| 2 | Cascade when Confirmed ShopPO is cancelled and Invoice already exists | Cancel is rejected (400) if a linked Invoice exists. Invoice must be voided separately before the ShopPO can be cancelled. No automatic cascade. |
| 3 | Cascade when Confirmed ShopPO is cancelled and it's in a LoadingSheet | Cancel is rejected (400) if the ShopPO appears in any Planned LoadingSheet. Operator must remove it from the sheet first. |
| 4 | `FinalizeInvoiceRequest` payload — free issues field shape | Deferred to a later pass. v1 `POST /api/invoices/{id}/finalize` takes no body and locks the invoice as-is. |
| 5 | Who can confirm a ShopPO? | No role restriction in v1 — any user can confirm. Gating deferred until the auth layer is implemented. |
### Still open
| # | Item | Blocks |
|---|---|---|
| 1 | Who holds `loading.confirm` permission? | Phase 9 — ConfirmAsync auth guard |
| 2 | Cascade when Confirmed ShopPO is cancelled and Invoice already exists | Phase 7 — CancelAsync |
| 3 | Cascade when Confirmed ShopPO is cancelled and it's in a LoadingSheet | Phase 7 — CancelAsync |
| 4 | `FinalizeInvoiceRequest` payload — free issues field shape | Phase 6 — FinalizeAsync |
| 5 | Who can confirm a ShopPO? (agent, office, either?) | Phase 7 — ConfirmAsync permission |
| 1 | Who holds `loading.confirm` permission? | Permission seeding (`loading.populate`, `loading.confirm`) — explicitly noted as **Pending** in the API reference. Must decide role before seeding. |
### New items — identified during frontend refactor (2026-09-17)
| # | Item | Area |
|---|---|---|
| 6 | `order-return-edit-dialog.tsx` — file not verified; client imports it but it was not reviewed during the refactor pass. Needs to be checked for old `orderId`/`OrderResponse` references. | Returns |
| 7 | `sales-visits/` components — any components in this section that interact with sales/orders need auditing against the new ShopPO/Invoice types. | Sales Visits |
| 8 | SysConfig management page not built — the backend has a `SysConfig` model and the `InvoiceCreationMode` config key is read by `ShopPOController`. A UI to view and toggle system config is missing. | Config |
| 9 | InvoiceCreationMode (ModeA vs ModeB) UI branching — the ShopPO confirm button calls `confirm` or `confirmAndCreateInvoice` depending on mode, but the mode is not currently read from the backend. The UI should fetch `GET /api/sys-config` and gate the action accordingly. | Sales / Invoice |
| 10 | Loading Sheet item population UI — `PUT /api/loading-sheets/{id}/items` exists in the API layer but no UI for populating/editing items on a Planned sheet has been built. | Dispatch |
| 11 | `PaymentMethod` enum is missing `Cheque` — per `invoice_collection.md`, the final design includes `Cash`, `Cheque`, `Credit`. The frontend only has `Cash` and `Credit`. Cheque-specific fields (`ChequeNumber`, `ChequeDate`) and `EntryMode` (`RealTime`, `DayEndManual`) are also unimplemented. | Payments |
---