@synapsor/runner 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/README.md CHANGED
@@ -1,74 +1,109 @@
1
1
  # Synapsor Runner Docs
2
2
 
3
- Start with the README. Use these docs only when you need the next level of
4
- detail.
3
+ Start with the README. Use this index when you need the task-specific next
4
+ step. The order is intentional: run something first, wire your database second,
5
+ then read the concepts once the safety boundary is visible.
5
6
 
6
- ## First Setup
7
+ ## 01 Quickstart
8
+
9
+ - [README](../README.md): wedge, no-DB quick demo, five-line model, and the
10
+ shortest own-database path.
11
+ - [Troubleshooting First Run](troubleshooting-first-run.md): common first-run
12
+ failures, redacted diagnostics, and fixes.
13
+
14
+ ## 02 Why Raw SQL Is Dangerous
15
+
16
+ - [Security Boundary](security-boundary.md): what the model can and cannot see.
17
+ - [MCP Audit](mcp-audit.md): static review for risky database MCP tools such as
18
+ `execute_sql`, broad query tools, model-controlled tenant filters, or
19
+ model-facing approval/commit tools.
20
+
21
+ ## 03 Run The Demo
22
+
23
+ - `examples/support-billing-agent/`: flagship support/billing agent demo with
24
+ `make demo`, expected output, and the raw-SQL-vs-Synapsor contrast.
25
+ - `examples/raw-sql-vs-synapsor/`: no-database fear/fix demo.
26
+ - `examples/reference-support-billing-app/`: shared fixture used by the
27
+ flagship demo and package smoke tests.
28
+
29
+ ## 04 Connect Your DB
7
30
 
8
31
  - [Connect Your Own Database](getting-started-own-database.md): inspect a
9
32
  staging Postgres/MySQL database, generate `synapsor.runner.json`, preview
10
33
  semantic tools, and serve them over MCP.
11
34
  - [Use Your Own Database](use-your-own-database.md): short entry point that
12
35
  links to the canonical own-database guide.
36
+ - [Doctor](doctor.md): redacted setup checks, handler probes, direct SQL
37
+ writeback probes, and receipt-table guidance.
38
+
39
+ ## 05 Generate Capabilities
40
+
41
+ - [Capability Authoring](capability-authoring.md): define read/proposal
42
+ capabilities, model-facing descriptions, result envelopes, trusted context,
43
+ and writeback guards.
44
+ - [Recipes](recipes.md): starter business-capability templates.
45
+ - [JSON Schema](../schemas/synapsor.runner.schema.json): editor validation for
46
+ `synapsor.runner.json`.
47
+
48
+ ## 06 Serve MCP
49
+
13
50
  - [MCP Client Setup](mcp-client-setup.md): connect Claude, Cursor, VS Code, or
14
51
  another stdio MCP client.
52
+ - `examples/claude-desktop-postgres/`: copy-paste Claude Desktop config for the
53
+ Postgres billing fixture.
54
+ - `examples/cursor-postgres/`: copy-paste Cursor config for the Postgres
55
+ billing fixture.
15
56
  - [HTTP MCP](http-mcp.md): run Synapsor Runner as an authenticated HTTP MCP
16
57
  service for app/server agents.
17
58
  - [OpenAI Agents SDK](openai-agents-sdk.md): use Streamable HTTP MCP with
18
59
  OpenAI-safe tool aliases.
19
- - [Capability Authoring](capability-authoring.md): define read/proposal
20
- capabilities, model-facing descriptions, result envelopes, trusted context,
21
- and writeback guards. JSON Schema:
22
- `../schemas/synapsor.runner.schema.json`.
23
- - [Result Envelope v2](result-envelope-v2.md): the generated-config default
24
- `ok`/`summary`/`data`/`proposal`/`error` response shape for MCP tools.
25
- - [Handler Helper](handler-helper.md): TypeScript helper for safe app-owned
26
- rich-write handlers.
27
- - RFC source context:
28
- [001 result envelope](rfcs/001-result-envelope-v2.md),
29
- [002 handler helper](rfcs/002-app-owned-handler-helper.md),
30
- [003 integrator teardown](rfcs/003-integrator-feedback-teardown.md).
31
60
 
