Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

SYNCRO uses the [Supabase CLI](https://supabase.com/docs/guides/cli) to manage database migrations.
All migration files live in `supabase/migrations/` and are applied in lexicographic order.
`supabase/migrations/` is the canonical migration source of truth for this repository.
Legacy SQL snapshots under `backend/migrations/` and `backend/scripts/` are kept for reference only.

### Prerequisites

Expand Down Expand Up @@ -90,12 +92,15 @@ Every pull request that touches `supabase/migrations/` triggers the
2. Applies all migrations from scratch (`supabase db push`)
3. Runs `supabase db lint` to catch SQL issues

Changes under `backend/migrations/` and `backend/scripts/` are not part of the canonical migration validation path.

A PR cannot be merged if this workflow fails.

### Seed data

`supabase/seed.sql` contains fake data for local development only.
It is applied automatically by `supabase db reset`.
Use the same seed file for local development and E2E bootstrap runs.

**Never add real emails, payment data, or any PII to seed.sql.**
Thank you for your interest in contributing! This guide will help you set up the project, follow conventions, and submit high-quality contributions.
Expand Down
3 changes: 3 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ STRIPE_WEBHOOK_SECRET=whsec_...

# Telegram Bot
TELEGRAM_BOT_TOKEN=your_telegram_bot_token

# Slack notifications
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
# Secret token sent by Telegram in X-Telegram-Bot-Api-Secret-Token header (set via setWebhook)
TELEGRAM_WEBHOOK_SECRET=your_telegram_webhook_secret

Expand Down
11 changes: 10 additions & 1 deletion backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The backend is responsible for:
- **Authentication**: JWT-based auth with HTTP-only cookies; role-based access control (RBAC)
- **Email Integration**: Gmail and Outlook OAuth scanning for subscription detection
- **Payment Processing**: Stripe and Paystack webhook handling
- **Notifications**: Telegram bot, push notifications (Web Push/VAPID), email digests, and quiet-hours support
- **Notifications**: Telegram bot, Slack webhooks, push notifications (Web Push/VAPID), email digests, and quiet-hours support
- **Blockchain**: Soroban/Stellar event indexing with Redis-backed dead-letter queue fallback
- **Observability**: Sentry error tracking, Winston structured logging, health snapshots

Expand Down Expand Up @@ -122,6 +122,9 @@ STRIPE_WEBHOOK_SECRET=whsec_...
# Telegram Bot
TELEGRAM_BOT_TOKEN=...

# Slack notifications
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...

# Encryption (for stored API keys)
ENCRYPTION_KEY=your_32_byte_encryption_key

Expand Down Expand Up @@ -344,6 +347,12 @@ All routes are registered in `src/index.ts`. Auth middleware (`authenticate`) is
| GET | `/status` | Get push notification status |
| GET | `/vapid-public-key` | Get VAPID public key |

### Slack Integration — `/api/integrations/slack`

| Method | Path | Description |
|--------|------|-------------|
| GET | `/status` | Check whether Slack webhook delivery is configured |

### Risk Score — `/api/risk-score`

| Method | Path | Description |
Expand Down
14 changes: 14 additions & 0 deletions backend/routes/integrations/slack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Router, Response, NextFunction } from 'express';
import { AuthenticatedRequest } from '../../src/middleware/auth';
import { slackService } from '../../src/services/slack-service';

const router: Router = Router();

router.get('/status', (_req: AuthenticatedRequest, res: Response, _next: NextFunction) => {
res.json({
success: true,
data: slackService.getStatus(),
});
});

export default router;
3 changes: 1 addition & 2 deletions backend/scripts/007_create_reminder_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ create table if not exists public.notification_deliveries (
id uuid primary key default gen_random_uuid(),
reminder_schedule_id uuid not null references public.reminder_schedules(id) on delete cascade,
user_id uuid not null references auth.users(id) on delete cascade,
channel text not null check (channel in ('email', 'push')),
channel text not null check (channel in ('email', 'push', 'slack')),
status text not null check (status in ('pending', 'sent', 'failed', 'retrying')),
attempt_count integer default 0,
max_attempts integer default 3,
Expand Down Expand Up @@ -103,4 +103,3 @@ create index if not exists blockchain_logs_user_id_idx on public.blockchain_logs
create index if not exists blockchain_logs_event_type_idx on public.blockchain_logs(event_type);
create index if not exists blockchain_logs_status_idx on public.blockchain_logs(status);
create index if not exists blockchain_logs_transaction_hash_idx on public.blockchain_logs(transaction_hash);

2 changes: 2 additions & 0 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import walletRoutes from './routes/wallet';
import emailRescanRoutes from './routes/email-rescan';
import gmailRouter from '../routes/integrations/gmail'
import outlookRouter from '../routes/integrations/outlook'
import slackRouter from '../routes/integrations/slack'
import { createExchangeRatesRouter } from './routes/exchange-rates';
import { ExchangeRateService } from './services/exchange-rate/exchange-rate-service';
import { FiatRateProvider } from './services/exchange-rate/fiat-provider';
Expand Down Expand Up @@ -128,6 +129,7 @@ app.use('/api/team', teamRoutes);
app.use('/api/audit', auditRoutes);
app.use('/api/integrations/gmail', authenticate, gmailRouter);
app.use('/api/integrations/outlook', authenticate, outlookRouter);
app.use('/api/integrations/slack', authenticate, slackRouter);
app.use('/api/integrations/email', authenticate, emailRescanRoutes);
app.use('/api/webhooks', webhookRoutes);
app.use('/api/compliance', complianceRoutes);
Expand Down
Loading
Loading