vibecarbon 0.1.6 → 0.2.0
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/carbon/.env.example +3 -2
- package/carbon/DEVELOPMENT.md +18 -3
- package/carbon/PRODUCTION.md +1 -1
- package/carbon/content/docs/cli.mdx +3 -3
- package/carbon/content/docs/deployment.mdx +1 -1
- package/carbon/content/docs/development.mdx +1 -1
- package/carbon/content/docs/getting-started.mdx +0 -1
- package/carbon/docker-compose.prod.yml +11 -1
- package/carbon/scripts/dev-init.js +1 -1
- package/carbon/scripts/generate-dev-configs.sh +5 -7
- package/carbon/scripts/validate-dev-configs.sh +5 -7
- package/carbon/src/client/components/TechStackSection.tsx +0 -68
- package/carbon/src/client/index.css +0 -14
- package/carbon/src/client/locales/de.json +0 -18
- package/carbon/src/client/locales/en.json +86 -36
- package/carbon/src/client/locales/es.json +0 -18
- package/carbon/src/client/locales/fr.json +0 -18
- package/carbon/src/client/locales/pt.json +0 -18
- package/carbon/src/client/pages/Home.tsx +0 -3
- package/package.json +4 -2
- package/services/index.json +29 -0
- package/services/metabase/compose/docker-compose.override.yml +14 -0
- package/services/metabase/compose/docker-compose.prod.yml +29 -0
- package/services/metabase/compose/docker-compose.yml +68 -0
- package/services/metabase/db/init.sh +29 -0
- package/services/metabase/docs/integration.md +191 -0
- package/services/metabase/k8s/deployment.yaml +88 -0
- package/services/metabase/k8s/ingressroute.yaml +22 -0
- package/services/metabase/k8s/kustomization.yaml +9 -0
- package/services/metabase/k8s/network-policy.yaml +74 -0
- package/services/metabase/k8s/pvc.yaml +12 -0
- package/services/metabase/k8s/service.yaml +15 -0
- package/services/metabase/manifest.json +34 -0
- package/services/metabase/scripts/setup.sh +152 -0
- package/services/n8n/compose/docker-compose.override.yml +14 -0
- package/services/n8n/compose/docker-compose.prod.yml +32 -0
- package/services/n8n/compose/docker-compose.yml +99 -0
- package/services/n8n/db/init.sh +25 -0
- package/services/n8n/docs/SSO.md +124 -0
- package/services/n8n/docs/integration.md +155 -0
- package/services/n8n/hooks/hooks.js +131 -0
- package/services/n8n/k8s/deployment.yaml +116 -0
- package/services/n8n/k8s/ingressroute.yaml +24 -0
- package/services/n8n/k8s/kustomization.yaml +9 -0
- package/services/n8n/k8s/network-policy.yaml +82 -0
- package/services/n8n/k8s/pvc.yaml +14 -0
- package/services/n8n/k8s/service.yaml +14 -0
- package/services/n8n/manifest.json +36 -0
- package/services/n8n/scripts/setup.sh +42 -0
- package/{carbon/docker-compose.observability.prod.yml → services/observability/compose/docker-compose.prod.yml} +8 -0
- package/services/observability/docs/integration.md +31 -0
- package/services/observability/k8s/grafana-deployment.yaml +107 -0
- package/services/observability/k8s/grafana-provisioning-configmap.yaml +65 -0
- package/services/observability/k8s/grafana-pvc.yaml +14 -0
- package/services/observability/k8s/grafana-service.yaml +16 -0
- package/services/observability/k8s/ingressroute.yaml +22 -0
- package/services/observability/k8s/kustomization.yaml +24 -0
- package/services/observability/k8s/loki-configmap.yaml +74 -0
- package/services/observability/k8s/loki-deployment.yaml +72 -0
- package/services/observability/k8s/loki-pvc.yaml +14 -0
- package/services/observability/k8s/loki-service.yaml +16 -0
- package/services/observability/k8s/network-policy.yaml +141 -0
- package/services/observability/k8s/prometheus-configmap.yaml +80 -0
- package/services/observability/k8s/prometheus-deployment.yaml +78 -0
- package/services/observability/k8s/prometheus-pvc.yaml +14 -0
- package/services/observability/k8s/prometheus-rbac.yaml +55 -0
- package/services/observability/k8s/prometheus-service.yaml +16 -0
- package/services/observability/manifest.json +28 -0
- package/services/redis/compose/docker-compose.prod.yml +10 -0
- package/services/redis/compose/docker-compose.yml +24 -0
- package/services/redis/docs/integration.md +148 -0
- package/services/redis/k8s/deployment.yaml +70 -0
- package/services/redis/k8s/kustomization.yaml +8 -0
- package/services/redis/k8s/network-policy.yaml +20 -0
- package/services/redis/k8s/pvc.yaml +12 -0
- package/services/redis/k8s/service.yaml +15 -0
- package/services/redis/manifest.json +30 -0
- package/services/s3/compose/docker-compose.s3-ha.yml +86 -0
- package/services/s3/compose/docker-compose.s3.yml +35 -0
- package/services/s3/manifest.json +87 -0
- package/src/add.js +57 -89
- package/src/cli.js +1 -1
- package/src/create.js +3 -87
- package/src/lib/deploy/bundle.js +4 -2
- package/src/lib/deploy/compose/index.js +45 -17
- package/src/lib/deploy/orchestrator.js +13 -1
- package/src/remove.js +9 -6
- package/carbon/content/docs/optional-services.mdx +0 -160
- package/carbon/src/client/components/MetricsStrip.tsx +0 -48
- /package/{carbon/docker-compose.observability.override.yml → services/observability/compose/docker-compose.override.yml} +0 -0
- /package/{carbon/docker-compose.observability.yml → services/observability/compose/docker-compose.yml} +0 -0
- /package/{carbon → services/observability}/volumes/grafana/dashboards/logs.json +0 -0
- /package/{carbon → services/observability}/volumes/grafana/dashboards/overview.json +0 -0
- /package/{carbon → services/observability}/volumes/grafana/dashboards/postgresql.json +0 -0
- /package/{carbon → services/observability}/volumes/grafana/dashboards.dev/logs.json +0 -0
- /package/{carbon → services/observability}/volumes/grafana/dashboards.dev/overview.json +0 -0
- /package/{carbon → services/observability}/volumes/grafana/dashboards.dev/postgresql.json +0 -0
- /package/{carbon → services/observability}/volumes/grafana/provisioning/dashboards/dashboards.dev.yml +0 -0
- /package/{carbon → services/observability}/volumes/grafana/provisioning/dashboards/dashboards.yml +0 -0
- /package/{carbon → services/observability}/volumes/grafana/provisioning/datasources/datasources.yml +0 -0
- /package/{carbon → services/observability}/volumes/loki/loki-config.yml +0 -0
- /package/{carbon → services/observability}/volumes/prometheus/prometheus.yml +0 -0
- /package/{carbon → services/observability}/volumes/promtail/promtail-config.yml +0 -0
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibecarbon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Create and manage production-ready Vibecarbon applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./src/cli.js",
|
|
7
7
|
"files": [
|
|
8
8
|
"src",
|
|
9
|
-
"carbon"
|
|
9
|
+
"carbon",
|
|
10
|
+
"services"
|
|
10
11
|
],
|
|
11
12
|
"scripts": {
|
|
13
|
+
"dev": "node scripts/dev.js",
|
|
12
14
|
"lint": "node scripts/check-shell-safety.js && node scripts/check-stale-deploy-references.js && biome check src/ tests/",
|
|
13
15
|
"lint:shell": "node scripts/check-shell-safety.js",
|
|
14
16
|
"lint:stale-deploy": "node scripts/check-stale-deploy-references.js",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "observability",
|
|
4
|
+
"description": "Prometheus, Grafana, Loki monitoring stack",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"url": "http://grafana.localhost"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"name": "n8n",
|
|
10
|
+
"description": "Workflow automation platform",
|
|
11
|
+
"version": "1.0.0",
|
|
12
|
+
"port": 5678,
|
|
13
|
+
"url": "http://localhost:5678"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "redis",
|
|
17
|
+
"description": "In-memory data store for caching and sessions",
|
|
18
|
+
"version": "1.0.0",
|
|
19
|
+
"port": 6379,
|
|
20
|
+
"url": "redis://localhost:6379"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "metabase",
|
|
24
|
+
"description": "Business intelligence and analytics dashboard",
|
|
25
|
+
"version": "1.0.0",
|
|
26
|
+
"port": 3001,
|
|
27
|
+
"url": "http://metabase.localhost"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Development overrides for Metabase
|
|
2
|
+
# Use with: docker compose -f docker-compose.yml -f docker-compose.metabase.yml -f docker-compose.metabase.override.yml up -d
|
|
3
|
+
|
|
4
|
+
services:
|
|
5
|
+
metabase:
|
|
6
|
+
labels:
|
|
7
|
+
# Dev: No auth required (same as studio/traefik in local dev)
|
|
8
|
+
# Production uses ForwardAuth via docker-compose.metabase.yml labels
|
|
9
|
+
# Empty middlewares override removes ForwardAuth requirement
|
|
10
|
+
- "traefik.enable=true"
|
|
11
|
+
- "traefik.http.routers.metabase.rule=Host(`metabase.localhost`)"
|
|
12
|
+
- "traefik.http.routers.metabase.entrypoints=web"
|
|
13
|
+
- "traefik.http.routers.metabase.middlewares="
|
|
14
|
+
- "traefik.http.services.metabase.loadbalancer.server.port=3000"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Metabase Production Overrides
|
|
2
|
+
# Use with: docker compose -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.metabase.yml -f docker-compose.metabase.prod.yml up -d
|
|
3
|
+
#
|
|
4
|
+
# Adds:
|
|
5
|
+
# - SSL subdomain routing for Metabase (metabase.yourdomain.com)
|
|
6
|
+
# - ForwardAuth (super_admin role required)
|
|
7
|
+
# - HTTP to HTTPS redirect
|
|
8
|
+
|
|
9
|
+
services:
|
|
10
|
+
metabase:
|
|
11
|
+
environment:
|
|
12
|
+
# Override site URL for production subdomain
|
|
13
|
+
- MB_SITE_URL=https://metabase.${DOMAIN}
|
|
14
|
+
- MB_EMBEDDING_APP_ORIGIN=https://${DOMAIN}
|
|
15
|
+
ports: [] # Reached via Traefik over the compose network; no host port in prod
|
|
16
|
+
labels:
|
|
17
|
+
# Production Traefik routing with SSL
|
|
18
|
+
- "traefik.enable=true"
|
|
19
|
+
# HTTPS router with super_admin auth + security headers
|
|
20
|
+
- "traefik.http.routers.metabase.rule=Host(`metabase.${DOMAIN}`)"
|
|
21
|
+
- "traefik.http.routers.metabase.entrypoints=websecure"
|
|
22
|
+
- "traefik.http.routers.metabase.tls=true"
|
|
23
|
+
- "traefik.http.routers.metabase.tls.certresolver=letsencrypt"
|
|
24
|
+
- "traefik.http.routers.metabase.middlewares=super-admin-auth@file,security-headers@file"
|
|
25
|
+
- "traefik.http.services.metabase.loadbalancer.server.port=3000"
|
|
26
|
+
# HTTP to HTTPS redirect
|
|
27
|
+
- "traefik.http.routers.metabase-http.rule=Host(`metabase.${DOMAIN}`)"
|
|
28
|
+
- "traefik.http.routers.metabase-http.entrypoints=web"
|
|
29
|
+
- "traefik.http.routers.metabase-http.middlewares=redirect-to-https"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Metabase - Business intelligence dashboard
|
|
2
|
+
# Added via: vibecarbon add metabase
|
|
3
|
+
|
|
4
|
+
services:
|
|
5
|
+
metabase:
|
|
6
|
+
image: metabase/metabase:latest
|
|
7
|
+
container_name: {{PROJECT_NAME}}-metabase
|
|
8
|
+
restart: unless-stopped
|
|
9
|
+
ports:
|
|
10
|
+
- "3001:3000"
|
|
11
|
+
environment:
|
|
12
|
+
# Metabase application database (stores dashboards, questions, etc.)
|
|
13
|
+
MB_DB_TYPE: postgres
|
|
14
|
+
MB_DB_DBNAME: metabase
|
|
15
|
+
MB_DB_PORT: 5432
|
|
16
|
+
MB_DB_USER: metabase
|
|
17
|
+
MB_DB_PASS: ${POSTGRES_PASSWORD}
|
|
18
|
+
MB_DB_HOST: db
|
|
19
|
+
# Performance settings
|
|
20
|
+
JAVA_OPTS: "-Xmx1g"
|
|
21
|
+
volumes:
|
|
22
|
+
- metabase_plugins:/plugins
|
|
23
|
+
networks:
|
|
24
|
+
- vibecarbon-network
|
|
25
|
+
depends_on:
|
|
26
|
+
db:
|
|
27
|
+
condition: service_healthy
|
|
28
|
+
healthcheck:
|
|
29
|
+
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
|
30
|
+
interval: 15s
|
|
31
|
+
timeout: 5s
|
|
32
|
+
retries: 8
|
|
33
|
+
start_period: 120s
|
|
34
|
+
labels:
|
|
35
|
+
# Traefik routing with ForwardAuth protection
|
|
36
|
+
- "traefik.enable=true"
|
|
37
|
+
- "traefik.http.routers.metabase.rule=Host(`metabase.localhost`)"
|
|
38
|
+
- "traefik.http.routers.metabase.entrypoints=web"
|
|
39
|
+
# Note: No ForwardAuth - Metabase has its own authentication
|
|
40
|
+
- "traefik.http.services.metabase.loadbalancer.server.port=3000"
|
|
41
|
+
|
|
42
|
+
metabase-setup:
|
|
43
|
+
image: alpine:latest
|
|
44
|
+
container_name: {{PROJECT_NAME}}-metabase-setup
|
|
45
|
+
volumes:
|
|
46
|
+
- ./volumes/metabase/scripts:/scripts:ro
|
|
47
|
+
environment:
|
|
48
|
+
METABASE_URL: http://metabase:3000
|
|
49
|
+
METABASE_ADMIN_EMAIL: ${METABASE_ADMIN_EMAIL:-admin@localhost}
|
|
50
|
+
METABASE_ADMIN_PASSWORD: ${METABASE_ADMIN_PASSWORD}
|
|
51
|
+
METABASE_ADMIN_FIRST_NAME: ${METABASE_ADMIN_FIRST_NAME:-Admin}
|
|
52
|
+
METABASE_ADMIN_LAST_NAME: ${METABASE_ADMIN_LAST_NAME:-User}
|
|
53
|
+
APP_DB_HOST: db
|
|
54
|
+
APP_DB_PORT: 5432
|
|
55
|
+
APP_DB_NAME: postgres
|
|
56
|
+
APP_DB_USER: postgres
|
|
57
|
+
DB_PASSWORD: ${DB_PASSWORD}
|
|
58
|
+
entrypoint: ["/bin/sh", "-c", "apk add --no-cache curl jq && sh /scripts/setup.sh"]
|
|
59
|
+
depends_on:
|
|
60
|
+
metabase:
|
|
61
|
+
condition: service_healthy
|
|
62
|
+
networks:
|
|
63
|
+
- vibecarbon-network
|
|
64
|
+
restart: "no"
|
|
65
|
+
|
|
66
|
+
volumes:
|
|
67
|
+
metabase_plugins:
|
|
68
|
+
driver: local
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Metabase Database Initialization
|
|
5
|
+
# Creates the metabase database and user for analytics
|
|
6
|
+
# Password is injected from POSTGRES_PASSWORD env var at runtime (never hardcoded)
|
|
7
|
+
|
|
8
|
+
# Create metabase role if it doesn't exist (quoted heredoc — no variable expansion)
|
|
9
|
+
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<'EOSQL'
|
|
10
|
+
DO $$
|
|
11
|
+
BEGIN
|
|
12
|
+
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'metabase') THEN
|
|
13
|
+
CREATE ROLE metabase WITH LOGIN;
|
|
14
|
+
END IF;
|
|
15
|
+
END
|
|
16
|
+
$$;
|
|
17
|
+
EOSQL
|
|
18
|
+
|
|
19
|
+
# Set password and create database (unquoted heredoc — POSTGRES_PASSWORD is expanded)
|
|
20
|
+
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<EOSQL
|
|
21
|
+
ALTER ROLE metabase WITH PASSWORD '${POSTGRES_PASSWORD}';
|
|
22
|
+
SELECT 'CREATE DATABASE metabase WITH OWNER metabase ENCODING ''UTF8'' TEMPLATE template0'
|
|
23
|
+
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'metabase')\gexec
|
|
24
|
+
GRANT ALL PRIVILEGES ON DATABASE metabase TO metabase;
|
|
25
|
+
GRANT CONNECT ON DATABASE postgres TO metabase;
|
|
26
|
+
GRANT USAGE ON SCHEMA public TO metabase;
|
|
27
|
+
GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase;
|
|
28
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO metabase;
|
|
29
|
+
EOSQL
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Metabase Integration Guide
|
|
2
|
+
|
|
3
|
+
Metabase is an open-source business intelligence tool that lets you create dashboards and visualizations from your data without writing SQL.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
Metabase is **automatically configured** when you start your development environment:
|
|
8
|
+
|
|
9
|
+
1. **Start services**: `npx vibecarbon up`
|
|
10
|
+
2. **Access Metabase**: http://metabase.localhost
|
|
11
|
+
3. **Sign in** with your admin email and password
|
|
12
|
+
|
|
13
|
+
The setup container automatically:
|
|
14
|
+
- Creates the admin user
|
|
15
|
+
- Connects to your application database (named "Application Data")
|
|
16
|
+
- Configures recommended settings
|
|
17
|
+
|
|
18
|
+
> **Security Note**: In production, Metabase is protected by Traefik ForwardAuth requiring the `super_admin` role. Users must be signed in to the main application with super admin privileges to access it.
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
Metabase uses **two database connections**:
|
|
23
|
+
|
|
24
|
+
1. **Application Database** (`metabase` db): Stores Metabase's own data - dashboards, saved questions, user accounts, etc.
|
|
25
|
+
2. **Your Data** (`postgres` db): The database you want to analyze - automatically configured as "Application Data"
|
|
26
|
+
|
|
27
|
+
## Creating Dashboards
|
|
28
|
+
|
|
29
|
+
### Basic Workflow
|
|
30
|
+
|
|
31
|
+
1. **Ask a Question**: Click "New" > "Question"
|
|
32
|
+
2. **Choose Data**: Select "Application Data" and your table
|
|
33
|
+
3. **Build Query**: Use the visual query builder or write SQL
|
|
34
|
+
4. **Save & Visualize**: Save to a collection and add to dashboards
|
|
35
|
+
|
|
36
|
+
### Example Queries
|
|
37
|
+
|
|
38
|
+
**User signups over time:**
|
|
39
|
+
```sql
|
|
40
|
+
SELECT
|
|
41
|
+
DATE_TRUNC('day', created_at) as signup_date,
|
|
42
|
+
COUNT(*) as signups
|
|
43
|
+
FROM auth.users
|
|
44
|
+
GROUP BY 1
|
|
45
|
+
ORDER BY 1
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Active users last 30 days:**
|
|
49
|
+
```sql
|
|
50
|
+
SELECT COUNT(DISTINCT id)
|
|
51
|
+
FROM auth.users
|
|
52
|
+
WHERE last_sign_in_at > NOW() - INTERVAL '30 days'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Embedding Dashboards
|
|
56
|
+
|
|
57
|
+
Metabase supports embedding dashboards in your application:
|
|
58
|
+
|
|
59
|
+
### Public Links (Simple)
|
|
60
|
+
|
|
61
|
+
1. Enable sharing on dashboard
|
|
62
|
+
2. Copy public link
|
|
63
|
+
3. Embed via iframe
|
|
64
|
+
|
|
65
|
+
### Signed Embedding (Secure)
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import jwt from 'jsonwebtoken';
|
|
69
|
+
|
|
70
|
+
// Use environment variable for flexibility between local/production
|
|
71
|
+
const METABASE_SITE_URL = process.env.METABASE_URL || "http://localhost:3001";
|
|
72
|
+
// In production: "https://your-domain.com/admin/metabase"
|
|
73
|
+
|
|
74
|
+
const METABASE_SECRET_KEY = "your-embedding-secret"; // From Admin > Embedding
|
|
75
|
+
|
|
76
|
+
function getEmbedUrl(dashboardId: number, params: Record<string, any> = {}) {
|
|
77
|
+
const payload = {
|
|
78
|
+
resource: { dashboard: dashboardId },
|
|
79
|
+
params,
|
|
80
|
+
exp: Math.round(Date.now() / 1000) + (10 * 60) // 10 minute expiration
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const token = jwt.sign(payload, METABASE_SECRET_KEY);
|
|
84
|
+
return `${METABASE_SITE_URL}/embed/dashboard/${token}`;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Environment Variables
|
|
89
|
+
|
|
90
|
+
These are automatically configured:
|
|
91
|
+
|
|
92
|
+
```env
|
|
93
|
+
# Metabase admin credentials
|
|
94
|
+
METABASE_ADMIN_EMAIL=admin@localhost
|
|
95
|
+
METABASE_ADMIN_PASSWORD=<generated>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Manual Database Connection
|
|
99
|
+
|
|
100
|
+
If you need to add additional database connections manually:
|
|
101
|
+
|
|
102
|
+
| Setting | Value |
|
|
103
|
+
|---------|-------|
|
|
104
|
+
| Database type | PostgreSQL |
|
|
105
|
+
| Display name | Your choice |
|
|
106
|
+
| Host | `db` |
|
|
107
|
+
| Port | `5432` |
|
|
108
|
+
| Database name | Your database |
|
|
109
|
+
| Username | Your user |
|
|
110
|
+
| Password | Your password |
|
|
111
|
+
|
|
112
|
+
## Docker Commands
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# View Metabase logs
|
|
116
|
+
pnpm docker:logs metabase
|
|
117
|
+
|
|
118
|
+
# View setup logs
|
|
119
|
+
docker logs {{PROJECT_NAME}}-metabase-setup
|
|
120
|
+
|
|
121
|
+
# Restart Metabase
|
|
122
|
+
docker restart {{PROJECT_NAME}}-metabase
|
|
123
|
+
|
|
124
|
+
# Re-run setup (if needed)
|
|
125
|
+
docker restart {{PROJECT_NAME}}-metabase-setup
|
|
126
|
+
|
|
127
|
+
# Access Metabase shell
|
|
128
|
+
docker exec -it {{PROJECT_NAME}}-metabase /bin/sh
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Backup & Restore
|
|
132
|
+
|
|
133
|
+
### Backup Metabase Data
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Backup metabase database
|
|
137
|
+
docker exec {{PROJECT_NAME}}-db pg_dump -U postgres metabase > metabase-backup.sql
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Restore Metabase Data
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Restore metabase database
|
|
144
|
+
docker exec -i {{PROJECT_NAME}}-db psql -U postgres metabase < metabase-backup.sql
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Performance Tips
|
|
148
|
+
|
|
149
|
+
1. **Add database indexes** for columns you frequently filter/group by
|
|
150
|
+
2. **Use caching**: Admin > Performance > enable query caching
|
|
151
|
+
3. **Schedule refreshes**: Set dashboards to refresh on a schedule rather than live
|
|
152
|
+
4. **Limit results**: Use LIMIT in custom SQL to prevent large result sets
|
|
153
|
+
|
|
154
|
+
## Troubleshooting
|
|
155
|
+
|
|
156
|
+
### Setup didn't run
|
|
157
|
+
|
|
158
|
+
Check the setup container logs:
|
|
159
|
+
```bash
|
|
160
|
+
docker logs {{PROJECT_NAME}}-metabase-setup
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Re-run setup:
|
|
164
|
+
```bash
|
|
165
|
+
docker restart {{PROJECT_NAME}}-metabase-setup
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Metabase won't start
|
|
169
|
+
|
|
170
|
+
Check if the metabase database was created:
|
|
171
|
+
```bash
|
|
172
|
+
docker exec {{PROJECT_NAME}}-db psql -U postgres -c "\l" | grep metabase
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
If missing, run the init script:
|
|
176
|
+
```bash
|
|
177
|
+
docker exec {{PROJECT_NAME}}-db bash /docker-entrypoint-initdb.d/zz-metabase-init.sh
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Connection refused to db
|
|
181
|
+
|
|
182
|
+
Ensure the database is healthy:
|
|
183
|
+
```bash
|
|
184
|
+
docker exec {{PROJECT_NAME}}-db pg_isready
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Slow queries
|
|
188
|
+
|
|
189
|
+
1. Check query in Metabase > Admin > Troubleshooting > Logs
|
|
190
|
+
2. Add indexes to your database tables
|
|
191
|
+
3. Enable query caching in Admin > Performance
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
apiVersion: apps/v1
|
|
2
|
+
kind: Deployment
|
|
3
|
+
metadata:
|
|
4
|
+
name: metabase
|
|
5
|
+
labels:
|
|
6
|
+
app: metabase
|
|
7
|
+
spec:
|
|
8
|
+
replicas: 1
|
|
9
|
+
selector:
|
|
10
|
+
matchLabels:
|
|
11
|
+
app: metabase
|
|
12
|
+
template:
|
|
13
|
+
metadata:
|
|
14
|
+
labels:
|
|
15
|
+
app: metabase
|
|
16
|
+
spec:
|
|
17
|
+
containers:
|
|
18
|
+
- name: metabase
|
|
19
|
+
image: metabase/metabase:latest
|
|
20
|
+
ports:
|
|
21
|
+
- containerPort: 3000
|
|
22
|
+
env:
|
|
23
|
+
- name: MB_DB_TYPE
|
|
24
|
+
value: postgres
|
|
25
|
+
- name: MB_DB_DBNAME
|
|
26
|
+
value: metabase
|
|
27
|
+
- name: MB_DB_PORT
|
|
28
|
+
value: '5432'
|
|
29
|
+
- name: MB_DB_USER
|
|
30
|
+
value: metabase
|
|
31
|
+
- name: MB_DB_PASS
|
|
32
|
+
valueFrom:
|
|
33
|
+
secretKeyRef:
|
|
34
|
+
name: vibecarbon-secrets
|
|
35
|
+
key: DB_PASSWORD
|
|
36
|
+
- name: MB_DB_HOST
|
|
37
|
+
value: postgres
|
|
38
|
+
- name: MB_PASSWORD_COMPLEXITY
|
|
39
|
+
value: strong
|
|
40
|
+
- name: MB_SESSION_COOKIES
|
|
41
|
+
value: 'true'
|
|
42
|
+
- name: MB_COOKIE_SAMESITE
|
|
43
|
+
value: lax
|
|
44
|
+
- name: MB_SITE_URL
|
|
45
|
+
valueFrom:
|
|
46
|
+
configMapKeyRef:
|
|
47
|
+
name: vibecarbon-config
|
|
48
|
+
key: SITE_URL
|
|
49
|
+
- name: JAVA_OPTS
|
|
50
|
+
value: -Xmx1536m
|
|
51
|
+
volumeMounts:
|
|
52
|
+
- name: metabase-plugins
|
|
53
|
+
mountPath: /plugins
|
|
54
|
+
- name: tmp-vol-0
|
|
55
|
+
mountPath: /tmp
|
|
56
|
+
resources:
|
|
57
|
+
requests:
|
|
58
|
+
memory: 512Mi
|
|
59
|
+
cpu: 500m
|
|
60
|
+
limits:
|
|
61
|
+
memory: 2Gi
|
|
62
|
+
cpu: 1000m
|
|
63
|
+
livenessProbe:
|
|
64
|
+
httpGet:
|
|
65
|
+
path: /api/health
|
|
66
|
+
port: 3000
|
|
67
|
+
initialDelaySeconds: 120
|
|
68
|
+
periodSeconds: 30
|
|
69
|
+
timeoutSeconds: 10
|
|
70
|
+
readinessProbe:
|
|
71
|
+
httpGet:
|
|
72
|
+
path: /api/health
|
|
73
|
+
port: 3000
|
|
74
|
+
initialDelaySeconds: 60
|
|
75
|
+
periodSeconds: 10
|
|
76
|
+
timeoutSeconds: 5
|
|
77
|
+
securityContext:
|
|
78
|
+
allowPrivilegeEscalation: false
|
|
79
|
+
readOnlyRootFilesystem: true
|
|
80
|
+
volumes:
|
|
81
|
+
- name: metabase-plugins
|
|
82
|
+
persistentVolumeClaim:
|
|
83
|
+
claimName: metabase-plugins-pvc
|
|
84
|
+
- name: tmp-vol-0
|
|
85
|
+
emptyDir: {}
|
|
86
|
+
securityContext:
|
|
87
|
+
seccompProfile:
|
|
88
|
+
type: RuntimeDefault
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
apiVersion: traefik.io/v1alpha1
|
|
2
|
+
kind: IngressRoute
|
|
3
|
+
metadata:
|
|
4
|
+
name: vibecarbon-metabase
|
|
5
|
+
namespace: vibecarbon
|
|
6
|
+
spec:
|
|
7
|
+
entryPoints:
|
|
8
|
+
- websecure
|
|
9
|
+
routes:
|
|
10
|
+
# Metabase uses relative asset paths so strip-prefix works correctly.
|
|
11
|
+
- match: PathPrefix(`/admin/metabase`)
|
|
12
|
+
kind: Rule
|
|
13
|
+
priority: 20
|
|
14
|
+
services:
|
|
15
|
+
- name: metabase
|
|
16
|
+
port: 3000
|
|
17
|
+
middlewares:
|
|
18
|
+
- name: admin-auth
|
|
19
|
+
- name: security-headers
|
|
20
|
+
- name: strip-admin-metabase-prefix
|
|
21
|
+
tls:
|
|
22
|
+
secretName: vibecarbon-tls
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Network policy for Metabase analytics service
|
|
3
|
+
apiVersion: networking.k8s.io/v1
|
|
4
|
+
kind: NetworkPolicy
|
|
5
|
+
metadata:
|
|
6
|
+
name: metabase-policy
|
|
7
|
+
namespace: vibecarbon
|
|
8
|
+
spec:
|
|
9
|
+
podSelector:
|
|
10
|
+
matchLabels:
|
|
11
|
+
app: metabase
|
|
12
|
+
policyTypes:
|
|
13
|
+
- Ingress
|
|
14
|
+
- Egress
|
|
15
|
+
ingress:
|
|
16
|
+
- from:
|
|
17
|
+
- podSelector:
|
|
18
|
+
matchLabels:
|
|
19
|
+
app: vibecarbon-traefik
|
|
20
|
+
- podSelector:
|
|
21
|
+
matchLabels:
|
|
22
|
+
app: vibecarbon-app
|
|
23
|
+
ports:
|
|
24
|
+
- protocol: TCP
|
|
25
|
+
port: 3000
|
|
26
|
+
egress:
|
|
27
|
+
# DNS resolution
|
|
28
|
+
- ports:
|
|
29
|
+
- protocol: UDP
|
|
30
|
+
port: 53
|
|
31
|
+
- protocol: TCP
|
|
32
|
+
port: 53
|
|
33
|
+
# PostgreSQL
|
|
34
|
+
- to:
|
|
35
|
+
- podSelector:
|
|
36
|
+
matchLabels:
|
|
37
|
+
app: vibecarbon-postgres
|
|
38
|
+
ports:
|
|
39
|
+
- protocol: TCP
|
|
40
|
+
port: 5432
|
|
41
|
+
# External HTTP/HTTPS (for license checks, plugin downloads, etc.)
|
|
42
|
+
- to:
|
|
43
|
+
- ipBlock:
|
|
44
|
+
cidr: 0.0.0.0/0
|
|
45
|
+
except:
|
|
46
|
+
- 10.0.0.0/8
|
|
47
|
+
- 172.16.0.0/12
|
|
48
|
+
- 192.168.0.0/16
|
|
49
|
+
ports:
|
|
50
|
+
- protocol: TCP
|
|
51
|
+
port: 443
|
|
52
|
+
- protocol: TCP
|
|
53
|
+
port: 80
|
|
54
|
+
---
|
|
55
|
+
# Allow metabase to connect to postgres
|
|
56
|
+
apiVersion: networking.k8s.io/v1
|
|
57
|
+
kind: NetworkPolicy
|
|
58
|
+
metadata:
|
|
59
|
+
name: metabase-database-ingress
|
|
60
|
+
namespace: vibecarbon
|
|
61
|
+
spec:
|
|
62
|
+
podSelector:
|
|
63
|
+
matchLabels:
|
|
64
|
+
app: vibecarbon-postgres
|
|
65
|
+
policyTypes:
|
|
66
|
+
- Ingress
|
|
67
|
+
ingress:
|
|
68
|
+
- from:
|
|
69
|
+
- podSelector:
|
|
70
|
+
matchLabels:
|
|
71
|
+
app: metabase
|
|
72
|
+
ports:
|
|
73
|
+
- protocol: TCP
|
|
74
|
+
port: 5432
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "metabase",
|
|
3
|
+
"description": "Business intelligence and analytics dashboard",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"port": 3001,
|
|
6
|
+
"url": "http://metabase.localhost",
|
|
7
|
+
|
|
8
|
+
"files": {
|
|
9
|
+
"compose/docker-compose.yml": "docker-compose.metabase.yml",
|
|
10
|
+
"compose/docker-compose.prod.yml": "docker-compose.metabase.prod.yml",
|
|
11
|
+
"compose/docker-compose.override.yml": "docker-compose.metabase.override.yml",
|
|
12
|
+
"k8s/": "k8s/base/metabase/",
|
|
13
|
+
"db/init.sh": "volumes/db/metabase-init.sh",
|
|
14
|
+
"scripts/setup.sh": "volumes/metabase/scripts/setup.sh",
|
|
15
|
+
"docs/integration.md": "metabase-integration.md"
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
"envVars": {
|
|
19
|
+
"METABASE_ADMIN_PASSWORD": { "from": "ADMIN_PASSWORD" },
|
|
20
|
+
"METABASE_ADMIN_EMAIL": { "from": "ADMIN_EMAIL", "default": "admin@localhost" }
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
"kustomization": {
|
|
24
|
+
"entry": "metabase/"
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
"credentials": {
|
|
28
|
+
"title": "Metabase",
|
|
29
|
+
"fields": [
|
|
30
|
+
{ "label": "URL", "value": "http://metabase.localhost" },
|
|
31
|
+
{ "label": "Auth", "value": "Traefik ForwardAuth (super_admin)" }
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|