32
- ## Safety And Operations
61
+ ## 07 Propose, Approve, Apply
33
62
 
34
- - [Security Boundary](security-boundary.md): what the model can and cannot see.
35
- - [Current Limitations](limitations.md): current alpha scope.
36
- - [Current Scope](current-scope.md): compact alpha scope summary.
37
- - [Cloud Mode](cloud-mode.md): what stays local and what Cloud-linked mode adds.
38
- - [Release Notes](release-notes.md): alpha behavior, breaking changes, and the
39
- stable release policy.
40
- - [Release Policy](release-policy.md): alpha expectations, stable gates,
41
- result envelope migration, and publish verification.
42
- - [Licensing](licensing.md): Apache-2.0 scope, trademark boundary, and what is
43
- not included in this runner repo.
44
- - [Dependency License Inventory](dependency-license-inventory.md): current
45
- dependency license summary for release review.
46
- - [Troubleshooting First Run](troubleshooting-first-run.md): common setup
47
- failures and fixes.
48
- - [Doctor](doctor.md): redacted setup checks, handler probes, direct SQL
49
- writeback probes, and receipt-table guidance.
50
63
  - [Local Mode](local-mode.md): local store, proposals, approval, replay, and
51
64
  writeback flow.
52
- - [Store Lifecycle](store-lifecycle.md): active-store leases, prune safety,
53
- deleted-store behavior, and concurrent server guardrails.
54
-
55
- ## Features
56
-
57
- - [MCP Audit](mcp-audit.md): static risk review for database MCP tools.
58
- - [Recipes](recipes.md): starter business-capability templates.
59
65
  - [Writeback Executors](writeback-executors.md): app-owned writeback handlers
60
66
  for approved proposals.
61
67
  - [App-Owned Executors](app-owned-executors.md): short entry point for rich
62
68
  business transactions handled by your app.
63
- - `synapsor-runner events tail` and `events webhook`: local lifecycle events
64
- such as `proposal_created`, `proposal_approved`, `writeback_applied`, and
65
- `writeback_conflict`.
69
+ - [Handler Helper](handler-helper.md): TypeScript helper for safe app-owned
70
+ rich-write handlers.
66
71
 
67
- Useful examples:
72
+ ## 08 Replay And Audit
68
73
 
69
- - `examples/mcp-postgres-billing-app-handler/`: disposable Postgres app showing
70
- guarded SQL writeback and app-owned account-credit execution side by side.
74
+ - [Result Envelope v2](result-envelope-v2.md): stable
75
+ `ok`/`summary`/`data`/`proposal`/`error` MCP tool results.
76
+ - [Store Lifecycle](store-lifecycle.md): active-store leases, prune safety,
77
+ deleted-store behavior, and concurrent server guardrails.
78
+ - `synapsor-runner activity search`, `evidence`, `query-audit`, `receipts`,
79
+ `events tail`, and `events webhook`: local evidence, audit, receipt, replay,
80
+ and lifecycle inspection.
81
+ - `examples/mysql-refund-agent/`: MySQL order/refund review example using the
82
+ same proposal, approval, guarded writeback, and replay loop.
83
+
84
+ ## 09 App-Owned Handlers
85
+
86
+ - [Writeback Executors](writeback-executors.md): call direction, endpoint
87
+ contract, receipt shape, and the requirement to re-check tenant/scope,
88
+ expected version, idempotency, and allowed action inside your handler.
89
+ - [Handler Helper](handler-helper.md): helper API and examples.
90
+
91
+ ## 10 Concepts
92
+
93
+ - [Current Scope](current-scope.md): compact v0.1 scope summary.
94
+ - [Current Limitations](limitations.md): intentional safety limits.
95
+ - [Cloud Mode](cloud-mode.md): what stays local and what Cloud-linked mode adds.
96
+ - [Release Notes](release-notes.md): release history and behavior changes.
97
+ - [Release Policy](release-policy.md): stable gates and publish verification.
98
+ - [Licensing](licensing.md): Apache-2.0 scope, trademark boundary, and what is
99
+ not included in this runner repo.
100
+ - [Dependency License Inventory](dependency-license-inventory.md): current
101
+ dependency license summary for release review.
102
+ - RFC source context:
103
+ [001 result envelope](rfcs/001-result-envelope-v2.md),
104
+ [002 handler helper](rfcs/002-app-owned-handler-helper.md),
105
+ [003 integrator teardown](rfcs/003-integrator-feedback-teardown.md).
71
106
 
