Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
오픈소스 화이트라벨 포털 회원·행사·회비·뉴스·AI 비서 제공 자체 호스팅 또는 BolaLabs 운영
Open-source white-label portal for associations, communities and institutions: members, events, dues, news and an AI assistant. Self-hosted or run by BolaLabs. Client in production: arcva.pt.
소셜TypeScript · JavaScriptGitHub @brunobola-portfolio온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
Open-source white-label platform for cultural and recreational associations: members, events, dues, news and an AI assistant that answers from the portal's own content, all run by the board from its own backoffice. Reference instance: arcva.pt
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
The self-managed digital home for associations, communities and institutions
A white-label community platform for associations, clubs, parish councils, non-profits and
local institutions: realtime serverless backend, an AI assistant that answers from the
organisation's own published content (RAG), and a complete backoffice so the board runs
everything — events, news, members, dues, galleries — without a developer.README 전문 보기 ↗A white-label community platform for associations, clubs, parish councils, non-profits and local institutions: realtime serverless backend, an AI assistant that answers from the organisation's own published content (RAG), and a complete backoffice so the board runs everything — events, news, members, dues, galleries — without a developer.
Reference client and partner: arcva.pt, the portal of ARCVA, a Portuguese cultural and recreational association, runs its own instance of this platform. Product page: bolalabs.pt/en/community-platform.
Features · Getting Started · Architecture · AI Assistant · White-Label · Deploy
English · Português
This is not a SaaS: there is no sign-up, no tenant and no subscription plan. You either run the platform yourself, or you ask BolaLabs to run it for you.
| Option | What it means |
|---|---|
| Self-host | Clone the repository, deploy it on your own Convex project and your own server. Free and MIT-licensed, no contract with anyone. |
| Hosted and operated by BolaLabs | On request, BolaLabs sets up, hosts and operates your instance — deploys, updates and backups included. |
| Custom work | Features, integrations or design specific to your organisation, built on top of the same codebase. |
| If you are… | Start here |
|---|---|
| Anyone — technical or not | This page, top to bottom (~5 minutes) |
| A developer setting up locally | Getting Started → Commands |
| Launching a portal for another organisation | White-Label → docs/WHITE-LABEL.md |
| Running instances for clients (private repo + automated deploy) | docs/INSTANCE-REPO.md + templates/instance/ |
| Releasing or deploying | Deploy → DEPLOY.md (IIS) / DEPLOY-VPS.md (nginx) |
| Changing the UI / visual design | docs/DESIGN-SYSTEM.md |
| An AI coding agent | AGENTS.md (canonical guide) + |
Every screen below is the demo association that ships with the repository (npx convex run seed:seed), captured with no client branding. The one-minute tour lives on the
product page.
| Public portal (dark) | Events with registrations |
|---|---|
| Registration without an account | Registrations: confirm, door list, Excel |
|---|---|
| AI assistant grounded in the portal's content | Member area: digital card and dues |
|---|---|
| Backoffice dashboard | Events list: search, filters, sort |
|---|---|
| AI studio: one sentence becomes an event with its poster | Built-in help: guides, videos, "Como funciona" |
|---|---|
Cultural and recreational associations, sports clubs, parish councils, non-profits and other local institutions usually depend on a volunteer with technical skills — and stall when that person leaves. This platform removes the dependency: after the initial deploy, everything is managed from the admin panel. Events with dynamic registration forms, news with a rich text editor, team pages, photo galleries, member dues, documents, notifications, site settings, and the AI assistant itself — all database-first, all editable by the board.
Nothing in this repository names a real organisation. The demo seed is a fictitious
club; a real instance lives in three private layers that never reach git — the database
(admin panel), a gitignored .env.production for build-time meta tags, and a gitignored
.brand/ overlay for logos, photos and the OG image. A fresh deployment becomes your
organisation by filling in the admin settings, not by forking the code. See
docs/WHITE-LABEL.md.
The platform started as the new portal of ARCVA — a cultural and recreational association in Portugal — built by BolaLabs to replace a static site nobody could update. It grew into a generic product for any community organisation, and ARCVA remains its founding partner and reference client: every feature here runs in production for a real community first.
| Page | Highlights |
|---|---|
| Home | Animated hero, realtime stats, action areas, news bento grid, events carousel, partners marquee |
| History | Editable vertical timeline (admin-managed milestones), historical photo gallery, founding members |
| About | AI geo-assistant, interactive map, values pillars, contact form |
| Team | Governing bodies by tabs, photos, hierarchy |
| Events | A page per event with its full poster; registration without an account, per person or per team, with places, price, deadline and the event's own questions; confirmation by email; WhatsApp/Facebook sharing with the poster in the preview; calendar export (Google + ICS) |
| Blog | Featured article, category filters with counts, search |
| Post | Immersive reading, "Listen to article" TTS, tags, author bio, recommendations |
| Gallery | Albums with lightbox, arrow/keyboard navigation |
| Member area | 3D digital membership card, dues status, payment instructions (MB WAY/IBAN/Multibanco), my registrations (state, "I can't go"), private documents, notifications |
| 404 | Styled page with return navigation |
ASSOCIACAO / LOCAL / GERAL / FORA_DE_TEMA / INJECTION + regex pre-filterEvery list has search (/), filter chips with live counts, sort and a result counter.
Início (what needs attention) · Página inicial · Eventos (visual editor, poster optimised in the browser, registrations per person or team, deadline, tournaments) · Inscrições (confirm all pending at once, add phone-ins, open or close registrations, a list for the door to print, Excel export with the teams and the event's own questions, copy every email) · Notícias · Membros · Parceiros · Galeria (drag-and-drop multi-upload, captions, ordering, cover pick, bulk delete) · História · Mensagens recebidas (reply by email) · Sócios & Quotas · Documentos · Avisos aos sócios · Categorias · Níveis de Parceria · Acessos (accounts and roles, temporary passwords) · Email (service, sender, what is sent, live test, delivery log) · Assistente virtual (provider, models, guardrails, costs, a live test chat) · Definições (identity, brand, home photo, contacts, dues, About page, social links)
Built for volunteers: a privacy notice at /privacidade written from the settings, guest data
deleted 90 days after the event, and WCAG AA contrast in both themes, checked with axe.
The board picks the service in Email and pastes a key; nothing to deploy. Brevo, Resend
and Postmark go through their HTTP APIs, Microsoft 365 through Microsoft Graph (an Entra
app with Mail.Send, sending from the association's own Exchange mailbox, nothing kept in Sent
Items), and SMTP (Gmail, Outlook.com, the hosting provider's mailbox) through Nodemailer in a
Node action. What gets sent: registration received,
confirmed and cancelled to the participant (with a calendar link), alerts to the board for a
new registration, a member dropping out, a contact message or a sponsorship request, and replies
to contact messages written in the backoffice.
RESEND_API_KEY, BREVO_API_KEY, POSTMARK_SERVER_TOKEN, MS_GRAPH_*, SMTP_*)An Ajuda tab in the backoffice with step-by-step guides for every task (search, "Comece por
aqui", screenshots and short silent videos, an "Ir para" button that opens the right tab), a
Como funciona button on every tab that opens its guides in a dialog, and a public /ajuda
page for members and visitors (registering for an event, member area, dues, password). Guides
are typed data in content/help/ and name the association from the settings.
Image generation (Gemini image models, 1K–4K), tone-aware text enhancement, TTS narration — uploads go to Convex storage, never base64.
| Layer | Technology | Version |
|---|---|---|
| Frontend | React + TypeScript | 19.3 + 5.9 |
| Build | Vite (Rolldown) | 8.3 |
| Styling | Tailwind CSS (CSS-first, @tailwindcss/vite) + clsx + tailwind-merge | 4.3 |
| Backend | Convex (serverless, realtime) | 1.47 |
| Auth | @convex-dev/auth (password) | 0.0.95 |
| AI | Google Gemini (@google/genai), multi-provider layer | 1.52 |
| Sanitization | DOMPurify (client) + server-side | 3.4 |
Browser (React 19 + Vite)
│
├── React Context (DataContext) ← global state + Convex→frontend mapping
├── Convex Client (WebSocket) ← realtime sync, reactive queries
│
└── Convex Backend (cloud)
├── Queries (public) ← list, getById, getPublic
├── Mutations (auth guards) ← requireAdmin / requireAuth
├── Actions (server-side AI) ← GEMINI_API_KEY never leaves the server
│ ├── chat (RAG + guardrails + classification)
│ ├── tts · geoQuery · generateImage · enhanceText
└── Crons ← cleanupRateLimits (hourly), cleanupOldLogs (daily)
requireAdmin(ctx) first line of every admin mutation, requireAuth(ctx) for user mutationsisAdmin(ctx) in queries that return [] for non-admins (no throw)vite.config.ts), injected into the built HTML and mirrored as a response header in
public/web.configsettings.update, never echoed back (has*ApiKey flags)GEMINI_API_KEY: Convex environment variable only — never in code, .env files, or the bundleEvery deployment is a private repository with its own brand, so the running version is not
obvious from the outside. Each build publishes it from package.json, in two places:
curl -s https://example.org/version.json
# {"platform":"community-platform","version":"2.9.0","builtAt":"..."}
curl -s https://example.org/ | grep generator
# <meta name="generator" content="Community Platform 2.9.0">
version.json is the one to script against when checking several instances at once; the
meta tag is there for anyone who just opens the page. In the portal footer, the
"Community Platform by BolaLabs" line carries the same version as its tooltip.
Every event has its own address and a share bar (WhatsApp, Facebook, copy link). Link previews can carry each event's own poster; that needs one web-server rule, covered in docs/SHARING.md.
Optional and per instance. Set VITE_SENTRY_DSN in the build environment and the portal
reports uncaught errors to that Sentry project; leave it empty and the SDK is never
downloaded — the public demo and any instance without monitoring send nothing anywhere.
VITE_SENTRY_ENVIRONMENT separates staging from productionconnect-src in the generated CSP automatically; every other
instance keeps the tighter policysendDefaultPii is off, the user object is dropped
and query strings are stripped, because an association portal carries member namesVITE_SENTRY_TRACES_SAMPLE_RATE defaults to 0; performance tracing is billed and a
community portal rarely needs itThe admin dashboard shows whether monitoring is on, alongside the version this browser is running and the one the server is serving.
Database (admin panel) → process.env (server) → VITE_* (build) → hardcoded defaults
AI model defaults have a single source of truth: convex/lib/aiDefaults.ts — the frontend and the server actions both import from it.
Automated alternative:
bash scripts/setup.sh(Linux/macOS) orpowershell -ExecutionPolicy Bypass -File scripts/setup.ps1(Windows) runs steps 1–3.
# 1. Clone and install
git clone https://github.com/brunobola-portfolio/community-platform.git
cd community-platform
npm install
# 2. Configure Convex (creates the project and sets VITE_CONVEX_URL)
cp .env.example .env.local
npx convex dev --once
# 3. Gemini API key (server-side only)
npx convex env set GEMINI_API_KEY "AIza..."
# 4. Authentication (generates SITE_URL, JWT_PRIVATE_KEY, JWKS)
npx @convex-dev/auth --web-server-url http://localhost:3000 \
--skip-git-check
# 5. Seed the database with demo data
npx convex run seed:seed
# 6. Run (2 terminals)
npx convex dev # Terminal 1 — backend
npm run dev # Terminal 2 — frontend (http://localhost:3000)
No commands needed. While the database has no admin, every visit redirects to the
/setup wizard: create email + password (10+ characters, with an uppercase letter, a
lowercase letter and a digit) and you land in /admin.
Reset (rare): delete the user's
rolefield in the Convex Dashboard, or use the CLI fallbacknpx convex run access:grantFromCli '{"email":"...","role":"admin"}'.
| Command | Description |
|---|---|
npm run dev | Frontend at http://localhost:3000 (detects a busy port and asks) |
npm run dev:kill | Same, but kills whatever holds the port without asking |
npx convex dev | Convex backend (separate terminal) — regenerates convex/_generated |
npm run build | Production build (tsc && vite build) |
npm run dist | Build + validation + deploy-ready zip |
npm run type-check | TypeScript check |
npm run lint | ESLint (zero warnings) |
npm run preview | Preview the local build |
There is no test suite; type-check + lint + build are the verification gates.
Chat, guardrail classification and text enhancement can run on any OpenAI-compatible provider, configured in Admin > AI & Chatbot (keys are write-only — stored server-side, never returned to the browser):
| Provider | Configuration | Notes |
|---|---|---|
gemini (default) | GEMINI_API_KEY | The only one with grounding (search/maps) |
openrouter | Key + model (e.g. openai/gpt-4o-mini) | Hundreds of models |
custom | Base URL + model (e.g. http://localhost:11434/v1 + llama3.1) | Ollama, LM Studio, vLLM |
TTS, image generation and geo queries always use Gemini, regardless of the chat provider.
The admin tab includes a "Testar ligação" button (round-trip test against the configured provider, reporting model and latency) and a live model catalog for OpenRouter and custom endpoints, so an operator validates the provider before saving — no CLI needed.
All configurable per-instance in Admin > AI & Chatbot; defaults live in convex/lib/aiDefaults.ts:
| Function | Default model | Fallback |
|---|---|---|
| Chat | gemini-3.5-flash | gemini-3.5-flash-lite |
| TTS | gemini-2.5-flash-preview-tts | — |
| Image | gemini-3.1-flash-image | Unsplash placeholder |
| Action | Max tokens | Refill/min |
|---|---|---|
| ai:chat / ai:geoQuery / ai:enhanceText | 10 | 10 |
| ai:tts | 5 | 5 |
| ai:generateImage | 3 | 3 |
| content:create / content:update | 20 / 30 | 10 / 15 |
| registration:create | 5 | 5 |
| contact:create / sponsorship:create (per email) | 3 | 1 |
| contact:create:global / sponsorship:create:global | 30 / 20 | 10 / 5 |
| ai:chat:anonymous / ai:tts:anonymous / ai:geoQuery:anonymous (global) | 120 / 30 / 60 | 60 / 15 / 30 |
Without an API key, AI features show unavailability messages; the portal works fully without AI.
The short version — full checklist in docs/WHITE-LABEL.md:
/setup, create the admin accountindex.html meta tags, public/ logos and OG image,
(the brand colour and fonts are set in Admin > Settings > Brand)Step-by-step guides: DEPLOY.md (IIS/Windows) and DEPLOY-VPS.md (Linux VPS + nginx).
# Backend
npx convex deploy
npx convex env set GEMINI_API_KEY "AIza..." --prod
npx @convex-dev/auth --prod --web-server-url https://your-domain.example \
--skip-git-check
# Frontend (validates .env.production, builds, zips)
cp .env.production.example .env.production
npm run dist
The output is a static folder — any web server with SPA fallback works. The reference client's instance runs on IIS with a <60s rollback path (swap the site's Physical Path back).
Full reference in docs/DESIGN-SYSTEM.md.
| Property | Value |
|---|---|
| Theme | Light + dark (darkMode: 'class', dark default), glassmorphism |
| Brand color | Per instance, from Admin > Settings > Brand (default indigo #4f46e5); brand-50…950 derived at runtime with AA contrast kept |
| Accent | Gold #fbbf24 · Neutrals: slate (dark bg #020617, surface #0f172a) |
| Fonts | Per instance from a curated Google Fonts list (default Geist + Playfair Display) |
| Radius | rounded-xl 12px · rounded-2xl 16px · rounded-3xl 24px |
See CONTRIBUTING.md. Highlights: function components only, strict
TypeScript (no any), Tailwind exclusively, requireAdmin(ctx) first line of admin
mutations, files < 300 lines.
Security reports: see SECURITY.md. Release history: CHANGELOG.md. Planned work: ROADMAP.md.
The platform is free and MIT-licensed. If it saves your organisation a developer, you can keep it moving:
Hosted and operated instances, consulting and custom work for associations, communities and institutions: bolalabs.pt.
Code is MIT — see LICENSE.
Brand assets are not covered by the MIT license. The repository ships no real organisation's name, logo or photographs; a client's instance keeps them in a private overlay (see docs/WHITE-LABEL.md). The code belongs to BolaLabs; ARCVA is a partner, not a copyright holder, and its name and logo belong to the association. Third-party material used by the platform:
Contributor guidelines: CONTRIBUTING.md · CODE_OF_CONDUCT.md.
Built by BolaLabs · In production since 2026 at arcva.pt, our reference client