questions — Normalized questions with classification, status, voting
answers — Answers with author_type, rich content, key_verses, topics, strongs_refs
votes — User votes (+1/-1) on questions/answers (unique per user)
topic_anchor_questions — Links questions as anchor Q&A for topics
Answer Author Types
Type
Created by
Published by default?
bullet
Admin
Yes
admin
Admin
Yes
system
Import/seed
Yes
ai
Edge function
No (needs admin review)
community
Authenticated user
No (needs admin approval)
guest
Admin (Vieraskynä)
Yes — attributed to a guest_authors row via guest_author_id
Author display: account authors (author_id) resolve their public name via the
get_author_public_info RPC (profiles RLS is admin-or-self); guest authors (guest_author_id)
show display_name/@username from guest_authors. See Vieraskynä.
Question Status Flow
draft → needs_review → approved → published
└→ rejected
RLS Summary
Anon/Auth: Read published questions + published non-hidden answers
Auth: Read own questions + own community answers, insert votes, submit community answers
Admin: Full CRUD on all questions, answers, votes
Common Patterns
Add new answer type
Add CHECK constraint value in migration
Update AnswerData interface in QuestionsSearchSection.tsx
Update Answer type in useQuestions.ts
Add rendering logic in renderAnswerCard
Update admin management in AdminQuestionsPage.tsx
Add new question classification
Update classifier patterns in questionClassifier.ts
Model/vendor configured via ai_feature_bindings table
Add feature to community answers
Edge function: submit-community-answer/index.ts
Hook: useSubmitCommunityAnswer in useQuestions.ts
Form: CommunityAnswerForm.tsx (search) or inline in QuestionPage.tsx
Admin tab: "Yhteisövastaukset" in AdminQuestionsPage.tsx
Vieraskynä (guest authors)
Account-less named attribution for answers AND info-palat. An admin can credit a
piece to a bible_schema.guest_authors row (a named contributor with no login) via
guest_author_id + author_type='guest', instead of a real account.
Concern
File
List/CRUD hook
hooks/useGuestAuthors.ts (RPC get_guest_authors for active list; bibleSchemaTable("guest_authors") for admin CRUD)
Admin picker
components/admin/GuestAuthorSelect.tsx (used in NewAdminAnswerForm, InfoBlockEditor)
Gotcha: account authors' public names come from get_author_public_info (SECURITY
DEFINER) because public.profiles SELECT is admin-or-self — a direct profiles read returns
nothing to guests, so named authors would silently not render. The old account-only
AuthorSelect.tsx + lib/designatedAuthors.ts were removed — don't reference them.
Anonymous-submission bot protection
Anon submit paths (upsert-question, submit-community-answer, submit-feedback) gate
on supabase/functions/_shared/verify-human.ts: honeypot (empty hidden field + ≥1500 ms
on screen), Cloudflare Turnstile (verified via TURNSTILE_SECRET_KEY; skipped when the
secret is unset, so dev/staging just work), and a rate-limit (check_and_record_throttle
→ public.submission_throttle, service_role-only). Client widget/fields:
components/security/HumanCheckFields.tsx + useHumanCheck.ts (wired into
QuestionConsentBlock, AskQuestionButton, AppFeedbackForm). When adding a new anon
submit path, add the fields client-side and call verifyHuman(...) server-side.
AI answers hidden from users
AI answer generation still exists (ai answer type, generate-ai-answer) but its UI is
hidden from non-admin users — lib/aiVisibility.ts#shouldHideAIForUser(plan) returns true
for everyone except admin (AI quotas are zeroed for all user plans). Gate any AI
button/panel/token display behind it. Exception: plan-from-summary (kooste→lukusuunnitelma)
is NOT gated — it stays visible for Pro/Premium.
Info-palaset (info blocks)
Reusable content blocks (bible_schema.info_blocks) attached to questions, topics, and
spiritual paths. One of two answer mechanisms for a question (alongside community
answers). Admin-curated — no AI generation and no classifier (unlike questions).
[!important] Key invariant
An info-pala is rendered by TWO components: InfoTextCard (page-tila) and InfoView
(cinema-tila). Edit whichever the request targets and keep both in sync.
QuestionCinemaApp renders published community answers (via answerToInfoBlock()) +
attached info blocks through the same InfoFlow/InfoView — answers first, then info blocks.
Common patterns
Create/edit an info-pala → InfoBlockEditor (fill both FI + EN; is_core gates attachability).
Attach to question/topic/path → attach dialog → junction row with sort_order.