Operations

Bilko operational runbooks, incident management, and SLA documentation

Go-Live Runbook

Go-Live Runbook

Project: Bilko Version: 0.1 — Initial Production Launch Date: 2026-02-23 Author: Ops Architect Status: Draft Reviewers: Tech Lead, Alem Bašić

Document History

Version Date Author Changes
0.1 2026-02-23 Ops Architect Initial draft

1. Go-Live Overview

What: Bilko v1.0 — first production launch of the cloud accounting SaaS Target date: TBD (set when MVP backend complete) Deployment window: 2-hour window (prefer low-traffic: Tuesday–Thursday 10:00–12:00 CET) Go-Live Type: New product launch — no existing users to migrate

Incident Commander: Alem Bašić (+47 40 47 42 51) — primary Technical Lead: Alem Bašić (also, at MVP) War Room: Slack #bilko-deploys (create dedicated #bilko-launch channel for day-of) Status Page: status.bilko.io (PLANNED — configure BetterStack before launch)


2. Pre-Launch Checklist

T-7 Days: Infrastructure Verification

Owner: Alem Bašić | Due: T-7 days


T-5 Days: DNS Configuration

Owner: Alem Bašić | Due: T-5 days


T-5 Days: SSL Certificates

Owner: Alem Bašić | Due: T-5 days


T-3 Days: Third-Party Integrations

Owner: Alem Bašić | Due: T-3 days


T-2 Days: Monitoring Setup

Owner: Alem Bašić | Due: T-2 days


Owner: Alem Bašić | Due: T-1 day


T-1 Day: Backup Verification

Owner: Alem Bašić | Due: T-1 day


T-0: Final Checks (1 hour before launch)


3. Launch Day Procedure

H+0:00 — Deployment Start

Time Action Owner Status
H+0:00 Post in #bilko-launch: "Bilko launch starting" Alem
H+0:00 Confirm Railway deployment pipeline ready Alem
H+0:05 Trigger production deployment from main branch Alem
H+0:10 Monitor Railway build logs Alem

H+0:10 → H+0:20 — Deploy Verification

Time Action Owner Status
H+0:15 Confirm Railway deployment successful Alem
H+0:15 Verify health check: curl https://api.bilko.io/health Alem
H+0:20 Confirm Vercel frontend deployment successful Alem
H+0:20 Verify frontend: open https://bilko.io in browser Alem

H+0:20 → H+0:45 — Smoke Tests

Time Action Owner Status
H+0:20 Register new test account on bilko.io Alem
H+0:25 Create test invoice (RSD, 20% VAT) Alem
H+0:30 Verify invoice totals (subtotal + VAT = total) Alem
H+0:35 Create test expense with receipt upload Alem
H+0:40 Generate VAT report for current month Alem
H+0:45 All smoke tests PASS → proceed Alem

H+0:45 — Go-Live Declaration

Time Action Owner Status
H+0:45 Post in #bilko-launch: "Bilko is LIVE! bilko.io" Alem
H+0:50 Update status page: "All systems operational" Alem
H+1:00 Send launch announcement (if planned) Alem

4. Post-Launch Monitoring (First 48 Hours)

Period Check Frequency What to Watch
H+0 to H+4 Every 30 min BetterStack dashboard, Railway metrics, Sentry errors
H+4 to H+24 Every 60 min Same as above
Day 2 Every 4 hours Same as above
Day 3+ Standard monitoring BetterStack alerts only

Healthy indicators:


5. Rollback Triggers & Procedure

Rollback if:

Rollback procedure:

  1. Post in #bilko-launch: "Rolling back — [reason]"
  2. Frontend: Vercel Dashboard → Deployments → Promote previous → instant
  3. Backend: Railway Dashboard → Deployments → Redeploy previous → ~2 min
  4. Verify health: curl https://api.bilko.io/health
  5. Post update when rollback complete

6. Communication Plan

Launch Day Communications

Audience Channel When Message
Internal Slack #bilko-launch H+0 "Deployment started"
Internal Slack #bilko-launch H+0:45 "Bilko is live! bilko.io"
Beta users (if any) Email H+1:00 Launch announcement
Status page status.bilko.io H+0:45 "All systems operational"


Approval

Role Name Date Signature
Author Ops Architect 2026-02-23
Reviewer Tech Lead
Approver Alem Bašić

Incident Report Template

Incident Report

