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>
This commit is contained in:
Hardik 2026-06-19 12:12:04 +05:30
parent e31014d45c
commit f17df1ec6b
4 changed files with 45 additions and 32 deletions

View file

@ -21,8 +21,8 @@ The portal is an internal line-of-business app with a well-defined data model, m
| **Charts** | Recharts | Lightweight; composable; works well with server-fetched data in RSC | | **Charts** | Recharts | Lightweight; composable; works well with server-fetched data in RSC |
| **Validation** | Zod | Schema validation shared between server actions and client form validation | | **Validation** | Zod | Schema validation shared between server actions and client form validation |
| **Testing** | Vitest + React Testing Library + Playwright | Unit/integration fast with Vitest; E2E critical paths with Playwright | | **Testing** | Vitest + React Testing Library + Playwright | Unit/integration fast with Vitest; E2E critical paths with Playwright |
| **CI/CD** | GitHub Actions | Lint, type-check, test, build on every PR; deploy on merge to main | | **CI/CD** | Forgejo + Forgejo Actions (self-hosted on the `pms1` server) | Issue→fix→PR pipeline; a release tag (`vX.Y.Z`) triggers a runner that deploys. See [`../automation/README.md`](../automation/README.md) |
| **Hosting** | Vercel (app) + Supabase (Postgres + Storage fallback) | Zero-config deploys; Vercel serverless functions match Next.js well | | **Hosting** | Self-hosted on `pms1` (Ubuntu); Next.js under **pm2**, **PostgreSQL 16** native on the same host; fronted by a Pangolin/Traefik tunnel | Single-VM self-host, no external PaaS; full control of data |
--- ---
@ -497,31 +497,42 @@ All other data operations (create PO, approve, reject, etc.) are Server Actions
## 10. Deployment Architecture ## 10. Deployment Architecture
The app is **self-hosted on a single server (`pms1`, Ubuntu)** — not a managed PaaS.
Public traffic reaches it through a Pangolin/Traefik tunnel; the Next.js app, database,
and the CI runner all live on the same host.
``` ```
┌────────────────────────────────────────────────┐ Internet (HTTPS, pms.pelagiamarine.com)
│ Vercel │
│ │ ┌───────────▼────────────┐
│ ┌──────────────────────────────────────────┐ │ │ Pangolin / Traefik │ reverse proxy + tunnel
│ │ Next.js App (Edge + Node.js) │ │ └───────────┬────────────┘
│ │ - Static assets via Vercel CDN │ │
│ │ - Server Components on Node.js runtime │ │ ┌─────────────────────────────────────────────────────────────┐
│ │ - API routes / Server Actions │ │ │ pms1 (Ubuntu) │
│ └──────────────────────────────────────────┘ │ │ │
└────────────────────────────────────────────────┘ │ ┌──────────────────────────┐ ┌────────────────────────┐ │
│ │ │ │ Next.js app (pm2: ppms) │ │ PostgreSQL 16 (native, │ │
┌────────▼──────┐ ┌────────▼──────────────┐ │ │ `next start`, port 3000 │──▶│ localhost:5432, db │ │
│ Supabase │ │ Cloudflare R2 │ │ │ Server Components/Actions│ │ `pelagia`) │ │
│ PostgreSQL │ │ (document storage) │ │ └──────────────────────────┘ └────────────────────────┘ │
│ (managed, │ │ │ │ │ │
│ auto-backup)│ └────────────────────────┘ │ ├─▶ Cloudflare R2 (document storage, prod) │
└───────────────┘ │ └─▶ Resend (email, prod) │
│ │
┌────────▼──────┐ │ ┌──────────────────────────────────────────────────────┐ │
│ Resend │ │ │ Forgejo (Docker) + Actions runner (pm2) │ │
│ (email API) │ │ │ issue→fix→PR→tag deploy — see automation/README.md │ │
└───────────────┘ │ │ Also: pelagia_test (prod-mirror DB) + staging │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
``` ```
**Deploy flow:** merge a PR to `master`, push a release tag `vX.Y.Z` → a Forgejo
Actions runner checks out the tag into `~/pms`, runs `pnpm install && pnpm build &&
prisma migrate deploy`, and `pm2 restart ppms`. Full runbook in
[`../automation/README.md`](../automation/README.md).
### Environment Variables ### Environment Variables
The set of required variables differs between development and production. The switch is automatic — controlled by `NODE_ENV` (set to `development` by `next dev` and `production` by `next build/start`). The set of required variables differs between development and production. The switch is automatic — controlled by `NODE_ENV` (set to `development` by `next dev` and `production` by `next build/start`).
@ -553,14 +564,16 @@ In development, uploaded files are stored in `.dev-uploads/` at the project root
| E2E | Playwright | Full happy paths per role: create PO → approve → pay → confirm receipt | | E2E | Playwright | Full happy paths per role: create PO → approve → pay → confirm receipt |
| Accessibility | axe-core + Playwright | WCAG violations on key pages | | Accessibility | axe-core + Playwright | WCAG violations on key pages |
CI runs all tests on every pull request. Playwright E2E runs against a preview deployment. Tests run on pull requests via Forgejo Actions. Automated fixes and the staging instance
run integration tests / a dev server against `pelagia_test`, a daily mirror of the
production database (see [`../automation/README.md`](../automation/README.md)).
--- ---
## 12. Development Conventions ## 12. Development Conventions
- **Branch strategy**: `main` (production) ← `staging` ← feature branches (`feat/`, `fix/`, `chore/`). - **Branch strategy**: `master` is the trunk and the source of releases. Work lands via PRs (feature branches `feat/`/`fix/`/`chore/`, or `claude/issue-N` from the automated pipeline); production is whatever `vX.Y.Z` tag is currently deployed. Staging is a deployed instance of latest `master`, not a branch.
- **Commit style**: Conventional Commits (`feat:`, `fix:`, `refactor:`). - **Commit style**: Conventional Commits (`feat:`, `fix:`, `refactor:`).
- **Code quality**: ESLint (Next.js config) + Prettier + TypeScript strict mode; enforced via husky pre-commit hook. - **Code quality**: ESLint (Next.js config) + Prettier + TypeScript strict mode; enforced via husky pre-commit hook.
- **Database migrations**: Never edit `schema.prisma` without generating and committing a migration (`prisma migrate dev`). Migration files are committed and reviewed in PRs. - **Database migrations**: Never edit `schema.prisma` without generating and committing a migration (`prisma migrate dev`). Migration files are committed and reviewed in PRs.
- **Secrets**: Never committed; managed via Vercel environment variable UI and `.env.local` locally (`.env.local` is git-ignored). - **Secrets**: Never committed. On the server they live in `~/pms/App/.env` / `.env.production`; locally in `.env.local` (git-ignored).

