@synapsor/runner 1.6.2 → 1.6.4
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/AGENTS.md +2 -2
- package/CHANGELOG.md +141 -2
- package/CONTRIBUTING.md +10 -3
- package/README.md +65 -83
- package/SECURITY.md +14 -2
- package/THREAT_MODEL.md +64 -4
- package/dist/authoring.mjs +151 -16
- package/dist/cli.d.ts +31 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +145 -1
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +37488 -19009
- package/dist/runtime.mjs +4056 -235
- package/dist/shadow.mjs +2423 -65
- package/docs/README.md +36 -2
- package/docs/agent-guided-setup.md +239 -0
- package/docs/aggregate-reads.md +14 -5
- package/docs/app-owned-executors.md +5 -6
- package/docs/approval-roles-and-operator-identity.md +353 -0
- package/docs/auto-boundary-and-scoped-explore.md +89 -11
- package/docs/capability-authoring.md +21 -2
- package/docs/client-recipes.md +1 -1
- package/docs/cloud-mode.md +7 -7
- package/docs/conformance.md +6 -3
- package/docs/current-scope.md +32 -2
- package/docs/cursor-plugin.md +3 -3
- package/docs/database-enforced-scope.md +6 -0
- package/docs/dsl-json-parity.md +75 -0
- package/docs/dsl-reference.md +22 -1
- package/docs/fresh-developer-usability.md +155 -80
- package/docs/getting-started-own-database.md +45 -44
- package/docs/guarded-crud-writeback.md +19 -0
- package/docs/guided-onboarding.md +399 -0
- package/docs/human-attention-notifications.md +367 -0
- package/docs/limitations.md +49 -13
- package/docs/local-mode.md +36 -22
- package/docs/mcp-audit.md +14 -14
- package/docs/mcp-client-setup.md +11 -14
- package/docs/mcp-clients.md +1 -1
- package/docs/migrating-to-synapsor-spec.md +42 -0
- package/docs/openai-agents-sdk.md +2 -2
- package/docs/production.md +39 -0
- package/docs/proposal-evidence-freshness.md +7 -7
- package/docs/recipes.md +6 -6
- package/docs/release-notes.md +144 -4
- package/docs/release-policy.md +20 -7
- package/docs/reversible-change-sets.md +1 -1
- package/docs/reviewed-database-views.md +132 -0
- package/docs/reviewed-relationships.md +245 -0
- package/docs/rfcs/006-reviewed-reversible-change-sets.md +1 -1
- package/docs/runner-bundles.md +7 -7
- package/docs/runner-config-reference.md +132 -0
- package/docs/running-a-runner-fleet.md +16 -1
- package/docs/schema-api-candidates.md +1 -1
- package/docs/security-boundary.md +54 -0
- package/docs/store-lifecycle.md +20 -1
- package/docs/supervised-automatic-apply.md +267 -0
- package/docs/troubleshooting-first-run.md +85 -10
- package/docs/use-your-own-database.md +6 -4
- package/docs/workbench-ask.md +279 -0
- package/docs/writeback-executors.md +7 -7
- package/examples/auto-boundary-churn/README.md +1 -1
- package/examples/community-solar-clean-room/README.md +7 -0
- package/examples/community-solar-clean-room/docker-compose.yml +16 -0
- package/examples/community-solar-clean-room/package.json +15 -0
- package/examples/community-solar-clean-room/prisma/schema.prisma +171 -0
- package/examples/community-solar-clean-room/seed/postgres.sql +571 -0
- package/examples/fitflow-guided-onboarding/README.md +43 -0
- package/examples/fitflow-guided-onboarding/app/page.tsx +8 -0
- package/examples/fitflow-guided-onboarding/docker-compose.yml +16 -0
- package/examples/fitflow-guided-onboarding/package.json +18 -0
- package/examples/fitflow-guided-onboarding/prisma/schema.prisma +98 -0
- package/examples/fitflow-guided-onboarding/seed/postgres.sql +401 -0
- package/examples/openai-agents-http/Makefile +1 -1
- package/examples/openai-agents-http/README.md +1 -1
- package/examples/openai-agents-stdio/Makefile +1 -1
- package/examples/openai-agents-stdio/README.md +2 -2
- package/examples/openai-agents-stdio/agent.py +1 -4
- package/examples/operator-oidc/issuer.mjs +188 -0
- package/examples/reference-support-billing-app/README.md +16 -16
- package/examples/retail-clean-room/README.md +7 -0
- package/examples/retail-clean-room/docker-compose.yml +16 -0
- package/examples/retail-clean-room/package.json +9 -0
- package/examples/retail-clean-room/prisma/schema.prisma +239 -0
- package/examples/retail-clean-room/seed/postgres.sql +781 -0
- package/examples/retail-clean-room/view-recipe/average-retained-revenue.synapsor.sql +21 -0
- package/examples/retail-clean-room/view-recipe/synapsor.runner.json +25 -0
- package/examples/support-plan-credit/README.md +6 -2
- package/examples/support-plan-credit/mcp-client-examples/claude-code.sh +1 -4
- package/examples/support-plan-credit/mcp-client-examples/claude-desktop.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/codex.config.toml +1 -4
- package/examples/support-plan-credit/mcp-client-examples/cursor-global.mcp.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/cursor-project.mcp.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/generic-stdio.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/generic-stdio.mjs +1 -1
- package/examples/support-plan-credit/mcp-client-examples/google-adk.py +1 -1
- package/examples/support-plan-credit/mcp-client-examples/langchain.mjs +1 -1
- package/examples/support-plan-credit/mcp-client-examples/llamaindex.py +1 -1
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +1 -1
- package/examples/support-plan-credit/mcp-client-examples/vscode.mcp.json +1 -4
- package/fixtures/compatibility/published-1.6.3/manifest.json +76 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
- package/llms.txt +10 -5
- package/package.json +11 -3
- package/schemas/schema-candidate-review.schema.json +42 -0
- package/schemas/synapsor.runner.schema.json +227 -4
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "postgresql"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
model Organization {
|
|
11
|
+
id String @id
|
|
12
|
+
name String
|
|
13
|
+
locations Location[]
|
|
14
|
+
trainers Trainer[]
|
|
15
|
+
members Member[]
|
|
16
|
+
classes Class[]
|
|
17
|
+
checkIns CheckIn[]
|
|
18
|
+
|
|
19
|
+
@@map("organizations")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
model Location {
|
|
23
|
+
id String @id
|
|
24
|
+
organizationId String @map("organization_id")
|
|
25
|
+
name String
|
|
26
|
+
region String
|
|
27
|
+
organization Organization @relation(fields: [organizationId], references: [id])
|
|
28
|
+
members Member[]
|
|
29
|
+
classes Class[]
|
|
30
|
+
checkIns CheckIn[]
|
|
31
|
+
|
|
32
|
+
@@unique([organizationId, name])
|
|
33
|
+
@@map("locations")
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
model Trainer {
|
|
37
|
+
id String @id
|
|
38
|
+
organizationId String @map("organization_id")
|
|
39
|
+
displayName String @map("display_name")
|
|
40
|
+
organization Organization @relation(fields: [organizationId], references: [id])
|
|
41
|
+
members Member[]
|
|
42
|
+
classes Class[]
|
|
43
|
+
|
|
44
|
+
@@map("trainers")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
model Member {
|
|
48
|
+
id String @id
|
|
49
|
+
organizationId String @map("organization_id")
|
|
50
|
+
locationId String @map("location_id")
|
|
51
|
+
assignedTrainerId String @map("assigned_trainer_id")
|
|
52
|
+
membershipStatus String @map("membership_status")
|
|
53
|
+
membershipTier String @map("membership_tier")
|
|
54
|
+
loyaltyBalance Int @map("loyalty_balance")
|
|
55
|
+
version Int
|
|
56
|
+
paymentMethod String @map("payment_method")
|
|
57
|
+
homeAddress String @map("home_address")
|
|
58
|
+
medicalWaiverNotes String @map("medical_waiver_notes")
|
|
59
|
+
organization Organization @relation(fields: [organizationId], references: [id])
|
|
60
|
+
location Location @relation(fields: [locationId], references: [id])
|
|
61
|
+
assignedTrainer Trainer @relation(fields: [assignedTrainerId], references: [id])
|
|
62
|
+
checkIns CheckIn[]
|
|
63
|
+
|
|
64
|
+
@@index([organizationId, assignedTrainerId])
|
|
65
|
+
@@map("members")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
model Class {
|
|
69
|
+
id String @id
|
|
70
|
+
organizationId String @map("organization_id")
|
|
71
|
+
locationId String @map("location_id")
|
|
72
|
+
trainerId String @map("trainer_id")
|
|
73
|
+
classType String @map("class_type")
|
|
74
|
+
startsAt DateTime @map("starts_at") @db.Timestamptz(6)
|
|
75
|
+
organization Organization @relation(fields: [organizationId], references: [id])
|
|
76
|
+
location Location @relation(fields: [locationId], references: [id])
|
|
77
|
+
trainer Trainer @relation(fields: [trainerId], references: [id])
|
|
78
|
+
checkIns CheckIn[]
|
|
79
|
+
|
|
80
|
+
@@map("classes")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
model CheckIn {
|
|
84
|
+
id String @id
|
|
85
|
+
organizationId String @map("organization_id")
|
|
86
|
+
locationId String @map("location_id")
|
|
87
|
+
memberId String @map("member_id")
|
|
88
|
+
classId String @map("class_id")
|
|
89
|
+
outcome String
|
|
90
|
+
checkedInAt DateTime @map("checked_in_at") @db.Timestamptz(6)
|
|
91
|
+
organization Organization @relation(fields: [organizationId], references: [id])
|
|
92
|
+
location Location @relation(fields: [locationId], references: [id])
|
|
93
|
+
member Member @relation(fields: [memberId], references: [id])
|
|
94
|
+
fitnessClass Class @relation(fields: [classId], references: [id])
|
|
95
|
+
|
|
96
|
+
@@index([organizationId, checkedInAt])
|
|
97
|
+
@@map("check_ins")
|
|
98
|
+
}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
DO $$
|
|
2
|
+
BEGIN
|
|
3
|
+
CREATE ROLE fitflow_analytics_reader LOGIN PASSWORD 'fitflow_analytics_reader_password';
|
|
4
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
5
|
+
END
|
|
6
|
+
$$;
|
|
7
|
+
|
|
8
|
+
DO $$
|
|
9
|
+
BEGIN
|
|
10
|
+
CREATE ROLE fitflow_trainer_reader LOGIN PASSWORD 'fitflow_trainer_reader_password';
|
|
11
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
12
|
+
END
|
|
13
|
+
$$;
|
|
14
|
+
|
|
15
|
+
DO $$
|
|
16
|
+
BEGIN
|
|
17
|
+
CREATE ROLE fitflow_writer LOGIN PASSWORD 'fitflow_writer_password';
|
|
18
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
19
|
+
END
|
|
20
|
+
$$;
|
|
21
|
+
|
|
22
|
+
DO $$
|
|
23
|
+
BEGIN
|
|
24
|
+
CREATE ROLE fitflow_setup LOGIN PASSWORD 'fitflow_setup_password';
|
|
25
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
26
|
+
END
|
|
27
|
+
$$;
|
|
28
|
+
|
|
29
|
+
ALTER ROLE fitflow_analytics_reader SET default_transaction_read_only = on;
|
|
30
|
+
ALTER ROLE fitflow_trainer_reader SET default_transaction_read_only = on;
|
|
31
|
+
|
|
32
|
+
CREATE TABLE public.organizations (
|
|
33
|
+
id text PRIMARY KEY,
|
|
34
|
+
name text NOT NULL
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
CREATE TABLE public.locations (
|
|
38
|
+
id text PRIMARY KEY,
|
|
39
|
+
organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
|
|
40
|
+
name text NOT NULL,
|
|
41
|
+
region text NOT NULL CHECK (region IN ('central', 'east', 'north', 'south', 'west')),
|
|
42
|
+
UNIQUE (organization_id, name)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE TABLE public.trainers (
|
|
46
|
+
id text PRIMARY KEY,
|
|
47
|
+
organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
|
|
48
|
+
display_name text NOT NULL
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
CREATE TABLE public.members (
|
|
52
|
+
id text PRIMARY KEY,
|
|
53
|
+
organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
|
|
54
|
+
location_id text NOT NULL REFERENCES public.locations(id) ON DELETE RESTRICT,
|
|
55
|
+
assigned_trainer_id text NOT NULL REFERENCES public.trainers(id) ON DELETE RESTRICT,
|
|
56
|
+
membership_status text NOT NULL CHECK (membership_status IN ('active', 'frozen', 'cancelled')),
|
|
57
|
+
membership_tier text NOT NULL CHECK (membership_tier IN ('basic', 'plus', 'elite')),
|
|
58
|
+
loyalty_balance integer NOT NULL CHECK (loyalty_balance BETWEEN 0 AND 10000),
|
|
59
|
+
version integer NOT NULL DEFAULT 1 CHECK (version >= 1),
|
|
60
|
+
payment_method text NOT NULL,
|
|
61
|
+
home_address text NOT NULL,
|
|
62
|
+
medical_waiver_notes text NOT NULL
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
CREATE INDEX members_trusted_scope_idx
|
|
66
|
+
ON public.members(organization_id, assigned_trainer_id);
|
|
67
|
+
|
|
68
|
+
CREATE TABLE public.classes (
|
|
69
|
+
id text PRIMARY KEY,
|
|
70
|
+
organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
|
|
71
|
+
location_id text NOT NULL REFERENCES public.locations(id) ON DELETE RESTRICT,
|
|
72
|
+
trainer_id text NOT NULL REFERENCES public.trainers(id) ON DELETE RESTRICT,
|
|
73
|
+
class_type text NOT NULL CHECK (class_type IN ('cycling', 'strength', 'yoga')),
|
|
74
|
+
starts_at timestamptz NOT NULL
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
CREATE TABLE public.check_ins (
|
|
78
|
+
id text PRIMARY KEY,
|
|
79
|
+
organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
|
|
80
|
+
location_id text NOT NULL REFERENCES public.locations(id) ON DELETE RESTRICT,
|
|
81
|
+
member_id text NOT NULL REFERENCES public.members(id) ON DELETE RESTRICT,
|
|
82
|
+
class_id text NOT NULL REFERENCES public.classes(id) ON DELETE RESTRICT,
|
|
83
|
+
outcome text NOT NULL CHECK (outcome IN ('attended', 'late_cancel', 'no_show')),
|
|
84
|
+
checked_in_at timestamptz NOT NULL
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
CREATE INDEX check_ins_tenant_time_idx
|
|
88
|
+
ON public.check_ins(organization_id, checked_in_at);
|
|
89
|
+
|
|
90
|
+
-- A realistic application has much more schema than the first agent pack
|
|
91
|
+
-- needs. These metadata-only subsystems exercise whole-application review
|
|
92
|
+
-- without adding irrelevant rows to the onboarding result.
|
|
93
|
+
DO $$
|
|
94
|
+
DECLARE
|
|
95
|
+
relation_name text;
|
|
96
|
+
BEGIN
|
|
97
|
+
FOREACH relation_name IN ARRAY ARRAY[
|
|
98
|
+
'plans',
|
|
99
|
+
'membership_events',
|
|
100
|
+
'membership_freezes',
|
|
101
|
+
'membership_cancellations',
|
|
102
|
+
'class_bookings',
|
|
103
|
+
'class_waitlists',
|
|
104
|
+
'attendance_adjustments',
|
|
105
|
+
'trainer_certifications',
|
|
106
|
+
'trainer_schedules',
|
|
107
|
+
'staff_users',
|
|
108
|
+
'staff_roles',
|
|
109
|
+
'location_hours',
|
|
110
|
+
'rooms',
|
|
111
|
+
'equipment',
|
|
112
|
+
'equipment_maintenance',
|
|
113
|
+
'workout_programs',
|
|
114
|
+
'workout_exercises',
|
|
115
|
+
'member_goals',
|
|
116
|
+
'body_metrics',
|
|
117
|
+
'health_flags',
|
|
118
|
+
'waivers',
|
|
119
|
+
'billing_accounts',
|
|
120
|
+
'payment_methods',
|
|
121
|
+
'invoices',
|
|
122
|
+
'invoice_items',
|
|
123
|
+
'payments',
|
|
124
|
+
'refunds',
|
|
125
|
+
'promo_codes',
|
|
126
|
+
'member_promotions',
|
|
127
|
+
'leads',
|
|
128
|
+
'referrals',
|
|
129
|
+
'campaigns',
|
|
130
|
+
'notification_preferences',
|
|
131
|
+
'support_tickets'
|
|
132
|
+
]
|
|
133
|
+
LOOP
|
|
134
|
+
EXECUTE format(
|
|
135
|
+
'CREATE TABLE public.%I (
|
|
136
|
+
id text PRIMARY KEY,
|
|
137
|
+
organization_id text NOT NULL REFERENCES public.organizations(id) ON DELETE RESTRICT,
|
|
138
|
+
status text NOT NULL,
|
|
139
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp()
|
|
140
|
+
)',
|
|
141
|
+
relation_name
|
|
142
|
+
);
|
|
143
|
+
END LOOP;
|
|
144
|
+
END
|
|
145
|
+
$$;
|
|
146
|
+
|
|
147
|
+
INSERT INTO public.organizations (id, name) VALUES
|
|
148
|
+
('org-fitflow', 'FitFlow'),
|
|
149
|
+
('org-other', 'Other Fitness');
|
|
150
|
+
|
|
151
|
+
INSERT INTO public.locations (id, organization_id, name, region) VALUES
|
|
152
|
+
('loc-downtown', 'org-fitflow', 'Downtown', 'central'),
|
|
153
|
+
('loc-east', 'org-fitflow', 'Eastside', 'east'),
|
|
154
|
+
('loc-north', 'org-fitflow', 'North Loop', 'north'),
|
|
155
|
+
('loc-other', 'org-other', 'Other Downtown', 'west');
|
|
156
|
+
|
|
157
|
+
INSERT INTO public.trainers (id, organization_id, display_name) VALUES
|
|
158
|
+
('trainer-alex', 'org-fitflow', 'Alex'),
|
|
159
|
+
('trainer-jordan', 'org-fitflow', 'Jordan'),
|
|
160
|
+
('trainer-other', 'org-other', 'Other Trainer');
|
|
161
|
+
|
|
162
|
+
WITH member_rows AS (
|
|
163
|
+
SELECT
|
|
164
|
+
item,
|
|
165
|
+
CASE
|
|
166
|
+
WHEN item <= 12 THEN 'loc-downtown'
|
|
167
|
+
WHEN item <= 22 THEN 'loc-east'
|
|
168
|
+
ELSE 'loc-north'
|
|
169
|
+
END AS location_id,
|
|
170
|
+
CASE WHEN item % 2 = 0 THEN 'trainer-alex' ELSE 'trainer-jordan' END AS trainer_id,
|
|
171
|
+
CASE WHEN item % 7 = 0 THEN 'frozen' ELSE 'active' END AS status,
|
|
172
|
+
CASE WHEN item % 3 = 0 THEN 'elite' WHEN item % 2 = 0 THEN 'plus' ELSE 'basic' END AS tier
|
|
173
|
+
FROM generate_series(1, 30) AS item
|
|
174
|
+
)
|
|
175
|
+
INSERT INTO public.members (
|
|
176
|
+
id,
|
|
177
|
+
organization_id,
|
|
178
|
+
location_id,
|
|
179
|
+
assigned_trainer_id,
|
|
180
|
+
membership_status,
|
|
181
|
+
membership_tier,
|
|
182
|
+
loyalty_balance,
|
|
183
|
+
version,
|
|
184
|
+
payment_method,
|
|
185
|
+
home_address,
|
|
186
|
+
medical_waiver_notes
|
|
187
|
+
)
|
|
188
|
+
SELECT
|
|
189
|
+
'member-' || lpad(item::text, 3, '0'),
|
|
190
|
+
'org-fitflow',
|
|
191
|
+
location_id,
|
|
192
|
+
trainer_id,
|
|
193
|
+
status,
|
|
194
|
+
tier,
|
|
195
|
+
item * 10,
|
|
196
|
+
1,
|
|
197
|
+
'synthetic-card-token-' || item,
|
|
198
|
+
item || ' Synthetic Street',
|
|
199
|
+
'synthetic private medical note ' || item
|
|
200
|
+
FROM member_rows;
|
|
201
|
+
|
|
202
|
+
INSERT INTO public.members (
|
|
203
|
+
id,
|
|
204
|
+
organization_id,
|
|
205
|
+
location_id,
|
|
206
|
+
assigned_trainer_id,
|
|
207
|
+
membership_status,
|
|
208
|
+
membership_tier,
|
|
209
|
+
loyalty_balance,
|
|
210
|
+
version,
|
|
211
|
+
payment_method,
|
|
212
|
+
home_address,
|
|
213
|
+
medical_waiver_notes
|
|
214
|
+
) VALUES (
|
|
215
|
+
'other-member-001',
|
|
216
|
+
'org-other',
|
|
217
|
+
'loc-other',
|
|
218
|
+
'trainer-other',
|
|
219
|
+
'active',
|
|
220
|
+
'elite',
|
|
221
|
+
9999,
|
|
222
|
+
1,
|
|
223
|
+
'other-secret-payment',
|
|
224
|
+
'Other Tenant Address',
|
|
225
|
+
'other tenant private medical note'
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
INSERT INTO public.classes (id, organization_id, location_id, trainer_id, class_type, starts_at) VALUES
|
|
229
|
+
('class-downtown-w1', 'org-fitflow', 'loc-downtown', 'trainer-alex', 'strength', '2026-07-06T17:00:00Z'),
|
|
230
|
+
('class-downtown-w2', 'org-fitflow', 'loc-downtown', 'trainer-alex', 'cycling', '2026-07-13T17:00:00Z'),
|
|
231
|
+
('class-east-w1', 'org-fitflow', 'loc-east', 'trainer-jordan', 'yoga', '2026-07-06T18:00:00Z'),
|
|
232
|
+
('class-north-w2', 'org-fitflow', 'loc-north', 'trainer-jordan', 'strength', '2026-07-13T18:00:00Z'),
|
|
233
|
+
('class-other', 'org-other', 'loc-other', 'trainer-other', 'cycling', '2026-07-13T19:00:00Z');
|
|
234
|
+
|
|
235
|
+
WITH groups(prefix, organization_id, location_id, class_id, outcome, checked_in_at, first_member, group_size) AS (
|
|
236
|
+
VALUES
|
|
237
|
+
('downtown-w1', 'org-fitflow', 'loc-downtown', 'class-downtown-w1', 'attended', '2026-07-06T17:00:00Z'::timestamptz, 1, 6),
|
|
238
|
+
('downtown-w2', 'org-fitflow', 'loc-downtown', 'class-downtown-w2', 'attended', '2026-07-13T17:00:00Z'::timestamptz, 1, 9),
|
|
239
|
+
('east-w1', 'org-fitflow', 'loc-east', 'class-east-w1', 'late_cancel', '2026-07-06T18:00:00Z'::timestamptz, 13, 5),
|
|
240
|
+
('north-w2', 'org-fitflow', 'loc-north', 'class-north-w2', 'no_show', '2026-07-13T18:00:00Z'::timestamptz, 23, 2)
|
|
241
|
+
)
|
|
242
|
+
INSERT INTO public.check_ins (
|
|
243
|
+
id,
|
|
244
|
+
organization_id,
|
|
245
|
+
location_id,
|
|
246
|
+
member_id,
|
|
247
|
+
class_id,
|
|
248
|
+
outcome,
|
|
249
|
+
checked_in_at
|
|
250
|
+
)
|
|
251
|
+
SELECT
|
|
252
|
+
'checkin-' || prefix || '-' || item,
|
|
253
|
+
organization_id,
|
|
254
|
+
location_id,
|
|
255
|
+
'member-' || lpad((first_member + item - 1)::text, 3, '0'),
|
|
256
|
+
class_id,
|
|
257
|
+
outcome,
|
|
258
|
+
checked_in_at
|
|
259
|
+
FROM groups
|
|
260
|
+
CROSS JOIN LATERAL generate_series(1, group_size) AS item;
|
|
261
|
+
|
|
262
|
+
INSERT INTO public.check_ins (
|
|
263
|
+
id,
|
|
264
|
+
organization_id,
|
|
265
|
+
location_id,
|
|
266
|
+
member_id,
|
|
267
|
+
class_id,
|
|
268
|
+
outcome,
|
|
269
|
+
checked_in_at
|
|
270
|
+
)
|
|
271
|
+
SELECT
|
|
272
|
+
'other-checkin-' || item,
|
|
273
|
+
'org-other',
|
|
274
|
+
'loc-other',
|
|
275
|
+
'other-member-001',
|
|
276
|
+
'class-other',
|
|
277
|
+
'attended',
|
|
278
|
+
'2026-07-13T19:00:00Z'::timestamptz
|
|
279
|
+
FROM generate_series(1, 8) AS item;
|
|
280
|
+
|
|
281
|
+
ALTER TABLE public.organizations ENABLE ROW LEVEL SECURITY;
|
|
282
|
+
ALTER TABLE public.organizations FORCE ROW LEVEL SECURITY;
|
|
283
|
+
ALTER TABLE public.locations ENABLE ROW LEVEL SECURITY;
|
|
284
|
+
ALTER TABLE public.locations FORCE ROW LEVEL SECURITY;
|
|
285
|
+
ALTER TABLE public.trainers ENABLE ROW LEVEL SECURITY;
|
|
286
|
+
ALTER TABLE public.trainers FORCE ROW LEVEL SECURITY;
|
|
287
|
+
ALTER TABLE public.members ENABLE ROW LEVEL SECURITY;
|
|
288
|
+
ALTER TABLE public.members FORCE ROW LEVEL SECURITY;
|
|
289
|
+
ALTER TABLE public.classes ENABLE ROW LEVEL SECURITY;
|
|
290
|
+
ALTER TABLE public.classes FORCE ROW LEVEL SECURITY;
|
|
291
|
+
ALTER TABLE public.check_ins ENABLE ROW LEVEL SECURITY;
|
|
292
|
+
ALTER TABLE public.check_ins FORCE ROW LEVEL SECURITY;
|
|
293
|
+
|
|
294
|
+
CREATE POLICY organizations_org_read ON public.organizations
|
|
295
|
+
FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
|
|
296
|
+
USING (id = current_setting('app.tenant_id', true));
|
|
297
|
+
|
|
298
|
+
CREATE POLICY locations_org_read ON public.locations
|
|
299
|
+
FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
|
|
300
|
+
USING (organization_id = current_setting('app.tenant_id', true));
|
|
301
|
+
|
|
302
|
+
CREATE POLICY trainers_org_read ON public.trainers
|
|
303
|
+
FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
|
|
304
|
+
USING (organization_id = current_setting('app.tenant_id', true));
|
|
305
|
+
|
|
306
|
+
CREATE POLICY members_analytics_read ON public.members
|
|
307
|
+
FOR SELECT TO fitflow_analytics_reader
|
|
308
|
+
USING (organization_id = current_setting('app.tenant_id', true));
|
|
309
|
+
|
|
310
|
+
CREATE POLICY members_trainer_read ON public.members
|
|
311
|
+
FOR SELECT TO fitflow_trainer_reader, fitflow_writer
|
|
312
|
+
USING (
|
|
313
|
+
organization_id = current_setting('app.tenant_id', true)
|
|
314
|
+
AND assigned_trainer_id = current_setting('app.principal', true)
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
CREATE POLICY members_guarded_update ON public.members
|
|
318
|
+
FOR UPDATE TO fitflow_writer
|
|
319
|
+
USING (
|
|
320
|
+
organization_id = current_setting('app.tenant_id', true)
|
|
321
|
+
AND assigned_trainer_id = current_setting('app.principal', true)
|
|
322
|
+
)
|
|
323
|
+
WITH CHECK (
|
|
324
|
+
organization_id = current_setting('app.tenant_id', true)
|
|
325
|
+
AND assigned_trainer_id = current_setting('app.principal', true)
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
CREATE POLICY classes_org_read ON public.classes
|
|
329
|
+
FOR SELECT TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer
|
|
330
|
+
USING (organization_id = current_setting('app.tenant_id', true));
|
|
331
|
+
|
|
332
|
+
CREATE POLICY check_ins_org_read ON public.check_ins
|
|
333
|
+
FOR SELECT TO fitflow_analytics_reader
|
|
334
|
+
USING (organization_id = current_setting('app.tenant_id', true));
|
|
335
|
+
|
|
336
|
+
DO $$
|
|
337
|
+
DECLARE
|
|
338
|
+
relation_name text;
|
|
339
|
+
BEGIN
|
|
340
|
+
FOREACH relation_name IN ARRAY ARRAY[
|
|
341
|
+
'plans',
|
|
342
|
+
'membership_events',
|
|
343
|
+
'membership_freezes',
|
|
344
|
+
'membership_cancellations',
|
|
345
|
+
'class_bookings',
|
|
346
|
+
'class_waitlists',
|
|
347
|
+
'attendance_adjustments',
|
|
348
|
+
'trainer_certifications',
|
|
349
|
+
'trainer_schedules',
|
|
350
|
+
'staff_users',
|
|
351
|
+
'staff_roles',
|
|
352
|
+
'location_hours',
|
|
353
|
+
'rooms',
|
|
354
|
+
'equipment',
|
|
355
|
+
'equipment_maintenance',
|
|
356
|
+
'workout_programs',
|
|
357
|
+
'workout_exercises',
|
|
358
|
+
'member_goals',
|
|
359
|
+
'body_metrics',
|
|
360
|
+
'health_flags',
|
|
361
|
+
'waivers',
|
|
362
|
+
'billing_accounts',
|
|
363
|
+
'payment_methods',
|
|
364
|
+
'invoices',
|
|
365
|
+
'invoice_items',
|
|
366
|
+
'payments',
|
|
367
|
+
'refunds',
|
|
368
|
+
'promo_codes',
|
|
369
|
+
'member_promotions',
|
|
370
|
+
'leads',
|
|
371
|
+
'referrals',
|
|
372
|
+
'campaigns',
|
|
373
|
+
'notification_preferences',
|
|
374
|
+
'support_tickets'
|
|
375
|
+
]
|
|
376
|
+
LOOP
|
|
377
|
+
EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', relation_name);
|
|
378
|
+
EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', relation_name);
|
|
379
|
+
EXECUTE format(
|
|
380
|
+
'CREATE POLICY %I ON public.%I
|
|
381
|
+
FOR SELECT TO fitflow_analytics_reader
|
|
382
|
+
USING (organization_id = current_setting(''app.tenant_id'', true))',
|
|
383
|
+
relation_name || '_org_read',
|
|
384
|
+
relation_name
|
|
385
|
+
);
|
|
386
|
+
EXECUTE format('GRANT SELECT ON public.%I TO fitflow_analytics_reader', relation_name);
|
|
387
|
+
END LOOP;
|
|
388
|
+
END
|
|
389
|
+
$$;
|
|
390
|
+
|
|
391
|
+
GRANT CONNECT ON DATABASE fitflow TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer, fitflow_setup;
|
|
392
|
+
GRANT USAGE ON SCHEMA public TO fitflow_analytics_reader, fitflow_trainer_reader, fitflow_writer, fitflow_setup;
|
|
393
|
+
GRANT SELECT ON public.organizations, public.locations, public.trainers, public.members, public.classes, public.check_ins TO fitflow_analytics_reader;
|
|
394
|
+
GRANT SELECT ON public.organizations, public.locations, public.trainers, public.members, public.classes TO fitflow_trainer_reader;
|
|
395
|
+
GRANT SELECT, UPDATE (membership_status, loyalty_balance, version) ON public.members TO fitflow_writer;
|
|
396
|
+
GRANT CREATE ON SCHEMA public TO fitflow_setup;
|
|
397
|
+
|
|
398
|
+
CREATE TABLE public.synapsor_fixture_ready (
|
|
399
|
+
initialized_at timestamptz NOT NULL
|
|
400
|
+
);
|
|
401
|
+
INSERT INTO public.synapsor_fixture_ready (initialized_at) VALUES (clock_timestamp());
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
|
|
3
3
|
smoke:
|
|
4
4
|
python3 -m py_compile agent.py
|
|
5
|
-
npx -y
|
|
5
|
+
npx -y @synapsor/runner mcp serve-streamable-http --help >/dev/null
|
|
6
6
|
@printf '%s\n' "OpenAI Agents Streamable HTTP example smoke passed."
|
|
@@ -42,7 +42,7 @@ export SYNAPSOR_TENANT_ID="acme"
|
|
|
42
42
|
export SYNAPSOR_PRINCIPAL="openai_agent_demo"
|
|
43
43
|
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
44
44
|
|
|
45
|
-
npx -y
|
|
45
|
+
npx -y @synapsor/runner mcp serve-streamable-http \
|
|
46
46
|
--config ./synapsor.runner.json \
|
|
47
47
|
--store ./.synapsor/local.db \
|
|
48
48
|
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
|
|
@@ -30,13 +30,13 @@ OpenAI Agents stdio example smoke passed.
|
|
|
30
30
|
Generate `synapsor.runner.json` first:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
npx -y
|
|
33
|
+
npx -y @synapsor/runner demo
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
or connect your own staging database:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
npx -y
|
|
39
|
+
npx -y @synapsor/runner onboard db --from-env DATABASE_URL
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Then install the Python dependencies:
|