GPI Platform
Cybersecurity assessment at national scale.
The Problem
Government entities need to assess their cybersecurity posture against national standards. The assessment process involves surveys, scoring across multiple pillars, targeting specific entities, assigning reviewers, and aggregating results at both organization and sector levels. This was being done manually or with fragmented tools — no unified platform existed.
The Approach
I joined NITS as the backend engineer responsible for designing and implementing the entire backend for the Government Performance Index platform. This is a production system serving 5+ government entities.
Key architectural decisions
Five-tier RBAC — not just admin/user. The system has 5 distinct permission levels mapped to real organizational roles (super admin, sector admin, organization admin, reviewer, viewer), each with different data access scopes.
Organization-scoped JWT authentication — every token carries the user's organization context. API endpoints automatically scope data to the user's org without requiring explicit org ID in every request.
Queryset-level permission enforcement — instead of checking permissions in views (error-prone), I enforce data isolation at the queryset level. Every database query is automatically filtered by the user's organization. You literally cannot access another org's data even if you construct the query manually.
Pillar-based scoring aggregation — cybersecurity assessment results are aggregated across multiple pillars (e.g., governance, protection, detection) at both organization and sector levels, with weighted scoring.
Technical Deep-Dive
API architecture
- ▸70+ RESTful endpoints organized by domain: surveys, targets, assignments, reviews, analytics, users, organizations
- ▸Structured validation on every endpoint with serializer-level and model-level checks
- ▸Consistent error handling with standardized error response format
- ▸Pagination, filtering, and ordering on all list endpoints
Multi-tenant data isolation
- ▸Shared database, queryset-level isolation — all organizations live in the same PostgreSQL database, but every queryset is filtered by the requesting user's organization
- ▸Row-level permission enforcement prevents cross-entity data leakage
- ▸Verified via manual security testing: attempted cross-org access returns empty results, not 403 (no information leakage about existence)
Performance optimization
- ▸Identified and fixed N+1 query patterns using select_related and prefetch_related
- ▸Added database indexes on frequently filtered columns (organization_id, status, pillar)
- ▸Pillar-based scoring uses aggregation queries instead of Python-level computation
Key Metrics
Challenges & Solutions
Challenge 1:N+1 queries in AI-generated code
Early codebase had serializers that triggered separate database queries for every related object. Verified via EXPLAIN ANALYZE that some list endpoints were generating 100+ queries. Fix: Systematic audit of all querysets, added select_related/prefetch_related patterns, built a code review checklist for catching N+1s.
Challenge 2:Permission model complexity
Five tiers of access control with different scopes per tier. Initial implementation checked permissions in views, leading to inconsistent enforcement. Fix: Moved all permission logic to the queryset level — every manager method automatically filters by the user's context. Views never need to think about permissions.
Challenge 3:Scoring aggregation performance
Computing pillar scores across all entities and sectors in Python was slow. Fix: Moved aggregation logic to PostgreSQL using Django ORM aggregation functions (Avg, Sum, Count with annotate), reducing computation time significantly.
Lessons Learned
Queryset-level permissions are the right pattern for multi-tenant Django apps. View-level permission checks are fragile — one missed check = data leak. Queryset-level enforcement is structural, not behavioral.
AI-generated code needs auditing. The codebase I inherited had patterns that looked correct but performed terribly. The lesson: always run EXPLAIN ANALYZE on any query that touches more than one table.
Government systems have zero tolerance for data leakage. Cross-entity data exposure isn't a bug — it's a security incident. This shaped my approach to data isolation in all subsequent projects.