View file

@ -12,5 +12,5 @@ Track decisions that need sign-off before the corresponding feature is built. Up
| 6 | Should rejected POs be hard-deleted after a retention period or permanently archived? How long is the retention window? | Legal / compliance | Open | — | | 6 | Should rejected POs be hard-deleted after a retention period or permanently archived? How long is the retention window? | Legal / compliance | Open | — |
| 7 | Should documents (PO attachments, receipts) be publicly accessible via URL, or always served through a signed/authenticated download? | Security review | Open | — | | 7 | Should documents (PO attachments, receipts) be publicly accessible via URL, or always served through a signed/authenticated download? | Security review | Open | — |
| 8 | Are there specific vessels or accounts that certain submitters are restricted to (i.e., row-level vessel permissions), or is any submitter able to raise a PO against any vessel? | Design review | Open | — | | 8 | Are there specific vessels or accounts that certain submitters are restricted to (i.e., row-level vessel permissions), or is any submitter able to raise a PO against any vessel? | Design review | Open | — |
| 9 | What is the expected volume? (POs per day, concurrent users) — affects connection-pool sizing and whether Vercel serverless is sufficient. | Architecture review | Open | — | | 9 | What is the expected volume? (POs per day, concurrent users) — affects connection-pool sizing and `pms1` resourcing. | Architecture review | Open | — |
| 10 | Should Manager analytics (spend by vessel/month) include only CLOSED POs, or all POs from MGR_APPROVED onwards? | Design review | Open | — | | 10 | Should Manager analytics (spend by vessel/month) include only CLOSED POs, or all POs from MGR_APPROVED onwards? | Design review | Open | — |

View file

@ -302,7 +302,7 @@ HTML report at `playwright-report/index.html` after every run.
ambiguous elements (unit price input, line-item rows) so specs don't depend on ambiguous elements (unit price input, line-item rows) so specs don't depend on
implementation details like placeholder text or CSS class names. implementation details like placeholder text or CSS class names.
4. **CI integration** — Run `pnpm test:e2e` in GitHub Actions on every PR. 4. **CI integration** — Run `pnpm test:e2e` in Forgejo Actions (runner on `pms1`) on every PR.
Use `workers: 1` and `retries: 2` (already wired for `process.env.CI`). Use `workers: 1` and `retries: 2` (already wired for `process.env.CI`).
5. **Visual regression** — Add Percy or Playwright's built-in screenshot comparison 5. **Visual regression** — Add Percy or Playwright's built-in screenshot comparison

View file

@ -218,10 +218,10 @@ The following areas are not yet covered by automated E2E tests:
## 9 · Continuous Integration (Planned) ## 9 · Continuous Integration (Planned)
When wired into CI (GitHub Actions), the following configuration applies: When wired into CI (Forgejo Actions, runner on `pms1`), the following configuration applies:
```yaml ```yaml
# .github/workflows/e2e.yml # .forgejo/workflows/e2e.yml
- name: Install Playwright browsers - name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium run: pnpm exec playwright install --with-deps chromium
@ -229,7 +229,7 @@ When wired into CI (GitHub Actions), the following configuration applies:
run: pnpm test:e2e run: pnpm test:e2e
env: env:
CI: "true" CI: "true"
DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }} DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }} # e.g. the pelagia_test mirror
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }} NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
NEXTAUTH_URL: "http://localhost:3000" NEXTAUTH_URL: "http://localhost:3000"
``` ```