feat: Ipad app production readiness, Colony orchestration, Social posting (#44)

#38 Ipad app production readiness, Colony orchestration, Social posting

Co-authored-by: Sayan Datta <sayan@Sayans-MacBook-Air.local>
Reviewed-on: sagnik/Project_Velocity#44
This commit is contained in:
2026-05-03 18:30:38 +05:30
parent 59d398abc3
commit eeb684b46c
86 changed files with 20349 additions and 1655 deletions

View File

@@ -0,0 +1,198 @@
#!/usr/bin/env bash
set -euo pipefail
if ! command -v aws >/dev/null 2>&1; then
echo "aws CLI is required. Install AWS CLI v2 and authenticate before running." >&2
exit 1
fi
AWS_REGION="${AWS_REGION:-ap-south-1}"
AWS_ACCOUNT_ID="${AWS_ACCOUNT_ID:-$(aws sts get-caller-identity --query Account --output text)}"
BUCKET_NAME="${VELOCITY_MEDIA_BUCKET:-velocity-media-${AWS_ACCOUNT_ID}-${AWS_REGION}}"
IAM_USER_NAME="${VELOCITY_MEDIA_IAM_USER:-velocity-media-app}"
IAM_POLICY_NAME="${VELOCITY_MEDIA_IAM_POLICY_NAME:-VelocityMediaBucketReadWriteObjects}"
CORS_ORIGIN="${VELOCITY_MEDIA_CORS_ORIGIN:-https://velocity.desineuron.in}"
TMP_DIR="$(mktemp -d)"
cleanup() {
rm -rf "${TMP_DIR}"
}
trap cleanup EXIT
bucket_exists() {
aws s3api head-bucket --bucket "${BUCKET_NAME}" >/dev/null 2>&1
}
create_bucket() {
if bucket_exists; then
echo "S3 bucket already exists: ${BUCKET_NAME}"
return
fi
echo "Creating private S3 bucket: ${BUCKET_NAME} (${AWS_REGION})"
if [[ "${AWS_REGION}" == "us-east-1" ]]; then
aws s3api create-bucket --bucket "${BUCKET_NAME}" --region "${AWS_REGION}" >/dev/null
else
aws s3api create-bucket \
--bucket "${BUCKET_NAME}" \
--region "${AWS_REGION}" \
--create-bucket-configuration "LocationConstraint=${AWS_REGION}" >/dev/null
fi
aws s3api wait bucket-exists --bucket "${BUCKET_NAME}"
}
secure_bucket() {
echo "Applying private bucket controls"
aws s3api put-public-access-block \
--bucket "${BUCKET_NAME}" \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api put-bucket-ownership-controls \
--bucket "${BUCKET_NAME}" \
--ownership-controls '{
"Rules": [
{
"ObjectOwnership": "BucketOwnerEnforced"
}
]
}'
aws s3api put-bucket-encryption \
--bucket "${BUCKET_NAME}" \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
},
"BucketKeyEnabled": true
}
]
}'
aws s3api put-bucket-versioning \
--bucket "${BUCKET_NAME}" \
--versioning-configuration Status=Enabled
}
apply_cors() {
local cors_file="${TMP_DIR}/cors.json"
cat >"${cors_file}" <<JSON
{
"CORSRules": [
{
"AllowedOrigins": ["${CORS_ORIGIN}"],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["Authorization", "Content-Type", "Content-MD5", "x-amz-*"],
"ExposeHeaders": ["ETag", "x-amz-request-id", "x-amz-version-id"],
"MaxAgeSeconds": 3000
}
]
}
JSON
echo "Applying CORS policy for ${CORS_ORIGIN}"
aws s3api put-bucket-cors \
--bucket "${BUCKET_NAME}" \
--cors-configuration "file://${cors_file}"
}
apply_https_only_bucket_policy() {
local bucket_policy_file="${TMP_DIR}/bucket-policy.json"
cat >"${bucket_policy_file}" <<JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::${BUCKET_NAME}",
"arn:aws:s3:::${BUCKET_NAME}/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
JSON
echo "Applying HTTPS-only bucket policy"
aws s3api put-bucket-policy \
--bucket "${BUCKET_NAME}" \
--policy "file://${bucket_policy_file}"
}
ensure_iam_user() {
if aws iam get-user --user-name "${IAM_USER_NAME}" >/dev/null 2>&1; then
echo "IAM user already exists: ${IAM_USER_NAME}"
return
fi
echo "Creating IAM user: ${IAM_USER_NAME}"
aws iam create-user \
--user-name "${IAM_USER_NAME}" \
--tags Key=Project,Value=Velocity Key=Purpose,Value=MediaStorage >/dev/null
}
attach_restricted_policy() {
local policy_file="${TMP_DIR}/iam-policy.json"
cat >"${policy_file}" <<JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VelocityMediaObjectReadWriteOnly",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::${BUCKET_NAME}/*"
}
]
}
JSON
echo "Attaching restricted inline IAM policy: ${IAM_POLICY_NAME}"
aws iam put-user-policy \
--user-name "${IAM_USER_NAME}" \
--policy-name "${IAM_POLICY_NAME}" \
--policy-document "file://${policy_file}"
}
print_summary() {
cat <<SUMMARY
Project Velocity media bucket provisioning complete.
Bucket: ${BUCKET_NAME}
Region: ${AWS_REGION}
CORS origin: ${CORS_ORIGIN}
IAM user: ${IAM_USER_NAME}
Inline policy: ${IAM_POLICY_NAME}
Environment values for backend/.env.production:
AWS_REGION=${AWS_REGION}
AWS_S3_BUCKET=${BUCKET_NAME}
AWS_S3_MEDIA_PREFIX=velocity-production
This script does not print or create long-lived access keys. Use your preferred
AWS credential vending path for production secrets.
SUMMARY
}
create_bucket
secure_bucket
apply_cors
apply_https_only_bucket_policy
ensure_iam_user
attach_restricted_policy
print_summary

