A directory-first community portal for RaidGuild that centralizes profiles and curated modules into a single public home.
- Provide one cohesive portal URL with coherent navigation and SEO.
- Make profiles the core artifact (directory + public profiles).
- Let teams ship independently by registering modules (link or embed) with optional summaries.
- Support module-owned data via a simple portal API.
- Next.js App Router + TypeScript + Tailwind CSS.
- Module registry in
modules/registry.json(source of truth for modules). - Module surfaces driven by tags (
start-here,people-tools,profile-tools-public,me-tools). - Supabase auth + profiles + avatar storage + module data API.
- Shared dashboard shell with responsive left-rail/top-bar navigation.
/home and start-here modules/peoplepublic directory/people/[handle]public profile/meprofile dashboard (auth required): read-only profile view, profile wizard, and modal profile editor/modulesmodule directory/modules/[id]module detail (optional)/modules/announcementsannouncements module/modules/billingbilling module/modules/cohort-applicationcohort application module/modules/cohort-hubcohort hub module/modules/profile-generatorsprofile generators module/modules/skills-explorerskills explorer module/api/modulesregistry JSON/api/healthdeploy/smoke health check (returns ok + git sha)/api/module-datamodule data API/api/announcementsannouncements API/api/cohortscohorts API/api/cohort-applicationscohort applications API/api/me/entitlementsentitlement status API/api/me/rolesroles API/api/profileprofile write API (portal-owned modules)/api/stripe/checkoutStripe Checkout session/api/stripe/portalStripe Customer Portal session/api/stripe/webhookStripe webhook for entitlements
npm install
npm run devnpm run devstart the app locallynpm run buildproduction buildnpm run startrun the production buildnpm run lintlintnpm run sync:modulessync registry intopublic.modules(Supabase)npm run module:keycreate a module key + hash (Supabase)npm run snapshot:dao-members -- --dao <0xdao> --graph <graphql-endpoint>write a DAO member snapshot JSONnpm run sync:dao-members -- --dao <0xdao> --chain <chain-id> --graph <graphql-endpoint>syncpublic.dao_memberships+dao-memberentitlements
Create a point-in-time membership snapshot before claim rollout:
npm run snapshot:dao-members -- \
--dao 0xYourDaoAddress \
--graph https://your-subgraph.example.com/subgraphs/name/daoEnv/flags:
DAO_ID/--dao: DAO contract address (required).DAO_GRAPH_URL/--graph: GraphQL endpoint (required).DAO_CHAIN_ID/--chain: chain id (optional metadata).DAO_PAGE_SIZE/--pageSize: pagination batch size (default500).DAO_GRAPH_API_KEY/--graphApiKey: bearer token for protected graph endpoints.DAO_INCLUDE_ZERO_POWER/--includeZeroPower: include members withshares + loot = 0(default false).DAO_SNAPSHOT_OUTPUT/--output: output path (defaultsnapshots/dao-members-<dao>-<timestamp>.json).DAO_SEED_PROFILES/--seedProfiles: iftrue, inserts missing claimable rows intopublic.profiles(requiresSUPABASE_URL+SUPABASE_SERVICE_ROLE_KEY).DAO_UPSERT_MEMBERSHIPS/--upsertMemberships: iftrue, upsertspublic.dao_memberships(requires--chain+ Supabase service-role envs).DAO_SYNC_ENTITLEMENTS/--syncEntitlements: iftrue, upsertsdao-memberentitlements for claimed rows.DAO_DEACTIVATE_MISSING/--deactivateMissing: iftrue, marks previously-active memberships inactive when missing from latest snapshot.
The portal expects Supabase for profile data, auth, and module data APIs.
Env vars:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYSUPABASE_URLSUPABASE_SERVICE_ROLE_KEYVENICE_API_KEY(profile generators)VENICE_MODEL(profile generators, text)VENICE_IMAGE_MODEL(profile generators, image)VENICE_API_BASE_URL(optional; defaults tohttps://api.venice.ai/api/v1)GUILD_GRIMOIRE_TRANSCRIPTION_WEBHOOK_URL(n8n/worker webhook for async audio transcription)GUILD_GRIMOIRE_TRANSCRIPTION_WEBHOOK_KEY(optional bearer token sent to webhook)GUILD_GRIMOIRE_TRANSCRIPTION_CALLBACK_KEY(required secret used by n8n callback endpoint)STRIPE_SECRET_KEY(billing)STRIPE_WEBHOOK_SECRET(billing)STRIPE_PRICE_ID(billing)STRIPE_PORTAL_CONFIG_ID(billing, optional)
Behavior notes:
/peopleand/people/[handle]require Supabase data; configure envs and run migrations./merequires Supabase auth; missing env vars will throw at runtime.
- Module registry:
modules/registry.json - Module authoring guide:
docs/module-authoring.md - Module registry notes:
modules/README.md - Card sizing in surfaces is controlled by
presentation.layout:compact: small stats/data tiledefault: standard stackable module cardwide: full-width module card
- Summary cards can also render dynamic widgets via
summary.layout: "widget"andsummary.widget(data-rendered or embedded iframe).
- Migrations and seeds live in
supabase/ - Type generation and local auth notes:
supabase/README.md - Entitlements are stored in
public.entitlementsand used for module access gating.
- Product kickoff:
docs/kickoff-spec.md - Architecture overview:
docs/architecture.md - Brand and UI tokens:
RG_BRAND_AGENTS.md - Cohort hub (v1):
docs/cohort-hub.md