-- name: ListProjectsForOrganization :many SELECT p.*, pm.role AS membership_role FROM core.projects p LEFT JOIN core.project_members pm ON pm.project_id = p.id AND pm.user_id = $2 WHERE p.organization_id = $1 AND ( btrim($3) = '' OR p.slug ILIKE '%' || btrim($3) || '%' OR p.name ILIKE '%' || btrim($3) || '%' OR COALESCE(p.description, '') ILIKE '%' || btrim($3) || '%' ) ORDER BY p.created_at ASC; -- name: CreateProject :one INSERT INTO core.projects ( organization_id, slug, name, description ) VALUES ($1, $2, $3, $4) RETURNING *; -- name: UpdateProjectByID :one UPDATE core.projects SET slug = $2, name = $3, description = $4 WHERE id = $1 RETURNING *; -- name: AddProjectMember :one INSERT INTO core.project_members (project_id, user_id, role) VALUES ($1, $2, $3) ON CONFLICT (project_id, user_id) DO UPDATE SET role = EXCLUDED.role RETURNING *; -- name: GetProjectMembership :one SELECT pm.*, p.organization_id FROM core.project_members pm JOIN core.projects p ON p.id = pm.project_id WHERE pm.project_id = $1 AND pm.user_id = $2; -- name: ListProjectMembers :many SELECT pm.project_id, pm.user_id, pm.role, pm.created_at, u.email, u.name, u.email_verified FROM core.project_members pm JOIN core.users u ON u.id = pm.user_id WHERE pm.project_id = $1 ORDER BY pm.created_at ASC; -- name: UpdateProjectMemberRole :one UPDATE core.project_members SET role = $3 WHERE project_id = $1 AND user_id = $2 RETURNING *; -- name: RemoveProjectMember :one DELETE FROM core.project_members WHERE project_id = $1 AND user_id = $2 RETURNING *; -- name: CountProjectAdmins :one SELECT COUNT(*)::BIGINT FROM core.project_members WHERE project_id = $1 AND role = 'admin'; -- name: GetProjectByID :one SELECT * FROM core.projects WHERE id = $1; -- name: GetProjectOverview :one SELECT p.id AS project_id, p.organization_id, p.slug AS project_slug, p.name AS project_name, ( SELECT COUNT(*)::BIGINT FROM core.project_members pm WHERE pm.project_id = p.id ) AS member_count, ( SELECT COUNT(*)::BIGINT FROM core.api_keys ak WHERE ak.project_id = p.id AND ak.revoked_at IS NULL ) AS active_api_key_count, ( SELECT COUNT(*)::BIGINT FROM core.buckets b WHERE b.project_id = p.id ) AS bucket_count, ( SELECT COUNT(*)::BIGINT FROM core.bucket_objects bo JOIN core.buckets b ON b.id = bo.bucket_id WHERE b.project_id = p.id ) AS object_count, ( SELECT COALESCE(SUM(bo.size_bytes), 0)::BIGINT FROM core.bucket_objects bo JOIN core.buckets b ON b.id = bo.bucket_id WHERE b.project_id = p.id ) AS object_bytes_total, ( SELECT COUNT(*)::BIGINT FROM core.project_invitations pi WHERE pi.organization_id = p.organization_id AND (pi.project_id IS NULL OR pi.project_id = p.id) AND pi.accepted_at IS NULL AND pi.expires_at > NOW() ) AS pending_invitation_count, ( SELECT COUNT(*)::BIGINT FROM core.audit_logs al WHERE al.project_id = p.id AND al.created_at >= NOW() - INTERVAL '24 hours' ) AS audit_events_24h, ( SELECT MAX(al.created_at)::TIMESTAMPTZ FROM core.audit_logs al WHERE al.project_id = p.id ) AS last_audit_at FROM core.projects p WHERE p.id = $1; -- name: DeleteProjectByID :one DELETE FROM core.projects WHERE id = $1 RETURNING *;