View File

@@ -1,60 +1,154 @@
{
email admin@desineuron.in
admin 127.0.0.1:2019
auto_https enable_redirects
servers {
protocols h1 h2 h3
}
log {
output file /var/log/caddy/admin.log
format json
}
}
office.desineuron.in, git.desineuron.in, cloud.desineuron.in, projects.desineuron.in, talk.desineuron.in, vpn.desineuron.in {
tls /etc/caddy/tls/fullchain.pem /etc/caddy/tls/privkey.pem
(velocity_security_headers) {
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
}
(velocity_proxy_headers) {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Port {server_port}
}
api.desineuron.in {
import velocity_security_headers
log {
output file /var/log/caddy/access.log
output file /var/log/caddy/api.desineuron.in.access.log
format json
}
reverse_proxy https://127.0.0.1:8443 {
header_up Host {host}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote_host}
@websockets {
header Connection *Upgrade*
header Upgrade websocket
}
reverse_proxy @websockets 127.0.0.1:8001 127.0.0.1:8000 {
import velocity_proxy_headers
flush_interval -1
transport http {
tls_insecure_skip_verify
versions 1.1
dial_timeout 30s
read_timeout 3600s
write_timeout 3600s
}
}
reverse_proxy 127.0.0.1:8001 127.0.0.1:8000 {
import velocity_proxy_headers
transport http {
versions 1.1
dial_timeout 30s
read_timeout 3600s
write_timeout 3600s
}
lb_policy first
health_uri /health
health_interval 15s
}
}
dreamweaver.desineuron.in {
import velocity_security_headers
log {
output file /var/log/caddy/dreamweaver.desineuron.in.access.log
format json
}
reverse_proxy 127.0.0.1:8082 {
import velocity_proxy_headers
transport http {
versions 1.1
dial_timeout 30s
read_timeout 3600s
write_timeout 3600s
}
}
}
velocity.desineuron.in {
import velocity_security_headers
log {
output file /var/log/caddy/access.log
output file /var/log/caddy/velocity.desineuron.in.access.log
format json
}
import /etc/caddy/managed/llm_upstream.caddy_inc
handle /api/* {
reverse_proxy 127.0.0.1:8001 127.0.0.1:8000 {
import velocity_proxy_headers
transport http {
versions 1.1
dial_timeout 30s
read_timeout 3600s
write_timeout 3600s
}
lb_policy first
health_uri /health
health_interval 15s
}
}
handle {
reverse_proxy https://127.0.0.1:8443 {
import velocity_proxy_headers
transport http {
tls_insecure_skip_verify
}
}
}
}
ops.desineuron.in {
import velocity_security_headers
log {
output file /var/log/caddy/ops.desineuron.in.access.log
format json
}
reverse_proxy https://127.0.0.1:8443 {
header_up Host {host}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote_host}
import velocity_proxy_headers
transport http {
tls_insecure_skip_verify
}
}
}
ops.desineuron.in {
office.desineuron.in, git.desineuron.in, cloud.desineuron.in, projects.desineuron.in, talk.desineuron.in, vpn.desineuron.in {
tls /etc/caddy/tls/fullchain.pem /etc/caddy/tls/privkey.pem
import velocity_security_headers
log {
output file /var/log/caddy/access.log
format json
}
reverse_proxy https://127.0.0.1:8443 {
header_up Host {host}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote_host}
import velocity_proxy_headers
transport http {
tls_insecure_skip_verify
}

View File

@@ -1,21 +1,95 @@
# Project Velocity production API ingress.
#
# Install into /etc/nginx/sites-available/api.desineuron.in.conf and symlink to
# sites-enabled when Nginx is the public TLS terminator. Do not enable this
# 80/443 vhost at the same time as the Caddy public terminator for this domain.
map $http_upgrade $velocity_connection_upgrade {
default upgrade;
"" close;
}
upstream velocity_fastapi_backend {
server 127.0.0.1:8001 max_fails=3 fail_timeout=10s;
server 127.0.0.1:8000 backup max_fails=3 fail_timeout=10s;
keepalive 64;
}
server {
listen 443 ssl http2;
listen 80;
listen [::]:80;
server_name api.desineuron.in;
ssl_certificate /etc/letsencrypt/live/desineuron-infra/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/desineuron-infra/privkey.pem;
access_log /var/log/nginx/api.desineuron.in.access.log;
error_log /var/log/nginx/api.desineuron.in.error.log;
location ^~ /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type "text/plain";
}
location / {
proxy_pass http://127.0.0.1:8001;
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.desineuron.in;
ssl_certificate /etc/letsencrypt/live/api.desineuron.in/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.desineuron.in/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:VelocityAPI:20m;
ssl_session_timeout 1d;
ssl_session_tickets off;
client_max_body_size 250m;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
access_log /var/log/nginx/api.desineuron.in.access.log;
error_log /var/log/nginx/api.desineuron.in.error.log warn;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location = /health {
proxy_pass http://velocity_fastapi_backend/health;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
}
location ~ ^/(api/sentinel/ws|api/oracle/ws|ws|api/.*/ws) {
proxy_pass http://velocity_fastapi_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $velocity_connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_buffering off;
}
location / {
proxy_pass http://velocity_fastapi_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $velocity_connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Request-ID $request_id;
proxy_redirect off;
}
}