api shell

This commit is contained in:
Jason Ross
2026-03-22 12:57:16 -05:00
parent 2910468199
commit 7dfada7690
10 changed files with 235 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
POSTGRES_USER=admin
POSTGRES_PASSWORD=changeme
POSTGRES_DB=postcard-im-app
REDIS_URL=redis://redis:6379
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=changeme
MINIO_BUCKET=media
MINIO_ENDPOINT=http://minio:9000
JWT_SECRET=changeme
BACKEND_URL=http://backend:8080
+1
View File
@@ -0,0 +1 @@
.env
+11
View File
@@ -0,0 +1,11 @@
:80 {
route /api/* {
reverse_proxy backend:8080
}
route /ws {
reverse_proxy backend:8080
}
route /* {
reverse_proxy web:3000
}
}
+6
View File
@@ -0,0 +1,6 @@
[package]
name = "backend"
version = "0.1.0"
edition = "2021"
[dependencies]
+12
View File
@@ -0,0 +1,12 @@
# syntax=docker/dockerfile:1
FROM rust:1.82-slim AS builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:trixie-slim
WORKDIR /app
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/backend /app/backend
EXPOSE 8080
CMD ["/app/backend"]
+9
View File
@@ -0,0 +1,9 @@
use std::time::Duration;
use std::thread;
fn main() {
println!("Backend stub started...");
loop {
thread::sleep(Duration::from_secs(60));
}
}
+56
View File
@@ -0,0 +1,56 @@
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(32) UNIQUE NOT NULL,
display_name VARCHAR(64) NOT NULL,
avatar_url TEXT,
password_hash TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
next_sequence BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE conversation_participants (
conversation_id UUID REFERENCES conversations(id),
user_id UUID REFERENCES users(id),
last_read_seq BIGINT NOT NULL DEFAULT 0,
joined_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (conversation_id, user_id),
UNIQUE (conversation_id, user_id)
);
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID REFERENCES conversations(id) NOT NULL,
sender_id UUID REFERENCES users(id) NOT NULL,
sequence BIGINT NOT NULL,
message_type VARCHAR(16) NOT NULL,
body TEXT,
media_metadata JSONB,
client_msg_id UUID NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'sent',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (conversation_id, sequence),
UNIQUE (client_msg_id)
);
CREATE TABLE sticker_packs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(64) NOT NULL,
author VARCHAR(64),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE stickers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
pack_id UUID REFERENCES sticker_packs(id) NOT NULL,
emoji_tag VARCHAR(8),
image_url TEXT NOT NULL,
thumbnail_url TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
+7
View File
@@ -0,0 +1,7 @@
-- Unique constraints on (conversation_id, sequence) and (client_msg_id)
-- inherently create indexes in PostgreSQL, so we only need to explicitly
-- define the remaining requested indexes.
CREATE INDEX idx_messages_conv_created_at ON messages(conversation_id, created_at);
CREATE INDEX idx_conv_participants_user_id ON conversation_participants(user_id);
CREATE INDEX idx_stickers_pack_id ON stickers(pack_id);
+13
View File
@@ -0,0 +1,13 @@
-- Atomic sequence increment for message ordering
CREATE OR REPLACE FUNCTION next_message_sequence(conv_id UUID)
RETURNS BIGINT AS $$
DECLARE
seq BIGINT;
BEGIN
UPDATE conversations
SET next_sequence = next_sequence + 1, updated_at = now()
WHERE id = conv_id
RETURNING next_sequence INTO seq;
RETURN seq;
END;
$$ LANGUAGE plpgsql;
+110
View File
@@ -0,0 +1,110 @@
version: '3.8'
services:
postgres:
image: postgres:18
environment:
POSTGRES_USER: ${POSTGRES_USER:-admin}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-Lord5673}
POSTGRES_DB: ${POSTGRES_DB:-postcard-im-app}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./migrations:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-admin} -d ${POSTGRES_DB:-postcard-im-app}"]
interval: 5s
timeout: 5s
retries: 5
ports:
- "5432:5432"
redis:
image: redis:8
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
minio:
image: minio/minio:latest
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-ChuckNorris52!}
volumes:
- minio_data:/data
command: server /data --console-address ":9001"
ports:
- "9000:9000"
- "9001:9001"
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 5s
timeout: 5s
retries: 5
minio-init:
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
/usr/bin/mc alias set myminio http://minio:9000 ${MINIO_ROOT_USER:-minioadmin} ${MINIO_ROOT_PASSWORD:-ChuckNorris52!} &&
/usr/bin/mc mb myminio/${MINIO_BUCKET:-media} --ignore-existing &&
/usr/bin/mc anonymous set public myminio/${MINIO_BUCKET:-media}
"
backend:
build:
context: ./backend
dockerfile: Containerfile
environment:
- DATABASE_URL=postgres://${POSTGRES_USER:-admin}:${POSTGRES_PASSWORD:-Lord5673}@postgres:5432/${POSTGRES_DB:-postcard-im-app}
- REDIS_URL=${REDIS_URL:-redis://redis:6379}
- MINIO_ENDPOINT=${MINIO_ENDPOINT:-http://minio:9000}
- MINIO_ROOT_USER=${MINIO_ROOT_USER:-minioadmin}
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-ChuckNorris52!}
- MINIO_BUCKET=${MINIO_BUCKET:-media}
- JWT_SECRET=${JWT_SECRET:-changeme}
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio:
condition: service_healthy
web:
build:
context: ./web
dockerfile: Containerfile
environment:
- BACKEND_URL=${BACKEND_URL:-http://backend:8080}
ports:
- "3000:3000"
depends_on:
- backend
caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
depends_on:
- backend
- web
volumes:
postgres_data:
minio_data:
caddy_data:
caddy_config: