···11+# SQLite path (default: gleamview.db in CWD)
22+DATABASE_URL=sqlite:gleamview.db
33+44+# Public URL used for OAuth metadata / did:web (use 127.0.0.1, not localhost)
55+PUBLIC_URL=http://127.0.0.1:3000
66+77+HOST=0.0.0.0
88+PORT=3000
99+1010+# Session cookie signing (at least 64 chars in production)
1111+SESSION_SECRET=dev-secret-change-me-please-use-at-least-64-characters-long!!
1212+1313+# Bootstrap admin API key shown once on first start if no users exist
1414+# GLEAMVIEW_ADMIN_KEY=gv_admin_...
1515+1616+JETSTREAM_URL=wss://jetstream1.us-east.bsky.network
1717+# Set to 0 to disable Jetstream
1818+JETSTREAM_ENABLED=1
1919+2020+PLC_URL=https://plc.directory
2121+RELAY_URL=https://bsky.network
2222+2323+# Dev-only: allow unauthenticated local procedure writes into the index
2424+# (HappyView always proxies to the user's PDS; GleamView MVP can index locally)
2525+ALLOW_LOCAL_WRITES=1
···11+MIT License
22+33+Copyright (c) 2026 GleamView contributors
44+55+Permission is hereby granted, free of charge, to any person obtaining a copy
66+of this software and associated documentation files (the "Software"), to deal
77+in the Software without restriction, including without limitation the rights
88+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99+copies of the Software, and to permit persons to whom the Software is
1010+furnished to do so, subject to the following conditions:
1111+1212+The above copyright notice and this permission notice shall be included in all
1313+copies or substantial portions of the Software.
1414+1515+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121+SOFTWARE.
···11+-- GleamView schema (HappyView-compatible table names / shapes where practical)
22+33+CREATE TABLE IF NOT EXISTS happyview_records (
44+ uri TEXT PRIMARY KEY,
55+ did TEXT NOT NULL,
66+ collection TEXT NOT NULL,
77+ rkey TEXT NOT NULL,
88+ record TEXT NOT NULL,
99+ cid TEXT NOT NULL DEFAULT '',
1010+ indexed_at TEXT NOT NULL,
1111+ created_at TEXT NOT NULL
1212+);
1313+1414+CREATE INDEX IF NOT EXISTS idx_records_did_collection
1515+ ON happyview_records (did, collection);
1616+CREATE INDEX IF NOT EXISTS idx_records_collection
1717+ ON happyview_records (collection);
1818+CREATE INDEX IF NOT EXISTS idx_records_created_at_uri
1919+ ON happyview_records (created_at DESC, uri DESC);
2020+2121+CREATE TABLE IF NOT EXISTS happyview_lexicons (
2222+ id TEXT PRIMARY KEY,
2323+ revision INTEGER NOT NULL DEFAULT 1,
2424+ lexicon_json TEXT NOT NULL,
2525+ backfill INTEGER NOT NULL DEFAULT 1,
2626+ target_collection TEXT,
2727+ action TEXT,
2828+ token_cost INTEGER,
2929+ source TEXT NOT NULL DEFAULT 'manual',
3030+ authority_did TEXT,
3131+ last_fetched_at TEXT,
3232+ created_at TEXT NOT NULL,
3333+ updated_at TEXT NOT NULL
3434+);
3535+3636+CREATE TABLE IF NOT EXISTS happyview_users (
3737+ id TEXT PRIMARY KEY,
3838+ did TEXT NOT NULL UNIQUE,
3939+ is_super INTEGER NOT NULL DEFAULT 0,
4040+ created_at TEXT NOT NULL,
4141+ last_used_at TEXT
4242+);
4343+4444+CREATE TABLE IF NOT EXISTS happyview_user_permissions (
4545+ user_id TEXT NOT NULL REFERENCES happyview_users(id) ON DELETE CASCADE,
4646+ permission TEXT NOT NULL,
4747+ granted_at TEXT NOT NULL,
4848+ granted_by TEXT,
4949+ PRIMARY KEY (user_id, permission)
5050+);
5151+5252+CREATE TABLE IF NOT EXISTS happyview_api_keys (
5353+ id TEXT PRIMARY KEY,
5454+ user_id TEXT NOT NULL REFERENCES happyview_users(id) ON DELETE CASCADE,
5555+ name TEXT NOT NULL,
5656+ key_hash TEXT NOT NULL,
5757+ key_prefix TEXT NOT NULL,
5858+ permissions TEXT NOT NULL DEFAULT '[]',
5959+ created_at TEXT NOT NULL,
6060+ last_used_at TEXT,
6161+ revoked_at TEXT
6262+);
6363+6464+CREATE INDEX IF NOT EXISTS idx_api_keys_key_hash ON happyview_api_keys(key_hash);
6565+6666+CREATE TABLE IF NOT EXISTS happyview_api_clients (
6767+ id TEXT PRIMARY KEY,
6868+ name TEXT NOT NULL,
6969+ client_key TEXT NOT NULL UNIQUE,
7070+ client_secret_hash TEXT NOT NULL,
7171+ client_uri TEXT,
7272+ capacity INTEGER NOT NULL DEFAULT 100,
7373+ refill_rate REAL NOT NULL DEFAULT 2.0,
7474+ created_at TEXT NOT NULL,
7575+ revoked_at TEXT
7676+);
7777+7878+CREATE INDEX IF NOT EXISTS idx_api_clients_key ON happyview_api_clients(client_key);
7979+8080+CREATE TABLE IF NOT EXISTS happyview_instance_settings (
8181+ key TEXT PRIMARY KEY,
8282+ value TEXT NOT NULL,
8383+ updated_at TEXT NOT NULL
8484+);
8585+8686+CREATE TABLE IF NOT EXISTS happyview_event_logs (
8787+ id TEXT PRIMARY KEY,
8888+ event_type TEXT NOT NULL,
8989+ severity TEXT NOT NULL DEFAULT 'info',
9090+ actor_did TEXT,
9191+ subject TEXT,
9292+ detail TEXT NOT NULL DEFAULT '{}',
9393+ created_at TEXT NOT NULL
9494+);
9595+9696+CREATE INDEX IF NOT EXISTS idx_event_logs_created_at ON happyview_event_logs (created_at);
9797+CREATE INDEX IF NOT EXISTS idx_event_logs_event_type ON happyview_event_logs (event_type);
9898+9999+CREATE TABLE IF NOT EXISTS happyview_record_refs (
100100+ source_uri TEXT NOT NULL REFERENCES happyview_records(uri) ON DELETE CASCADE,
101101+ target_uri TEXT NOT NULL,
102102+ collection TEXT NOT NULL,
103103+ PRIMARY KEY (source_uri, target_uri)
104104+);
105105+106106+CREATE INDEX IF NOT EXISTS idx_record_refs_target
107107+ ON happyview_record_refs (target_uri, collection);