72
- The public docs intentionally stay small. Historical implementation reports,
73
- release checklists, and internal planning notes are not part of the public
107
+ The public docs intentionally stay task-first. Historical implementation
108
+ reports, release checklists, and internal planning notes are not part of the
74
109
  getting-started path.
@@ -10,6 +10,27 @@ npx -y -p @synapsor/runner synapsor-runner demo --quick
10
10
  The OSS runner command is `synapsor-runner`. The `synapsor` command is reserved
11
11
  for the Synapsor Cloud CLI.
12
12
 
13
+ ## 0.1.1
14
+
15
+ ### OSS Launch Readiness
16
+
17
+ - Reworked the README and packaged npm README so the first screen leads with
18
+ the `execute_sql` risk, the reviewed-business-action alternative, badges, and
19
+ the no-database quick demo.
20
+ - Added the self-contained `examples/support-billing-agent/` flagship demo with
21
+ schema, seed data, reviewed contract, app-boundary note, one-command
22
+ `make demo`, and the exact support/billing model-facing tool list.
23
+ - Added copy-paste example entry points for raw SQL vs Synapsor, Claude
24
+ Desktop, Cursor, OpenAI Agents SDK over Streamable HTTP and stdio, and MySQL
25
+ refund review.
26
+ - Added agent-native repo guidance files and verified that an agent can create
27
+ an inspect/propose capability with the non-interactive CLI without reading
28
+ generated `dist/` files.
29
+ - Restructured the docs index into a task-first path and added release-gate
30
+ repo hygiene assets.
31
+ - Hardened package building so generated `.synapsor` local ledgers are not
32
+ included in npm examples.
33
+
13
34
  ## 0.1.0
14
35
 
15
36
  ### Stable Channel
