Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ed101f5
feat(mobile): implement responsive layout and mobile UX (#1035)
CodedTricks Aug 29, 2026
d4a27b0
feat:Implement Database Backup & Restore (#1121)
Hunter-baddie Aug 30, 2026
2710ef5
feat(marketplace): add RefinementPanel with faceted search (#1031) (#…
CodedTricks Aug 30, 2026
0f4cd76
Feat/performance optimization (#1123)
De-hunterJS Aug 30, 2026
afd4395
feat: add exponential backoff rate limiting and account lockout (#1112)
BABAT-CODE Aug 30, 2026
8c45522
feat(docker): optimize images with multi-stage builds and .dockerigno…
kenzy-hue Aug 30, 2026
bda4669
feat(audit): immutable audit logging for admin actions with retention…
kenzy-hue Aug 30, 2026
ecb6cd0
feat: service worker for offline support (#1073) (#1104)
bonatkenneth-web Aug 30, 2026
a01a182
docs(api): consolidate openapi.yaml, serve Swagger UI, add Postman co…
progidyken-hub Aug 30, 2026
a7b6d4a
docs: add comprehensive API integration guide (#1111)
BABAT-CODE Aug 30, 2026
62575dc
feat(auth): implement TOTP and email OTP two-factor authentication (#…
kenzy-hue Aug 30, 2026
93d5a95
feat(analytics): integrate Segment/Mixpanel analytics SDK (#1117)
FaveTeamz Aug 30, 2026
50cd4b4
test: add proptest target, marketplace-flow E2E, and integration cove…
gideonpius7-design Aug 30, 2026
b16ca96
Feature/api webhooks serial optimization (#1127)
Prz-droid Aug 30, 2026
396e761
feat(slack): add Slack webhook notifications for team events (#1118)
FaveTeamz Aug 30, 2026
03fec7b
feat: database connection pooling with metrics (#1072) (#1103)
bonatkenneth-web Aug 30, 2026
86299a0
feat(security): strict CORS and security headers (#1077) (#1107)
kenzy-hue Aug 30, 2026
e445e2a
feat(contracts): implement upgrade_governance contract with multi-sig…
FaveTeamz Aug 30, 2026
91e4f02
Fix: implementation of access roles to Soroban contracts (#1122)
NadirMansur Aug 30, 2026
c584668
Merge branch 'main' into feat/mobile-responsive-frontend
dev-fatima-24 Aug 30, 2026
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
248 changes: 248 additions & 0 deletions .env.backup-restore.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
# Database Backup & Restore - Environment Configuration Template

# Copy this file to /opt/carbonledger/.env and fill in the values
# This file is sourced by systemd service files for backup and restore operations

# ── PostgreSQL Configuration ────────────────────────────────────────────────
# Full PostgreSQL connection string
# Format: postgresql://username:password@host:port/database
# Example: postgresql://carbonledger:mypassword@db.example.com:5432/carbonledger
DATABASE_URL="postgresql://carbonledger:changeme@localhost:5432/carbonledger"

# ── AWS S3 Backup Storage ───────────────────────────────────────────────────
# S3 bucket name for PostgreSQL backups
# Terraform automatically creates: {project}-db-backups-{workspace}
# Example: carbonledger-db-backups-production
BACKUP_S3_BUCKET="carbonledger-db-backups-production"

# ── AWS Credentials & Region ────────────────────────────────────────────────
# AWS region where S3 bucket and RDS instance are located
AWS_REGION="us-east-1"

# AWS Access Key ID for backup user
# Recommendation: Use IAM role instead of keys when running on EC2/ECS
# Create a backup-specific IAM user with least-privilege S3 permissions
AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"

# AWS Secret Access Key (keep secure, use IAM role when possible)
# Recommendation: Rotate every 90 days, use secrets manager
AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# ── Slack/Discord Notifications ─────────────────────────────────────────────
# Webhook URL for backup alerts (Slack/Discord)
# Receives notifications when backup fails, restore fails, or SLA violated
# Example: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX
ADMIN_ALERT_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"

# Webhook URL for monthly restore test notifications
# Receives detailed report of monthly restore test execution
# Example: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX
RESTORE_TEST_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"

# ── Optional: CloudWatch Metrics ─────────────────────────────────────────────
# Enable sending backup metrics to CloudWatch
# Requires IAM permissions for cloudwatch:PutMetricData
ENABLE_CLOUDWATCH_METRICS="false"

# CloudWatch namespace for metrics
CLOUDWATCH_NAMESPACE="CarbonLedger/Backups"

# ── Optional: Database Metrics ───────────────────────────────────────────────
# Enable recording metrics to backup_metrics table
# Requires backup_metrics table to exist (see migration)
ENABLE_DATABASE_METRICS="true"

# ── Logging ─────────────────────────────────────────────────────────────────
# Log file locations (must be writable by carbonledger user)
# These are appended to by backup and restore scripts
BACKUP_LOG_FILE="/var/log/carbonledger/backup.log"
BACKUP_METRICS_FILE="/var/log/carbonledger/backup-metrics.json"
RESTORE_TEST_LOG_FILE="/var/log/carbonledger/restore-test.log"

# Log retention (in days) - managed by logrotate
LOG_RETENTION_DAYS="30"

# ── Performance Tuning ──────────────────────────────────────────────────────
# Number of parallel jobs for pg_dump (for large databases)
# Set to number of CPU cores available, 1 to disable parallel backup
# Parallel mode requires --format=directory or --format=custom with -j
PG_DUMP_PARALLEL_JOBS="1"

# Number of parallel jobs for pg_restore (for large databases)
# Set to number of CPU cores available, 1 to disable parallel restore
# Note: May impact database performance, use cautiously
PG_RESTORE_PARALLEL_JOBS="1"

# ── Database Verification ──────────────────────────────────────────────────
# Enable full integrity checks during restore test
# Set to "true" to perform ANALYZE and VACUUM after restore
VERIFY_RESTORED_DATABASE="true"

# Tables to sample for integrity check (comma-separated)
# Sampled during monthly restore test to verify data completeness
SAMPLE_TABLES="carbon_credits,marketplace_listings,users,transactions"

# ── SLA Configuration ───────────────────────────────────────────────────────
# Maximum restore time in seconds (default 30 minutes = 1800 seconds)
# Restore test will warn if restore exceeds this threshold
MAX_RESTORE_TIME_SECONDS="1800"

# Maximum backup size in bytes (default 50GB)
# Alert if backup exceeds this size (may indicate bloat or misconfiguration)
MAX_BACKUP_SIZE_BYTES="53687091200"

# ── Retention Policy ────────────────────────────────────────────────────────
# Backup retention in days (managed by S3 lifecycle policy)
# S3 will automatically delete backups older than this
BACKUP_RETENTION_DAYS="30"

# Versioning: Keep all versions for this many days
# S3 will delete previous versions after this period
VERSION_RETENTION_DAYS="30"

# ── S3 Storage Configuration ────────────────────────────────────────────────
# S3 storage class for backups
# Options: STANDARD, STANDARD_IA, GLACIER, DEEP_ARCHIVE
# STANDARD_IA provides cost savings for infrequently accessed backups
S3_STORAGE_CLASS="STANDARD_IA"

# Enable S3 encryption
# Options: true (AES-256), false (no encryption - not recommended)
ENABLE_S3_ENCRYPTION="true"

# S3 encryption algorithm
# Options: AES256, aws:kms, aws:kms:dsse
S3_ENCRYPTION_ALGORITHM="AES256"

# Optional: KMS key ID for server-side encryption
# Only required if S3_ENCRYPTION_ALGORITHM is aws:kms
KMS_KEY_ID=""

# ── Backup Location ────────────────────────────────────────────────────────
# S3 prefix/folder for daily backups
# Backups organized as: s3://bucket/{BACKUP_PREFIX}/TIMESTAMP.dump
BACKUP_PREFIX="daily"

# Optional: Enable date-based folder structure
# If true, creates: s3://bucket/daily/2024/08/29/TIMESTAMP.dump
USE_DATED_FOLDERS="false"

# ── Advanced: Compression ───────────────────────────────────────────────────
# PostgreSQL backup format
# Options: custom (binary, compressed, fastest restore), plain (text SQL)
PG_BACKUP_FORMAT="custom"

# Compression level for custom format backups
# Range: 0-9 (0=no compression, 9=maximum compression, default=6)
PG_COMPRESSION_LEVEL="6"

# ── Advanced: Connection Pooling ───────────────────────────────────────────
# Connection pool size for pg_dump
# Recommended: 1 for standard backups, higher for large concurrent databases
# If using PgBouncer, ensure pool size is sufficient
BACKUP_POOL_SIZE="1"

# Idle timeout for backup connections (seconds)
# Connection will be terminated if idle for this duration
BACKUP_IDLE_TIMEOUT="600"

# ── Advanced: Staging Database Name ─────────────────────────────────────────
# Default name for restore test staging database
# Monthly test creates temporary database with this prefix
# Format: {STAGING_DB_PREFIX}_TIMESTAMP
STAGING_DB_PREFIX="carbonledger_restore_test"

# Drop staging database after test completes
# Set to false to keep database for manual inspection
DROP_STAGING_DB_AFTER_TEST="true"

# ── Disaster Recovery ───────────────────────────────────────────────────────
# Enable automatic failover to restore if primary backup fails
# If true, will attempt restore from previous day's backup
ENABLE_BACKUP_FAILOVER="true"

# Maximum number of previous backups to attempt failover
FAILOVER_ATTEMPTS="3"

# ── Monitoring Thresholds ───────────────────────────────────────────────────
# Alert if backup takes longer than this (seconds)
# Default: 3600 (1 hour)
BACKUP_TIMEOUT_SECONDS="3600"

# Alert if restore takes longer than this (seconds)
# Default: 1800 (30 minutes)
RESTORE_TIMEOUT_SECONDS="1800"

# Alert if backup size increase exceeds this percentage from previous backup
# Example: 0.20 = alert if size increases by >20%
BACKUP_SIZE_INCREASE_THRESHOLD="0.20"

# ── Slack Message Configuration ─────────────────────────────────────────────
# Slack channel (if using incoming webhooks, this is ignored)
# Only used if SLACK_BOT_TOKEN is set for richer formatting
SLACK_CHANNEL="#database-alerts"

# Slack message format (compact or detailed)
# Options: compact (emoji + status), detailed (includes metrics)
SLACK_MESSAGE_FORMAT="detailed"

# ── Email Alerts (Alternative to Slack) ─────────────────────────────────────
# Enable email notifications (requires mail/sendmail configured)
ENABLE_EMAIL_ALERTS="false"

# Email address for backup alerts
ALERT_EMAIL="ops-team@example.com"

# SMTP server for email alerts (if not using system mail)
SMTP_SERVER="smtp.example.com"
SMTP_PORT="587"
SMTP_USERNAME="alerts@example.com"
SMTP_PASSWORD="changeme"

# ── Local Testing ───────────────────────────────────────────────────────────
# Development mode: skip S3 operations, keep local backups
# Do NOT use in production
DEV_MODE="false"

# Local backup directory (if DEV_MODE=true)
LOCAL_BACKUP_DIR="/tmp/carbonledger-backups"

# ── Compliance & Audit ──────────────────────────────────────────────────────
# Enable audit logging for all backup/restore operations
ENABLE_AUDIT_LOG="true"

# Audit log file location
AUDIT_LOG_FILE="/var/log/carbonledger/backup-audit.log"

# Include database connections in audit log
# May increase log verbosity, useful for compliance
AUDIT_LOG_CONNECTIONS="false"

# ── Backup Window ───────────────────────────────────────────────────────────
# Production backup schedule (hour in UTC)
# Default: 02:00 UTC (see systemd/carbonledger-backup.timer)
BACKUP_HOUR_UTC="02"
BACKUP_MINUTE_UTC="00"

# Staging backup schedule (can be different from production)
STAGING_BACKUP_HOUR_UTC="02"
STAGING_BACKUP_MINUTE_UTC="30"

# Monthly restore test schedule
# Default: 1st of month at 03:00 UTC (see systemd/carbonledger-restore-test.timer)
RESTORE_TEST_DAY="1"
RESTORE_TEST_HOUR_UTC="03"
RESTORE_TEST_MINUTE_UTC="00"

# ── Environment-Specific Flags ──────────────────────────────────────────────
# Set based on environment: production, staging, development
ENVIRONMENT="production"

# Enable debug logging
DEBUG="false"

# Verbose output
VERBOSE="false"

# Dry-run mode (shows what would be done without executing)
DRY_RUN="false"
16 changes: 16 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CARBON_REGISTRY_CONTRACT_ID=
CARBON_CREDIT_CONTRACT_ID=
CARBON_MARKETPLACE_CONTRACT_ID=
CARBON_ORACLE_CONTRACT_ID=
UPGRADE_GOVERNANCE_CONTRACT_ID=
USDC_CONTRACT_ID=

# ── Canary Deployment (contract upgrade traffic splitting) ────────────────────
Expand Down Expand Up @@ -43,6 +44,9 @@ DB_POOL_MAX=10
DB_POOL_TIMEOUT_MS=10000
# Seconds to wait when opening a new TCP connection to PostgreSQL (default: 10).
DB_CONNECT_TIMEOUT_S=10
# Milliseconds before an idle connection is eligible for release (default: 900000 = 15 min).
# Reduce to 300000 (5 min) under memory-constrained environments.
DB_POOL_IDLE_TIMEOUT_MS=900000

# ── Slow Query Logging ────────────────────────────────────────────────────────
# HTTP request duration (ms) above which a "SLOW_QUERY" warning is emitted to
Expand Down Expand Up @@ -94,7 +98,19 @@ VERRA_VCS_API_URL=https://api.verra.org
VERRA_VCS_API_KEY=your_verra_vcs_api_key_here

# ── Alerts ────────────────────────────────────────────────────────────────────
# Slack incoming webhook URL for all team notifications
ADMIN_ALERT_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
# Minimum credit amount that triggers a high-value transaction Slack alert (default: 10000)
SLACK_HIGH_VALUE_THRESHOLD=10000

# ── Analytics ────────────────────────────────────────────────────────────────
# Segment (preferred): set SEGMENT_WRITE_KEY to enable Segment analytics
SEGMENT_WRITE_KEY=
# Required for GDPR deletion requests via Segment Regulations API
SEGMENT_WORKSPACE_SLUG=
SEGMENT_ACCESS_TOKEN=
# Mixpanel (fallback): set MIXPANEL_TOKEN to use Mixpanel when Segment is not configured
MIXPANEL_TOKEN=

# ── Database Backups ──────────────────────────────────────────────────────────
# S3 bucket name for daily pg_dump backups (created by Terraform).
Expand Down
1 change: 1 addition & 0 deletions .env.staging.example
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ POSTGRES_PASSWORD=
DB_POOL_MAX=5
DB_POOL_TIMEOUT_MS=15000
DB_CONNECT_TIMEOUT_S=15
DB_POOL_IDLE_TIMEOUT_MS=600000

# ── Auth (staging-specific secrets) ──────────────────────────────────────────
JWT_SECRET=
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,18 @@ jobs:
npx playwright test tests/checkout.spec.ts \
--project=chromium \
--reporter=list,html,junit
# Issue #1049: full browse → search → buy → retire → certificate journey
# with a per-transaction performance baseline. Screenshots/traces on
# failure are uploaded with the report below.
- name: Run marketplace flow E2E tests (#1049)
if: always()
env:
CI: "true"
NEXT_PUBLIC_APP_URL: http://localhost:3000
run: |
npx playwright test tests/e2e/marketplace-flow.spec.ts \
--project=chromium \
--reporter=list,html,junit
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -733,6 +745,14 @@ jobs:
PROPTEST_CASES: 1000
run: "cargo test -p carbon_credit 'proptest_invariant_tests::' -- --nocapture"

# Issue #1051: dedicated property-based test target — supply-conservation
# and ownership-consistency invariants against the public contract API.
- name: Run property-based test target (carbon_credit, cargo test --test proptest)
working-directory: contracts
env:
PROPTEST_CASES: 1000
run: "cargo test -p carbon_credit --test proptest -- --nocapture"

- name: Run fuzz tests (carbon_marketplace)
working-directory: contracts
env:
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/openapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: OpenAPI Spec Drift Check

on:
pull_request:
branches: [main, develop]
paths:
- 'backend/**'
- '.github/workflows/openapi.yml'
push:
branches: [main]
workflow_dispatch:

jobs:
openapi-drift:
name: OpenAPI spec + Postman collection are up to date
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install PyYAML
run: pip install pyyaml

- name: Regenerate spec + Postman artifacts
working-directory: ./backend
run: python3 scripts/generate_openapi.py

- name: Fail on drift
working-directory: ./backend
run: |
git --no-pager diff --exit-code -- docs/openapi.json docs/api/openapi.yaml docs/api/openapi.json docs/api/carbonledger.postman_collection.json \
|| (echo "::error::Committed OpenAPI/Postman artifacts are out of date. Run 'python3 scripts/generate_openapi.py' in backend/ and commit the regenerated files." && exit 1)
Loading
Loading