feat: add fluxer upstream source and self-hosting documentation
- Clone of github.com/fluxerapp/fluxer (official upstream) - SELF_HOSTING.md: full VM rebuild procedure, architecture overview, service reference, step-by-step setup, troubleshooting, seattle reference - dev/.env.example: all env vars with secrets redacted and generation instructions - dev/livekit.yaml: LiveKit config template with placeholder keys - fluxer-seattle/: existing seattle deployment setup scripts
This commit is contained in:
16
fluxer/fluxer_devops/caddy-gateway/Caddyfile.global
Normal file
16
fluxer/fluxer_devops/caddy-gateway/Caddyfile.global
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
servers {
|
||||
listener_wrappers {
|
||||
proxy_protocol {
|
||||
timeout 5s
|
||||
allow 127.0.0.0/8
|
||||
allow 10.0.0.0/8
|
||||
allow 172.16.0.0/12
|
||||
allow ::1/128
|
||||
}
|
||||
tls
|
||||
}
|
||||
trusted_proxies static private_ranges
|
||||
trusted_proxies_strict
|
||||
}
|
||||
}
|
||||
38
fluxer/fluxer_devops/caddy-gateway/compose.yaml
Normal file
38
fluxer/fluxer_devops/caddy-gateway/compose.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
services:
|
||||
caddy-gateway:
|
||||
image: lucaslorentz/caddy-docker-proxy:ci-alpine
|
||||
environment:
|
||||
- CADDY_INGRESS_NETWORKS=fluxer-shared
|
||||
- CADDY_DOCKER_LABEL_PREFIX=caddy_gw
|
||||
- CADDY_DOCKER_CADDYFILE_PATH=/config/Caddyfile.base
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- caddy_gateway_data:/data
|
||||
configs:
|
||||
- source: caddyfile_config
|
||||
target: /config/Caddyfile.base
|
||||
networks:
|
||||
- fluxer-shared
|
||||
ports:
|
||||
- target: 443
|
||||
published: 9443
|
||||
protocol: tcp
|
||||
mode: host
|
||||
deploy:
|
||||
mode: global
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
configs:
|
||||
caddyfile_config:
|
||||
file: ./Caddyfile.global
|
||||
|
||||
networks:
|
||||
fluxer-shared:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
caddy_gateway_data:
|
||||
16
fluxer/fluxer_devops/caddy/Caddyfile.global
Normal file
16
fluxer/fluxer_devops/caddy/Caddyfile.global
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
servers {
|
||||
listener_wrappers {
|
||||
proxy_protocol {
|
||||
timeout 5s
|
||||
allow 127.0.0.0/8
|
||||
allow 10.0.0.0/8
|
||||
allow 172.16.0.0/12
|
||||
allow ::1/128
|
||||
}
|
||||
tls
|
||||
}
|
||||
trusted_proxies static private_ranges
|
||||
trusted_proxies_strict
|
||||
}
|
||||
}
|
||||
41
fluxer/fluxer_devops/caddy/compose.yaml
Normal file
41
fluxer/fluxer_devops/caddy/compose.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
services:
|
||||
caddy:
|
||||
image: lucaslorentz/caddy-docker-proxy:ci-alpine
|
||||
environment:
|
||||
- CADDY_INGRESS_NETWORKS=fluxer-shared
|
||||
- CADDY_DOCKER_CADDYFILE_PATH=/config/Caddyfile.base
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- caddy_data:/data
|
||||
configs:
|
||||
- source: caddyfile_config
|
||||
target: /config/Caddyfile.base
|
||||
networks:
|
||||
- fluxer-shared
|
||||
ports:
|
||||
- target: 80
|
||||
published: 8080
|
||||
protocol: tcp
|
||||
mode: host
|
||||
- target: 443
|
||||
published: 8443
|
||||
protocol: tcp
|
||||
mode: host
|
||||
deploy:
|
||||
mode: global
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
|
||||
configs:
|
||||
caddyfile_config:
|
||||
file: ./Caddyfile.global
|
||||
|
||||
networks:
|
||||
fluxer-shared:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
caddy_data:
|
||||
42
fluxer/fluxer_devops/cassandra/Dockerfile.backup
Normal file
42
fluxer/fluxer_devops/cassandra/Dockerfile.backup
Normal file
@@ -0,0 +1,42 @@
|
||||
FROM cassandra:5.0
|
||||
|
||||
# Install backup tools only
|
||||
RUN apt-get update && apt-get install -y \
|
||||
age \
|
||||
awscli \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy backup script
|
||||
COPY backup.sh /usr/local/bin/backup.sh
|
||||
RUN chmod +x /usr/local/bin/backup.sh
|
||||
|
||||
# Create entrypoint that runs backups in a loop
|
||||
RUN echo '#!/bin/bash\n\
|
||||
set -e\n\
|
||||
\n\
|
||||
# Create age public key file from environment variable\n\
|
||||
if [ -n "${AGE_PUBLIC_KEY}" ]; then\n\
|
||||
echo "${AGE_PUBLIC_KEY}" > /tmp/age_public_key.txt\n\
|
||||
chmod 644 /tmp/age_public_key.txt\n\
|
||||
echo "Age encryption enabled for backups"\n\
|
||||
else\n\
|
||||
echo "Warning: AGE_PUBLIC_KEY not set - backups will not be encrypted"\n\
|
||||
fi\n\
|
||||
\n\
|
||||
echo "Starting backup service - first backup in 5 minutes, then hourly"\n\
|
||||
\n\
|
||||
# Wait 5 minutes before first backup\n\
|
||||
echo "Waiting 5 minutes for Cassandra to be ready..."\n\
|
||||
sleep 300\n\
|
||||
\n\
|
||||
# Run backups in a loop\n\
|
||||
while true; do\n\
|
||||
echo "-----------------------------------"\n\
|
||||
echo "Starting backup at $(date)"\n\
|
||||
/usr/local/bin/backup.sh || echo "Backup failed at $(date)"\n\
|
||||
echo "Next backup in 1 hour"\n\
|
||||
sleep 3600\n\
|
||||
done\n\
|
||||
' > /usr/local/bin/backup-entrypoint.sh && chmod +x /usr/local/bin/backup-entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/backup-entrypoint.sh"]
|
||||
146
fluxer/fluxer_devops/cassandra/RESTORE.md
Normal file
146
fluxer/fluxer_devops/cassandra/RESTORE.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Cassandra Restore
|
||||
|
||||
## Fresh Instance from Local Backup
|
||||
|
||||
```bash
|
||||
# 1. Create volume and start Cassandra
|
||||
docker volume create cassandra_data
|
||||
docker run -d --name cass -v cassandra_data:/var/lib/cassandra -p 9042:9042 cassandra:5.0
|
||||
echo "Waiting for Cassandra to start..."
|
||||
sleep 30
|
||||
|
||||
# 2. Extract backup and apply schema
|
||||
docker exec cass sh -c 'apt-get update -qq && apt-get install -y -qq age'
|
||||
docker cp ~/Downloads/backup.tar.age cass:/tmp/
|
||||
docker cp ~/Downloads/key.txt cass:/tmp/
|
||||
docker exec cass sh -c 'age -d -i /tmp/key.txt /tmp/backup.tar.age | tar -C /tmp -xf -'
|
||||
docker exec cass sh -c 'sed "/^WARNING:/d" /tmp/cassandra-backup-*/schema.cql | cqlsh'
|
||||
|
||||
# 3. Copy backup to volume and stop Cassandra
|
||||
docker exec cass sh -c 'cp -r /tmp/cassandra-backup-* /var/lib/cassandra/'
|
||||
docker stop cass
|
||||
docker run -d --name cass-util -v cassandra_data:/var/lib/cassandra --entrypoint sleep cassandra:5.0 infinity
|
||||
docker exec cass-util sh -c '
|
||||
BACKUP_DIR=$(ls -d /var/lib/cassandra/cassandra-backup-* | head -1)
|
||||
DATA_DIR=/var/lib/cassandra/data
|
||||
for keyspace_dir in "$BACKUP_DIR"/*/; do
|
||||
keyspace=$(basename "$keyspace_dir")
|
||||
[[ "$keyspace" =~ ^system ]] && continue
|
||||
[ ! -d "$keyspace_dir" ] && continue
|
||||
for snapshot_dir in "$keyspace_dir"/*/snapshots/backup-*/; do
|
||||
[ ! -d "$snapshot_dir" ] && continue
|
||||
table_with_uuid=$(basename $(dirname $(dirname "$snapshot_dir")))
|
||||
table_name=$(echo "$table_with_uuid" | cut -d- -f1)
|
||||
target_dir=$(ls -d "$DATA_DIR/$keyspace/${table_name}"-* 2>/dev/null | head -1)
|
||||
if [ -n "$target_dir" ]; then
|
||||
cp "$snapshot_dir"/* "$target_dir"/ 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
done
|
||||
chown -R cassandra:cassandra "$DATA_DIR"
|
||||
'
|
||||
|
||||
# 4. Restart Cassandra and refresh tables
|
||||
docker rm -f cass-util
|
||||
docker start cass
|
||||
sleep 30
|
||||
|
||||
# 5. Run nodetool refresh on all tables
|
||||
docker exec cass sh -c '
|
||||
BACKUP_DIR=$(ls -d /var/lib/cassandra/cassandra-backup-* | head -1)
|
||||
for keyspace_dir in "$BACKUP_DIR"/*/; do
|
||||
keyspace=$(basename "$keyspace_dir")
|
||||
[[ "$keyspace" =~ ^system ]] && continue
|
||||
for snapshot_dir in "$keyspace_dir"/*/snapshots/backup-*/; do
|
||||
[ ! -d "$snapshot_dir" ] && continue
|
||||
table_with_uuid=$(basename $(dirname $(dirname "$snapshot_dir")))
|
||||
table_name=$(echo "$table_with_uuid" | cut -d- -f1)
|
||||
nodetool refresh -- "$keyspace" "$table_name" 2>&1 | grep -v deprecated || true
|
||||
done
|
||||
done
|
||||
'
|
||||
|
||||
# 6. Verify
|
||||
docker exec cass cqlsh -e "SELECT COUNT(*) FROM fluxer.users;"
|
||||
```
|
||||
|
||||
## Production Restore from B2
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This assumes you have B2 credentials configured on the server.
|
||||
|
||||
```bash
|
||||
# 0. Set variables
|
||||
BACKUP_NAME="cassandra-backup-20251016-103753.tar.age" # Replace with actual backup name
|
||||
CASSANDRA_CONTAINER="cassandra-prod"
|
||||
|
||||
# 1. Download backup from B2 (on the server)
|
||||
export AWS_ACCESS_KEY_ID="${B2_KEY_ID}"
|
||||
export AWS_SECRET_ACCESS_KEY="${B2_APPLICATION_KEY}"
|
||||
export AWS_DEFAULT_REGION="${B2_REGION}"
|
||||
B2_ENDPOINT_URL="https://${B2_ENDPOINT}"
|
||||
|
||||
aws s3 cp "s3://${B2_BUCKET_NAME}/${BACKUP_NAME}" \
|
||||
"/tmp/${BACKUP_NAME}" \
|
||||
--endpoint-url="${B2_ENDPOINT_URL}"
|
||||
|
||||
# 2. Copy backup and key to Cassandra container
|
||||
docker cp "/tmp/${BACKUP_NAME}" ${CASSANDRA_CONTAINER}:/tmp/
|
||||
docker cp /etc/cassandra/age_private_key.txt ${CASSANDRA_CONTAINER}:/tmp/key.txt
|
||||
|
||||
# 3. Stop Cassandra and prepare
|
||||
docker exec ${CASSANDRA_CONTAINER} sh -c 'apt-get update -qq && apt-get install -y -qq age'
|
||||
docker stop ${CASSANDRA_CONTAINER}
|
||||
|
||||
# 4. Extract backup in utility container
|
||||
docker run -d --name cass-restore-util --volumes-from ${CASSANDRA_CONTAINER} --entrypoint sleep cassandra:5.0 infinity
|
||||
docker exec cass-restore-util sh -c 'age -d -i /tmp/key.txt /tmp/${BACKUP_NAME} | tar -C /tmp -xf -'
|
||||
docker exec cass-restore-util sh -c 'cp -r /tmp/cassandra-backup-* /var/lib/cassandra/'
|
||||
|
||||
# 5. Copy SSTable files to existing schema directories
|
||||
docker exec cass-restore-util sh -c '
|
||||
BACKUP_DIR=$(ls -d /var/lib/cassandra/cassandra-backup-* | head -1)
|
||||
DATA_DIR=/var/lib/cassandra/data
|
||||
for keyspace_dir in "$BACKUP_DIR"/*/; do
|
||||
keyspace=$(basename "$keyspace_dir")
|
||||
[[ "$keyspace" =~ ^system ]] && continue
|
||||
[ ! -d "$keyspace_dir" ] && continue
|
||||
for snapshot_dir in "$keyspace_dir"/*/snapshots/backup-*/; do
|
||||
[ ! -d "$snapshot_dir" ] && continue
|
||||
table_with_uuid=$(basename $(dirname $(dirname "$snapshot_dir")))
|
||||
table_name=$(echo "$table_with_uuid" | cut -d- -f1)
|
||||
target_dir=$(ls -d "$DATA_DIR/$keyspace/${table_name}"-* 2>/dev/null | head -1)
|
||||
if [ -n "$target_dir" ]; then
|
||||
cp "$snapshot_dir"/* "$target_dir"/ 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
done
|
||||
chown -R cassandra:cassandra "$DATA_DIR"
|
||||
'
|
||||
|
||||
# 6. Restart Cassandra
|
||||
docker rm -f cass-restore-util
|
||||
docker start ${CASSANDRA_CONTAINER}
|
||||
sleep 30
|
||||
|
||||
# 7. Run nodetool refresh
|
||||
docker exec ${CASSANDRA_CONTAINER} sh -c '
|
||||
BACKUP_DIR=$(ls -d /var/lib/cassandra/cassandra-backup-* | head -1)
|
||||
for keyspace_dir in "$BACKUP_DIR"/*/; do
|
||||
keyspace=$(basename "$keyspace_dir")
|
||||
[[ "$keyspace" =~ ^system ]] && continue
|
||||
for snapshot_dir in "$keyspace_dir"/*/snapshots/backup-*/; do
|
||||
[ ! -d "$snapshot_dir" ] && continue
|
||||
table_with_uuid=$(basename $(dirname $(dirname "$snapshot_dir")))
|
||||
table_name=$(echo "$table_with_uuid" | cut -d- -f1)
|
||||
nodetool refresh -- "$keyspace" "$table_name" 2>&1 | grep -v deprecated || true
|
||||
done
|
||||
done
|
||||
'
|
||||
|
||||
# 8. Verify
|
||||
docker exec ${CASSANDRA_CONTAINER} cqlsh -e "SELECT COUNT(*) FROM fluxer.users;"
|
||||
|
||||
# 9. Cleanup
|
||||
rm -f "/tmp/${BACKUP_NAME}"
|
||||
```
|
||||
140
fluxer/fluxer_devops/cassandra/backup.sh
Executable file
140
fluxer/fluxer_devops/cassandra/backup.sh
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Copyright (C) 2026 Fluxer Contributors
|
||||
#
|
||||
# This file is part of Fluxer.
|
||||
#
|
||||
# Fluxer is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Fluxer is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
set -eu
|
||||
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
BACKUP_NAME="cassandra-backup-${TIMESTAMP}"
|
||||
SNAPSHOT_TAG="backup-${TIMESTAMP}"
|
||||
DATA_DIR="/var/lib/cassandra/data"
|
||||
TEMP_DIR="/tmp/${BACKUP_NAME}"
|
||||
AGE_PUBLIC_KEY_FILE="${AGE_PUBLIC_KEY_FILE:-/tmp/age_public_key.txt}"
|
||||
ENCRYPTED_BACKUP="${BACKUP_NAME}.tar.age"
|
||||
MAX_BACKUP_COUNT=168 # 7 days of hourly backups
|
||||
CASSANDRA_HOST="${CASSANDRA_HOST:-cassandra}"
|
||||
|
||||
# AWS CLI configuration for B2
|
||||
export AWS_ACCESS_KEY_ID="${B2_KEY_ID}"
|
||||
export AWS_SECRET_ACCESS_KEY="${B2_APPLICATION_KEY}"
|
||||
export AWS_DEFAULT_REGION="${B2_REGION}"
|
||||
B2_ENDPOINT_URL="https://${B2_ENDPOINT}"
|
||||
|
||||
echo "[$(date)] Starting Cassandra backup: ${BACKUP_NAME}"
|
||||
|
||||
# Step 1: Create snapshot
|
||||
echo "[$(date)] Creating Cassandra snapshot: ${SNAPSHOT_TAG}"
|
||||
if ! nodetool -h "${CASSANDRA_HOST}" snapshot -t "${SNAPSHOT_TAG}"; then
|
||||
echo "[$(date)] Error: Failed to create snapshot"
|
||||
exit 1
|
||||
fi
|
||||
echo "[$(date)] Snapshot created successfully"
|
||||
|
||||
# Step 2: Collect snapshot files
|
||||
echo "[$(date)] Collecting snapshot files"
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
|
||||
# Find all snapshot directories and copy to temp location
|
||||
find "${DATA_DIR}" -type d -name "${SNAPSHOT_TAG}" | while IFS= read -r snapshot_dir; do
|
||||
# Get relative path from data dir
|
||||
rel_path=$(dirname "${snapshot_dir#$DATA_DIR/}")
|
||||
target_dir="${TEMP_DIR}/${rel_path}"
|
||||
mkdir -p "${target_dir}"
|
||||
cp -r "${snapshot_dir}" "${target_dir}/"
|
||||
done
|
||||
|
||||
# Copy schema
|
||||
echo "[$(date)] Saving schema"
|
||||
if [ -n "${CASSANDRA_PASSWORD:-}" ]; then
|
||||
if ! cqlsh -u cassandra -p "${CASSANDRA_PASSWORD}" "${CASSANDRA_HOST}" -e "DESC SCHEMA;" 2>/dev/null | sed '/^WARNING:/d' > "${TEMP_DIR}/schema.cql"; then
|
||||
echo "Warning: Could not export schema"
|
||||
fi
|
||||
else
|
||||
if ! cqlsh "${CASSANDRA_HOST}" -e "DESC SCHEMA;" 2>/dev/null | sed '/^WARNING:/d' > "${TEMP_DIR}/schema.cql"; then
|
||||
echo "Warning: Could not export schema (no password set)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Save cluster topology info
|
||||
nodetool -h "${CASSANDRA_HOST}" describecluster > "${TEMP_DIR}/cluster_topology.txt" 2>/dev/null || true
|
||||
nodetool -h "${CASSANDRA_HOST}" status > "${TEMP_DIR}/cluster_status.txt" 2>/dev/null || true
|
||||
|
||||
echo "[$(date)] Snapshot collection completed"
|
||||
|
||||
# Step 3: Check if encryption is enabled
|
||||
if [ ! -f "${AGE_PUBLIC_KEY_FILE}" ]; then
|
||||
echo "[$(date)] Warning: Age public key not found - skipping encryption and upload"
|
||||
echo "[$(date)] Backup stored locally at: ${TEMP_DIR}"
|
||||
|
||||
# Clear snapshot from Cassandra
|
||||
nodetool -h "${CASSANDRA_HOST}" clearsnapshot -t "${SNAPSHOT_TAG}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Step 4: Create tar archive and encrypt with age (streaming)
|
||||
echo "[$(date)] Encrypting backup with age..."
|
||||
if ! tar -C /tmp -cf - "${BACKUP_NAME}" | \
|
||||
age -r "$(cat "${AGE_PUBLIC_KEY_FILE}")" -o "/tmp/${ENCRYPTED_BACKUP}"; then
|
||||
echo "[$(date)] Error: Encryption failed"
|
||||
rm -rf "${TEMP_DIR}"
|
||||
nodetool -h "${CASSANDRA_HOST}" clearsnapshot -t "${SNAPSHOT_TAG}"
|
||||
exit 1
|
||||
fi
|
||||
echo "[$(date)] Encryption completed: ${ENCRYPTED_BACKUP}"
|
||||
|
||||
# Get file size
|
||||
BACKUP_SIZE=$(du -h "/tmp/${ENCRYPTED_BACKUP}" | cut -f1)
|
||||
echo "[$(date)] Encrypted backup size: ${BACKUP_SIZE}"
|
||||
|
||||
# Step 5: Upload encrypted backup to B2
|
||||
echo "[$(date)] Uploading encrypted backup to B2..."
|
||||
if ! aws s3 cp "/tmp/${ENCRYPTED_BACKUP}" \
|
||||
"s3://${B2_BUCKET_NAME}/${ENCRYPTED_BACKUP}" \
|
||||
--endpoint-url="${B2_ENDPOINT_URL}"; then
|
||||
echo "[$(date)] Error: Upload to B2 failed"
|
||||
rm -f "/tmp/${ENCRYPTED_BACKUP}"
|
||||
rm -rf "${TEMP_DIR}"
|
||||
nodetool -h "${CASSANDRA_HOST}" clearsnapshot -t "${SNAPSHOT_TAG}"
|
||||
exit 1
|
||||
fi
|
||||
echo "[$(date)] Upload completed successfully"
|
||||
|
||||
# Step 6: Cleanup
|
||||
echo "[$(date)] Cleaning up temporary files..."
|
||||
rm -f "/tmp/${ENCRYPTED_BACKUP}"
|
||||
rm -rf "${TEMP_DIR}"
|
||||
|
||||
# Clear snapshot from Cassandra
|
||||
echo "[$(date)] Clearing snapshot from Cassandra"
|
||||
nodetool -h "${CASSANDRA_HOST}" clearsnapshot -t "${SNAPSHOT_TAG}"
|
||||
|
||||
# Step 7: Purge old backups from B2
|
||||
echo "[$(date)] Purging old backups from B2 (keeping last ${MAX_BACKUP_COUNT})..."
|
||||
aws s3 ls "s3://${B2_BUCKET_NAME}/" --endpoint-url="${B2_ENDPOINT_URL}" | \
|
||||
grep "cassandra-backup-.*\.tar\.age$" | \
|
||||
awk '{print $4}' | \
|
||||
sort -r | \
|
||||
tail -n +$((MAX_BACKUP_COUNT + 1)) | \
|
||||
while IFS= read -r old_backup; do
|
||||
echo "[$(date)] Deleting old backup: ${old_backup}"
|
||||
aws s3 rm "s3://${B2_BUCKET_NAME}/${old_backup}" --endpoint-url="${B2_ENDPOINT_URL}" || true
|
||||
done
|
||||
|
||||
echo "[$(date)] Backup process completed successfully"
|
||||
echo "[$(date)] Backup name: ${ENCRYPTED_BACKUP}"
|
||||
echo "[$(date)] Backup size: ${BACKUP_SIZE}"
|
||||
95
fluxer/fluxer_devops/cassandra/compose.yaml
Normal file
95
fluxer/fluxer_devops/cassandra/compose.yaml
Normal file
@@ -0,0 +1,95 @@
|
||||
services:
|
||||
cassandra:
|
||||
image: ${CASSANDRA_IMAGE:-cassandra:5.0}
|
||||
hostname: cassandra
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- CASSANDRA_CLUSTER_NAME=fluxer-cluster
|
||||
- CASSANDRA_DC=dc1
|
||||
- CASSANDRA_RACK=rack1
|
||||
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
|
||||
- CASSANDRA_SEEDS=cassandra
|
||||
- MAX_HEAP_SIZE=32G
|
||||
- CASSANDRA_BROADCAST_ADDRESS=cassandra
|
||||
- CASSANDRA_LISTEN_ADDRESS=auto
|
||||
- CASSANDRA_RPC_ADDRESS=0.0.0.0
|
||||
- CASSANDRA_AUTHENTICATOR=PasswordAuthenticator
|
||||
- CASSANDRA_AUTHORIZER=CassandraAuthorizer
|
||||
volumes:
|
||||
- cassandra_data:/var/lib/cassandra
|
||||
- ./conf/cassandra.yaml:/etc/cassandra/cassandra.yaml
|
||||
- ./conf/jvm-server.options:/etc/cassandra/jvm-server.options
|
||||
networks:
|
||||
- fluxer-shared
|
||||
ports:
|
||||
- target: 9042
|
||||
published: 9042
|
||||
protocol: tcp
|
||||
mode: host
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 30s
|
||||
max_attempts: 3
|
||||
resources:
|
||||
limits:
|
||||
cpus: '6'
|
||||
memory: 64G
|
||||
reservations:
|
||||
cpus: '4'
|
||||
memory: 48G
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'nodetool status']
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 120s
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 100000
|
||||
hard: 100000
|
||||
cap_add:
|
||||
- IPC_LOCK
|
||||
|
||||
cassandra-backup:
|
||||
image: ${CASSANDRA_BACKUP_IMAGE:-fluxer-cassandra-backup:latest}
|
||||
environment:
|
||||
- AGE_PUBLIC_KEY
|
||||
- B2_KEY_ID
|
||||
- B2_APPLICATION_KEY
|
||||
- B2_BUCKET_NAME
|
||||
- B2_ENDPOINT
|
||||
- B2_REGION
|
||||
- CASSANDRA_PASSWORD
|
||||
volumes:
|
||||
- cassandra_data:/var/lib/cassandra:ro
|
||||
networks:
|
||||
- fluxer-shared
|
||||
depends_on:
|
||||
- cassandra
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 30s
|
||||
max_attempts: 3
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 2G
|
||||
reservations:
|
||||
cpus: '0.5'
|
||||
memory: 1G
|
||||
|
||||
networks:
|
||||
fluxer-shared:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
cassandra_data:
|
||||
driver: local
|
||||
69
fluxer/fluxer_devops/cassandra/conf/cassandra.yaml
Normal file
69
fluxer/fluxer_devops/cassandra/conf/cassandra.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
cluster_name: 'fluxer-cluster'
|
||||
num_tokens: 256
|
||||
partitioner: org.apache.cassandra.dht.Murmur3Partitioner
|
||||
seed_provider:
|
||||
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
|
||||
parameters:
|
||||
- seeds: 'cassandra'
|
||||
listen_address: auto
|
||||
broadcast_address: cassandra
|
||||
rpc_address: 0.0.0.0
|
||||
broadcast_rpc_address: cassandra
|
||||
storage_port: 7000
|
||||
ssl_storage_port: 7001
|
||||
native_transport_port: 9042
|
||||
endpoint_snitch: GossipingPropertyFileSnitch
|
||||
data_file_directories:
|
||||
- /var/lib/cassandra/data
|
||||
commitlog_directory: /var/lib/cassandra/commitlog
|
||||
saved_caches_directory: /var/lib/cassandra/saved_caches
|
||||
hints_directory: /var/lib/cassandra/hints
|
||||
concurrent_reads: 32
|
||||
concurrent_writes: 32
|
||||
concurrent_counter_writes: 32
|
||||
concurrent_materialized_view_writes: 32
|
||||
memtable_allocation_type: heap_buffers
|
||||
memtable_flush_writers: 4
|
||||
commitlog_sync: periodic
|
||||
commitlog_sync_period: 10000ms
|
||||
commitlog_segment_size: 32MiB
|
||||
commitlog_total_space: 8192MiB
|
||||
compaction_throughput: 64MiB/s
|
||||
concurrent_compactors: 4
|
||||
sstable_preemptive_open_interval: 50MiB
|
||||
key_cache_size: 2048MiB
|
||||
key_cache_save_period: 14400
|
||||
row_cache_size: 0MiB
|
||||
counter_cache_size: 256MiB
|
||||
counter_cache_save_period: 7200
|
||||
read_request_timeout: 10000ms
|
||||
write_request_timeout: 10000ms
|
||||
counter_write_request_timeout: 10000ms
|
||||
range_request_timeout: 20000ms
|
||||
request_timeout: 20000ms
|
||||
authenticator: PasswordAuthenticator
|
||||
authorizer: CassandraAuthorizer
|
||||
role_manager: CassandraRoleManager
|
||||
native_transport_max_threads: 128
|
||||
native_transport_max_frame_size: 256MiB
|
||||
auto_snapshot: true
|
||||
snapshot_before_compaction: false
|
||||
tombstone_warn_threshold: 10000
|
||||
tombstone_failure_threshold: 100000
|
||||
disk_optimization_strategy: ssd
|
||||
disk_access_mode: auto
|
||||
stream_throughput_outbound: 400MiB/s
|
||||
inter_dc_stream_throughput_outbound: 200MiB/s
|
||||
max_hints_delivery_threads: 4
|
||||
hints_flush_period: 10000ms
|
||||
gc_warn_threshold: 1000ms
|
||||
gc_log_threshold: 200ms
|
||||
batch_size_warn_threshold: 5KiB
|
||||
batch_size_fail_threshold: 50KiB
|
||||
prepared_statements_cache_size: 10MiB
|
||||
client_encryption_options:
|
||||
enabled: false
|
||||
optional: false
|
||||
server_encryption_options:
|
||||
internode_encryption: none
|
||||
optional: false
|
||||
48
fluxer/fluxer_devops/cassandra/conf/jvm-server.options
Normal file
48
fluxer/fluxer_devops/cassandra/conf/jvm-server.options
Normal file
@@ -0,0 +1,48 @@
|
||||
-Xms32G
|
||||
-Xmx32G
|
||||
-XX:+UseG1GC
|
||||
-XX:+ParallelRefProcEnabled
|
||||
-XX:MaxTenuringThreshold=2
|
||||
-XX:G1HeapRegionSize=16m
|
||||
-XX:G1RSetUpdatingPauseTimePercent=5
|
||||
-XX:MaxGCPauseMillis=300
|
||||
-XX:InitiatingHeapOccupancyPercent=70
|
||||
-Xlog:gc*,gc+age=trace,safepoint:file=/var/log/cassandra/gc.log:time,uptime,level,tags:filecount=10,filesize=100M
|
||||
-XX:+AlwaysPreTouch
|
||||
-XX:+IgnoreUnrecognizedVMOptions
|
||||
-Xss512k
|
||||
-XX:+UseTLAB
|
||||
-XX:+ResizeTLAB
|
||||
-XX:+PerfDisableSharedMem
|
||||
-XX:+UseStringDeduplication
|
||||
-XX:+HeapDumpOnOutOfMemoryError
|
||||
-XX:HeapDumpPath=/var/lib/cassandra/dumps
|
||||
-Djdk.attach.allowAttachSelf=true
|
||||
--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED
|
||||
--add-exports=java.base/jdk.internal.ref=ALL-UNNAMED
|
||||
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED
|
||||
--add-exports=java.management.rmi/com.sun.jmx.remote.internal.rmi=ALL-UNNAMED
|
||||
--add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED
|
||||
--add-exports=java.rmi/sun.rmi.server=ALL-UNNAMED
|
||||
--add-exports=java.sql/java.sql=ALL-UNNAMED
|
||||
--add-opens=java.base/java.lang.module=ALL-UNNAMED
|
||||
--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED
|
||||
--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED
|
||||
--add-opens=java.base/jdk.internal.reflect=ALL-UNNAMED
|
||||
--add-opens=java.base/jdk.internal.math=ALL-UNNAMED
|
||||
--add-opens=java.base/jdk.internal.module=ALL-UNNAMED
|
||||
--add-opens=java.base/jdk.internal.util.jar=ALL-UNNAMED
|
||||
--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED
|
||||
-Dcom.sun.management.jmxremote.authenticate=false
|
||||
-Dcom.sun.management.jmxremote.ssl=false
|
||||
-Dcassandra.jmx.local.port=7199
|
||||
-Dcassandra.jmx.remote.port=7199
|
||||
-Djava.net.preferIPv4Stack=true
|
||||
-Dio.netty.tryReflectionSetAccessible=true
|
||||
-Dio.netty.allocator.useCacheForAllThreads=true
|
||||
-Dio.netty.eventLoop.maxPendingTasks=65536
|
||||
-Dcassandra.config=file:///etc/cassandra/cassandra.yaml
|
||||
-Dcassandra.logdir=/var/log/cassandra
|
||||
-Dcassandra.storagedir=/var/lib/cassandra
|
||||
-Djava.security.egd=file:/dev/urandom
|
||||
-Dfile.encoding=UTF-8
|
||||
@@ -0,0 +1,919 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.users (
|
||||
user_id bigint,
|
||||
username text,
|
||||
discriminator int,
|
||||
bot boolean,
|
||||
system boolean,
|
||||
email text,
|
||||
email_verified boolean,
|
||||
email_bounced boolean,
|
||||
phone text,
|
||||
password_hash text,
|
||||
totp_secret text,
|
||||
authenticator_types set<int>,
|
||||
avatar_hash text,
|
||||
banner_hash text,
|
||||
bio text,
|
||||
accent_color int,
|
||||
date_of_birth date,
|
||||
locale text,
|
||||
flags bigint,
|
||||
premium_type int,
|
||||
premium_since timestamp,
|
||||
premium_until timestamp,
|
||||
premium_lifetime_sequence int,
|
||||
stripe_subscription_id text,
|
||||
stripe_customer_id text,
|
||||
suspicious_activity_flags int,
|
||||
terms_agreed_at timestamp,
|
||||
privacy_agreed_at timestamp,
|
||||
last_active_at timestamp,
|
||||
last_active_ip text,
|
||||
temp_banned_until timestamp,
|
||||
pending_deletion_at timestamp,
|
||||
password_last_changed_at timestamp,
|
||||
pronouns text,
|
||||
acls set<text>,
|
||||
deletion_reason_code int,
|
||||
deletion_public_reason text,
|
||||
deletion_audit_log_reason text,
|
||||
first_refund_at timestamp,
|
||||
PRIMARY KEY ((user_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.users_by_email (
|
||||
email_lower text,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((email_lower), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.users_by_phone (
|
||||
phone text,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((phone), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.users_by_username (
|
||||
username text,
|
||||
discriminator int,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((username), discriminator, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.users_by_stripe_subscription_id (
|
||||
stripe_subscription_id text,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((stripe_subscription_id), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.users_by_stripe_customer_id (
|
||||
stripe_customer_id text,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((stripe_customer_id), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.user_activity_tracking (
|
||||
activity_month text,
|
||||
last_active_at timestamp,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((activity_month), last_active_at, user_id)
|
||||
) WITH CLUSTERING ORDER BY (last_active_at ASC, user_id ASC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.users_pending_deletion (
|
||||
deletion_date date,
|
||||
pending_deletion_at timestamp,
|
||||
user_id bigint,
|
||||
deletion_reason_code int,
|
||||
PRIMARY KEY ((deletion_date), pending_deletion_at, user_id)
|
||||
) WITH CLUSTERING ORDER BY (pending_deletion_at ASC, user_id ASC);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.custom_status (
|
||||
text text,
|
||||
emoji_id bigint,
|
||||
emoji_name text,
|
||||
emoji_animated boolean,
|
||||
expires_at timestamp
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.guild_folder (
|
||||
folder_id int,
|
||||
name text,
|
||||
color int,
|
||||
guild_ids list<bigint>
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.user_settings (
|
||||
user_id bigint,
|
||||
locale text,
|
||||
theme text,
|
||||
status text,
|
||||
custom_status frozen<custom_status>,
|
||||
developer_mode boolean,
|
||||
message_display_compact boolean,
|
||||
animate_emoji boolean,
|
||||
animate_stickers int,
|
||||
gif_auto_play boolean,
|
||||
render_embeds boolean,
|
||||
render_reactions boolean,
|
||||
render_spoilers int,
|
||||
inline_attachment_media boolean,
|
||||
inline_embed_media boolean,
|
||||
explicit_content_filter int,
|
||||
friend_source_flags int,
|
||||
default_guilds_restricted boolean,
|
||||
restricted_guilds set<bigint>,
|
||||
guild_positions list<bigint>,
|
||||
guild_folders frozen<list<guild_folder>>,
|
||||
afk_timeout int,
|
||||
time_format int,
|
||||
PRIMARY KEY ((user_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.relationships (
|
||||
source_user_id bigint,
|
||||
target_user_id bigint,
|
||||
type int,
|
||||
nickname text,
|
||||
since timestamp,
|
||||
PRIMARY KEY ((source_user_id), target_user_id, type)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.notes (
|
||||
source_user_id bigint,
|
||||
target_user_id bigint,
|
||||
note text,
|
||||
PRIMARY KEY ((source_user_id), target_user_id)
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.mute_config (
|
||||
end_time timestamp,
|
||||
selected_time_window int
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.channel_override (
|
||||
collapsed boolean,
|
||||
message_notifications int,
|
||||
muted boolean,
|
||||
mute_config frozen<mute_config>
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.user_guild_settings (
|
||||
user_id bigint,
|
||||
guild_id bigint,
|
||||
message_notifications int,
|
||||
muted boolean,
|
||||
mute_config frozen<mute_config>,
|
||||
mobile_push boolean,
|
||||
suppress_everyone boolean,
|
||||
suppress_roles boolean,
|
||||
hide_muted_channels boolean,
|
||||
channel_overrides frozen<map<bigint, channel_override>>,
|
||||
version int,
|
||||
PRIMARY KEY ((user_id), guild_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.private_channels (
|
||||
user_id bigint,
|
||||
channel_id bigint,
|
||||
is_gdm boolean,
|
||||
PRIMARY KEY ((user_id), channel_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.dm_states (
|
||||
hi_user_id bigint,
|
||||
lo_user_id bigint,
|
||||
channel_id bigint,
|
||||
PRIMARY KEY ((hi_user_id, lo_user_id), channel_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.read_states (
|
||||
user_id bigint,
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
mention_count int,
|
||||
last_pin_timestamp timestamp,
|
||||
PRIMARY KEY ((user_id), channel_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.recent_mentions (
|
||||
user_id bigint,
|
||||
message_id bigint,
|
||||
channel_id bigint,
|
||||
guild_id bigint,
|
||||
is_everyone boolean,
|
||||
is_role boolean,
|
||||
PRIMARY KEY ((user_id), message_id)
|
||||
) WITH CLUSTERING ORDER BY (message_id DESC)
|
||||
AND default_time_to_live = 604800;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.recent_mentions_by_guild (
|
||||
user_id bigint,
|
||||
guild_id bigint,
|
||||
message_id bigint,
|
||||
channel_id bigint,
|
||||
is_everyone boolean,
|
||||
is_role boolean,
|
||||
PRIMARY KEY ((user_id, guild_id), message_id)
|
||||
) WITH CLUSTERING ORDER BY (message_id DESC)
|
||||
AND default_time_to_live = 604800;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.saved_messages (
|
||||
user_id bigint,
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
saved_at timestamp,
|
||||
PRIMARY KEY ((user_id), message_id)
|
||||
) WITH CLUSTERING ORDER BY (message_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.auth_sessions (
|
||||
session_id_hash blob,
|
||||
user_id bigint,
|
||||
created_at timestamp,
|
||||
approx_last_used_at timestamp,
|
||||
client_ip text,
|
||||
client_os text,
|
||||
client_platform text,
|
||||
client_country text,
|
||||
PRIMARY KEY ((session_id_hash))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.auth_sessions_by_user_id (
|
||||
user_id bigint,
|
||||
session_id_hash blob,
|
||||
PRIMARY KEY ((user_id), session_id_hash)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.mfa_backup_codes (
|
||||
user_id bigint,
|
||||
code text,
|
||||
consumed boolean,
|
||||
PRIMARY KEY ((user_id), code)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.webauthn_credentials (
|
||||
user_id bigint,
|
||||
credential_id text,
|
||||
public_key blob,
|
||||
counter bigint,
|
||||
transports set<text>,
|
||||
name text,
|
||||
created_at timestamp,
|
||||
last_used_at timestamp,
|
||||
PRIMARY KEY (user_id, credential_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.webauthn_credential_lookup (
|
||||
credential_id text PRIMARY KEY,
|
||||
user_id bigint
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.email_verification_tokens (
|
||||
token_ text,
|
||||
user_id bigint,
|
||||
email text,
|
||||
PRIMARY KEY ((token_), user_id)
|
||||
) WITH default_time_to_live = 86400;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.password_reset_tokens (
|
||||
token_ text,
|
||||
user_id bigint,
|
||||
email text,
|
||||
PRIMARY KEY ((token_), user_id)
|
||||
) WITH default_time_to_live = 3600;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.ip_authorization_tokens (
|
||||
token_ text,
|
||||
user_id bigint,
|
||||
email text,
|
||||
PRIMARY KEY ((token_), user_id)
|
||||
) WITH default_time_to_live = 1800;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.email_revert_tokens (
|
||||
token_ text,
|
||||
user_id bigint,
|
||||
email text,
|
||||
PRIMARY KEY ((token_), user_id)
|
||||
) WITH default_time_to_live = 172800;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.mfa_tickets (
|
||||
ticket text,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((ticket), user_id)
|
||||
) WITH default_time_to_live = 300;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.phone_tokens (
|
||||
token_ text PRIMARY KEY,
|
||||
phone text,
|
||||
user_id bigint
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.authorized_ips (
|
||||
user_id bigint,
|
||||
ip text,
|
||||
PRIMARY KEY ((user_id, ip))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.banned_emails (
|
||||
email_lower text PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.banned_phones (
|
||||
phone text PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.banned_ips (
|
||||
ip text PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.beta_codes (
|
||||
code text,
|
||||
creator_id bigint,
|
||||
created_at timestamp,
|
||||
redeemer_id bigint,
|
||||
redeemed_at timestamp,
|
||||
PRIMARY KEY ((creator_id), code)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.beta_codes_by_code (
|
||||
code text,
|
||||
creator_id bigint,
|
||||
PRIMARY KEY ((code), creator_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.gift_codes (
|
||||
code text,
|
||||
amount_cents int,
|
||||
duration_months int,
|
||||
created_at timestamp,
|
||||
created_by_user_id bigint,
|
||||
redeemed_at timestamp,
|
||||
redeemed_by_user_id bigint,
|
||||
stripe_payment_intent_id text,
|
||||
PRIMARY KEY ((code))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.gift_codes_by_creator (
|
||||
created_by_user_id bigint,
|
||||
code text,
|
||||
PRIMARY KEY ((created_by_user_id), code)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.gift_codes_by_redeemer (
|
||||
redeemed_by_user_id bigint,
|
||||
code text,
|
||||
PRIMARY KEY ((redeemed_by_user_id), code)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.gift_codes_by_payment_intent (
|
||||
stripe_payment_intent_id text,
|
||||
code text,
|
||||
PRIMARY KEY ((stripe_payment_intent_id), code)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guilds (
|
||||
guild_id bigint,
|
||||
owner_id bigint,
|
||||
name text,
|
||||
vanity_url_code text,
|
||||
icon_hash text,
|
||||
banner_hash text,
|
||||
splash_hash text,
|
||||
features set<text>,
|
||||
verification_level int,
|
||||
mfa_level int,
|
||||
nsfw_level int,
|
||||
explicit_content_filter int,
|
||||
default_message_notifications int,
|
||||
system_channel_id bigint,
|
||||
system_channel_flags int,
|
||||
rules_channel_id bigint,
|
||||
afk_channel_id bigint,
|
||||
afk_timeout int,
|
||||
disabled_operations int,
|
||||
max_presences int,
|
||||
member_count int,
|
||||
audit_logs_indexed_at timestamp,
|
||||
PRIMARY KEY ((guild_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guilds_by_owner_id (
|
||||
owner_id bigint,
|
||||
guild_id bigint,
|
||||
PRIMARY KEY ((guild_id), owner_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_members (
|
||||
guild_id bigint,
|
||||
user_id bigint,
|
||||
joined_at timestamp,
|
||||
nick text,
|
||||
avatar_hash text,
|
||||
banner_hash text,
|
||||
join_source_type int,
|
||||
source_invite_code text,
|
||||
inviter_id bigint,
|
||||
deaf boolean,
|
||||
mute boolean,
|
||||
communication_disabled_until timestamp,
|
||||
role_ids set<bigint>,
|
||||
is_premium_sanitized boolean,
|
||||
bio text,
|
||||
accent_color int,
|
||||
pronouns text,
|
||||
temporary boolean,
|
||||
PRIMARY KEY ((guild_id), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_members_by_user_id (
|
||||
user_id bigint,
|
||||
guild_id bigint,
|
||||
PRIMARY KEY ((user_id), guild_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_roles (
|
||||
guild_id bigint,
|
||||
role_id bigint,
|
||||
name text,
|
||||
permissions bigint,
|
||||
position int,
|
||||
color int,
|
||||
icon_hash text,
|
||||
unicode_emoji text,
|
||||
hoist boolean,
|
||||
mentionable boolean,
|
||||
PRIMARY KEY ((guild_id), role_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_bans (
|
||||
guild_id bigint,
|
||||
user_id bigint,
|
||||
moderator_id bigint,
|
||||
banned_at timestamp,
|
||||
expires_at timestamp,
|
||||
reason text,
|
||||
ip text,
|
||||
PRIMARY KEY ((guild_id), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_bans_by_ip (
|
||||
guild_id bigint,
|
||||
ip text,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((guild_id, ip), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_emojis (
|
||||
guild_id bigint,
|
||||
emoji_id bigint,
|
||||
name text,
|
||||
creator_id bigint,
|
||||
animated boolean,
|
||||
PRIMARY KEY ((guild_id), emoji_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_emojis_by_emoji_id (
|
||||
emoji_id bigint,
|
||||
guild_id bigint,
|
||||
name text,
|
||||
creator_id bigint,
|
||||
animated boolean,
|
||||
PRIMARY KEY ((emoji_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_stickers (
|
||||
guild_id bigint,
|
||||
sticker_id bigint,
|
||||
name text,
|
||||
description text,
|
||||
format_type int,
|
||||
tags list<text>,
|
||||
creator_id bigint,
|
||||
PRIMARY KEY ((guild_id), sticker_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_stickers_by_sticker_id (
|
||||
sticker_id bigint,
|
||||
guild_id bigint,
|
||||
name text,
|
||||
description text,
|
||||
format_type int,
|
||||
tags list<text>,
|
||||
creator_id bigint,
|
||||
PRIMARY KEY ((sticker_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_audit_logs (
|
||||
guild_id bigint,
|
||||
log_id bigint,
|
||||
user_id bigint,
|
||||
target_type text,
|
||||
target_id text,
|
||||
action text,
|
||||
audit_log_reason text,
|
||||
metadata map<text, text>,
|
||||
changes text,
|
||||
created_at timestamp,
|
||||
PRIMARY KEY ((guild_id), log_id)
|
||||
) WITH CLUSTERING ORDER BY (log_id DESC);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.permission_overwrite (
|
||||
type int,
|
||||
allow_ bigint,
|
||||
deny_ bigint
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.channels (
|
||||
channel_id bigint,
|
||||
guild_id bigint,
|
||||
type int,
|
||||
name text,
|
||||
topic text,
|
||||
icon_hash text,
|
||||
url text,
|
||||
parent_id bigint,
|
||||
position int,
|
||||
owner_id bigint,
|
||||
recipient_ids set<bigint>,
|
||||
nsfw boolean,
|
||||
rate_limit_per_user int,
|
||||
bitrate int,
|
||||
user_limit int,
|
||||
rtc_region text,
|
||||
last_message_id bigint,
|
||||
last_pin_timestamp timestamp,
|
||||
permission_overwrites frozen<map<bigint, permission_overwrite>>,
|
||||
nicks map<text, text>,
|
||||
soft_deleted boolean,
|
||||
indexed_at timestamp,
|
||||
PRIMARY KEY ((channel_id, soft_deleted))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.channels_by_guild_id (
|
||||
guild_id bigint,
|
||||
channel_id bigint,
|
||||
PRIMARY KEY ((guild_id), channel_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.invites (
|
||||
code text,
|
||||
type int,
|
||||
guild_id bigint,
|
||||
channel_id bigint,
|
||||
inviter_id bigint,
|
||||
created_at timestamp,
|
||||
uses int,
|
||||
max_uses int,
|
||||
max_age int,
|
||||
temporary boolean,
|
||||
PRIMARY KEY ((code))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.invites_by_guild_id (
|
||||
guild_id bigint,
|
||||
code text,
|
||||
PRIMARY KEY ((guild_id), code)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.invites_by_channel_id (
|
||||
channel_id bigint,
|
||||
code text,
|
||||
PRIMARY KEY ((channel_id), code)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.webhooks (
|
||||
webhook_id bigint,
|
||||
webhook_token text,
|
||||
type int,
|
||||
guild_id bigint,
|
||||
channel_id bigint,
|
||||
creator_id bigint,
|
||||
name text,
|
||||
avatar_hash text,
|
||||
PRIMARY KEY ((webhook_id), webhook_token)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.webhooks_by_guild_id (
|
||||
guild_id bigint,
|
||||
webhook_id bigint,
|
||||
PRIMARY KEY ((guild_id), webhook_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.webhooks_by_channel_id (
|
||||
channel_id bigint,
|
||||
webhook_id bigint,
|
||||
PRIMARY KEY ((channel_id), webhook_id)
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_attachment (
|
||||
attachment_id bigint,
|
||||
filename text,
|
||||
size bigint,
|
||||
title text,
|
||||
description text,
|
||||
width int,
|
||||
height int,
|
||||
duration int,
|
||||
content_type text,
|
||||
content_hash text,
|
||||
placeholder text,
|
||||
flags int,
|
||||
nsfw boolean
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_embed_author (
|
||||
name text,
|
||||
url text,
|
||||
icon_url text
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_embed_provider (
|
||||
name text,
|
||||
url text
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_embed_footer (
|
||||
text text,
|
||||
icon_url text
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_embed_media (
|
||||
url text,
|
||||
width int,
|
||||
height int,
|
||||
duration int,
|
||||
description text,
|
||||
content_type text,
|
||||
content_hash text,
|
||||
placeholder text,
|
||||
flags int
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_embed_field (
|
||||
name text,
|
||||
value text,
|
||||
inline boolean
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_embed (
|
||||
type text,
|
||||
title text,
|
||||
description text,
|
||||
url text,
|
||||
timestamp timestamp,
|
||||
color int,
|
||||
author frozen<message_embed_author>,
|
||||
provider frozen<message_embed_provider>,
|
||||
thumbnail frozen<message_embed_media>,
|
||||
image frozen<message_embed_media>,
|
||||
video frozen<message_embed_media>,
|
||||
footer frozen<message_embed_footer>,
|
||||
fields frozen<list<message_embed_field>>,
|
||||
nsfw boolean
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_sticker_item (
|
||||
sticker_id bigint,
|
||||
name text,
|
||||
format_type int
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_reference (
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
guild_id bigint,
|
||||
type int
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_call (
|
||||
participant_ids set<bigint>,
|
||||
ended_timestamp timestamp
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_snapshot (
|
||||
content text,
|
||||
timestamp timestamp,
|
||||
edited_timestmap timestamp,
|
||||
mention_users set<bigint>,
|
||||
mention_roles set<bigint>,
|
||||
mention_channels set<bigint>,
|
||||
attachments frozen<list<message_attachment>>,
|
||||
embeds frozen<list<message_embed>>,
|
||||
sticker_items frozen<list<message_sticker_item>>,
|
||||
type int,
|
||||
flags int
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.messages (
|
||||
channel_id bigint,
|
||||
bucket int,
|
||||
message_id bigint,
|
||||
author_id bigint,
|
||||
type int,
|
||||
webhook_id bigint,
|
||||
webhook_name text,
|
||||
webhook_avatar_hash text,
|
||||
content text,
|
||||
edited_timestamp timestamp,
|
||||
pinned_timestamp timestamp,
|
||||
flags int,
|
||||
mention_everyone boolean,
|
||||
mention_users set<bigint>,
|
||||
mention_roles set<bigint>,
|
||||
mention_channels set<bigint>,
|
||||
attachments frozen<list<message_attachment>>,
|
||||
embeds frozen<list<message_embed>>,
|
||||
sticker_items frozen<list<message_sticker_item>>,
|
||||
message_reference frozen<message_reference>,
|
||||
call frozen<message_call>,
|
||||
message_snapshots frozen<list<message_snapshot>>,
|
||||
PRIMARY KEY ((channel_id, bucket), message_id)
|
||||
) WITH CLUSTERING ORDER BY (message_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.channel_pins (
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
pinned_timestamp timestamp,
|
||||
PRIMARY KEY ((channel_id), pinned_timestamp, message_id)
|
||||
) WITH CLUSTERING ORDER BY (pinned_timestamp DESC, message_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.messages_by_author_id (
|
||||
author_id bigint,
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
PRIMARY KEY ((author_id), channel_id, message_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.message_reactions (
|
||||
channel_id bigint,
|
||||
bucket int,
|
||||
message_id bigint,
|
||||
emoji_id bigint,
|
||||
emoji_name text,
|
||||
user_id bigint,
|
||||
emoji_animated boolean,
|
||||
PRIMARY KEY ((channel_id, bucket), message_id, emoji_id, emoji_name, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.attachment_lookup (
|
||||
channel_id bigint,
|
||||
attachment_id bigint,
|
||||
filename text,
|
||||
message_id bigint,
|
||||
PRIMARY KEY ((channel_id), attachment_id, filename)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.favorite_memes (
|
||||
user_id bigint,
|
||||
meme_id bigint,
|
||||
name text,
|
||||
alt_text text,
|
||||
tags list<text>,
|
||||
attachment_id bigint,
|
||||
filename text,
|
||||
content_type text,
|
||||
content_hash text,
|
||||
size bigint,
|
||||
width int,
|
||||
height int,
|
||||
duration int,
|
||||
storage_key text,
|
||||
created_at timestamp,
|
||||
PRIMARY KEY ((user_id), meme_id)
|
||||
) WITH CLUSTERING ORDER BY (meme_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.favorite_memes_by_meme_id (
|
||||
meme_id bigint,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((meme_id), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.push_subscriptions (
|
||||
user_id bigint,
|
||||
subscription_id text,
|
||||
endpoint text,
|
||||
p256dh_key text,
|
||||
auth_key text,
|
||||
user_agent text,
|
||||
PRIMARY KEY ((user_id), subscription_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.processed_payments (
|
||||
payment_intent_id text,
|
||||
user_id bigint,
|
||||
checkout_session_id text,
|
||||
price_id text,
|
||||
product_type text,
|
||||
amount_cents int,
|
||||
currency text,
|
||||
is_gift boolean,
|
||||
processed_at timestamp,
|
||||
PRIMARY KEY ((payment_intent_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.processed_payments_by_user (
|
||||
user_id bigint,
|
||||
payment_intent_id text,
|
||||
processed_at timestamp,
|
||||
PRIMARY KEY ((user_id), processed_at, payment_intent_id)
|
||||
) WITH CLUSTERING ORDER BY (processed_at DESC, payment_intent_id ASC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.visionary_purchases (
|
||||
purchase_id bigint,
|
||||
user_id bigint,
|
||||
purchased_at timestamp,
|
||||
sequence_number int,
|
||||
stripe_payment_intent_id text,
|
||||
PRIMARY KEY ((purchase_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.visionary_purchases_by_user (
|
||||
user_id bigint,
|
||||
purchase_id bigint,
|
||||
PRIMARY KEY ((user_id), purchase_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.user_harvests (
|
||||
user_id bigint,
|
||||
harvest_id bigint,
|
||||
requested_at timestamp,
|
||||
started_at timestamp,
|
||||
completed_at timestamp,
|
||||
failed_at timestamp,
|
||||
storage_key text,
|
||||
file_size bigint,
|
||||
progress_percent int,
|
||||
progress_step text,
|
||||
error_message text,
|
||||
download_url_expires_at timestamp,
|
||||
PRIMARY KEY (user_id, harvest_id)
|
||||
) WITH CLUSTERING ORDER BY (harvest_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.admin_audit_logs (
|
||||
log_id bigint PRIMARY KEY,
|
||||
admin_user_id bigint,
|
||||
target_type text,
|
||||
target_id bigint,
|
||||
action text,
|
||||
audit_log_reason text,
|
||||
metadata map<text, text>,
|
||||
created_at timestamp
|
||||
);
|
||||
|
||||
CREATE TYPE IF NOT EXISTS fluxer.iar_message_context (
|
||||
message_id bigint,
|
||||
author_id bigint,
|
||||
author_username text,
|
||||
author_discriminator int,
|
||||
author_avatar_hash text,
|
||||
content text,
|
||||
timestamp timestamp,
|
||||
edited_timestamp timestamp,
|
||||
type int,
|
||||
flags int,
|
||||
mention_everyone boolean,
|
||||
mention_users set<bigint>,
|
||||
mention_roles set<bigint>,
|
||||
mention_channels set<bigint>,
|
||||
attachments frozen<list<message_attachment>>,
|
||||
embeds frozen<list<message_embed>>,
|
||||
sticker_items frozen<list<message_sticker_item>>
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.iar_submissions (
|
||||
report_id bigint,
|
||||
reporter_id bigint,
|
||||
reported_at timestamp,
|
||||
status int,
|
||||
report_type int,
|
||||
category text,
|
||||
additional_info text,
|
||||
reported_user_id bigint,
|
||||
reported_user_username text,
|
||||
reported_user_discriminator int,
|
||||
reported_user_avatar_hash text,
|
||||
reported_guild_id bigint,
|
||||
reported_guild_name text,
|
||||
reported_guild_icon_hash text,
|
||||
reported_message_id bigint,
|
||||
reported_channel_id bigint,
|
||||
reported_channel_name text,
|
||||
message_context frozen<list<iar_message_context>>,
|
||||
guild_context_id bigint,
|
||||
resolved_at timestamp,
|
||||
resolved_by_admin_id bigint,
|
||||
public_comment text,
|
||||
audit_log_reason text,
|
||||
PRIMARY KEY ((report_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.pending_verifications (
|
||||
user_id bigint,
|
||||
created_at timestamp,
|
||||
PRIMARY KEY ((user_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.pending_verifications_by_time (
|
||||
created_at timestamp,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((created_at), user_id)
|
||||
) WITH CLUSTERING ORDER BY (user_id ASC);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.gift_codes ADD visionary_sequence_number int;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.users ADD beta_code_allowance int;
|
||||
ALTER TABLE fluxer.users ADD beta_code_last_reset_at timestamp;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.users ADD premium_will_cancel boolean;
|
||||
ALTER TABLE fluxer.users ADD has_ever_purchased boolean;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.users ADD premium_billing_cycle text;
|
||||
@@ -0,0 +1,64 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.payments (
|
||||
checkout_session_id text,
|
||||
user_id bigint,
|
||||
stripe_customer_id text,
|
||||
payment_intent_id text,
|
||||
subscription_id text,
|
||||
invoice_id text,
|
||||
price_id text,
|
||||
product_type text,
|
||||
amount_cents int,
|
||||
currency text,
|
||||
status text,
|
||||
is_gift boolean,
|
||||
gift_code text,
|
||||
created_at timestamp,
|
||||
completed_at timestamp,
|
||||
PRIMARY KEY ((checkout_session_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.payments_by_payment_intent (
|
||||
payment_intent_id text,
|
||||
checkout_session_id text,
|
||||
PRIMARY KEY ((payment_intent_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.payments_by_subscription (
|
||||
subscription_id text,
|
||||
checkout_session_id text,
|
||||
user_id bigint,
|
||||
price_id text,
|
||||
product_type text,
|
||||
PRIMARY KEY ((subscription_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.payments_by_user (
|
||||
user_id bigint,
|
||||
created_at timestamp,
|
||||
checkout_session_id text,
|
||||
PRIMARY KEY ((user_id), created_at)
|
||||
) WITH CLUSTERING ORDER BY (created_at DESC);
|
||||
|
||||
ALTER TABLE fluxer.gift_codes ADD checkout_session_id text;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.visionary_users (
|
||||
sequence_number int,
|
||||
user_id bigint,
|
||||
checkout_session_id text,
|
||||
gift_code text,
|
||||
granted_at timestamp,
|
||||
PRIMARY KEY ((sequence_number))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.visionary_users_by_user (
|
||||
user_id bigint,
|
||||
sequence_number int,
|
||||
granted_at timestamp,
|
||||
PRIMARY KEY ((user_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.visionary_counter (
|
||||
id text,
|
||||
next_sequence_number counter,
|
||||
PRIMARY KEY ((id))
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.users ADD gift_inventory_server_seq int;
|
||||
ALTER TABLE fluxer.users ADD gift_inventory_client_seq int;
|
||||
@@ -0,0 +1,5 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.visionary_slots (
|
||||
slot_index int,
|
||||
user_id bigint,
|
||||
PRIMARY KEY ((slot_index))
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.favorite_memes ADD is_gifv boolean;
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.pinned_dms (
|
||||
user_id bigint,
|
||||
channel_id bigint,
|
||||
sort_order int,
|
||||
PRIMARY KEY ((user_id), channel_id)
|
||||
);
|
||||
@@ -0,0 +1,32 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.voice_regions (
|
||||
id text PRIMARY KEY,
|
||||
name text,
|
||||
emoji text,
|
||||
latitude double,
|
||||
longitude double,
|
||||
priority int,
|
||||
is_default boolean,
|
||||
vip_only boolean,
|
||||
required_guild_features set<text>,
|
||||
allowed_guild_ids set<bigint>,
|
||||
allowed_user_ids set<bigint>,
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.voice_servers (
|
||||
region_id text,
|
||||
server_id text,
|
||||
endpoint text,
|
||||
api_key text,
|
||||
api_secret text,
|
||||
priority int,
|
||||
is_active boolean,
|
||||
vip_only boolean,
|
||||
required_guild_features set<text>,
|
||||
allowed_guild_ids set<bigint>,
|
||||
allowed_user_ids set<bigint>,
|
||||
created_at timestamp,
|
||||
updated_at timestamp,
|
||||
PRIMARY KEY (region_id, server_id)
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.user_settings ADD incoming_call_flags int;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.user_settings ADD group_dm_add_permission_flags int;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.favorite_memes ADD tenor_id bigint;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.users ADD global_name text;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.users ADD premium_onboarding_dismissed_at timestamp;
|
||||
@@ -0,0 +1,135 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_clients (
|
||||
client_id bigint PRIMARY KEY,
|
||||
client_secret_hash text,
|
||||
name text,
|
||||
description text,
|
||||
icon_url text,
|
||||
owner_user_id bigint,
|
||||
team_id bigint,
|
||||
type text,
|
||||
redirect_uris set<text>,
|
||||
scopes set<text>,
|
||||
grant_types set<text>,
|
||||
homepage_url text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_clients_by_owner (
|
||||
owner_user_id bigint,
|
||||
client_id bigint,
|
||||
PRIMARY KEY ((owner_user_id), client_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_authorization_requests (
|
||||
request_id text PRIMARY KEY,
|
||||
client_id bigint,
|
||||
redirect_uri text,
|
||||
scope set<text>,
|
||||
state text,
|
||||
code_challenge text,
|
||||
code_challenge_method text,
|
||||
nonce text,
|
||||
created_at timestamp,
|
||||
expires_at timestamp
|
||||
) WITH default_time_to_live = 900;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_authorization_codes (
|
||||
code text PRIMARY KEY,
|
||||
client_id bigint,
|
||||
user_id bigint,
|
||||
redirect_uri text,
|
||||
scope set<text>,
|
||||
code_challenge text,
|
||||
code_challenge_method text,
|
||||
nonce text,
|
||||
created_at timestamp,
|
||||
expires_at timestamp
|
||||
) WITH default_time_to_live = 900;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_access_tokens (
|
||||
token_ text PRIMARY KEY,
|
||||
client_id bigint,
|
||||
user_id bigint,
|
||||
scope set<text>,
|
||||
created_at timestamp,
|
||||
expires_at timestamp
|
||||
) WITH default_time_to_live = 86400;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_access_tokens_by_client (
|
||||
client_id bigint,
|
||||
token_ text,
|
||||
PRIMARY KEY ((client_id), token_)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_access_tokens_by_user (
|
||||
user_id bigint,
|
||||
token_ text,
|
||||
PRIMARY KEY ((user_id), token_)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_refresh_tokens (
|
||||
token_ text PRIMARY KEY,
|
||||
client_id bigint,
|
||||
user_id bigint,
|
||||
scope set<text>,
|
||||
created_at timestamp,
|
||||
expires_at timestamp
|
||||
) WITH default_time_to_live = 2592000;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_refresh_tokens_by_client (
|
||||
client_id bigint,
|
||||
token_ text,
|
||||
PRIMARY KEY ((client_id), token_)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_refresh_tokens_by_user (
|
||||
user_id bigint,
|
||||
token_ text,
|
||||
PRIMARY KEY ((user_id), token_)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_teams (
|
||||
team_id bigint PRIMARY KEY,
|
||||
name text,
|
||||
owner_user_id bigint,
|
||||
created_at timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_teams_by_owner (
|
||||
owner_user_id bigint,
|
||||
team_id bigint,
|
||||
PRIMARY KEY ((owner_user_id), team_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_team_members (
|
||||
team_id bigint,
|
||||
user_id bigint,
|
||||
role text,
|
||||
added_at timestamp,
|
||||
PRIMARY KEY ((team_id), user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_team_members_by_user (
|
||||
user_id bigint,
|
||||
team_id bigint,
|
||||
PRIMARY KEY ((user_id), team_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_bot_tokens (
|
||||
token_ text PRIMARY KEY,
|
||||
client_id bigint,
|
||||
user_id bigint,
|
||||
scopes set<text>,
|
||||
created_at timestamp,
|
||||
revoked boolean
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oidc_keys (
|
||||
kid text PRIMARY KEY,
|
||||
alg text,
|
||||
public_jwk text,
|
||||
private_jwk text,
|
||||
created_at timestamp,
|
||||
active boolean
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.favorite_memes ADD tenor_id_str text;
|
||||
@@ -0,0 +1,14 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oidc_keys_by_kid (
|
||||
kid text PRIMARY KEY,
|
||||
alg text,
|
||||
public_jwk text,
|
||||
private_jwk text,
|
||||
created_at timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oidc_key_status (
|
||||
name text PRIMARY KEY,
|
||||
active_kid text,
|
||||
published_kids set<text>,
|
||||
updated_at timestamp
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.guild_members ADD profile_flags int;
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.push_devices (
|
||||
user_id bigint,
|
||||
device_id text,
|
||||
fcm_token text,
|
||||
platform text,
|
||||
device_name text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp,
|
||||
PRIMARY KEY (user_id, device_id)
|
||||
);
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.push_devices_by_fcm_token (
|
||||
fcm_token text,
|
||||
user_id bigint,
|
||||
device_id text,
|
||||
PRIMARY KEY ((fcm_token), user_id, device_id)
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE fluxer.push_devices WITH default_time_to_live = 7776000;
|
||||
|
||||
ALTER TABLE fluxer.push_devices_by_fcm_token WITH default_time_to_live = 7776000;
|
||||
|
||||
ALTER TABLE fluxer.push_subscriptions WITH default_time_to_live = 7776000;
|
||||
|
||||
ALTER TABLE fluxer.phone_tokens WITH default_time_to_live = 2592000;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.oauth_clients ADD bot_is_public boolean;
|
||||
@@ -0,0 +1,8 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth_bot_tokens_by_client (
|
||||
client_id bigint,
|
||||
token_ text,
|
||||
user_id bigint,
|
||||
scopes set<text>,
|
||||
created_at timestamp,
|
||||
PRIMARY KEY (client_id, token_)
|
||||
);
|
||||
@@ -0,0 +1,63 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.applications (
|
||||
application_id bigint PRIMARY KEY,
|
||||
owner_user_id bigint,
|
||||
name text,
|
||||
bot_user_id bigint,
|
||||
is_confidential boolean,
|
||||
oauth2_redirect_uris set<text>,
|
||||
oauth2_scopes set<text>,
|
||||
client_secret_hash text,
|
||||
bot_token_hash text,
|
||||
bot_token_preview text,
|
||||
bot_token_created_at timestamp,
|
||||
client_secret_created_at timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.applications_by_owner (
|
||||
owner_user_id bigint,
|
||||
application_id bigint,
|
||||
PRIMARY KEY ((owner_user_id), application_id)
|
||||
) WITH CLUSTERING ORDER BY (application_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth2_authorization_codes (
|
||||
code text PRIMARY KEY,
|
||||
application_id bigint,
|
||||
user_id bigint,
|
||||
redirect_uri text,
|
||||
scope set<text>,
|
||||
code_challenge text,
|
||||
code_challenge_method text,
|
||||
nonce text,
|
||||
created_at timestamp,
|
||||
expires_at timestamp
|
||||
) WITH default_time_to_live = 600;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth2_access_tokens (
|
||||
token_ text PRIMARY KEY,
|
||||
application_id bigint,
|
||||
user_id bigint,
|
||||
scope set<text>,
|
||||
created_at timestamp,
|
||||
expires_at timestamp
|
||||
) WITH default_time_to_live = 3600;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth2_access_tokens_by_user (
|
||||
user_id bigint,
|
||||
token_ text,
|
||||
PRIMARY KEY ((user_id), token_)
|
||||
) WITH CLUSTERING ORDER BY (token_ DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth2_refresh_tokens (
|
||||
token_ text PRIMARY KEY,
|
||||
application_id bigint,
|
||||
user_id bigint,
|
||||
scope set<text>,
|
||||
created_at timestamp,
|
||||
expires_at timestamp
|
||||
) WITH default_time_to_live = 2592000;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.oauth2_refresh_tokens_by_user (
|
||||
user_id bigint,
|
||||
token_ text,
|
||||
PRIMARY KEY ((user_id), token_)
|
||||
) WITH CLUSTERING ORDER BY (token_ DESC);
|
||||
@@ -0,0 +1,5 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.authorized_ips_v2 (
|
||||
user_id bigint,
|
||||
ip text,
|
||||
PRIMARY KEY (user_id, ip)
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.guilds ADD banner_height int;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.guilds ADD banner_width int;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.applications ADD bot_is_public boolean;
|
||||
@@ -0,0 +1,56 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.admin_archives_by_subject (
|
||||
subject_type text,
|
||||
subject_id bigint,
|
||||
archive_id bigint,
|
||||
requested_by bigint,
|
||||
requested_at timestamp,
|
||||
started_at timestamp,
|
||||
completed_at timestamp,
|
||||
failed_at timestamp,
|
||||
storage_key text,
|
||||
file_size bigint,
|
||||
progress_percent int,
|
||||
progress_step text,
|
||||
error_message text,
|
||||
download_url_expires_at timestamp,
|
||||
expires_at timestamp,
|
||||
PRIMARY KEY ((subject_type, subject_id), archive_id)
|
||||
) WITH CLUSTERING ORDER BY (archive_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.admin_archives_by_requester (
|
||||
requested_by bigint,
|
||||
archive_id bigint,
|
||||
subject_type text,
|
||||
subject_id bigint,
|
||||
requested_at timestamp,
|
||||
started_at timestamp,
|
||||
completed_at timestamp,
|
||||
failed_at timestamp,
|
||||
storage_key text,
|
||||
file_size bigint,
|
||||
progress_percent int,
|
||||
progress_step text,
|
||||
error_message text,
|
||||
download_url_expires_at timestamp,
|
||||
expires_at timestamp,
|
||||
PRIMARY KEY ((requested_by), archive_id)
|
||||
) WITH CLUSTERING ORDER BY (archive_id DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.admin_archives_by_type (
|
||||
subject_type text,
|
||||
archive_id bigint,
|
||||
subject_id bigint,
|
||||
requested_by bigint,
|
||||
requested_at timestamp,
|
||||
started_at timestamp,
|
||||
completed_at timestamp,
|
||||
failed_at timestamp,
|
||||
storage_key text,
|
||||
file_size bigint,
|
||||
progress_percent int,
|
||||
progress_step text,
|
||||
error_message text,
|
||||
download_url_expires_at timestamp,
|
||||
expires_at timestamp,
|
||||
PRIMARY KEY ((subject_type), archive_id)
|
||||
) WITH CLUSTERING ORDER BY (archive_id DESC);
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE fluxer.oauth2_access_tokens
|
||||
WITH default_time_to_live = 604800;
|
||||
|
||||
ALTER TABLE fluxer.oauth2_access_tokens_by_user
|
||||
WITH default_time_to_live = 604800;
|
||||
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.attachment_decay_by_id (
|
||||
attachment_id bigint PRIMARY KEY,
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
filename text,
|
||||
size_bytes varint,
|
||||
uploaded_at timestamp,
|
||||
expires_at timestamp,
|
||||
last_accessed_at timestamp,
|
||||
cost double,
|
||||
lifetime_days int,
|
||||
status text
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.attachment_decay_by_expiry (
|
||||
expiry_bucket int,
|
||||
expires_at timestamp,
|
||||
attachment_id bigint,
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
PRIMARY KEY ((expiry_bucket), expires_at, attachment_id)
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.email_change_tickets (
|
||||
ticket text PRIMARY KEY,
|
||||
user_id bigint,
|
||||
require_original boolean,
|
||||
original_email text,
|
||||
original_verified boolean,
|
||||
original_code text,
|
||||
original_code_sent_at timestamp,
|
||||
original_code_expires_at timestamp,
|
||||
new_email text,
|
||||
new_code text,
|
||||
new_code_sent_at timestamp,
|
||||
new_code_expires_at timestamp,
|
||||
status text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.email_change_tokens (
|
||||
token_ text PRIMARY KEY,
|
||||
user_id bigint,
|
||||
new_email text,
|
||||
expires_at timestamp,
|
||||
created_at timestamp
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.email_change_tickets ADD original_proof text;
|
||||
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.user_contact_change_logs (
|
||||
user_id bigint,
|
||||
event_id timeuuid,
|
||||
field text,
|
||||
old_value text,
|
||||
new_value text,
|
||||
reason text,
|
||||
actor_user_id bigint,
|
||||
event_at timestamp,
|
||||
PRIMARY KEY ((user_id), event_id)
|
||||
) WITH CLUSTERING ORDER BY (event_id DESC);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.users ADD avatar_color int;
|
||||
ALTER TABLE fluxer.users ADD banner_color int;
|
||||
@@ -0,0 +1,51 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_audit_logs_v2 (
|
||||
guild_id bigint,
|
||||
log_id bigint,
|
||||
user_id bigint,
|
||||
target_id text,
|
||||
action_type int,
|
||||
reason text,
|
||||
options map<text, text>,
|
||||
changes text,
|
||||
PRIMARY KEY ((guild_id), log_id)
|
||||
) WITH CLUSTERING ORDER BY (log_id DESC)
|
||||
AND default_time_to_live = 3888000;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_audit_logs_v2_by_user (
|
||||
guild_id bigint,
|
||||
user_id bigint,
|
||||
log_id bigint,
|
||||
target_id text,
|
||||
action_type int,
|
||||
reason text,
|
||||
options map<text, text>,
|
||||
changes text,
|
||||
PRIMARY KEY ((guild_id, user_id), log_id)
|
||||
) WITH CLUSTERING ORDER BY (log_id DESC)
|
||||
AND default_time_to_live = 3888000;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_audit_logs_v2_by_action (
|
||||
guild_id bigint,
|
||||
action_type int,
|
||||
log_id bigint,
|
||||
user_id bigint,
|
||||
target_id text,
|
||||
reason text,
|
||||
options map<text, text>,
|
||||
changes text,
|
||||
PRIMARY KEY ((guild_id, action_type), log_id)
|
||||
) WITH CLUSTERING ORDER BY (log_id DESC)
|
||||
AND default_time_to_live = 3888000;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_audit_logs_v2_by_user_action (
|
||||
guild_id bigint,
|
||||
user_id bigint,
|
||||
action_type int,
|
||||
log_id bigint,
|
||||
target_id text,
|
||||
reason text,
|
||||
options map<text, text>,
|
||||
changes text,
|
||||
PRIMARY KEY ((guild_id, user_id, action_type), log_id)
|
||||
) WITH CLUSTERING ORDER BY (log_id DESC)
|
||||
AND default_time_to_live = 3888000;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE fluxer.users ADD pending_bulk_message_deletion_at timestamp;
|
||||
ALTER TABLE fluxer.users ADD pending_bulk_message_deletion_channel_count int;
|
||||
ALTER TABLE fluxer.users ADD pending_bulk_message_deletion_message_count int;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.guilds ADD splash_width int;
|
||||
ALTER TABLE fluxer.guilds ADD splash_height int;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE fluxer.guilds ADD embed_splash_hash text;
|
||||
ALTER TABLE fluxer.guilds ADD embed_splash_width int;
|
||||
ALTER TABLE fluxer.guilds ADD embed_splash_height int;
|
||||
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.channel_state (
|
||||
channel_id bigint PRIMARY KEY,
|
||||
created_bucket int,
|
||||
has_messages boolean,
|
||||
last_message_id bigint,
|
||||
last_message_bucket int,
|
||||
updated_at timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.channel_message_buckets (
|
||||
channel_id bigint,
|
||||
bucket int,
|
||||
updated_at timestamp,
|
||||
PRIMARY KEY (channel_id, bucket)
|
||||
) WITH CLUSTERING ORDER BY (bucket DESC);
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.channel_empty_buckets (
|
||||
channel_id bigint,
|
||||
bucket int,
|
||||
updated_at timestamp,
|
||||
PRIMARY KEY ((channel_id), bucket)
|
||||
) WITH CLUSTERING ORDER BY (bucket DESC);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.payments ADD version int;
|
||||
@@ -0,0 +1,20 @@
|
||||
ALTER TABLE fluxer.users ADD version int;
|
||||
ALTER TABLE fluxer.user_settings ADD version int;
|
||||
ALTER TABLE fluxer.guilds ADD version int;
|
||||
ALTER TABLE fluxer.guild_members ADD version int;
|
||||
ALTER TABLE fluxer.guild_roles ADD version int;
|
||||
ALTER TABLE fluxer.guild_emojis ADD version int;
|
||||
ALTER TABLE fluxer.guild_stickers ADD version int;
|
||||
ALTER TABLE fluxer.channels ADD version int;
|
||||
ALTER TABLE fluxer.messages ADD version int;
|
||||
ALTER TABLE fluxer.notes ADD version int;
|
||||
ALTER TABLE fluxer.relationships ADD version int;
|
||||
ALTER TABLE fluxer.favorite_memes ADD version int;
|
||||
ALTER TABLE fluxer.invites ADD version int;
|
||||
ALTER TABLE fluxer.webhooks ADD version int;
|
||||
ALTER TABLE fluxer.applications ADD version int;
|
||||
ALTER TABLE fluxer.auth_sessions ADD version int;
|
||||
ALTER TABLE fluxer.gift_codes ADD version int;
|
||||
ALTER TABLE fluxer.beta_codes ADD version int;
|
||||
ALTER TABLE fluxer.pending_verifications ADD version int;
|
||||
ALTER TABLE fluxer.webauthn_credentials ADD version int;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.guilds ADD splash_card_alignment int;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.messages ADD has_reaction boolean;
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.instance_configuration (
|
||||
key text PRIMARY KEY,
|
||||
value text,
|
||||
updated_at timestamp
|
||||
);
|
||||
|
||||
INSERT INTO fluxer.instance_configuration (key, value, updated_at)
|
||||
VALUES ('manual_review_enabled', 'true', toTimestamp(now()));
|
||||
|
||||
INSERT INTO fluxer.instance_configuration (key, value, updated_at)
|
||||
VALUES ('manual_review_schedule_enabled', 'false', toTimestamp(now()));
|
||||
|
||||
INSERT INTO fluxer.instance_configuration (key, value, updated_at)
|
||||
VALUES ('manual_review_schedule_start_hour_utc', '0', toTimestamp(now()));
|
||||
|
||||
INSERT INTO fluxer.instance_configuration (key, value, updated_at)
|
||||
VALUES ('manual_review_schedule_end_hour_utc', '23', toTimestamp(now()));
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.expression_packs (
|
||||
pack_id bigint PRIMARY KEY,
|
||||
pack_type text,
|
||||
creator_id bigint,
|
||||
name text,
|
||||
description text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp,
|
||||
version int
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.pack_installations (
|
||||
user_id bigint,
|
||||
pack_id bigint,
|
||||
pack_type text,
|
||||
installed_at timestamp,
|
||||
PRIMARY KEY (user_id, pack_id)
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.pending_verifications ADD metadata map<text, text>;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.auth_sessions ADD client_location text;
|
||||
@@ -0,0 +1,14 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.scheduled_messages (
|
||||
user_id bigint,
|
||||
scheduled_message_id bigint,
|
||||
channel_id bigint,
|
||||
payload text,
|
||||
scheduled_at timestamp,
|
||||
scheduled_local_at text,
|
||||
timezone text,
|
||||
status text,
|
||||
status_reason text,
|
||||
created_at timestamp,
|
||||
invalidated_at timestamp,
|
||||
PRIMARY KEY (user_id, scheduled_message_id)
|
||||
) WITH CLUSTERING ORDER BY (scheduled_message_id DESC);
|
||||
@@ -0,0 +1,20 @@
|
||||
ALTER TABLE fluxer.iar_submissions ADD reporter_email text;
|
||||
ALTER TABLE fluxer.iar_submissions ADD reporter_full_legal_name text;
|
||||
ALTER TABLE fluxer.iar_submissions ADD reporter_country_of_residence text;
|
||||
ALTER TABLE fluxer.iar_submissions ADD reported_guild_invite_code text;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.dsa_report_email_verifications (
|
||||
email_lower text,
|
||||
code_hash text,
|
||||
expires_at timestamp,
|
||||
last_sent_at timestamp,
|
||||
PRIMARY KEY ((email_lower))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.dsa_report_tickets (
|
||||
ticket text,
|
||||
email_lower text,
|
||||
expires_at timestamp,
|
||||
created_at timestamp,
|
||||
PRIMARY KEY ((ticket))
|
||||
);
|
||||
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.expression_packs_by_creator (
|
||||
creator_id bigint,
|
||||
pack_id bigint,
|
||||
pack_type text,
|
||||
name text,
|
||||
description text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp,
|
||||
version int,
|
||||
PRIMARY KEY (creator_id, pack_id)
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.user_settings ADD status_resets_at timestamp;
|
||||
ALTER TABLE fluxer.user_settings ADD status_resets_to text;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.guild_roles ADD hoist_position int;
|
||||
@@ -0,0 +1,28 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.swish_payments (
|
||||
payment_id text,
|
||||
user_id bigint,
|
||||
product_type text,
|
||||
status text,
|
||||
is_gift boolean,
|
||||
amount int,
|
||||
currency text,
|
||||
message text,
|
||||
payer_alias text,
|
||||
payment_reference text,
|
||||
gift_code text,
|
||||
created_at timestamp,
|
||||
completed_at timestamp,
|
||||
PRIMARY KEY ((payment_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.swish_payments_by_user (
|
||||
user_id bigint,
|
||||
payment_id text,
|
||||
product_type text,
|
||||
status text,
|
||||
is_gift boolean,
|
||||
amount int,
|
||||
currency text,
|
||||
created_at timestamp,
|
||||
PRIMARY KEY ((user_id), created_at)
|
||||
) WITH CLUSTERING ORDER BY (created_at DESC);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.auth_sessions ADD client_user_agent text;
|
||||
ALTER TABLE fluxer.auth_sessions ADD client_is_desktop boolean;
|
||||
@@ -0,0 +1,5 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.user_dm_history (
|
||||
user_id bigint,
|
||||
channel_id bigint,
|
||||
PRIMARY KEY ((user_id), channel_id)
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TYPE fluxer.message_snapshot ADD edited_timestamp timestamp;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.users ADD traits set<text>;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.user_settings ADD bot_default_guilds_restricted boolean;
|
||||
ALTER TABLE fluxer.user_settings ADD bot_restricted_guilds set<bigint>;
|
||||
@@ -0,0 +1,20 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.system_dm_jobs (
|
||||
job_type text,
|
||||
job_id bigint,
|
||||
admin_user_id bigint,
|
||||
status text,
|
||||
content text,
|
||||
registration_start timestamp,
|
||||
registration_end timestamp,
|
||||
excluded_guild_ids set<text>,
|
||||
target_count int,
|
||||
sent_count int,
|
||||
failed_count int,
|
||||
last_error text,
|
||||
worker_job_key text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp,
|
||||
approved_by bigint,
|
||||
approved_at timestamp,
|
||||
PRIMARY KEY ((job_type), job_id)
|
||||
) WITH CLUSTERING ORDER BY (job_id DESC);
|
||||
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.admin_api_keys (
|
||||
key_id bigint,
|
||||
key_hash text,
|
||||
name text,
|
||||
created_by_user_id bigint,
|
||||
created_at timestamp,
|
||||
last_used_at timestamp,
|
||||
expires_at timestamp,
|
||||
version int,
|
||||
PRIMARY KEY (key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.admin_api_keys_by_creator (
|
||||
created_by_user_id bigint,
|
||||
key_id bigint,
|
||||
created_at timestamp,
|
||||
name text,
|
||||
expires_at timestamp,
|
||||
last_used_at timestamp,
|
||||
version int,
|
||||
PRIMARY KEY (created_by_user_id, key_id)
|
||||
) WITH CLUSTERING ORDER BY (key_id DESC);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.admin_api_keys ADD acls set<text>;
|
||||
ALTER TABLE fluxer.admin_api_keys_by_creator ADD acls set<text>;
|
||||
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.relationships_by_target (
|
||||
target_user_id bigint,
|
||||
source_user_id bigint,
|
||||
type int,
|
||||
nickname text,
|
||||
since timestamp,
|
||||
version int,
|
||||
PRIMARY KEY (target_user_id, source_user_id, type)
|
||||
) WITH CLUSTERING ORDER BY (source_user_id ASC, type ASC);
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.messages_by_author_id_v2 (
|
||||
author_id bigint,
|
||||
message_id bigint,
|
||||
channel_id bigint,
|
||||
PRIMARY KEY ((author_id), message_id)
|
||||
) WITH CLUSTERING ORDER BY (message_id DESC);
|
||||
@@ -0,0 +1,28 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.csam_evidence_packages (
|
||||
report_id bigint PRIMARY KEY,
|
||||
resource_type text,
|
||||
bucket text,
|
||||
key text,
|
||||
cdn_url text,
|
||||
filename text,
|
||||
content_type text,
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
guild_id bigint,
|
||||
user_id bigint,
|
||||
match_tracking_id text,
|
||||
match_details text,
|
||||
frames text,
|
||||
hashes text,
|
||||
context_snapshot text,
|
||||
created_at timestamp,
|
||||
expires_at timestamp,
|
||||
integrity_sha256 text,
|
||||
evidence_zip_key text
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.csam_evidence_legal_holds (
|
||||
report_id bigint PRIMARY KEY,
|
||||
held_until timestamp,
|
||||
created_at timestamp
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.csam_scan_jobs (
|
||||
job_id text PRIMARY KEY,
|
||||
resource_type text,
|
||||
bucket text,
|
||||
key text,
|
||||
cdn_url text,
|
||||
filename text,
|
||||
content_type text,
|
||||
channel_id bigint,
|
||||
message_id bigint,
|
||||
guild_id bigint,
|
||||
user_id bigint,
|
||||
status text,
|
||||
enqueue_time timestamp,
|
||||
last_updated timestamp,
|
||||
match_tracking_id text,
|
||||
match_details text,
|
||||
hashes text,
|
||||
error_message text,
|
||||
expires_at timestamp
|
||||
);
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.csam_evidence_expirations (
|
||||
bucket text,
|
||||
expires_at timestamp,
|
||||
report_id bigint,
|
||||
PRIMARY KEY ((bucket), expires_at, report_id)
|
||||
) WITH CLUSTERING ORDER BY (expires_at ASC);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE fluxer.guild_stickers ADD animated boolean;
|
||||
ALTER TABLE fluxer.guild_stickers_by_sticker_id ADD animated boolean;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TYPE fluxer.message_sticker_item ADD animated boolean;
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.ncmec_submissions (
|
||||
report_id bigint PRIMARY KEY,
|
||||
status text,
|
||||
ncmec_report_id text,
|
||||
submitted_at timestamp,
|
||||
submitted_by_admin_id bigint,
|
||||
failure_reason text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TYPE fluxer.message_attachment ADD duration_secs int;
|
||||
ALTER TYPE fluxer.message_attachment ADD waveform text;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.favorite_memes ADD klipy_slug text;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.user_settings ADD trusted_domains set<text>;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.user_settings ADD default_hide_muted_channels boolean;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TYPE fluxer.guild_folder ADD flags int;
|
||||
ALTER TYPE fluxer.guild_folder ADD icon text;
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TYPE IF NOT EXISTS fluxer.message_embed_child (
|
||||
type text,
|
||||
title text,
|
||||
description text,
|
||||
url text,
|
||||
timestamp timestamp,
|
||||
color int,
|
||||
author frozen<message_embed_author>,
|
||||
provider frozen<message_embed_provider>,
|
||||
thumbnail frozen<message_embed_media>,
|
||||
image frozen<message_embed_media>,
|
||||
video frozen<message_embed_media>,
|
||||
footer frozen<message_embed_footer>,
|
||||
fields frozen<list<message_embed_field>>,
|
||||
nsfw boolean
|
||||
);
|
||||
ALTER TYPE fluxer.message_embed ADD children frozen<list<message_embed_child>>;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.guilds ADD message_history_cutoff timestamp;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.guilds ADD members_indexed_at timestamp;
|
||||
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.user_connections (
|
||||
user_id bigint,
|
||||
connection_type text,
|
||||
connection_id text,
|
||||
identifier text,
|
||||
name text,
|
||||
verified boolean,
|
||||
visibility_flags int,
|
||||
sort_order int,
|
||||
verification_token text,
|
||||
verified_at timestamp,
|
||||
last_verified_at timestamp,
|
||||
created_at timestamp,
|
||||
version int,
|
||||
PRIMARY KEY ((user_id), connection_type, connection_id)
|
||||
) WITH CLUSTERING ORDER BY (connection_type ASC, connection_id DESC);
|
||||
@@ -0,0 +1,46 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.donors (
|
||||
email text,
|
||||
stripe_customer_id text,
|
||||
|
||||
business_name text,
|
||||
tax_id text,
|
||||
tax_id_type text,
|
||||
|
||||
stripe_subscription_id text,
|
||||
subscription_amount_cents int,
|
||||
subscription_currency text,
|
||||
subscription_interval text,
|
||||
subscription_current_period_end timestamp,
|
||||
subscription_cancel_at timestamp,
|
||||
|
||||
created_at timestamp,
|
||||
updated_at timestamp,
|
||||
version int,
|
||||
PRIMARY KEY ((email))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.donors_by_stripe_customer_id (
|
||||
stripe_customer_id text,
|
||||
email text,
|
||||
PRIMARY KEY ((stripe_customer_id), email)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.donors_by_stripe_subscription_id (
|
||||
stripe_subscription_id text,
|
||||
email text,
|
||||
PRIMARY KEY ((stripe_subscription_id), email)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.donor_magic_link_tokens (
|
||||
token_ text,
|
||||
donor_email text,
|
||||
expires_at timestamp,
|
||||
used_at timestamp,
|
||||
PRIMARY KEY ((token_))
|
||||
) WITH default_time_to_live = 900;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.donor_magic_link_tokens_by_email (
|
||||
donor_email text,
|
||||
token_ text,
|
||||
PRIMARY KEY ((donor_email), token_)
|
||||
) WITH default_time_to_live = 900;
|
||||
@@ -0,0 +1,12 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.password_change_tickets (
|
||||
ticket text PRIMARY KEY,
|
||||
user_id bigint,
|
||||
code text,
|
||||
code_sent_at timestamp,
|
||||
code_expires_at timestamp,
|
||||
verified boolean,
|
||||
verification_proof text,
|
||||
status text,
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE fluxer.applications ADD bot_require_code_grant boolean;
|
||||
@@ -0,0 +1,21 @@
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_discovery (
|
||||
guild_id bigint,
|
||||
status text,
|
||||
category_type int,
|
||||
description text,
|
||||
applied_at timestamp,
|
||||
reviewed_at timestamp,
|
||||
reviewed_by bigint,
|
||||
review_reason text,
|
||||
removed_at timestamp,
|
||||
removed_by bigint,
|
||||
removal_reason text,
|
||||
PRIMARY KEY ((guild_id))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fluxer.guild_discovery_by_status (
|
||||
status text,
|
||||
applied_at timestamp,
|
||||
guild_id bigint,
|
||||
PRIMARY KEY ((status), applied_at, guild_id)
|
||||
) WITH CLUSTERING ORDER BY (applied_at DESC, guild_id DESC);
|
||||
38
fluxer/fluxer_devops/clamav/compose.yaml
Normal file
38
fluxer/fluxer_devops/clamav/compose.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
services:
|
||||
clamav:
|
||||
image: clamav/clamav:1.4
|
||||
hostname: clamav
|
||||
volumes:
|
||||
- clamav_data:/var/lib/clamav
|
||||
- ./conf/clamd.conf:/etc/clamav/clamd.conf:ro
|
||||
networks:
|
||||
- fluxer-shared
|
||||
ports:
|
||||
- '3310:3310'
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 10s
|
||||
max_attempts: 3
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2'
|
||||
memory: 4G
|
||||
reservations:
|
||||
cpus: '1'
|
||||
memory: 2G
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'clamdscan --version || exit 1']
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
|
||||
networks:
|
||||
fluxer-shared:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
clamav_data:
|
||||
driver: local
|
||||
54
fluxer/fluxer_devops/clamav/conf/clamd.conf
Normal file
54
fluxer/fluxer_devops/clamav/conf/clamd.conf
Normal file
@@ -0,0 +1,54 @@
|
||||
# Listening
|
||||
LocalSocket /tmp/clamd.sock
|
||||
TCPSocket 3310
|
||||
TCPAddr 0.0.0.0
|
||||
|
||||
# Threading
|
||||
MaxThreads 12
|
||||
MaxConnectionQueueLength 30
|
||||
|
||||
# Scanner limits
|
||||
MaxScanSize 150M
|
||||
MaxFileSize 100M
|
||||
MaxRecursion 16
|
||||
MaxFiles 10000
|
||||
MaxEmbeddedPE 10M
|
||||
MaxHTMLNormalize 10M
|
||||
MaxHTMLNoTags 2M
|
||||
MaxScriptNormalize 5M
|
||||
MaxZipTypeRcg 1M
|
||||
|
||||
# Scanning options
|
||||
ScanPE yes
|
||||
ScanELF yes
|
||||
ScanOLE2 yes
|
||||
ScanPDF yes
|
||||
ScanSWF yes
|
||||
ScanHTML yes
|
||||
ScanMail yes
|
||||
ScanArchive yes
|
||||
ScanPartialMessages yes
|
||||
AlertBrokenExecutables yes
|
||||
AlertEncrypted no
|
||||
AlertEncryptedArchive no
|
||||
AlertEncryptedDoc no
|
||||
AlertOLE2Macros yes
|
||||
AlertPhishingSSLMismatch no
|
||||
AlertPhishingCloak no
|
||||
|
||||
# Database
|
||||
DatabaseDirectory /var/lib/clamav
|
||||
OfficialDatabaseOnly no
|
||||
DetectPUA yes
|
||||
ExcludePUA NetTool
|
||||
ExcludePUA PWTool
|
||||
HeuristicScanPrecedence yes
|
||||
|
||||
# Logging
|
||||
LogTime yes
|
||||
LogClean no
|
||||
LogVerbose no
|
||||
ExtendedDetectionInfo yes
|
||||
|
||||
# Performance
|
||||
BytecodeTimeout 60000
|
||||
86
fluxer/fluxer_devops/ghost_blog/compose.yaml
Normal file
86
fluxer/fluxer_devops/ghost_blog/compose.yaml
Normal file
@@ -0,0 +1,86 @@
|
||||
services:
|
||||
ghost-blog-mysql:
|
||||
image: mysql:8.0
|
||||
hostname: ghost-blog-mysql
|
||||
env_file:
|
||||
- /etc/fluxer/ghost-blog.env
|
||||
environment:
|
||||
- MYSQL_DATABASE=ghost
|
||||
volumes:
|
||||
- ghost_blog_mysql:/var/lib/mysql
|
||||
networks:
|
||||
- fluxer-shared
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 10s
|
||||
max_attempts: 3
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2'
|
||||
memory: 2G
|
||||
healthcheck:
|
||||
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
ghost-blog:
|
||||
image: ghost:5-alpine
|
||||
hostname: ghost-blog
|
||||
env_file:
|
||||
- /etc/fluxer/ghost-blog.env
|
||||
environment:
|
||||
- url=https://blog.fluxer.app
|
||||
- database__client=mysql
|
||||
- database__connection__host=ghost-blog-mysql
|
||||
- database__connection__database=ghost
|
||||
- database__pool__min=0
|
||||
- database__pool__acquireTimeoutMillis=60000
|
||||
- database__connection__connectTimeout=60000
|
||||
volumes:
|
||||
- ghost_blog_content:/var/lib/ghost/content
|
||||
networks:
|
||||
- fluxer-shared
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 10s
|
||||
max_attempts: 3
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2'
|
||||
memory: 1G
|
||||
labels:
|
||||
- 'caddy=blog.fluxer.app'
|
||||
- 'caddy.reverse_proxy={{upstreams 2368}}'
|
||||
- 'caddy.header.Strict-Transport-Security="max-age=31536000; includeSubDomains; preload"'
|
||||
- 'caddy.header.X-Xss-Protection="1; mode=block"'
|
||||
- 'caddy.header.X-Content-Type-Options=nosniff'
|
||||
- 'caddy.header.Referrer-Policy=strict-origin-when-cross-origin'
|
||||
- 'caddy.header.X-Frame-Options=SAMEORIGIN'
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
'CMD',
|
||||
'node',
|
||||
'-e',
|
||||
"require('http').get('http://127.0.0.1:2368/', r => process.exit(r.statusCode < 400 ? 0 : 1)).on('error', () => process.exit(1))",
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 120s
|
||||
|
||||
networks:
|
||||
fluxer-shared:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
ghost_blog_mysql:
|
||||
driver: local
|
||||
ghost_blog_content:
|
||||
driver: local
|
||||
172
fluxer/fluxer_devops/livekitctl/README.md
Normal file
172
fluxer/fluxer_devops/livekitctl/README.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# livekitctl
|
||||
|
||||
A CLI tool for bootstrapping self-hosted LiveKit SFU infrastructure for Fluxer voice and video.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
curl -fsSL https://fluxer.app/get/livekitctl | sudo bash
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
livekitctl automates the installation and configuration of a complete LiveKit media server stack including:
|
||||
|
||||
- **LiveKit** - WebRTC SFU for voice and video
|
||||
- **Caddy** - Reverse proxy with automatic TLS (built with L4 module for TCP/UDP)
|
||||
- **coturn** - TURN/STUN server for NAT traversal
|
||||
- **KV store** - Redis-compatible key-value store for LiveKit state
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Linux server (Debian/Ubuntu, RHEL/CentOS, or Arch-based)
|
||||
- Root access
|
||||
- DNS records configured for your LiveKit and TURN domains pointing to your server's public IP
|
||||
|
||||
## Commands
|
||||
|
||||
### bootstrap
|
||||
|
||||
Install and configure the complete LiveKit stack.
|
||||
|
||||
```bash
|
||||
livekitctl bootstrap \
|
||||
--livekit-domain livekit.example.com \
|
||||
--turn-domain turn.example.com \
|
||||
--email admin@example.com
|
||||
```
|
||||
|
||||
Required flags:
|
||||
|
||||
- `--livekit-domain <domain>` - Domain for LiveKit WebSocket/HTTP connections
|
||||
- `--turn-domain <domain>` - Domain for TURN relay server
|
||||
- `--email <email>` - ACME email for TLS certificate issuance
|
||||
|
||||
Optional flags:
|
||||
|
||||
- `--livekit-version <version>` - LiveKit version (default: v1.9.11)
|
||||
- `--caddy-version <version>` - Caddy version (default: v2.10.2)
|
||||
- `--caddy-l4-version <version>` - Caddy L4 module version (default: master)
|
||||
- `--xcaddy-version <version>` - xcaddy build tool version (default: v0.4.5)
|
||||
- `--install-dir <path>` - Override LiveKit install directory (default: /opt/livekit)
|
||||
- `--firewall` - Configure detected firewall tool (ufw, firewalld, iptables)
|
||||
- `--kv-port <port>` - KV store port (default: 6379)
|
||||
- `--kv-port-auto` - Pick a free KV port from 6379-6382
|
||||
- `--webhook-url <url>` - Webhook URL (repeatable)
|
||||
- `--webhook-urls-file <file>` - File with webhook URLs (one per line)
|
||||
- `--allow-http-webhooks` - Allow http:// webhook URLs
|
||||
- `--dns-timeout <seconds>` - DNS wait timeout (default: 900)
|
||||
- `--dns-interval <seconds>` - DNS check interval (default: 10)
|
||||
- `--print-secrets` - Print generated secrets JSON to stdout
|
||||
|
||||
### status
|
||||
|
||||
Show systemd service status for all managed services.
|
||||
|
||||
```bash
|
||||
livekitctl status
|
||||
```
|
||||
|
||||
### logs
|
||||
|
||||
Show systemd logs for a specific service.
|
||||
|
||||
```bash
|
||||
livekitctl logs --service livekit.service [--lines 200]
|
||||
```
|
||||
|
||||
Flags:
|
||||
|
||||
- `--service <unit>` - systemd unit name (required), e.g., `livekit.service`, `caddy.service`
|
||||
- `--lines <n>` - Number of log lines to show (default: 200)
|
||||
|
||||
### restart
|
||||
|
||||
Restart one or more services. If no services specified, restarts all managed services.
|
||||
|
||||
```bash
|
||||
livekitctl restart [services...]
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
livekitctl restart # Restart all services
|
||||
livekitctl restart livekit.service # Restart only LiveKit
|
||||
livekitctl restart caddy.service livekit-coturn.service
|
||||
```
|
||||
|
||||
Managed services:
|
||||
|
||||
- `livekit-kv.service` - KV store
|
||||
- `livekit-coturn.service` - TURN server
|
||||
- `livekit.service` - LiveKit SFU
|
||||
- `caddy.service` - Reverse proxy
|
||||
|
||||
### webhook
|
||||
|
||||
Manage LiveKit webhook URLs. Changes are written to config and LiveKit is restarted.
|
||||
|
||||
```bash
|
||||
livekitctl webhook list
|
||||
livekitctl webhook add <url> [--allow-http-webhooks]
|
||||
livekitctl webhook remove <url>
|
||||
livekitctl webhook set --url <url> [--url <url>...] [--file <path>] [--allow-http-webhooks]
|
||||
```
|
||||
|
||||
Subcommands:
|
||||
|
||||
- `list` - List configured webhook URLs
|
||||
- `add <url>` - Add a webhook URL
|
||||
- `remove <url>` - Remove a webhook URL
|
||||
- `set` - Replace all webhook URLs
|
||||
|
||||
## Port configuration
|
||||
|
||||
Default port allocations:
|
||||
|
||||
| Port | Protocol | Service |
|
||||
| ----------- | -------- | ------------------------- |
|
||||
| 7880 | TCP | LiveKit HTTP (internal) |
|
||||
| 7881 | TCP | LiveKit RTC |
|
||||
| 50000-60000 | UDP | LiveKit RTC media |
|
||||
| 3478 | UDP | TURN listen |
|
||||
| 40000-49999 | UDP | TURN relay |
|
||||
| 6379 | TCP | KV store (localhost only) |
|
||||
|
||||
## State and configuration files
|
||||
|
||||
```
|
||||
/etc/livekit/
|
||||
livekitctl-state.json # Bootstrap state
|
||||
secrets.json # Generated API keys and secrets
|
||||
livekit.yaml # LiveKit server config
|
||||
caddy.json # Caddy config
|
||||
coturn.conf # TURN server config
|
||||
|
||||
/opt/livekit/
|
||||
bin/
|
||||
livekit-server # LiveKit binary
|
||||
```
|
||||
|
||||
## DNS setup
|
||||
|
||||
Before running bootstrap, create DNS records pointing to your server's public IP:
|
||||
|
||||
```
|
||||
A livekit.example.com → <your-ipv4>
|
||||
A turn.example.com → <your-ipv4>
|
||||
```
|
||||
|
||||
If your server has IPv6:
|
||||
|
||||
```
|
||||
AAAA livekit.example.com → <your-ipv6>
|
||||
AAAA turn.example.com → <your-ipv6>
|
||||
```
|
||||
|
||||
The bootstrap command waits for DNS propagation before requesting TLS certificates.
|
||||
|
||||
## Global flags
|
||||
|
||||
- `--state <path>` - Path to state file (default: /etc/livekit/livekitctl-state.json)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user