04 / Community Platform
SK Nexus
A public information and transparency platform for a barangay youth council.
Built with Next.js and Supabase around two clearly separated audiences: public visitors who need open access to community information, and officers who manage that content through a private admin interface.
- Role
- Personal Project
- Type
- Community Platform
- Maturity
- Functional MVP · Ongoing Refinement
- Stack
- Next.js 14 · Supabase · PostgreSQL

Product Model
Two audiences, one platform.
Public
No login required. Residents can browse community information and send feedback without creating an account.
- homepage content
- events
- announcements
- budget/transparency information
- project tracking
- expenses
- reports
- calendar
- officer profiles
- anonymous feedback
Admin
A hidden /sk-admin area lets officers manage content through a deliberately scoped shared-admin flow.
- shared-passphrase authentication
- create/update/publish content
- file management
- feedback review
- transparency records
Public Experience
More than an announcement board.
The public side gives residents account-free access to civic information: events, announcements, transparency records, calendar updates, officer profiles, and an anonymous feedback channel.
homepage content
events
announcements
budget/transparency information
project tracking
expenses
reports
calendar
officer profiles
anonymous feedback
Privacy-First Feedback
Anonymous feedback avoids collecting identity data.
- 1
Visitor
- 2
Anonymous feedback form
- 3
/api/feedback
- 4
Rate-limit check
- 5
Supabase insert
Stored
- category
- optional area
- message
Not stored
- name
- persisted IP
- device identity
The public API uses an in-memory IP-based rate limiter for abuse control, but the IP is not stored in the feedback table.
Publication Boundary
Public data is filtered at the database layer.
Public reads use a Supabase anon-key client. Row Level Security determines which rows are visible publicly, so drafts are not merely hidden by the interface.
The database policy is part of the enforcement boundary for publication state.
- published events only
- published announcements
- publish_at-aware scheduled announcements
- unpublished drafts remain private
Admin Write Path
Mutations pass through server-side checks.
- 1
Admin form
- 2
Server Action
- 3
requireAdminAuth()
- 4
Service-role Supabase client
- 5
PostgreSQL / Storage
- 6
revalidatePath()
- 7
Updated public content
Admin Authentication
A custom HMAC session fits the shared-admin model.
Officers open /sk-admin and enter a shared passphrase. The server checks lockout state, verifies a bcrypt-hashed passphrase, and creates an HMAC-signed session token.
The final admin auth implementation diverged from the original specification, using a custom HMAC-signed session model instead of Supabase Auth.
Session properties
- httpOnly
- secure
- sameSite=strict
- 8-hour expiry
HMAC Session Note
The token is compact and tamper-evident.
lib/admin-session.ts signs a compact payload with HMAC-SHA256 using server-only secret material. The payload includes version, issued-at, expiry, and nonce fields.
payload
version
payload
issued-at
payload
expiry
payload
nonce
Login Hardening
The shared credential has a persistent lockout boundary.
Attempts
5 failures
Window
15 minutes
Lockout
15 minutes
Failed login state is persisted in the database, the client identifier is HMAC-hashed, and stale rows are cleaned up. That matters because one shared admin credential needs brute-force protection.
Content + Files
Rich content and uploads use narrow validation boundaries.
Announcements use Tiptap for stored rich text. Before rendering through dangerouslySetInnerHTML, the content is sanitized with DOMPurify as a stored-XSS mitigation boundary.
Admin uploads cover event photos, announcement PDFs, receipts, and report PDFs through Supabase Storage. The code uses MIME-type allowlists for image/PDF validation.
Architecture
Two access paths, separated by trust.
Public visitor
- 01Next.js public routes
- 02Supabase anon client
- 03PostgreSQL + RLS
/api/feedbackAdmin officer
- 01/sk-admin
- 02HMAC session
- 03Server Actions
- 04Supabase service-role client
- 05PostgreSQL + Storage
/api/admin/authMutation Layer
Server Actions keep admin forms close to their writes.
CRUD-heavy admin mutations are implemented through React Server Actions rather than a conventional REST API. For this project, that keeps form handling near mutation logic, reduces API boilerplate, allows explicit server-side auth rechecks, and works naturally with revalidatePath().
Transparency Domain
The platform is not only content publishing.
budget categories
project tracking
itemized expenses
annual reports
SK Nexus gives residents a public view into council activity and financial/transparency records, without inventing a full accounting workflow.
Where It Stands
A functional civic MVP undergoing refinement.
Implemented
- public content browsing
- admin CRUD
- anonymous feedback
- RLS-backed publishing
- file uploads
- scheduled announcements
- rich text
- custom admin session
- login lockout
Current limitations
- no automated tests
- no CI/CD
- public feedback limiter is in-memory
- repository has only one git commit
- current working tree includes substantial uncommitted visual/auth refinement
- Supabase Auth was specified originally but is not used in the actual code
Stack
The technical surface area.
- Next.js 14
- TypeScript
- React
- Supabase
- PostgreSQL
- Supabase Storage
- Tailwind CSS
- Tiptap
- DOMPurify
- bcrypt
- Web Crypto HMAC-SHA256
- Row Level Security
Reflection
The work became about trust boundaries.
SK Nexus became less about building a generic content system and more about defining boundaries: what the public can read, what admins can mutate, what anonymous users should never need to provide, and what should be enforced by the database rather than the interface.