feat(db): add community host lookup seam

Co-authored-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf
2026-06-26 11:54:35 -04:00
parent ab4b518d5d
commit 1adbfbe210
4 changed files with 100 additions and 1 deletions
+71 -1
View File
@@ -47,7 +47,7 @@ use sqlx::{PgPool, QueryBuilder, Row};
use std::time::Duration;
use uuid::Uuid;
use buzz_core::StoredEvent;
use buzz_core::{CommunityId, StoredEvent};
/// Extract p-tag mentions from an event and insert into the `event_mentions` table.
///
@@ -162,6 +162,15 @@ impl Default for DbConfig {
}
}
/// Community host-map row returned by [`Db::lookup_community_by_host`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CommunityRecord {
/// Stable server-resolved community id.
pub id: CommunityId,
/// Normalized host that maps to this community.
pub host: String,
}
/// Token summary returned by [`Db::list_active_tokens`].
#[derive(Debug, Clone)]
pub struct TokenSummary {
@@ -216,6 +225,67 @@ impl Db {
self.pool.begin().await.map_err(Into::into)
}
/// Returns the community mapped to a normalized request host, if one exists.
///
/// The caller owns host normalization and turns `None` into the fail-closed
/// request/connection error. buzz-db only reads the durable host map.
pub async fn lookup_community_by_host(
&self,
normalized_host: &str,
) -> Result<Option<CommunityRecord>> {
let row = sqlx::query(
r#"
SELECT id, host
FROM communities
WHERE host = $1
"#,
)
.bind(normalized_host)
.fetch_optional(&self.pool)
.await?;
row.map(|row| {
let id: Uuid = row.try_get("id")?;
let host: String = row.try_get("host")?;
Ok(CommunityRecord {
id: CommunityId::from_uuid(id),
host,
})
})
.transpose()
}
/// Ensure a configured community host exists and return its row.
///
/// This is the startup/config seeding path for N=1 deployments. Migrations
/// create the schema only; deployment-specific hosts are not hardcoded into
/// schema history.
pub async fn ensure_configured_community(
&self,
normalized_host: &str,
) -> Result<CommunityRecord> {
let row = sqlx::query(
r#"
INSERT INTO communities (host)
VALUES ($1)
ON CONFLICT (host) DO UPDATE SET host = EXCLUDED.host
RETURNING id, host
"#,
)
.bind(normalized_host)
.fetch_one(&self.pool)
.await?;
let id: Uuid = row.try_get("id")?;
let host: String = row.try_get("host")?;
Ok(CommunityRecord {
id: CommunityId::from_uuid(id),
host,
})
}
/// Inserts an event. Returns `(StoredEvent, was_inserted)` — `false` on duplicate.
pub async fn insert_event(
&self,
+7
View File
@@ -131,6 +131,13 @@ mod tests {
assert_eq!(migrations.len(), 3);
assert_eq!(migrations[0].version, 1);
assert_eq!(&*migrations[0].description, "initial schema");
assert!(
migrations[0]
.sql
.as_str()
.contains("CREATE TABLE communities"),
"initial schema migration should include tenant host map"
);
assert!(
migrations[0].sql.as_str().contains("CREATE TABLE channels"),
"initial schema migration should include Buzz core tables"
+11
View File
@@ -17,6 +17,17 @@ CREATE TYPE subscription_status AS ENUM ('active', 'paused', 'deleted');
CREATE TYPE pause_reason AS ENUM ('user', 'system', 'rate_limit');
CREATE TYPE channel_add_policy AS ENUM ('anyone', 'owner_only', 'nobody');
-- ── Communities ───────────────────────────────────────────────────────────────
CREATE TABLE communities (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
host VARCHAR(255) NOT NULL UNIQUE,
signing_key BYTEA,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chk_communities_host_not_empty CHECK (LENGTH(TRIM(host)) > 0),
CONSTRAINT chk_communities_host_normalized CHECK (host = LOWER(host))
);
-- ── Channels ──────────────────────────────────────────────────────────────────
CREATE TABLE channels (
+11
View File
@@ -18,6 +18,17 @@ CREATE TYPE subscription_status AS ENUM ('active', 'paused', 'deleted');
CREATE TYPE pause_reason AS ENUM ('user', 'system', 'rate_limit');
CREATE TYPE channel_add_policy AS ENUM ('anyone', 'owner_only', 'nobody');
-- ── Communities ───────────────────────────────────────────────────────────────
CREATE TABLE communities (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
host VARCHAR(255) NOT NULL UNIQUE,
signing_key BYTEA,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chk_communities_host_not_empty CHECK (LENGTH(TRIM(host)) > 0),
CONSTRAINT chk_communities_host_normalized CHECK (host = LOWER(host))
);
-- ── Channels ──────────────────────────────────────────────────────────────────
CREATE TABLE channels (