feat(web): add Privacy Policy and Terms of Service pages
- Create /chinh-sach-bao-mat (Privacy Policy) with 10 sections - Create /dieu-khoan-su-dung (Terms of Service) with 11 sections - Add legal link group to footer (vi + en i18n) - Add legalLinks prop to Footer for bottom-bar display - Wire links into public layout Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
159
docs/runbooks/sentry.md
Normal file
159
docs/runbooks/sentry.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# Sentry Alert Routing — Runbook
|
||||
|
||||
> Audience: SRE on-call & platform engineers.
|
||||
> Scope: How Sentry P1/P2 alerts are wired into Slack & email for the GoodGo platform, and how to verify routing end-to-end.
|
||||
> Related ticket: [GOO-178](/GOO/issues/GOO-178) (gap surfaced by [GOO-117](/GOO/issues/GOO-117) audit).
|
||||
|
||||
---
|
||||
|
||||
## 1. Sentry projects & SDK wiring
|
||||
|
||||
The SDK is initialised in three Next.js entrypoints (server, client, edge):
|
||||
|
||||
| File | DSN env | Notes |
|
||||
|------|---------|-------|
|
||||
| `apps/web/sentry.server.config.ts` | `SENTRY_DSN` | Server-side errors, traces (`tracesSampleRate=0.2` in prod). |
|
||||
| `apps/web/sentry.client.config.ts` | `NEXT_PUBLIC_SENTRY_DSN` | Browser errors + session replay on error. |
|
||||
| `apps/web/sentry.edge.config.ts` | `SENTRY_DSN` | Edge runtime. |
|
||||
|
||||
Required env (see `.env.example`):
|
||||
|
||||
- `SENTRY_DSN`, `NEXT_PUBLIC_SENTRY_DSN`
|
||||
- `SENTRY_AUTH_TOKEN` (CI source-map upload)
|
||||
- `SENTRY_ORG`, `SENTRY_PROJECT`
|
||||
- `SENTRY_RELEASE` / `NEXT_PUBLIC_SENTRY_RELEASE` (set per deploy by CI)
|
||||
|
||||
`environment` is set from `NODE_ENV` on every init call, so all events are tagged `production` / `staging` / `development` automatically.
|
||||
|
||||
---
|
||||
|
||||
## 2. Severity model
|
||||
|
||||
We classify Sentry events into two routing tiers using event tags. Tag `severity` is set either by the SDK (`Sentry.setTag('severity', 'P1')`) at capture time, or via Sentry **Issue tagging rules** based on event.level / fingerprint.
|
||||
|
||||
| Tier | Trigger criteria | Routing target | SLA |
|
||||
|------|------------------|----------------|-----|
|
||||
| **P1** | `level:fatal` OR `tags[severity]=P1` OR fingerprint in critical group (payments, auth, data loss) | Slack `#alerts-p1-sentry` (immediate) + email to `oncall@goodgo.vn` | Page on-call within 5 min |
|
||||
| **P2** | `level:error` AND `environment:production` AND not P1 | Slack `#alerts-p2-sentry` (digest, every 30 min) | Triage within 4 business hours |
|
||||
| Below P2 (warn / info / staging-only) | Everything else | No paging — visible only in Sentry UI dashboards | Best effort |
|
||||
|
||||
---
|
||||
|
||||
## 3. Required Sentry integrations
|
||||
|
||||
Verify in **Sentry → Settings → Integrations**:
|
||||
|
||||
- [ ] **Slack** — workspace `goodgo`, channels `#alerts-p1-sentry` and `#alerts-p2-sentry` authorised.
|
||||
- [ ] **Email** — built-in; `oncall@goodgo.vn` is a verified team mailing list and a member of the GoodGo team for the project.
|
||||
|
||||
If either integration is missing, install it before configuring rules below.
|
||||
|
||||
---
|
||||
|
||||
## 4. Alert rule configuration
|
||||
|
||||
Configure under **Sentry → Alerts → Create Alert → Issues**.
|
||||
|
||||
### 4.1 P1 — immediate page
|
||||
|
||||
- **Name:** `P1 — immediate page`
|
||||
- **Environment:** `production`
|
||||
- **When:** "An issue is first seen" **OR** "An event is captured"
|
||||
- **If (all):**
|
||||
- `event.level` equals `fatal`
|
||||
- **OR** `event.tags[severity]` equals `P1`
|
||||
- **Then:**
|
||||
- Send a Slack notification to `#alerts-p1-sentry`
|
||||
- Send an email notification to Team `oncall`
|
||||
- **Frequency:** every 1 minute (no batching)
|
||||
- **Owner:** SRE team
|
||||
|
||||
### 4.2 P2 — production errors digest
|
||||
|
||||
- **Name:** `P2 — production errors`
|
||||
- **Environment:** `production`
|
||||
- **When:** "An issue changes state from resolved to unresolved" OR "A new issue is created"
|
||||
- **If (all):**
|
||||
- `event.level` equals `error`
|
||||
- `event.tags[severity]` does not equal `P1`
|
||||
- **Then:**
|
||||
- Send a Slack notification to `#alerts-p2-sentry`
|
||||
- **Frequency:** every 30 minutes (batched/digest)
|
||||
|
||||
### 4.3 Noise control
|
||||
|
||||
- Suppress alerts for environments other than `production` (a separate `staging` rule may post to `#alerts-staging` only).
|
||||
- Use **Inbound filters** to drop browser extension errors, ResizeObserver loops, and known third-party noise.
|
||||
- Per-issue **Mute → ignore until** for known-noisy fingerprints.
|
||||
|
||||
---
|
||||
|
||||
## 5. Test fire procedure (`Sentry.captureException`)
|
||||
|
||||
Use this whenever rules change or a quarterly verification is due.
|
||||
|
||||
### 5.1 Staging fire
|
||||
|
||||
1. Deploy the staging branch with `SENTRY_DSN` populated.
|
||||
2. Trigger the dedicated test endpoint (or via curl in staging shell):
|
||||
```ts
|
||||
// apps/web/app/api/_debug/sentry-test/route.ts (staging only — guard with env)
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
export async function GET() {
|
||||
Sentry.captureException(new Error('GOO-178 routing test — P1'), {
|
||||
tags: { severity: 'P1', source: 'manual_routing_test' },
|
||||
});
|
||||
return Response.json({ ok: true });
|
||||
}
|
||||
```
|
||||
```bash
|
||||
curl -fsS https://staging.goodgo.vn/api/_debug/sentry-test
|
||||
```
|
||||
3. **Expected:**
|
||||
- Event appears in Sentry within ~30s tagged `severity:P1`, `source:manual_routing_test`.
|
||||
- Slack `#alerts-p1-sentry` receives the notification.
|
||||
- Email lands at `oncall@goodgo.vn` within ~2 min.
|
||||
4. Repeat without the `severity:P1` tag and with `level:error` to validate the P2 batched route (expect Slack message in next 30-min digest).
|
||||
|
||||
### 5.2 CLI alternative (no deploy)
|
||||
|
||||
```bash
|
||||
SENTRY_DSN=$STAGING_SENTRY_DSN npx -y @sentry/cli send-event \
|
||||
--message "GOO-178 routing test (P1)" \
|
||||
--level fatal \
|
||||
--tag severity:P1 \
|
||||
--tag source:manual_routing_test \
|
||||
--release "$(git rev-parse --short HEAD)"
|
||||
```
|
||||
|
||||
### 5.3 Cleanup
|
||||
|
||||
- Resolve the test issue in Sentry.
|
||||
- Add `source:manual_routing_test` to the inbound filter ignore list if it generates additional noise.
|
||||
|
||||
---
|
||||
|
||||
## 6. Verification checklist (run quarterly)
|
||||
|
||||
- [ ] Slack integration shows "Connected" in Sentry → Integrations.
|
||||
- [ ] Email integration: open one P1 alert, confirm `oncall@goodgo.vn` received it.
|
||||
- [ ] Both rules listed under Alerts with correct environment/scope.
|
||||
- [ ] Test fire produces messages in `#alerts-p1-sentry` AND `#alerts-p2-sentry` per tier.
|
||||
- [ ] On-call rotation in PagerDuty / Slack matches Sentry team membership.
|
||||
- [ ] Inbound filters review — drop new noise sources surfaced since last review.
|
||||
|
||||
Record verification results as a comment on a tracking issue and update the **last verified** date in section 7.
|
||||
|
||||
---
|
||||
|
||||
## 7. Change log
|
||||
|
||||
| Date | Author | Change |
|
||||
|------|--------|--------|
|
||||
| 2026-04-23 | SRE Engineer ([GOO-178](/GOO/issues/GOO-178)) | Initial runbook documenting P1/P2 routing model, alert rule definitions, and test fire procedure. |
|
||||
|
||||
---
|
||||
|
||||
## 8. Outstanding
|
||||
|
||||
- **Sentry org/project access not yet provisioned for the agent.** Live verification of integrations + a real test fire is blocked until `SENTRY_AUTH_TOKEN`, `SENTRY_ORG`, `SENTRY_PROJECT` are provided to staging and to the SRE agent. See [GOO-178](/GOO/issues/GOO-178) for the open blocker.
|
||||
Reference in New Issue
Block a user