Skip to content

[general] Add docker-compose for unified local development (Part 3) - #326

Closed
Menjay7 wants to merge 104 commits into
Stellarkard:mainfrom
Menjay7:men
Closed

Menjay7 wants to merge 104 commits into
Stellarkard:mainfrom
Menjay7:men

Conversation

@Menjay7

@Menjay7 Menjay7 commented Jul 29, 2026

Copy link
Copy Markdown

Summary

This PR completes the third phase of the unified local development environment by expanding the Docker Compose configuration. It streamlines project setup, ensures consistent development environments, and improves onboarding by orchestrating all required services through a single command.

Scope
Extended the Docker Compose configuration to support additional application services.
Improved service orchestration, networking, and dependency management.
Enhanced environment configuration for local development.
Optimized developer experience with faster startup and simplified workflows.
Changes
Added and configured missing services required for local development.
Improved service dependency ordering using health checks and startup conditions.
Added persistent Docker volumes for databases and other stateful services.
Configured shared Docker networks for secure inter-service communication.
Introduced environment variable templates and sensible defaults.
Added optional development profiles for running subsets of services.
Improved container naming and logging configuration.
Updated documentation with setup, startup, and troubleshooting instructions.
Benefits
Provides a consistent development environment across all machines.
Reduces onboarding time for new contributors.
Eliminates manual setup of supporting infrastructure.
Improves service reliability during local development.
Simplifies running the entire application stack with a single command.
Creates a stronger foundation for future development and testing workflows.
Testing
Verified all services start successfully using Docker Compose.
Confirmed service discovery and network connectivity between containers.
Validated persistent volumes retain data across container restarts.
Tested environment variable loading and configuration overrides.
Confirmed application functionality with the complete local stack running.
Breaking Changes

None. This PR enhances the local development environment without affecting existing production deployments or application behavior.
Closed #264

nursetechie and others added 30 commits July 27, 2026 22:38
Tests cover table existence after schema init, system_state seed rows,
orders CRUD and PRIMARY KEY uniqueness, api_keys UNIQUE key_hash
constraint, idempotency_keys composite PK behaviour, and WAL/foreign-key
pragma enforcement.
…ask-48

test(db): add unit tests for db.js schema and queries
…role storage

Closes Stellarkard#65
Closes Stellarkard#66
Closes Stellarkard#67
Closes Stellarkard#68

