feat(certifications): schema + RLS + permissions (data layer)
Migration 030 adds certifications (per-space cert types, optional validity_months, is_active archive) and member_certifications (per-member grants; expires_at snapshotted at grant time; soft revoke; partial unique on one active grant per member+cert). RLS is additive and default-deny: cert types readable by any space member, write-gated by certifications.manage; grants readable by managers/granters (all) or the member (own), written by certifications.grant, with no DELETE policy so the history is immutable. No anonymous path. Two new permission codes in the catalog (group Certifications): certifications.manage and certifications.grant (the Instructor capability, assignable to any role via the existing additive model). Seeded to board and backfilled. Mirrored idempotently in schema.sql; types and schema docs updated.
This commit is contained in:
@@ -106,6 +106,18 @@ export type Database = {
|
||||
Update: { id?: string; form_id?: string; space_id?: string; member_id?: string | null; submitter_email?: string | null; answers?: Json; form_snapshot?: Json; legal_text_snapshot?: string | null; form_version?: number; ip?: string | null; user_agent?: string | null; created_at?: string }
|
||||
Relationships: []
|
||||
}
|
||||
certifications: {
|
||||
Row: { id: string; space_id: string; name: string; description: string | null; validity_months: number | null; is_active: boolean; created_by: string | null; created_at: string; updated_at: string }
|
||||
Insert: { id?: string; space_id: string; name: string; description?: string | null; validity_months?: number | null; is_active?: boolean; created_by?: string | null; created_at?: string; updated_at?: string }
|
||||
Update: { id?: string; space_id?: string; name?: string; description?: string | null; validity_months?: number | null; is_active?: boolean; created_by?: string | null; created_at?: string; updated_at?: string }
|
||||
Relationships: []
|
||||
}
|
||||
member_certifications: {
|
||||
Row: { id: string; space_id: string; member_id: string; certification_id: string; granted_by: string | null; granted_at: string; expires_at: string | null; revoked_at: string | null; revoked_by: string | null; revoked_reason: string | null; note: string | null; created_at: string }
|
||||
Insert: { id?: string; space_id: string; member_id: string; certification_id: string; granted_by?: string | null; granted_at?: string; expires_at?: string | null; revoked_at?: string | null; revoked_by?: string | null; revoked_reason?: string | null; note?: string | null; created_at?: string }
|
||||
Update: { id?: string; space_id?: string; member_id?: string; certification_id?: string; granted_by?: string | null; granted_at?: string; expires_at?: string | null; revoked_at?: string | null; revoked_by?: string | null; revoked_reason?: string | null; note?: string | null; created_at?: string }
|
||||
Relationships: []
|
||||
}
|
||||
activity_log: {
|
||||
Row: {
|
||||
action: string
|
||||
|
||||
Reference in New Issue
Block a user