@@ -0,0 +1,6 @@
1
+ .PHONY: config
2
+
3
+ config:
4
+ cd ../.. && corepack pnpm runner mcp config claude-desktop \
5
+ --config ./examples/mcp-postgres-billing/synapsor.runner.json \
6
+ --store ./.synapsor/local.db
@@ -0,0 +1,40 @@
1
+ # Claude Desktop + Postgres
2
+
3
+ This example prints a Claude Desktop MCP config for a reviewed Postgres-backed
4
+ Synapsor Runner capability set.
5
+
6
+ It uses the local `examples/mcp-postgres-billing/synapsor.runner.json` fixture.
7
+ The config contains command paths and environment variable names only; it does
8
+ not include database URLs or write credentials.
9
+
10
+ ## Run
11
+
12
+ ```bash
13
+ make config
14
+ ```
15
+
16
+ Expected output includes:
17
+
18
+ ```json
19
+ {
20
+ "mcpServers": {
21
+ "synapsor": {
22
+ "command": "...",
23
+ "args": ["...", "mcp", "serve", "..."]
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ Then paste the JSON into Claude Desktop's MCP settings and set these
30
+ environment variables in the client environment:
31
+
32
+ ```bash
33
+ export BILLING_POSTGRES_READ_URL="postgres://readonly:..."
34
+ export SYNAPSOR_TENANT_ID="acme"
35
+ export SYNAPSOR_PRINCIPAL="local_billing_agent"
36
+ ```
37
+
38
+ The model sees semantic tools such as `billing.inspect_invoice` and
39
+ `billing.propose_late_fee_waiver`; it does not see raw SQL or approval/commit
40
+ tools.
@@ -0,0 +1,6 @@
1
+ .PHONY: config
2
+
3
+ config:
4
+ cd ../.. && corepack pnpm runner mcp config cursor \
5
+ --config ./examples/mcp-postgres-billing/synapsor.runner.json \
6
+ --store ./.synapsor/local.db
@@ -0,0 +1,30 @@
1
+ # Cursor + Postgres
2
+
3
+ This example prints a Cursor MCP config for a reviewed Postgres-backed Synapsor
4
+ Runner capability set.
5
+
6
+ It uses the local `examples/mcp-postgres-billing/synapsor.runner.json` fixture.
7
+ The config contains command paths and environment variable names only; it does
8
+ not include database URLs or write credentials.
9
+
10
+ ## Run
11
+
12
+ ```bash
13
+ make config
14
+ ```
15
+
16
+ Expected output includes a Cursor-compatible `mcpServers.synapsor` entry that
17
+ launches:
18
+
19
+ ```text
20
+ synapsor-runner mcp serve --config ./examples/mcp-postgres-billing/synapsor.runner.json --store ./.synapsor/local.db
21
+ ```
22
+
23
+ Set the database and trusted-context variables in the environment that launches
24
+ Cursor:
25
+
26
+ ```bash
27
+ export BILLING_POSTGRES_READ_URL="postgres://readonly:..."
28
+ export SYNAPSOR_TENANT_ID="acme"
29
+ export SYNAPSOR_PRINCIPAL="local_billing_agent"
30
+ ```
@@ -0,0 +1,4 @@
1
+ .PHONY: demo
2
+
3
+ demo:
4
+ cd ../.. && corepack pnpm test:mcp-local
@@ -0,0 +1,36 @@
1
+ # MySQL Refund Agent
2
+
3
+ This example points at the MySQL order/refund fixture and proves Synapsor
4
+ Runner is not Postgres-only.
5
+
6
+ The reviewed tools are:
7
+
8
+ - `orders.inspect_order`
9
+ - `orders.propose_refund_review`
10
+ - `orders.propose_status_change`
11
+
12
+ The refund proposal updates only review fields on one existing order. It does
13
+ not issue money movement, call a payment provider, or expose a generic SQL
14
+ tool.
15
+
16
+ ## Run
17
+
18
+ ```bash
19
+ make demo
20
+ ```
21
+
22
+ Expected output includes the shared local MCP smoke passing for the MySQL orders
23
+ scenario:
24
+
25
+ ```text
26
+ MySQL orders
27
+ ACCEPT execute_sql approval and commit tools absent
28
+ ```
29
+
30
+ The source database remains unchanged until a proposal is approved outside MCP
31
+ and applied through guarded writeback.
32
+
33
+ ## Underlying Fixture
34
+
35
+ This folder wraps `../mcp-mysql-orders/`, which contains the Docker compose
36
+ file, seed SQL, and `synapsor.runner.json` contract.
@@ -0,0 +1,6 @@
1
+ .PHONY: smoke
2
+
3
+ smoke:
4
+ python3 -m py_compile agent.py
5
+ npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http --help >/dev/null
6
+ @printf '%s\n' "OpenAI Agents Streamable HTTP example smoke passed."
@@ -20,6 +20,20 @@ metadata and maps calls back to the canonical Synapsor capability.
20
20
  The model still sees a semantic action. It does not receive raw SQL, database
21
21
  URLs, write credentials, approval tools, or commit tools.
22
22
 
23
+ ## Smoke Check
24
+
25
+ Run this without an OpenAI API key:
26
+
27
+ ```bash
28
+ make smoke
29
+ ```
30
+
31
+ Expected output:
32
+
33
+ ```text
34
+ OpenAI Agents Streamable HTTP example smoke passed.
35
+ ```
36
+
23
37
  ## Terminal 1: Start Synapsor Runner HTTP MCP
24
38
 
25
39
  ```bash
@@ -0,0 +1,6 @@
1
+ .PHONY: smoke
2
+
3
+ smoke:
4
+ python3 -m py_compile agent.py
5
+ npx -y -p @synapsor/runner synapsor-runner mcp serve --help >/dev/null
6
+ @printf '%s\n' "OpenAI Agents stdio example smoke passed."
@@ -11,6 +11,20 @@ it. The model
11
11
  does not receive raw SQL, database URLs, write credentials, approval tools, or
