MyZubster Engineering Dev Log
Sepolia E2E Infrastructure, Google OAuth Validation, Runtime Stabilization and the Road Toward a Production-Grade Platform
Over the last development cycle, we focused on one of the least visible but most important parts of the MyZubster architecture: making the development and Sepolia environments deterministic enough to support real authentication, blockchain payment validation, persistent backend services, and auditable CI/CD workflows.
This was not simply a feature implementation.
The work involved debugging several layers of the system simultaneously:
- Node.js runtime dependencies
- PM2 process supervision
- MongoDB connectivity
- reverse-proxy behavior
- Google OAuth callbacks
- frontend/backend routing
- Sepolia E2E infrastructure
- Git branch isolation
- secret hygiene
- GitHub CI evidence generation
- deployment diagnostics
The objective is to move MyZubster from a system where individual components work independently toward an environment where the entire lifecycle can be reproduced, tested and eventually promoted safely.
1. Starting Point
The environment initially had several runtime and infrastructure issues that prevented reliable E2E validation.
One of the first failures appeared in the UrbanLab Node.js service:
Error: Cannot find module 'helmet'
Require stack:
- /opt/I-ECO-01/server.js
Inspection of server.js showed that the application required:
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const mongoose = require('mongoose');
const { createServer } = require('http');
const { Server } = require('socket.io');
const winston = require('winston');
However, the original dependency tree only contained:
cors
dotenv
express
mongoose
Three runtime dependencies were missing:
helmet
socket.io
winston
This mismatch caused PM2 to continuously restart the application.
At one point, the process had accumulated millions of restart attempts.
This is an important operational lesson:
A process manager can keep a process alive, but it cannot make an invalid runtime healthy.
PM2 was correctly restarting the process. The actual problem was an incomplete dependency graph.
2. Runtime Dependency Repair
The missing modules were installed and persisted into package.json.
The resulting dependency set included:
{
"cors": "^2.8.5",
"dotenv": "^17.4.2",
"express": "^4.18.2",
"helmet": "^8.3.0",
"mongoose": "^9.9.2",
"socket.io": "^4.8.4",
"winston": "^3.19.0"
}
Module resolution was then explicitly verified.
OK: helmet
OK: socket.io
OK: winston
After repairing the dependency tree, the UrbanLab backend successfully initialized.
Runtime output confirmed:
Server started on port 5002
MongoDB connected
The health endpoint returned:
{
"status": "ok",
"service": "I-ECO-01",
"mongodb": "connected"
}
More importantly, PM2 stability was tested over time.
The PID remained unchanged and the restart counter stopped increasing.
This confirmed that the restart loop had actually been eliminated rather than temporarily hidden.
3. PM2 Runtime Stabilization
The next step was validating the persistent process topology.
The VPS currently runs multiple independently supervised services, including:
cloudflared
myzubster-sepolia-e2e
myzubster-social
myzubster-web
urbanlab
For the Sepolia backend, we verified that the process remained online after restart and that a stable PID was assigned.
After the final restart:
myzubster-sepolia-e2e → online
PID → 1152840
The active PM2 process list was then persisted using:
pm2 save
which generated:
/root/.pm2/dump.pm2
This matters because runtime recovery must survive more than an individual shell session.
A service that works until the VPS reboots is not a completed deployment.
4. MongoDB Connectivity
Database connectivity was validated alongside application startup.
The backend reported:
MongoDB connected
and the public health path remained responsive.
The architecture also contains a database gate around routes requiring persistence.
Conceptually:
HTTP request
│
▼
requireDatabase
│
├── MongoDB available ──► route handler
│
└── MongoDB unavailable ──► HTTP 503
This prevents database-dependent operations from silently executing against an unavailable persistence layer.
Instead, failure becomes explicit and observable.
5. Google OAuth Investigation
The next major objective was Google OAuth.
The public provider endpoint confirmed:
{
"success": true,
"data": {
"providers": {
"google": true,
"github": false,
"facebook": false
}
}
}
This result was reproduced against both the local backend and the public Sepolia endpoint.
Therefore:
Google → enabled
GitHub → disabled
Facebook → disabled
The provider configuration itself was not the primary problem.
The investigation moved deeper into the OAuth callback lifecycle.
6. OAuth Callback Observability
Temporary instrumentation was introduced at multiple points in the OAuth flow.
The goal was to answer a specific question:
Does Google's callback actually reach the intended backend process with the expected OAuth parameters?
Instrumentation captured:
method
path
host
x-forwarded-host
x-forwarded-proto
code presence
state presence
error presence
A clean callback produced:
[HTTP-GOOGLE-CALLBACK] {
method: 'GET',
path: '/api/auth/social/google/callback',
host: '127.0.0.1:5010',
forwardedHost: null,
forwardedProto: 'https',
hasCode: true,
hasState: true,
hasError: false
}
This result was extremely useful.
It demonstrated that:
- Google reached the callback.
- The callback reached the Node.js backend.
- The authorization
codewas present. - OAuth
statewas present. - Google did not return an OAuth-level error.
- HTTPS information survived the proxy path.
- The backend was listening behind the expected local port.
The effective request path is therefore approximately:
Google
│
▼
https://sepolia.myzubster.com
│
▼
reverse proxy / tunnel
│
▼
127.0.0.1:5010
│
▼
Express
│
▼
/api/auth/social/google/callback
That eliminated several possible failure classes at once.
7. OAuth Session Error Isolation
During investigation, an earlier callback produced:
[OAUTH-CALLBACK-ERROR] {
provider: 'google',
message: 'Sessione OAuth mancante. Riavvia il login dal pulsante MyZubster.'
}
Instead of assuming the provider itself was broken, logs were reset and the authentication flow was reproduced from a clean state.
The backend logs were truncated intentionally before the next test so historical errors could not be confused with current behavior.
After the clean test:
ERROR LOG
empty
while the output log showed the callback arriving correctly.
This distinction is operationally important.
Historical log entries are not evidence of a current failure.
For authentication debugging, each reproduction should ideally have a clearly bounded observation window.
8. Temporary Instrumentation Cleanup
Once the callback path had been verified, temporary HTTP-level debugging was removed from server.js.
The diagnostic block used during investigation was intentionally not kept as permanent production code.
Syntax validation was then performed again:
node --check server.js
Result:
backend syntax OK
Temporary backup files created during the investigation were also identified and removed from the Git working tree.
This left the repository in a controlled state instead of accidentally committing debug artifacts.
9. Permanent OAuth Error Logging
One diagnostic improvement was intentionally retained.
Previously, callback errors were handled essentially as:
catch (error) {
redirectError(res, error.message, provider);
}
This made failures visible to the browser but provided limited server-side evidence.
The callback now records a concise structured error:
catch (error) {
console.error('[OAUTH-CALLBACK-ERROR]', {
provider,
message: String(error?.message || error)
});
redirectError(res, error.message, provider);
}
This gives operators useful information without intentionally logging OAuth tokens or credentials.
The objective is not maximum logging.
The objective is minimum sufficient observability.
10. Secret Hygiene
Before committing anything, the working tree was explicitly inspected.
Special attention was given to:
.env
.env.local
.env.*.local
frontend/.env
backend/.env
The repository's .gitignore already excludes these files.
Staging was also checked independently to ensure no environment file had entered the Git index.
Result:
No ENV files staged
The modified files were inspected for obvious credentials, tokens or secrets before commit.
No evident secret was found in the intended patch.
This is particularly important for OAuth work because debugging often involves credentials, authorization codes and provider configuration.
Those values must never become part of the repository history.
11. Frontend Proxy Investigation
During troubleshooting, a Create React App development proxy was considered:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://127.0.0.1:5010',
changeOrigin: true
})
);
};
However, inspection showed:
http-proxy-middleware → not installed
Rather than introducing an unnecessary dependency or accidentally changing the deployment topology, the temporary proxy experiment was removed.
This kept the final change set focused on the problem actually being solved.
12. Repository Cleanup
Several investigation backups existed temporarily:
server.js.before-oauth-http-debug-...
server.js.oauth-working-...
socialAuthController.js.backup-debug
socialAuthController.js.before-google-token-debug
socialAuthController.js.before-oauth-debug
socialAuthController.js.oauth-working-...
These files were useful during live debugging but were not appropriate repository artifacts.
They were removed before the final commit.
After cleanup, the Git working tree contained only the intended source modification.
13. The Final Commit
The OAuth diagnostics improvement was isolated into a dedicated commit:
02f06f22
fix(auth): improve OAuth callback error logging
The commit modified only:
src/controllers/socialAuthController.js
The patch consisted of:
19 insertions
2 deletions
This was deliberate.
Infrastructure debugging often touches many files temporarily. A good final commit should contain the solution, not the entire debugging history.
14. Branch Isolation
The work was performed on:
vps/sepolia-e2e-test
The branch was pushed to the developer fork:
danieldirimini-myzubster/myzubster
and configured to track:
origin/vps/sepolia-e2e-test
The repository was clean after the push.
This provides a reproducible boundary between:
production/main development
│
└── isolated Sepolia validation branch
rather than making ad-hoc changes directly against the canonical branch.
15. Pull Request Created
The work was submitted upstream as:
PR #1394
fix(auth): improve OAuth callback error logging
The PR targets:
test/eth-sepolia-e2e-validation-20260925
from:
vps/sepolia-e2e-test
The PR currently contains one commit and one changed file.
GitHub reports the PR as mergeable, meaning there is currently no Git merge conflict blocking integration.
The PR was intentionally scoped to the OAuth callback diagnostics discovered during Sepolia E2E validation.
16. CI/CD Evidence Gate
Opening the PR triggered the project's:
Continuous Evidence Gate
The pipeline performs substantially more than a basic syntax check.
The observed stages include:
Set up job
│
▼
Checkout
│
▼
Set up Node
│
▼
Install exact dependency tree
│
▼
Run tests
│
▼
Run vulnerability audit
│
▼
Generate CycloneDX SBOM
│
▼
Build evidence manifest
│
▼
Upload auditable evidence
At the latest inspection, environment setup, checkout, Node setup and exact dependency installation had completed successfully.
The test stage was running.
This is an important architectural direction for MyZubster.
A successful change should eventually mean more than:
"It works on the VPS."
It should mean:
source
+
tests
+
dependency reproducibility
+
security audit
+
SBOM
+
evidence manifest
+
deployment validation
17. Sepolia E2E Work Already Present
The branch sits on top of a larger Sepolia payment-validation effort.
Relevant preceding commits include work for:
real-wallet Sepolia E2E harness
Sepolia E2E verifier
Sepolia E2E runbook
manual Sepolia evidence workflow
independent payment verifier
Sepolia ETH sandbox lifecycle
MetaMask payment UI tests
This means OAuth debugging is not an isolated feature.
It is part of a broader effort to establish a real sandbox where identity, wallet interaction, payment execution and backend persistence can eventually be tested together.
The target is a complete lifecycle:
User
│
▼
Authentication
│
▼
MyZubster Identity
│
▼
Wallet
│
▼
Marketplace / Service
│
▼
Sepolia Transaction
│
▼
Blockchain Verification
│
▼
Backend Persistence
│
▼
Application State Transition
│
▼
Auditable Evidence
18. What We Have Successfully Proven
At this stage, we have evidence for several important properties of the environment.
Runtime
Node.js services can remain stable under PM2 after dependency correction.
Database
MongoDB connectivity is available to the relevant backend environment.
Public routing
The Sepolia backend can be reached through the public endpoint.
OAuth provider discovery
Google is reported as enabled by both local and public provider endpoints.
OAuth transport
Google's callback reaches the intended backend with both code and state.
Proxy behavior
The callback reaches the internal service through the HTTPS-facing infrastructure.
Error observability
OAuth callback failures now produce concise structured server-side diagnostics.
Secret handling
Environment files were excluded from staging and were not intentionally committed.
Git hygiene
Temporary debugging artifacts were removed before the final commit.
Branch isolation
The work exists on a dedicated E2E validation branch.
Upstream integration
A dedicated pull request now exists for review.
CI evidence
The upstream CI evidence pipeline is executing against the exact commit submitted for integration.
19. What Is Not Finished Yet
This distinction is critical.
We have made substantial progress, but this does not yet mean that the entire MyZubster production architecture is complete.
Several layers still require additional work.
19.1 CI Must Complete
The active evidence gate must finish successfully.
In particular:
tests
vulnerability audit
SBOM generation
evidence manifest
evidence upload
need final confirmation.
A locally working OAuth callback is not sufficient reason by itself to merge.
19.2 OAuth Needs Full Application-Level Verification
Transport-level success has been demonstrated.
The next level is proving the entire application state transition.
We want to validate:
Google authorization
│
▼
callback
│
▼
provider profile retrieval
│
▼
verified MyZubster account
│
▼
social-login result ticket
│
▼
frontend redirect
│
▼
ticket exchange
│
▼
authenticated frontend session
Each boundary should have explicit success and failure tests.
20. OAuth State and Session Hardening
The earlier:
Sessione OAuth mancante
error demonstrates why OAuth state management deserves dedicated tests.
The system should explicitly test:
valid state
missing state
expired state
replayed state
invalid state
provider mismatch
callback without code
provider-denied authorization
expired login result ticket
reused login result ticket
The long-term goal should be to make OAuth state transitions deterministic and testable rather than dependent on manual browser observation.
21. GitHub and Facebook Providers
Provider discovery currently reports:
google = true
github = false
facebook = false
Therefore Google should be treated as the currently validated provider.
GitHub and Facebook should not be described as completed authentication integrations until they are enabled and tested through equivalent E2E flows.
GitHub deserves particular attention because the controller already contains logic related to GitHub automation authorization and encrypted access-token storage.
That path should eventually receive separate security and authorization tests.
22. Payment E2E Completion
The broader objective is not only authentication.
The Sepolia environment exists to validate real application flows against Ethereum's Sepolia test network.
The desired payment lifecycle is approximately:
Buyer
│
▼
MetaMask
│
▼
Sepolia transaction
│
▼
transaction hash
│
▼
MyZubster backend
│
▼
chain verification
│
├── wrong chain → reject
├── wrong receiver → reject
├── wrong amount → reject
├── failed tx → reject
└── valid payment → accept
│
▼
persist state
│
▼
marketplace order
The important property is that the backend must verify blockchain truth independently.
The browser must never be considered authoritative merely because it reports a successful transaction.
23. Idempotency
Payment verification must also be idempotent.
A transaction hash should not be usable to settle multiple orders accidentally.
Conceptually:
TX_HASH = 0xabc...
must transition from:
unseen
to:
verified / associated with order X
only once according to the application's business rules.
Repeated requests must not produce repeated financial state transitions.
This needs dedicated automated coverage.
24. Chain Finality Strategy
A production-grade blockchain integration also needs a defined confirmation policy.
A transaction being visible is not necessarily equivalent to a transaction being final enough for the application's risk model.
The architecture therefore needs an explicit rule such as:
transaction found
│
▼
receipt successful
│
▼
correct chain
│
▼
correct recipient
│
▼
correct value
│
▼
N confirmations
│
▼
settled
The exact confirmation threshold should be documented and configurable.
25. Observability Architecture
The OAuth investigation demonstrated the value of structured logs.
The next step should be extending that principle consistently.
Instead of scattered strings such as:
something failed
important events should use structured records:
{
"event": "oauth_callback_failed",
"provider": "google",
"requestId": "...",
"reason": "state_missing"
}
For blockchain verification:
{
"event": "payment_verification",
"chainId": 11155111,
"txHash": "...",
"orderId": "...",
"result": "verified"
}
Sensitive values must remain excluded.
26. Correlation IDs
One particularly useful improvement would be request correlation.
Today an OAuth operation crosses multiple systems:
browser
Google
reverse proxy
Express
MongoDB
frontend redirect
A generated correlation identifier would allow the same logical operation to be traced across those boundaries.
For example:
requestId=oauth_01H...
could appear in every safe diagnostic event related to that authentication attempt.
This would dramatically reduce debugging time without requiring verbose or sensitive logs.
27. Metrics and Alerting
PM2 status is useful operationally, but long-term infrastructure should expose machine-consumable metrics.
Useful signals include:
HTTP request rate
HTTP 4xx rate
HTTP 5xx rate
OAuth success rate
OAuth failure rate
MongoDB connection failures
payment verification failures
RPC latency
blockchain RPC errors
process restart count
memory usage
event-loop lag
The millions of historical UrbanLab restarts illustrate why this matters.
A restart loop should generate an alert quickly rather than being discovered manually.
28. Dependency Reproducibility
The initial UrbanLab incident also revealed a broader engineering requirement.
The repository must be sufficient to reconstruct the runtime.
That means the following must stay synchronized:
source imports
package.json
lockfile
CI dependency installation
deployment dependency installation
If the application imports a package that is absent from the dependency manifest, the build should fail before deployment.
This is precisely the type of issue CI should prevent.
29. Deployment Reproducibility
The long-term deployment goal should be:
git commit
│
▼
CI validation
│
▼
immutable build artifact
│
▼
staging / Sepolia
│
▼
E2E validation
│
▼
promotion
│
▼
production
rather than:
SSH into server
│
▼
edit files
│
▼
npm install
│
▼
restart PM2
Manual VPS work is useful during investigation.
It should not remain the final deployment architecture.
30. Infrastructure as Code
Another logical next step is representing deployment configuration as code.
The desired state of:
Node version
PM2 processes
environment requirements
reverse proxy
ports
health checks
MongoDB connectivity
Cloudflare tunnel
service restart behavior
should be reproducible.
The goal is to be able to rebuild the Sepolia environment from documented configuration instead of relying on historical knowledge of the current VPS.
31. Environment Separation
MyZubster should maintain strict boundaries between:
development
test
Sepolia staging
production
Each environment should have independent:
credentials
OAuth configuration
database
RPC endpoints
wallet configuration
frontend origin
backend origin
logging policy
A Sepolia environment should never accidentally consume production credentials or production payment configuration.
32. Security Model
Authentication and blockchain payments both operate on trust boundaries.
The backend must remain authoritative.
The browser may claim:
Google authenticated me.
The server must verify the provider result.
The browser may claim:
I paid this order.
The server must independently verify the chain.
The browser may claim:
This wallet belongs to me.
Ownership should be demonstrated cryptographically when required.
This leads to a simple architectural principle:
Client claims intent.
Server verifies truth.
33. Target Architecture
The system we are working toward can be represented as:
┌─────────────────────┐
│ Browser │
│ React / Web Client │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Edge / Proxy Layer │
│ TLS / Cloudflare │
└─────────┬───────────┘
│
▼
┌─────────────────────────────┐
│ MyZubster API │
│ Node.js / Express │
│ │
│ Auth │
│ Marketplace │
│ Payments │
│ Wallet │
│ Zorgax │
│ Metaverse │
└──────┬───────────┬──────────┘
│ │
┌────────▼───┐ ┌───▼──────────────┐
│ MongoDB │ │ Blockchain RPC │
│ persistence│ │ Sepolia / Mainnet│
└────────────┘ └──────────────────┘
External Trust Providers
│
┌────────────┼────────────┐
▼ ▼ ▼
Google GitHub Facebook
Around all of this should exist another layer:
CI
security audit
SBOM
tests
logs
metrics
deployment evidence
rollback capability
That operational layer is as important as the application itself.
34. Definition of Done
For this architecture, "done" should eventually have a strict technical meaning.
A feature should not be considered complete merely because a browser demonstration succeeds.
A stronger definition is:
implementation complete
+
unit tests
+
integration tests
+
E2E tests
+
security checks
+
dependency audit
+
no committed secrets
+
observability
+
documented deployment
+
documented rollback
+
reproducible environment
For payment-related functionality, add:
independent on-chain verification
idempotency
chain validation
recipient validation
amount validation
confirmation policy
For OAuth:
state validation
provider validation
ticket expiration
replay protection
safe logging
failure-path tests
35. Immediate Engineering Roadmap
The next development sequence should be:
PR #1394
│
▼
CI Evidence Gate passes
│
▼
review / merge
│
▼
full Google OAuth E2E automation
│
▼
OAuth state/replay/error tests
│
▼
Sepolia payment lifecycle validation
│
▼
idempotency + confirmation policy
│
▼
structured observability
│
▼
deployment reproducibility
│
▼
staging promotion gate
│
▼
production-readiness review
After that, additional providers and higher-level platform features can be introduced on top of a much stronger foundation.
36. Where We Want to Arrive
The ultimate objective is not simply to have Google Login working or to send an ETH transaction on Sepolia.
Those are individual capabilities.
The real target is a platform where a complete operation can be trusted from beginning to end.
For example:
User authenticates
│
▼
Identity is verified
│
▼
User enters marketplace
│
▼
Wallet is connected
│
▼
Transaction is initiated
│
▼
Blockchain records transaction
│
▼
Backend independently verifies transaction
│
▼
Database records authoritative state
│
▼
Application unlocks purchased resource/service
│
▼
Evidence remains auditable
And the entire system should be deployable again from source without depending on undocumented manual VPS state.
That is the engineering milestone we are moving toward:
a reproducible, observable, security-conscious and independently verifiable MyZubster platform spanning Web2 identity, persistent application state and Web3 settlement.
Current Status
At the end of this development cycle:
UrbanLab runtime dependency failure → FIXED
UrbanLab PM2 restart loop → FIXED
MongoDB runtime connectivity → VERIFIED
Sepolia backend public endpoint → VERIFIED
Google provider configuration → VERIFIED
Google callback transport → VERIFIED
OAuth code/state arrival → VERIFIED
Temporary OAuth instrumentation → REMOVED
Persistent OAuth error diagnostics → IMPLEMENTED
Secret/staging hygiene → VERIFIED
Temporary backup files → CLEANED
Dedicated Git commit → CREATED
Developer branch → PUSHED
Upstream PR → OPEN
PR mergeability → CONFIRMED
Continuous Evidence Gate → RUNNING
Full production readiness → NOT YET COMPLETE
The most important result is not any individual fix.
We now have a clearer boundary between what has actually been proven, what remains under validation, and what engineering work is required to transform the Sepolia environment into a reliable promotion gate for MyZubster production releases.
Top comments (0)