- Fail-safe (Stellarkard#65): new pause()/unpause()/is_paused() circuit breaker.
  pay_usdc/pay_xlm reject new payments with Error::ContractPaused while
  paused, checked before any balance/auth work runs.
- RBAC (Stellarkard#67): wires the existing (previously unused) Role system into
  actual access control — pause() requires at least the Operator role via
  has_role(), while unpause() deliberately requires the stricter DataKey::Admin
  address directly, matching init/upgrade's authority level.
- Storage optimization (Stellarkard#68): migrates role storage from a single growing
  Roles: Map<Address, Role> instance-storage entry to per-address
  DataKey::UserRole(Address) persistent entries. A Map entry re-serializes
  and rent-extends the *entire* map on every single grant/revoke; per-address
  keys mean each grant/revoke touches only its own entry.
- Tests (Stellarkard#66): 12 new tests covering pause/unpause authorization (Operator
  can pause, Viewer/no-role cannot, only the stored admin can unpause),
  paused-payment rejection for both pay_usdc and pay_xlm (including that
  balances are untouched), per-address role storage independence and
  overwrite behavior. All 43 pre-existing tests still pass unmodified.
Reconciles this branch's per-address role storage and RBAC-gated pause
with PR Stellarkard#233's independently-developed pause/RBAC/docs changes that
landed on main in the meantime. Standardizes on a single RBAC-gated
pause(env, caller) requiring at least the Operator role, removes the
resulting duplicate pause/unpause/is_paused definitions, and fixes
init() to grant the Admin role via per-address persistent storage.

Also fixes two test-only compile breaks surfaced by the merge: stale
is_paused() client calls (renamed to is_paused_view()) and a bare
vec! macro in a #![no_std] crate. test_upgrade_works now uploads the
contract's own compiled WASM so the upgrade success path is exercised
against a hash that actually exists in the test ledger, instead of an
arbitrary all-1s hash.
…rbac-storage-tests

feat(contract): pause circuit breaker, RBAC-gated pause, per-address role storage
…275-276-277-281

chore: add CONTRIBUTING guide, commitlint/Husky, CI cache keys, and modern Node deploy script
…trancy guard

Closes Stellarkard#57
Closes Stellarkard#58
Closes Stellarkard#59
Closes Stellarkard#60

- Fail-safe (Stellarkard#60): new rescue_tokens() recovers tokens sent to the contract
  by mistake (a direct transfer bypassing pay_usdc/pay_xlm, which forward
  straight to the treasury). Works for any SAC-compatible token, not just
  the configured USDC/XLM contracts.
- RBAC (Stellarkard#57): rescue_tokens() requires Admin authority — either the stored
  DataKey::Admin address or the Admin role via grant_role. Also adds
  transfer_admin(), a two-step admin handover requiring auth from BOTH the
  current admin and the proposed new admin, so a typo'd address can never
  silently become admin.
- Storage optimization (Stellarkard#58): moves the reentrancy guard from instance to
  temporary storage. The guard only needs to exist for the span of a
  single call (set on entry, cleared before return) — it has no reason to
  count toward the instance storage footprint that every pay_usdc/pay_xlm
  call already reads and rent-extends.
- Documentation (Stellarkard#59): adds module-level //! documentation describing the
  contract's overall architecture, plus full rustdoc for every new
  function (Arguments/Returns/Errors/Authorization/Panics sections,
  matching the existing functions' style).

Also fixes a real gap found while testing rescue_tokens: the deploying
DataKey::Admin address is never auto-granted the Admin *role* (grant_role/
has_role are a separate system) — a role-only authorization check would
have locked a fresh deployment out of its own rescue function until
someone remembered to self-grant the role. rescue_tokens now accepts
either form of admin authority, documented and tested both ways.

Tests: 9 new tests (52 total, up from 43), all pre-existing tests still
passing against the new storage layout.
…ct-rescue-admin-transfer-storage

feat(contract): token rescue, two-step admin transfer, temporary reentrancy guard
…roles-ttl-tests

feat(contract): batch role granting, TTL threshold optimization, doc audit
Add lint-staged pre-commit hook for incremental linting and
pre-push hook to run tests before pushing. Include tests validating
commitlint config and husky hook presence.
Create composite action for consistent Node.js setup with npm cache
across all workflows. Update test.yml to use the shared action.
Add a11y.yml workflow that runs Playwright tests and Storybook
accessibility checks on push, PR, and weekly schedule. Include
tests validating workflow configuration.
Add CI/CD badges to README, document project structure, and
expand getting started section. Update CONTRIBUTING.md with
git hooks documentation and CI/CD pipeline overview.
- Stellarkard#267: Add pre-commit hook with lint-staged. Install lint-staged and
  prettier in SDK devDeps. Pre-commit runs eslint --fix and prettier --write.
- Stellarkard#268: Add axe-core a11y audit CI workflow and e2e/a11y-audit.spec.ts.
  Tests wcag2a/2aa/21a/21aa rules against all dashboard routes.
- Stellarkard#269: Add .prettierrc.json and .prettierignore. Install eslint-config-prettier
  in frontend to disable rules that conflict with Prettier.
- Stellarkard#270: Enhance Playwright config with CI-aware timeouts, screenshot/video on
  failure, HTML+GitHub reporter. Add sharded e2e CI workflow with artifact upload.
…ovements

feat: implement tooling, CI caching, a11y audits, and documentation updates
…-e2e-all

feat: consolidate tooling, add a11y CI, and improve e2e stability
docs: review and update READMEs, docker-compose, cross-browser testin…
…0-261-262

chore: consolidate lint/format configs, stabilize e2e pipeline, extend dependabot coverage
- e2e.yml: run Mobile Chrome/Mobile Safari projects in CI (previously
  configured in playwright.config.ts but never exercised by the matrix),
  resolving each to its underlying chromium/webkit engine for install
  and cache-key purposes. Microsoft Edge stays local-only since
  ubuntu-latest has no system Edge browser.
- security.yml: add npm cache to the audit job (was uncached, causing
  a full npm ci --package-lock-only on every run).
- a11y.yml: cache Playwright browser binaries the same way e2e.yml does,
  instead of reinstalling Chromium on every run.
- docker-compose.yml: wire backend service to stellar_card-backend/.env.example
  via env_file so `docker compose up` gets Stellar/VCC config instead of
  only the four hardcoded vars.
- CICD.md: document the caching strategy across workflows and the E2E
  CI matrix's engine-resolution behavior.
- cross-browser.test.mjs: assert the e2e.yml matrix includes the mobile
  projects.
…-docs-ci-task-1

ci: extend cross-browser matrix, fix caching gaps, wire compose env (Part 1)
JSE19 and others added 25 commits July 29, 2026 13:43
app.js still carried the pre-extraction copy of every handler alongside
the registerRoutes() call that replaced them: /status, /v1/policy/check,
/v1/agent/status and /v1/usage were mounted twice, and a duplicated
`const { registerRoutes } = require('./routes')` made the module a
SyntaxError, so requiring the app failed outright.

Remove the ~470 lines of dead inline handlers and their limiters — every
one already lives in its own module under src/api/ and is mounted by
src/routes/index.js. app.js now owns application middleware, the mount
call, and the terminal error chain, which is what docs/ROUTING.md has
described all along.

Also drop the inline CORS-denial middleware: src/middleware/errorHandler.js
formats that same 403, so the two were competing to answer one error and
disagreed on whether it carried a req_id. The surviving one includes it,
matching every other error response.

errorHandler.js had the same duplicate-declaration problem (`const payload`
twice), which made the whole suite unrunnable. Removed the second one.

Closes Stellarkard#16
… the rest of /v1

Two validation modules had grown in parallel: src/lib/validate.js (body +
query + params, path-to-error-code mapping, non-coercing primitives) and
src/middleware/validate.js (body only, its own error-code options). They
disagreed on whether a 400 carries req_id, and /auth/login used the
narrower one while docs/REQUEST_VALIDATION.md documented the other.
/auth/login was also unrunnable — a bad merge had left two interleaved
copies of its handler body and a reference to an unimported `z`.

- Delete src/middleware/validate.js; /auth/login and /auth/verify now use
  validate() with the error codes their clients already match on.
- Add schemas for POST /v1/agent/claim, POST /v1/agent/status and
  GET /v1/policy/check, the last three routes on the agent surface still
  validating by hand.
- Repoint test/unit/validate.test.js at src/lib/validate.js and cover
  every primitive, the error-code fallback, first-issue-wins ordering,
  and the non-transformation guarantee.

Behaviour this tightens, all previously reachable:

- GET /v1/policy/check accepted "10abc" as 10 and "10.12345" as a valid
  amount, because the guard was isNaN(parseFloat(x)). It now shares the
  decimal shape POST /v1/orders enforces, so a preview cannot succeed for
  an amount the order endpoint would reject.
- POST /v1/agent/claim and POST /auth/verify accepted a whitespace-only
  code. Both handlers .trim() before hashing, so every such request
  hashed to the same empty-string digest.

POST /v1/agent/status keeps the absent-vs-null distinction its partial
UPDATE depends on, and its "provide at least one field" rule moves to an
object-level refinement mapped through defaultErrorCode.

Closes Stellarkard#17
The existing suite pinned schema, constraints and the orders aggregates.
The tables whose queries decide whether work actually happens were only
covered by a table-exists assertion, and every one of them fails quietly:
a retry scan that picks up too few rows drops customer webhooks, and one
that picks up too many re-fires deliveries that already succeeded.

Adds 30 tests across six suites:

- webhook_queue — the retry-scan predicate (undelivered, under the
  attempt cap, due), inclusive next_attempt, the abandoned-delivery
  counter /status reports, and an EXPLAIN QUERY PLAN check that the scan
  still resolves through idx_webhook_queue_next.
- credential expiry — the single predicate shared by login codes, agent
  claim codes and MPP challenges. datetime() yields NULL for an
  unparseable timestamp and NULL comparisons are NULL, so a malformed
  expires_at fails closed; rewriting it as a bare lexical comparison
  would fail open instead. Both halves are pinned.
- system_state — cursor advance-in-place, the missing-key case
  sysStateInt's optional-chained read depends on, and the TEXT-affinity coercion
  that turns a bound 42 into '42.0'.
- stellar_dead_letter — the tx_hash primary key that keeps a ledger
  replay from inflating the /status counter into a phantom incident.
- unmatched_payments — the un-refunded backlog query and its partial
  index.
- policy_decisions — per-key scoping, the composite index plan, and the
  nullable order_id a blocked-before-creation decision needs.

docs/DATABASE_TESTING.md gains a section on the three SQLite behaviours
behind these, and drops a stale reference to claim redemption living in
app.js.

Closes Stellarkard#18
The backend had no machine-readable contract. What documentation existed
was a hand-written endpoint list in README.md that had drifted completely
— it advertised GET /health, POST /api/v1/orders and POST /api/v1/auth/otp,
none of which this server has ever routed.

That is the failure mode worth designing against. Documentation being
absent is obvious to a reader; documentation being present and wrong is
not, and a client trusts it anyway.

- GET /api/openapi.json — OpenAPI 3.0.3 for the public and agent-facing
  surface.
- GET /api/docs — Swagger UI over it. Both unauthenticated (an integrator
  has to read the API before they have a key) and rate limited to 60/min
  per IP like the other public metadata routes.

The document is built by src/api/openapi.js rather than checked in as
YAML, so the values that can drift are imported from the modules that
enforce them: ORDER_STATUSES, the amount pattern, the min/max order
bounds, the metadata byte budget and the webhook URL cap all come from
api/orders.js, and info.version from the same frozen payload
GET /api/version returns. Changing a bound changes the published schema in
the same commit, or it does not change at all.

What that cannot catch is covered behaviourally in
test/integration/openapi.test.js: every documented path must reach a real
handler, every operation marked `security: []` must be reachable without a
credential and every one that is not must return 401, and every route the
app actually mounts must be either documented or listed in
UNDOCUMENTED_PREFIXES with a reason. That last check walks Express's real
layer stack, so a new public endpoint cannot ship undocumented.

The operator surface, the HMAC callback and the feature-flagged MPP routes
are deliberately excluded — no third-party clients, and publishing them to
anonymous readers only helps someone map the deployment.

Swagger UI needs inline script and style, which the app-wide helmet policy
blocks. CSP is re-applied for the /api/docs subtree only, with no external
host permitted, and the test asserts both that the docs page gets the
relaxation and that /api/version does not.

Adds one dependency, swagger-ui-express. It bundles its own assets, so the
page has no CDN dependency and works offline; npm audit reports the same
17 pre-existing advisories before and after.

Also adds the regression tests that keep Stellarkard#16 from recurring: app.js
declares no route handlers, and no path is mounted twice.

Closes Stellarkard#15
- Verified comprehensive documentation in PAYMENT_HANDLER.md
- Complete flow coverage including all phases and helper functions
- Security properties and audit findings (F0-F3) documented
- Operator runbooks and integration points included
- Test coverage documentation verified
…-task-4

fix(backend): standardize error middleware logging
Resolve conflicts across six files:

- src/app.js: keep this branch's route stack and OpenAPI annotations,
  append main's 404 catch-all and Sentry error chain before errorHandler.
  Restore the rateLimit/ipKeyGenerator imports, the router requires, and
  the adminLimiter definition that main's slimmed header dropped.
- src/api/auth.js: take main's validateLogin/validateVerify handler
  signatures (they supersede the inline body-shape guards) and keep the
  @openapi doc blocks from this branch.
- src/api/orders.js: same resolution for validateCreateOrder and
  validateListOrders.
- package.json: keep swagger-jsdoc alongside main's swagger-ui-express.
- package-lock.json: regenerated from main's lock plus swagger-jsdoc.
- README.md: keep main's endpoint table; the block on this branch listed
  routes (/api/v1/orders, /api/v1/auth/otp, /api/v1/webhooks/vcc) that
  do not exist in the codebase.
…ing-a11y-278-279

feat(tooling,a11y): partial implementation for ESLint consolidation and CI a11y audit (Stellarkard#278, Stellarkard#279)
[backend] Add Swagger/OpenAPI documentation
@netlify

netlify Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for stellarcard ready!

Name Link
🔨 Latest commit 9725190
🔍 Latest deploy log https://app.netlify.com/projects/stellarcard/deploys/6a6a4abac9655d000839565b
😎 Deploy Preview https://deploy-preview-326--stellarcard.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@Menjay7 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[general] Add docker-compose for unified local development (Part 3)