12
12
  commit tools.
13
13
 
14
+ ## Smoke Check
15
+
16
+ Run this without an OpenAI API key:
17
+
18
+ ```bash
19
+ make smoke
20
+ ```
21
+
22
+ Expected output:
23
+
24
+ ```text
25
+ OpenAI Agents stdio example smoke passed.
26
+ ```
27
+
14
28
  ## Prerequisites
15
29
 
16
30
  Generate `synapsor.runner.json` first:
@@ -0,0 +1,11 @@
1
+ .PHONY: demo
2
+
3
+ demo:
4
+ @printf '%s\n' "Unsafe shortcut:"
5
+ @printf '%s\n' ' agent -> execute_sql("UPDATE invoices SET late_fee_cents = 0 ...")'
6
+ @printf '%s\n' ""
7
+ @printf '%s\n' "Synapsor quick proof:"
8
+ npx -y @synapsor/runner demo --quick --no-interactive
9
+ @printf '%s\n' ""
10
+ @printf '%s\n' "Risk audit example:"
11
+ npx -y @synapsor/runner audit --example dangerous-db-mcp --format markdown
@@ -0,0 +1,41 @@
1
+ # Raw SQL vs Synapsor
2
+
3
+ This minimal example shows the fear and the fix without requiring Docker, an
4
+ agent SDK, or a database.
5
+
6
+ ## Run
7
+
8
+ ```bash
9
+ make demo
10
+ ```
11
+
12
+ Expected output includes:
13
+
14
+ ```text
15
+ execute_sql
16
+ Synapsor quick demo complete.
17
+ proposal created
18
+ source DB changed: no
19
+ approval required outside MCP
20
+ ```
21
+
22
+ The raw-SQL shortcut is:
23
+
24
+ ```text
25
+ agent -> execute_sql("UPDATE invoices SET late_fee_cents = 0 ...")
26
+ ```
27
+
28
+ The Synapsor path is:
29
+
30
+ ```text
31
+ agent -> billing.propose_late_fee_waiver(...)
32
+ human approves outside MCP
33
+ guarded writeback applies exactly one row
34
+ replay records what happened
35
+ ```
36
+
37
+ ## Why This Exists
38
+
39
+ Use this folder when you want to show the core idea quickly. It is not a full
40
+ database fixture; the full support/billing walkthrough lives in
41
+ `../support-billing-agent/`.
@@ -0,0 +1,19 @@
1
+ .PHONY: demo unsafe clean
2
+
3
+ demo:
4
+ cd ../.. && examples/support-billing-agent/scripts/run-demo.sh
5
+
6
+ unsafe:
7
+ @printf '%s\n' "Unsafe raw-SQL shortcut this demo avoids:"
8
+ @printf '%s\n' ""
9
+ @printf '%s\n' ' agent -> execute_sql("UPDATE invoices SET late_fee_cents = 0 WHERE status = '\''overdue'\''")'
10
+ @printf '%s\n' ""
11
+ @printf '%s\n' "Why it is risky:"
12
+ @printf '%s\n' " - the model controls SQL shape and scope"
13
+ @printf '%s\n' " - tenant filters can be omitted or hallucinated"
14
+ @printf '%s\n' " - there is no proposal, approval boundary, conflict receipt, or replay"
15
+ @printf '%s\n' ""
16
+ @printf '%s\n' "Run 'make demo' to see the Synapsor path: semantic tool -> proposal -> approval -> guarded writeback -> replay."
17
+
18
+ clean:
19
+ docker compose down -v --remove-orphans
@@ -0,0 +1,89 @@
1
+ # Support/Billing Agent Demo
2
+
3
+ This is the flagship Synapsor Runner demo.
4
+
5
+ It uses a disposable Postgres support/billing app and shows the full loop:
6
+
7
+ ```text
8
+ agent inspects scoped evidence
9
+ -> agent creates a proposal
10
+ -> source database is unchanged
11
+ -> human approves outside MCP
12
+ -> guarded writeback applies exactly one row
13
+ -> replay shows evidence, diff, approval, receipt, and conflict behavior
14
+ ```
15
+
16
+ ## Run It
17
+
18
+ From this folder:
19
+
20
+ ```bash
21
+ make demo
22
+ ```
23
+
24
+ Expected end state:
25
+
26
+ ```text
27
+ Reference support/billing app smoke passed.
28
+ ```
29
+
30
+ The model-facing tools are exactly:
31
+
32
+ - `support.inspect_ticket`
33
+ - `support.propose_plan_credit`
34
+ - `billing.inspect_invoice`
35
+ - `billing.propose_late_fee_waiver`
36
+
37
+ The demo proves:
38
+
39
+ - the model-facing tool list contains semantic capabilities such as
40
+ `billing.inspect_invoice` and `billing.propose_late_fee_waiver`;
41
+ - the model does not receive `execute_sql`, approval tools, commit/apply tools,
42
+ database URLs, write credentials, arbitrary table names, arbitrary column
43
+ names, or tenant authority;
44
+ - proposals do not mutate the source database;
45
+ - approved writeback uses tenant, primary-key, allowed-column,
46
+ idempotency, and `updated_at` conflict guards;
47
+ - replay contains the evidence and writeback receipt.
48
+
49
+ ## Compare The Unsafe Shortcut
50
+
51
+ To see why the boundary matters:
52
+
53
+ ```bash
54
+ make unsafe
55
+ ```
56
+
57
+ That target prints the raw-SQL shape this demo avoids. It does not mutate the
58
+ fixture; it shows the path an MCP client should not expose to the model:
59
+
60
+ ```text
61
+ execute_sql("UPDATE invoices SET late_fee_cents = 0 ...")
62
+ ```
63
+
64
+ Use `make demo` for the real proposal, approval, writeback, idempotent retry,
65
+ stale-row conflict, and replay proof.
66
+
67
+ ## What This Wraps
68
+
69
+ This folder is self-contained for readers and agents looking for the canonical
70
+ support/billing demo. The smoke logic is shared with the reference fixture so
71
+ the product-facing walkthrough and package tests exercise the same safety
72
+ checks.
73
+
74
+ Relevant files:
75
+
76
+ - `db/schema.sql`
77
+ - `db/seed.sql`
78
+ - `synapsor.runner.json`
79
+ - `scripts/run-demo.sh`
80
+ - `app/README.md`
81
+
82
+ ## Stop And Clean Up
83
+
84
+ The demo script cleans up its disposable Docker database automatically. If you
85
+ interrupt it, run:
86
+
87
+ ```bash
88
+ make clean
89
+ ```
@@ -0,0 +1,13 @@
1
+ # App Surface
2
+
3
+ This folder marks the customer application boundary for the flagship demo.
4
+
5
+ The model talks to Synapsor Runner MCP tools. It does not receive application
6
+ write credentials or direct SQL authority. After approval, the trusted runner
7
+ uses the reviewed `synapsor.runner.json` contract to apply the one-row
8
+ writeback with tenant, primary-key, allowed-column, idempotency, and
9
+ `updated_at` conflict guards.
10
+
11
+ For richer app actions, such as inserting a credit ledger row and emitting an
12
+ event, use the app-owned handler examples in `../app-owned-writeback/` and
13
+ `../mcp-postgres-billing-app-handler/`.
@@ -0,0 +1,91 @@
1
+ CREATE TABLE IF NOT EXISTS public.tenants (
2
+ id text PRIMARY KEY,
3
+ name text NOT NULL,
4
+ created_at timestamptz NOT NULL DEFAULT now(),
5
+ updated_at timestamptz NOT NULL DEFAULT now()
6
+ );
7
+
8
+ CREATE TABLE IF NOT EXISTS public.customers (
9
+ id text PRIMARY KEY,
10
+ tenant_id text NOT NULL REFERENCES public.tenants(id),
11
+ name text NOT NULL,
12
+ email text,
13
+ plan text NOT NULL,
14
+ plan_credit_cents integer NOT NULL DEFAULT 0,
15
+ credit_reason text,
16
+ created_at timestamptz NOT NULL DEFAULT now(),
17
+ updated_at timestamptz NOT NULL DEFAULT now()
18
+ );
19
+
20
+ CREATE TABLE IF NOT EXISTS public.support_tickets (
21
+ id text PRIMARY KEY,
22
+ tenant_id text NOT NULL REFERENCES public.tenants(id),
23
+ customer_id text NOT NULL REFERENCES public.customers(id),
24
+ subject text NOT NULL,
25
+ status text NOT NULL,
26
+ resolution_note text,
27
+ updated_at timestamptz NOT NULL DEFAULT now()
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS public.invoices (
31
+ id text PRIMARY KEY,
32
+ tenant_id text NOT NULL REFERENCES public.tenants(id),
33
+ customer_id text NOT NULL REFERENCES public.customers(id),
34
+ status text NOT NULL,
35
+ balance_cents integer NOT NULL,
36
+ late_fee_cents integer NOT NULL,
37
+ waiver_reason text,
38
+ updated_at timestamptz NOT NULL DEFAULT now()
39
+ );
40
+
41
+ CREATE TABLE IF NOT EXISTS public.credits (
42
+ id text PRIMARY KEY,
43
+ tenant_id text NOT NULL REFERENCES public.tenants(id),
44
+ customer_id text NOT NULL REFERENCES public.customers(id),
45
+ invoice_id text REFERENCES public.invoices(id),
46
+ amount_cents integer NOT NULL,
47
+ reason text NOT NULL,
48
+ status text NOT NULL,
49
+ created_at timestamptz NOT NULL DEFAULT now(),
50
+ updated_at timestamptz NOT NULL DEFAULT now()
51
+ );
52
+
53
+ CREATE TABLE IF NOT EXISTS public.agent_actions (
54
+ id text PRIMARY KEY,
55
+ tenant_id text NOT NULL REFERENCES public.tenants(id),
56
+ action_type text NOT NULL,
57
+ target_type text NOT NULL,
58
+ target_id text NOT NULL,
59
+ proposal_id text,
60
+ status text NOT NULL,
61
+ created_at timestamptz NOT NULL DEFAULT now()
62
+ );
63
+
64
+ CREATE TABLE IF NOT EXISTS public.orders (
65
+ id text PRIMARY KEY,
66
+ tenant_id text NOT NULL REFERENCES public.tenants(id),
67
+ customer_id text NOT NULL REFERENCES public.customers(id),
68
+ status text NOT NULL,
69
+ status_change_reason text,
70
+ updated_at timestamptz NOT NULL DEFAULT now()
71
+ );
72
+
73
+ DO $$
74
+ BEGIN
75
+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'synapsor_reader') THEN
76
+ CREATE ROLE synapsor_reader LOGIN PASSWORD 'synapsor_reader_password';
77
+ END IF;
78
+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'synapsor_writer') THEN
79
+ CREATE ROLE synapsor_writer LOGIN PASSWORD 'synapsor_writer_password';
80
+ END IF;
81
+ END
82
+ $$;
83
+
84
+ GRANT CONNECT ON DATABASE synapsor_support_billing_agent TO synapsor_reader, synapsor_writer;
85
+ GRANT USAGE ON SCHEMA public TO synapsor_reader, synapsor_writer;
86
+ GRANT CREATE ON SCHEMA public TO synapsor_writer;
87
+ GRANT SELECT ON public.tenants, public.customers, public.support_tickets, public.invoices, public.credits, public.agent_actions, public.orders TO synapsor_reader, synapsor_writer;
88
+ GRANT UPDATE (plan_credit_cents, credit_reason, updated_at) ON public.customers TO synapsor_writer;
89
+ GRANT UPDATE (status, resolution_note, updated_at) ON public.support_tickets TO synapsor_writer;
90
+ GRANT UPDATE (late_fee_cents, waiver_reason, updated_at) ON public.invoices TO synapsor_writer;
91
+ GRANT UPDATE (status, status_change_reason, updated_at) ON public.orders TO synapsor_writer;