mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
chore(harness): make repository agent-ready
Add concise routed context, task-aware agent roles, focused skills, and structured learning promotion.\n\nUnify local development and workspace tooling, add layered test and E2E verification, harden MCP authentication, and gate deployment behind verification and explicit production promotion.
This commit is contained in:
1 parent
5a69bbc1a5
commit
01bb8225ae
125 files changed
+5078
-24529
No files matched your search
@@ -0,0 +1,25 @@
|
||||
# Supabase backend
|
||||
|
||||
This directory owns local configuration, migrations, Edge Functions, seeds, and
|
||||
integration tests.
|
||||
|
||||
## Schema safety
|
||||
|
||||
- Create migrations only with `npm run db:migration:new -- <name>`.
|
||||
- Edit only `apps/supabase/migrations/`; this is the authoritative migration tree.
|
||||
- Never use any remote `apply_migration` tool.
|
||||
- Never execute DDL through MCP SQL tools; those tools are `SELECT`-only.
|
||||
- Never link or reset a remote project during local verification.
|
||||
- Cron/function URLs must resolve per environment, never hardcode production.
|
||||
|
||||
## Function boundaries
|
||||
|
||||
- Set deployment JWT configuration deliberately per function. A function using
|
||||
`verify_jwt = false` must implement the correct manual, webhook, cron, or internal
|
||||
authentication boundary; it is not permission to omit authorization.
|
||||
- Service-role clients never run in customer clients.
|
||||
- Preserve CORS handling and return non-sensitive errors.
|
||||
- Test RLS, authorization, and important side effects, not only HTTP status.
|
||||
|
||||
Verify with local reset, `npm run test:supabase`, invariant lint, and affected
|
||||
client tests. See `docs/operations/database-migrations.md`.
|
||||
@@ -1,136 +0,0 @@
|
||||
# Supabase - Agent Guidelines
|
||||
|
||||
**STRICT RULES - DO NOT VIOLATE**
|
||||
|
||||
## Architecture
|
||||
|
||||
This contains Supabase configuration:
|
||||
- **Migrations**: SQL migrations in `migrations/`
|
||||
- **Edge Functions**: Deno functions in `functions/`
|
||||
- **Email Templates**: Auth email templates in `email-templates/`
|
||||
- **Config**: Local development config in `config.toml`
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
functions/
|
||||
delete-relationship/ # Delete couple relationship
|
||||
manage-couple/ # Join/leave couple
|
||||
revenuecat-webhook/ # Subscription webhook handler
|
||||
send-message-notification/ # Push notification for messages
|
||||
send-notification/ # Push notification for matches
|
||||
submit-response/ # Save response, check matches
|
||||
sync-subscription/ # Sync RevenueCat status
|
||||
migrations/ # SQL migrations
|
||||
email-templates/ # Auth email templates
|
||||
config.toml # Local dev configuration
|
||||
```
|
||||
|
||||
## Critical Rules
|
||||
|
||||
### Edge Function Deployment
|
||||
|
||||
**ALWAYS use `verify_jwt: false`** when deploying via MCP tools.
|
||||
|
||||
Supabase's built-in JWT verification causes 401 errors. Handle auth manually:
|
||||
|
||||
```typescript
|
||||
const { data: { user }, error: authError } = await supabase.auth.getUser(
|
||||
authHeader.replace("Bearer ", "")
|
||||
);
|
||||
```
|
||||
|
||||
### Edge Function Pattern
|
||||
|
||||
All edge functions MUST follow this structure:
|
||||
|
||||
```typescript
|
||||
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
|
||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
|
||||
};
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
// Handle CORS preflight
|
||||
if (req.method === "OPTIONS") {
|
||||
return new Response("ok", { headers: corsHeaders });
|
||||
}
|
||||
|
||||
try {
|
||||
const supabase = createClient(
|
||||
Deno.env.get("SUPABASE_URL")!,
|
||||
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
|
||||
);
|
||||
|
||||
// Manual auth verification
|
||||
const authHeader = req.headers.get("Authorization");
|
||||
if (!authHeader) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Missing authorization header" }),
|
||||
{ status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
const { data: { user }, error: authError } = await supabase.auth.getUser(
|
||||
authHeader.replace("Bearer ", "")
|
||||
);
|
||||
|
||||
// ... function logic
|
||||
} catch (error) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Function Auth Methods
|
||||
|
||||
| Function | Auth Method |
|
||||
|----------|-------------|
|
||||
| `manage-couple` | Manual via getUser() |
|
||||
| `submit-response` | Manual via getUser() |
|
||||
| `sync-subscription` | Manual via getUser() |
|
||||
| `delete-relationship` | Manual via getUser() |
|
||||
| `revenuecat-webhook` | Webhook signature validation |
|
||||
| `send-notification` | Internal trigger (no auth) |
|
||||
| `send-message-notification` | Internal trigger (no auth) |
|
||||
|
||||
### Migration Rules
|
||||
|
||||
- Use `apply_migration` MCP tool for DDL operations
|
||||
- Never hardcode generated IDs in data migrations
|
||||
- Always verify target environment (prod vs non-prod) before running
|
||||
|
||||
### Database Patterns
|
||||
|
||||
- Use UPSERT with `onConflict` for responses: `onConflict: "user_id,question_id"`
|
||||
- Use UPSERT for matches: `onConflict: "couple_id,question_id"`
|
||||
- RLS policies enforce couple-level data isolation
|
||||
|
||||
### Profile Creation
|
||||
|
||||
The `on_auth_user_created` trigger automatically creates a profile. Never assume a profile exists without checking - check for null before operations.
|
||||
|
||||
## MCP Environments
|
||||
|
||||
| Environment | MCP Server |
|
||||
|-------------|------------|
|
||||
| Production | `mcp__sauci-prod__*` |
|
||||
| Non-Production | `mcp__sauci-non-prod__*` |
|
||||
|
||||
**ALWAYS verify environment before destructive operations.**
|
||||
|
||||
## Forbidden Actions
|
||||
|
||||
1. **DO NOT** use `verify_jwt: true` when deploying functions via MCP
|
||||
2. **DO NOT** skip CORS headers in responses
|
||||
3. **DO NOT** use service role key on client-side
|
||||
4. **DO NOT** hardcode IDs in migrations
|
||||
5. **DO NOT** assume profiles exist - always check for null
|
||||
6. **DO NOT** run migrations on production without explicit confirmation
|
||||
7. **DO NOT** expose internal error details in responses
|
||||
@@ -1,5 +1,11 @@
|
||||
{
|
||||
"name": "@sauci/supabase",
|
||||
"version": "1.0.0",
|
||||
"private": true
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "node ../../scripts/lint-harness.mjs --scope supabase",
|
||||
"test": "node -e \"console.log('Supabase integration tests run through npm run test:supabase')\"",
|
||||
"typecheck": "node -e \"console.log('Edge Functions are checked by Deno during test:supabase')\"",
|
||||
"build": "node -e \"console.log('Supabase deployables do not require a build step')\""
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ export async function createRedemptionCode() {
|
||||
const { data, error } = await adminClient.from("redemption_codes").insert({
|
||||
code,
|
||||
max_uses: 1,
|
||||
active: true,
|
||||
is_active: true,
|
||||
expires_at: new Date(Date.now() + 3600000).toISOString() // 1 hour
|
||||
}).select().single();
|
||||
|
||||
|
||||
Reference in new issue
Block a user