You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 67bcab3
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: README.md
+69-32Lines changed: 69 additions & 32 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@ Pactum lets any two parties register a real-world commitment on Stellar — a re
13
13
14
14
## The problem
15
15
16
-
Escrow contracts handle *one-time* deals — money goes in, money comes out once conditions are met. But a lot of real commitments aren't one-time payments at all:
16
+
Escrow contracts handle _one-time_ deals — money goes in, money comes out once conditions are met. But a lot of real commitments aren't one-time payments at all:
17
17
18
18
- A landlord promising to return a deposit within 30 days of move-out
19
19
- An API provider guaranteeing 99.9% uptime this quarter
@@ -81,43 +81,43 @@ See [`docs/architecture.md`](./docs/architecture.md) for the full breakdown.
| Testing | Cargo test (contract) · Jest (backend) · `node --test` (zk) |
95
+
| CI/CD | GitHub Actions|
96
96
97
97
---
98
98
99
99
## Contract interface (early draft)
100
100
101
-
| Method | Kind | Description |
102
-
|---|---|---|
103
-
|`create_commitment(issuer, counterparty, terms_hash, due_at)`| write | Register a new commitment between two addresses |
104
-
|`create_milestone_commitment(issuer, counterparty, terms_hash, due_at, resolver, milestone_count)`| write | Register a commitment fulfilled across several milestones |
105
-
|`attest(commitment_id, outcome)`| write | Mark the next pending milestone fulfilled, late, or breached — resolving the commitment if it is the last one |
106
-
|`attest_milestone(commitment_id, milestone_index, outcome)`| write | Mark one milestone of a commitment; the commitment resolves on the last one |
107
-
|`get_milestone(commitment_id, milestone_index)`| read | Fetch a single milestone's outcome, or nothing while it is pending |
108
-
|`dispute(commitment_id, reason)`| write | Flag a commitment as contested rather than resolved |
|`create_commitment(issuer, counterparty, terms_hash, due_at)`| write | Register a new commitment between two addresses|
104
+
|`create_milestone_commitment(issuer, counterparty, terms_hash, due_at, resolver, milestone_count)`| write | Register a commitment fulfilled across several milestones |
105
+
|`attest(commitment_id, outcome)`| write | Mark the next pending milestone fulfilled, late, or breached — resolving the commitment if it is the last one |
106
+
|`attest_milestone(commitment_id, milestone_index, outcome)`| write | Mark one milestone of a commitment; the commitment resolves on the last one|
107
+
|`get_milestone(commitment_id, milestone_index)`| read | Fetch a single milestone's outcome, or nothing while it is pending|
108
+
|`dispute(commitment_id, reason)`| write | Flag a commitment as contested rather than resolved|
109
+
|`resolve_dispute(commitment_id, outcome)`| write | Designated arbitrator/oracle settles a disputed commitment|
110
+
|`get_commitment(commitment_id)`| read | Fetch a single commitment's details and status|
111
+
|`get_reputation(address)`| read | Aggregate fulfilled / late / breached counts for an address|
112
112
113
113
Full spec lives in [`docs/contract-reference.md`](./docs/contract-reference.md) as the contract develops.
114
114
115
115
## Production Deployment
116
116
117
117
The contract is currently deployed on the Stellar Testnet for testing and integration.
cp .env.example .env # fill in DATABASE_URL, SOROBAN_RPC_URL, TIMESCALEDB_* config, etc.
155
155
npm run build
156
-
npm run migrate:timescale # Run TimescaleDB migrations
156
+
npm run migrate:up # Run all pending migrations
157
157
npm run dev
158
158
159
159
# 5. Start analytics worker (optional, for background data processing)
160
160
npm run analytics:worker
161
161
```
162
162
163
+
### Database migrations
164
+
165
+
Pactum uses a custom immutable migration runner built into the backend. Every migration file is content-addressed with a SHA-256 checksum frozen on first apply — editing an already-applied file is detected and rejected at startup, preventing silent schema drift between environments.
166
+
167
+
Migration files live in `backend/src/db/migrations/` and are numbered with a three-digit prefix (`001_`, `002_`, …) so they execute in a deterministic lexicographic order.
# Validate all migrations without touching the database (also runs in CI)
191
+
npm run migrate:dry-run
192
+
```
193
+
194
+
#### Immutability rules
195
+
196
+
-**Never edit a migration that has already been applied to any environment.** The runner stores the SHA-256 of each file at apply time and compares it on every subsequent run. A mismatch aborts the migration cycle and exits non-zero.
197
+
- To change something that was already applied, create a new migration that issues the corrective `ALTER`, `DROP`, or `CREATE` statement.
198
+
- The `migrate:dry-run` script is run automatically on every pull request by CI (see `.github/workflows/ci.yml` → `migration-dry-run` job).
199
+
163
200
### Running the whole stack with Docker
164
201
165
202
**Prerequisites:** Docker with Compose v2.
@@ -170,11 +207,11 @@ docker compose up --build
170
207
171
208
That boots TimescaleDB, the backend (which applies `backend/src/db/migrations/*.sql` on startup) and an nginx-served frontend build.
The frontend is built to call the API on its own origin, and nginx proxies `/api`, `/reputation`, `/commitments` and `/health` to the backend container. Database credentials and Soroban settings come from the same `TIMESCALEDB_*` / `SOROBAN_*` variables as `backend/.env.example`; set them in a root `.env` to override the defaults.
0 commit comments