Project: Bilko Version: 0.1 Date: 2026-02-23 Author: Ops Architect Status: Draft (Template — fill in per incident) Reviewers: Tech Lead, Alem Bašić

Document History

Version Date Author Changes
0.1 2026-02-23 Ops Architect Initial draft

INSTRUCTIONS

Create a new incident report file for each incident:


Incident Report: [SHORT TITLE]

Incident ID: INC-YYYY-MM-DD-NNN Reported by: [Name] Date detected: YYYY-MM-DD HH:MM CET Date resolved: YYYY-MM-DD HH:MM CET Total duration: X hours Y minutes Severity: P0 / P1 / P2 / P3


1. Incident Summary

[Example: On YYYY-MM-DD at HH:MM CET, the Bilko API became unavailable due to an out-of-memory error on Railway. All users were unable to create invoices or access their dashboard for 47 minutes. The incident was resolved by restarting the Railway service and deploying a memory optimization patch.]


2. Impact

Metric Value
Duration X min
Users affected [All / Specific org / None]
Data loss [None / Describe if any]
Financial records at risk [None / Describe if any]
Revenue impact [None / Describe if applicable]
GDPR reportable [Yes / No] — if Yes, notify Datatilsynet within 72h

3. Timeline

Time (CET) Event
HH:MM First signs of degradation (detected by: BetterStack / user report / Sentry)
HH:MM Incident declared by [Name]
HH:MM [First diagnosis step]
HH:MM [Root cause identified]
HH:MM [Fix applied]
HH:MM Service restored, health check green
HH:MM Incident resolved, monitoring period started
HH:MM Monitoring period ended — all clear

4. Root Cause Analysis

Root cause: [One sentence — the actual technical cause]

Example root causes for Bilko:

Contributing factors:


5. Detection

How was the incident detected?

Time to detect: [X minutes from first symptom to alert]

Was detection fast enough? [Yes / No — if No, document what would have caught it faster]


6. Response

Response Actions Taken

Time Action Result
HH:MM [Action taken] [Result]

What Worked Well

What Didn't Work


7. Financial Data Integrity Check

Required for all P0/P1 incidents. Skip for P2/P3 that don't touch accounting.

Verification query (run after incident):

-- Check for unbalanced entries during incident window
SELECT t.id, t.created_at, t.amount
FROM transactions t
WHERE t.created_at BETWEEN '<incident_start>' AND '<incident_end>'
  AND t.id NOT IN (
    SELECT DISTINCT "transactionId" FROM transaction_entries WHERE type = 'debit'
  );
-- Expected: 0 rows (all transactions have debit entries)

-- Check invoice totals match line item sums
SELECT i.id, i.total_amount,
       SUM(ii.quantity * ii.unit_price * (1 + ii.tax_rate/100)) as calculated_total
FROM invoices i
JOIN invoice_items ii ON ii."invoiceId" = i.id
WHERE i.created_at BETWEEN '<incident_start>' AND '<incident_end>'
GROUP BY i.id, i.total_amount
HAVING ABS(i.total_amount - SUM(ii.quantity * ii.unit_price * (1 + ii.tax_rate/100))) > 0.0001;
-- Expected: 0 rows

8. User Communication

Channel When Sent Content Summary
status.bilko.io HH:MM "Investigating service disruption"
status.bilko.io HH:MM Status update with ETA
status.bilko.io HH:MM "Service restored"
Email to affected users HH:MM (if needed) [Summary of impact and resolution]

9. Action Items

# Action Owner Due Date Priority
1 [Preventive action] [Owner] YYYY-MM-DD P0/P1/P2
2 [Detection improvement] [Owner] YYYY-MM-DD P1
3 [Documentation update] [Owner] YYYY-MM-DD P2

10. Follow-Up


Approval

Role Name Date Signature
Author (on-call)
Reviewer Alem Bašić

Operational Runbook

Operational Runbook

Project: Bilko Version: 0.1 Date: 2026-02-23 Author: Ops Architect Status: Draft Reviewers: Tech Lead, Alem Bašić

Document History

Version Date Author Changes
0.1 2026-02-23 Ops Architect Initial draft

1. Service Overview

Service URL Platform Health Check
Frontend https://bilko.io Vercel curl -I https://bilko.io → 200
API https://api.bilko.io Railway EU West curl https://api.bilko.io/health
Database bilko_prod Railway PostgreSQL 15 Health check via API
File storage bilko-receipts Cloudflare R2 API upload test
Email noreply@bilko.io SendGrid Test email send

