Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.git
.gitignore
.github
node_modules
pb_data
data
coverage
*.log
.env
.env.*
!/.env.example
src
test
dist
README.md
PLAN.md
ARCHITECTURE.md
RESEARCH.md
IMPLEMENTATION_SPEC.md
42 changes: 37 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
PORT=3000
HOST=0.0.0.0
TICKET_TTL_MINUTES=2
UPI_ID=
UPI_PAYEE_NAME=
# Required in normal serve mode
UPI_ID=operator@examplebank
UPI_PAYEE_NAME=PayGate Operator
PAYGATE_API_KEY=replace-with-at-least-24-random-characters
SMS_WEBHOOK_SECRET=replace-with-a-different-at-least-24-character-secret

# Persistence / external URL
PB_DATA_DIR=/app/pb_data

# DDM lifecycle
PAYMENT_TTL=5m
PAYMENT_QUARANTINE=24h

# PocketBase request rate limits
PAYGATE_RATE_LIMITS_ENABLED=true

# Optional Google Messages connector
GMESSAGES_ENABLED=false
# GMESSAGES_SESSION_PATH=/app/pb_data/gmessages/session.json

# Optional signed outgoing payment webhooks
OUTGOING_WEBHOOK_URL=
OUTGOING_WEBHOOK_SECRET=

# Migration-only compatibility for the old Android relay at POST /api/webhook.
# Leave disabled for new deployments. When enabled, WEBHOOK_SECRET is required.
LEGACY_SMS_WEBHOOK_ENABLED=false
WEBHOOK_SECRET=

# Other legacy prototype aliases still understood during migration:
# UPI_NAME=PayGate Operator
# TICKET_TTL_MINUTES=5
# AMOUNT_QUARANTINE_HOURS=24
# PAYMENT_WEBHOOK_URL=
# PAYMENT_WEBHOOK_SECRET=

# Tests only; do not enable in production.
PAYGATE_TEST_MODE=false
89 changes: 49 additions & 40 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,61 @@ name: CI

on:
push:
branches: [main]
branches: [main, rebuild-pocketbase]
pull_request:

permissions:
contents: read

jobs:
test:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v6

- uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true

- uses: actions/setup-node@v6
with:
node-version: 22
node-version: "22.23.1"
cache: npm
- run: npm ci
- run: npm run typecheck
- run: npm test

deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Wait for Dokploy auto-deploy
- name: Install frontend dependencies
run: npm ci

- name: Frontend dependency audit
run: npm audit --audit-level=high

- name: Frontend typecheck
run: npm run typecheck

- name: Frontend production build
run: npm run build

- name: Go formatting check
shell: bash
env:
URL: ${{ secrets.DOKPLOY_URL }}
COMPOSE_ID: ${{ secrets.DOKPLOY_APP_ID }}
TOKEN: ${{ secrets.DOKPLOY_API_TOKEN }}
SHA: ${{ github.sha }}
run: |
echo "Waiting for Dokploy deployment for commit ${SHA}..."
sleep 30
for i in $(seq 1 30); do
DATA=$(curl -s "${URL}/api/compose.one?composeId=${COMPOSE_ID}" -H "x-api-key: ${TOKEN}")
STATUS=$(echo "$DATA" | jq -r --arg sha "${SHA}" '
[.deployments[] | select(.description | contains($sha)) | .status][0] // "not_found"
')
echo "Attempt ${i}: commit ${SHA} deployment status = ${STATUS}"
if [ "${STATUS}" = "done" ]; then
echo "Deployment succeeded"
exit 0
elif [ "${STATUS}" = "error" ]; then
echo "Deployment failed"
exit 1
elif [ "${STATUS}" = "not_found" ]; then
echo "Deployment not yet created by Dokploy..."
fi
sleep 10
done
echo "Timed out waiting for deployment"
exit 1
run: test -z "$(gofmt -l cmd internal migrations)"

- name: Diff whitespace check
run: git diff --check

- name: Go tests
run: go test -count=1 ./...

- name: Go race tests
run: go test -race -count=1 ./internal/...

- name: Go vet
run: go vet ./...

- name: Static analysis
run: go run honnef.co/go/tools/cmd/staticcheck@v0.7.0 ./...

- name: Go vulnerability scan
run: go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...

- name: Build production container
run: docker build --pull -t paygate-ci:${{ github.sha }} .
87 changes: 32 additions & 55 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,63 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
**/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build
/data
/src/server/admin/public
# Dependencies
node_modules/

# Runtime data (PocketBase / legacy prototype)
pb_data/
data/
*.db
*.db-shm
*.db-wal

# Build/test output
dist/
build/
coverage/
*.test
*.out
*.tsbuildinfo

# misc
.DS_Store
# Environment / secrets
.env
.env.local
.env.production
.env.*.local
*.pem

# debug
# Logs / temporary files
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env
.env.local
.env.production
/pg-testing*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
.DS_Store
.tmp/
tmp/

# Tooling
.vscode/
.idea/
.vercel/
.dev.vars
.wrangler

# build artifacts
/dist

# test files
test*.js

# logs & test output
*.log
e2e_error.txt
test-out.txt
mail.txt
e2e_log*.txt
.wrangler/
Loading