On-call: Alem Bašić (+47 40 47 42 51)


2. Routine Operations

2.1 Check System Health

# API health
curl https://api.bilko.io/health
# Expected: {"status":"ok","db":"ok","timestamp":"..."}

# Frontend
curl -I https://bilko.io
# Expected: HTTP/2 200

# Railway logs (last 50 lines)
railway logs --tail 50

# Railway metrics (via dashboard)
# Railway Dashboard → Project → api → Metrics

2.2 Deploy New Version

Standard deploy (automatic):

  1. Merge PR to main branch
  2. GitHub Actions CI pipeline runs automatically
  3. On pass: Vercel and Railway auto-deploy
  4. Monitor: Railway logs + BetterStack for 15 min post-deploy

Manual deploy (emergency):

# Deploy frontend manually
cd apps/web && vercel --prod

# Deploy backend manually
railway up --service api --environment production

# Run migrations before backend deploy
railway run npx prisma migrate deploy

2.3 Database Migrations

Never run migrations directly in production without backup:

# Step 1: Take backup
railway run pg_dump $DATABASE_URL -f backup_$(date +%Y%m%d_%H%M).dump

# Step 2: Test migration on staging
railway run --environment staging npx prisma migrate deploy

# Step 3: Apply to production (after staging verification)
railway run npx prisma migrate deploy

# Step 4: Verify
railway run npx prisma db pull  # Confirm schema matches

2.4 View Application Logs

# Railway API logs (streaming)
railway logs --service api

# Railway API logs (last 100 lines)
railway logs --service api --tail 100

# Filter for errors
railway logs --service api | grep -i error

# Filter for specific organization
railway logs --service api | grep "organizationId=<uuid>"

2.5 Environment Variable Updates

# View current env vars (Railway)
railway variables list --service api

# Update a secret (Railway CLI)
railway variables set JWT_SECRET=<new-value> --service api --environment production
# Restart service after update
railway service restart --service api

# Vercel env var update
vercel env add NEXT_PUBLIC_API_URL production

3. Monitoring & Alerting

3.1 Normal Operating Ranges

Metric Normal Range Alert if
API CPU 5–30% > 70% for 5 min
API Memory 200–800MB > 1.5GB
DB connections 2–10 active > 20 active
API P95 latency < 200ms > 1000ms
Error rate (5xx) < 0.1% > 1%
Uptime 100% Any downtime > 2 min

3.2 BetterStack Dashboards (PLANNED)

3.3 Sentry Error Monitoring (PLANNED)


4. Incident Response Procedures

4.1 API Down (all requests failing)

  1. Check Railway Dashboard → api → Status
  2. Check health endpoint: curl https://api.bilko.io/health
  3. Check Railway logs: railway logs --service api --tail 50
  4. Common causes and fixes:
Cause Fix
Recent bad deploy Railway → Deployments → Redeploy previous
Out of memory (OOM) Restart service, investigate memory leak
Database connection exhausted Restart service, check PgBouncer config
Database down See 4.2
  1. If not resolved in 5 min → post to #bilko-alerts, start incident response

4.2 Database Issues

Connection refused:

# Check Railway PostgreSQL status
# Railway Dashboard → Project → PostgreSQL → Status

# Test connection manually
railway run psql $DATABASE_URL -c "SELECT 1;"

High connection count:

# Check active connections
railway run psql $DATABASE_URL -c "
SELECT count(*), state, wait_event_type
FROM pg_stat_activity
GROUP BY state, wait_event_type
ORDER BY count DESC;"

# Kill idle connections if needed (after investigation)
railway run psql $DATABASE_URL -c "
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
  AND state_change < NOW() - INTERVAL '10 minutes';"

Slow queries:

# Find long-running queries
railway run psql $DATABASE_URL -c "
SELECT pid, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active' AND query_start < NOW() - INTERVAL '5 seconds'
ORDER BY duration DESC;"

4.3 High Error Rate

  1. Open Sentry → bilko-backend → Issues → Sort by date
  2. Identify most frequent error in last 15 min
  3. Check if error is from recent deploy: Railway → Deployments → check timestamp
  4. If financial logic error (VAT/double-entry): treat as P0, rollback immediately
  5. If non-financial error: assess impact, investigate root cause before rollback

4.4 Storage (R2) Issues

# Test R2 connectivity from API
railway run node -e "
const { S3Client, HeadBucketCommand } = require('@aws-sdk/client-s3');
const client = new S3Client({ endpoint: process.env.R2_ENDPOINT, ... });
client.send(new HeadBucketCommand({ Bucket: 'bilko-receipts' }))
  .then(() => console.log('R2 OK'))
  .catch(e => console.error('R2 Error:', e.message));"

R2 outage: file uploads fail but core accounting functionality works. Log errors, retry uploads. R2 outages are typically < 15 min.

4.5 Email Delivery Failure

# Check SendGrid activity
# SendGrid Dashboard → Activity → Filter by date → Look for bounces/blocks

# Test email sending manually
railway run node -e "
const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
sgMail.send({ to: 'alem@alai.no', from: 'noreply@bilko.io', subject: 'Test', text: 'Test' })
  .then(() => console.log('Email sent'))
  .catch(e => console.error('Email error:', e.message));"

Email failure: invoices cannot be sent. Users can still create and download invoices. Not P0 but resolve within 2h.


5. Maintenance Operations

5.1 Routine Backup Verification (Monthly)

# Verify backup exists and restore to staging
# Railway Dashboard → PostgreSQL → Backups → Select latest

# Download backup
railway run pg_dump $DATABASE_URL -f monthly_verify_$(date +%Y%m).dump

# Restore to staging and verify counts
railway run psql $STAGING_DB_URL < monthly_verify_$(date +%Y%m).dump
railway run psql $STAGING_DB_URL -c "SELECT COUNT(*) FROM organizations;"
railway run psql $STAGING_DB_URL -c "SELECT COUNT(*) FROM invoices;"

5.2 Certificate Renewal

Certificates auto-renew via Vercel (Let's Encrypt) and Railway. Monitor expiry dates:

echo | openssl s_client -connect bilko.io:443 2>/dev/null | openssl x509 -noout -dates
echo | openssl s_client -connect api.bilko.io:443 2>/dev/null | openssl x509 -noout -dates

Alert if expiry < 30 days.

5.3 Secret Rotation (Annual / On Compromise)

# Generate new JWT secrets
openssl rand -base64 32  # JWT_SECRET
openssl rand -base64 32  # JWT_REFRESH_SECRET

# Update in Railway (this will invalidate ALL existing sessions)
railway variables set JWT_SECRET=<new> --service api --environment production
railway variables set JWT_REFRESH_SECRET=<new> --service api --environment production
railway service restart --service api

# Notify users: all sessions invalidated, need to log in again

6. Useful Commands Reference

# Railway CLI quick reference
railway login                          # Authenticate
railway status                         # Project status
railway logs --service api             # Stream logs
railway run <command>                  # Run in Railway context
railway variables list --service api   # Show env vars
railway service restart --service api  # Restart service

# Database quick reference
railway run psql $DATABASE_URL         # Connect to database
railway run npx prisma studio          # Database GUI (opens on localhost:5555)
railway run npx prisma migrate deploy  # Apply pending migrations

# Vercel quick reference
vercel ls                              # List deployments
vercel --prod                          # Deploy to production
vercel rollback                        # Rollback to previous


Approval

Role Name Date Signature
Author Ops Architect 2026-02-23
Reviewer Tech Lead
Approver Alem Bašić

Post-Mortem Template

Post-Mortem

Project: Bilko Version: 0.1 Date: 2026-02-23 Author: Ops Architect Status: Draft (Template — fill in per P0 incident) Reviewers: Tech Lead, Alem Bašić

Document History

Version Date Author Changes
0.1 2026-02-23 Ops Architect Initial draft

INSTRUCTIONS

Post-mortems are required for all P0 incidents and recommended for P1. Schedule within 5 business days of incident resolution.

Blameless culture: This document is about systems and processes, not people. The goal is to learn and prevent recurrence, not to assign blame.

Create a new file: POST-MORTEM-YYYY-MM-DD-<title>.md in docs/operations/post-mortems/


Post-Mortem: [INCIDENT TITLE]

Post-Mortem Date: YYYY-MM-DD Incident Date: YYYY-MM-DD Incident Reference: INC-YYYY-MM-DD-NNN Facilitator: [Name] Attendees: [Names] Duration of post-mortem session: [X minutes]


1. Executive Summary

What happened: [2-3 sentences: the incident, impact, and resolution]

Why it happened: [1-2 sentences: root cause in plain language]

What we're doing to prevent recurrence: [1-2 sentences: top action items]


2. Impact Summary

Metric Value
Incident duration X hours Y minutes
Detection time X minutes from first symptom
Response time X minutes from alert to first action
Users impacted [All / Specific org / None]
Financial records affected [None / Describe]
Downtime cost (est.) [€X in lost productivity / TBD]
GDPR breach notification required [Yes / No]

3. Timeline (Detailed)

Time (CET) Event Who Notes
HH:MM [Event] [Person] [Notes]

Key timestamps:


4. Root Cause Analysis

What happened technically

[Detailed technical explanation of the failure chain. Be specific: which component, which code path, which query.]

For Bilko financial incidents, this section must include:

Why it happened

[The "5 Whys" — trace back to the systemic cause]

  1. Why did users lose access? → API returned 503 errors
  2. Why did the API return 503? → Railway service restarted due to OOM
  3. Why did the service run out of memory? → Invoice PDF generation loaded entire result set into memory
  4. Why did we not catch this? → No memory profiling in development, load testing not done
  5. Why was there no load testing? → No performance test plan existed

Root cause (systemic): [e.g., "Lack of memory usage monitoring and load testing prior to feature launch"]

Contributing Factors

Factor Category Severity
[Factor] [Process / Code / Infrastructure / Communication] [High / Med / Low]

5. What Went Well


6. What Went Poorly


7. Action Items

High Priority (P0/P1 — complete within 2 weeks)

# Action Category Owner Due Status
1 [Action] Prevention [Name] YYYY-MM-DD Open
2 [Action] Detection [Name] YYYY-MM-DD Open

Medium Priority (P2 — complete within 1 month)

# Action Category Owner Due Status
3 [Action] Process [Name] YYYY-MM-DD Open

Low Priority (P3 — add to backlog)

# Action Category Owner Due Status
4 [Action] Nice-to-have [Name] Backlog Open

Action categories: Prevention, Detection, Response, Documentation, Process, Tooling


8. Lessons Learned

Technical Lessons

[What did we learn about the technology, the system design, or the code?]

For Bilko financial system incidents:

Process Lessons

[What did we learn about our operations process, monitoring, or communication?]

Culture Lessons

[What did we learn about team practices, communication patterns, or organizational factors?]


9. Metrics Targets for Next Quarter

Based on this incident, these metrics are now tracked:

Metric Current Target By
Mean time to detect (MTTD) X min < 3 min YYYY-MM-DD
Mean time to respond (MTTR) X min < 10 min YYYY-MM-DD
Mean time to resolve (MTTR) X min < 60 min YYYY-MM-DD

10. Follow-Up Schedule


Approval

Role Name Date Signature
Facilitator
Reviewer Alem Bašić

SLA Report

SLA Report

Project: Bilko Version: 0.1 Date: 2026-02-23 Author: Ops Architect Status: Draft (Template — fill in monthly) Reviewers: Tech Lead, Alem Bašić

Document History

Version Date Author Changes
0.1 2026-02-23 Ops Architect Initial draft

INSTRUCTIONS

Generate monthly SLA reports by the 5th business day of the following month. File location: docs/operations/sla-reports/SLA-YYYY-MM.md


SLA Report: [Month YYYY]

Reporting Period: YYYY-MM-01 to YYYY-MM-[last day] Report Date: YYYY-MM-DD Prepared by: Ops Architect


1. SLA Summary

Service Level Objectives (SLOs)

SLO Target Actual Status
API availability ≥ 99.5% / month X.XX% ✅ / ❌
API P95 response time < 500ms XXXms ✅ / ❌
API error rate (5xx) < 0.5% X.XX% ✅ / ❌
Frontend availability ≥ 99.9% / month X.XX% ✅ / ❌
Uptime (combined) ≥ 99.5% / month X.XX% ✅ / ❌

SLO Calculation

API Availability = (Total minutes in month - Downtime minutes) / Total minutes × 100

Total minutes in month (28 days) = 40,320
Total minutes in month (31 days) = 44,640

Allowed downtime at 99.5%:
- 28-day month: 201.6 minutes = ~3h 22min
- 31-day month: 223.2 minutes = ~3h 43min

2. Uptime Metrics

API (api.bilko.io)

Metric Value
Measured uptime X.XX%
Total downtime X minutes
Number of incidents X
Longest outage X minutes

Frontend (bilko.io)

Metric Value
Measured uptime X.XX%
Total downtime X minutes
Number of incidents X

Source: BetterStack uptime monitoring (1-min check interval)


3. Performance Metrics

API Response Times

Metric Target Week 1 Week 2 Week 3 Week 4 Month Avg
P50 < 100ms
P95 < 500ms
P99 < 1000ms

Critical Endpoint Performance

Endpoint P95 Target P95 Actual Status
POST /api/v1/invoices < 500ms XXXms ✅ / ❌
GET /api/v1/invoices < 200ms XXXms ✅ / ❌
GET /api/v1/reports/vat < 3000ms XXXms ✅ / ❌
POST /api/v1/auth/login < 300ms XXXms ✅ / ❌

Source: Railway metrics + Sentry performance monitoring


4. Error Metrics

Error Rate by Week

Week Total Requests 5xx Errors Error Rate Status
Week 1 X.XX%
Week 2 X.XX%
Week 3 X.XX%
Week 4 X.XX%
Month X.XX%

Top Errors (Sentry)

# Error Count Affected Users Status
1 [Error message] X X Fixed / Investigating
2
3

5. Incidents This Month

Incident ID Date Duration Severity Root Cause Resolved
INC-YYYY-MM-DD-001 YYYY-MM-DD X min P0/P1/P2 [Short description] Yes

Total downtime from incidents: X minutes P0 incidents: X (target: 0) P1 incidents: X (target: < 2/month)


6. Financial Data Integrity (Monthly Verification)

Required: Verify no financial data corruption occurred this month.

Check Method Result
Double-entry balance SQL: SUM(debits) = SUM(credits) per org ✅ Balanced / ❌ Issues found
Invoice total accuracy SQL: total = subtotal + tax - discount ✅ Accurate / ❌ Issues found
VAT calculation accuracy Spot-check 10 random invoices ✅ Accurate / ❌ Issues found
No orphaned transactions SQL: all transactions have debit+credit ✅ Clean / ❌ Issues found

Verification queries run on: YYYY-MM-DD Verified by: [Name]

-- Monthly double-entry balance verification
SELECT
  o.name as organization_name,
  SUM(CASE WHEN te.type = 'debit' THEN te.amount ELSE 0 END) as total_debits,
  SUM(CASE WHEN te.type = 'credit' THEN te.amount ELSE 0 END) as total_credits,
  ABS(SUM(CASE WHEN te.type = 'debit' THEN te.amount ELSE -te.amount END)) as imbalance
FROM transaction_entries te
JOIN transactions t ON t.id = te."transactionId"
JOIN organizations o ON o.id = t."organizationId"
WHERE t.created_at >= DATE_TRUNC('month', CURRENT_DATE)
  AND t.created_at < DATE_TRUNC('month', CURRENT_DATE) + INTERVAL '1 month'
GROUP BY o.id, o.name
HAVING ABS(SUM(CASE WHEN te.type = 'debit' THEN te.amount ELSE -te.amount END)) > 0.0001
ORDER BY imbalance DESC;
-- Expected: 0 rows (all organizations balanced)

7. Infrastructure Metrics

Railway (Backend + Database)

Resource Average Peak Trend
API CPU X% X% Stable / Growing / Decreasing
API Memory XMB XMB Stable / Growing / Decreasing
DB Connections X avg X peak Stable / Growing
DB Storage XGB +X GB this month

Vercel (Frontend)

Metric Value
Total page views X
Unique visitors X
Average LCP Xms
Average CLS X

8. Cost Report

Service Budget Actual Variance
Railway (API + DB) €20 €XX +/-€XX
Vercel €0 €XX +/-€XX
Cloudflare R2 €1 €XX +/-€XX
SendGrid €0 €XX +/-€XX
Total €21 €XX +/-€XX

Month API Uptime P95 Latency Error Rate Incidents
[Previous -2]
[Previous -1]
[This month] X.XX% XXXms X.XX% X

10. Action Items from This Report

# Issue Action Owner Due
1 [Issue] [Action] [Owner] YYYY-MM-DD

Approval

Role Name Date Signature
Author Ops Architect
Reviewer Alem Bašić