Angelo LorenoSoftware Developer | Technical Support

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
SK Nexus community platform homepage and transparency dashboard

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. 1

    Visitor

  2. 2

    Anonymous feedback form

  3. 3

    /api/feedback

  4. 4

    Rate-limit check

  5. 5

    Supabase insert

Stored

  • category
  • optional area
  • message

Not stored

  • name
  • email
  • 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. 1

    Admin form

  2. 2

    Server Action

  3. 3

    requireAdminAuth()

  4. 4

    Service-role Supabase client

  5. 5

    PostgreSQL / Storage

  6. 6

    revalidatePath()

  7. 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

  1. 01Next.js public routes
  2. 02Supabase anon client
  3. 03PostgreSQL + RLS
/api/feedback

Admin officer

  1. 01/sk-admin
  2. 02HMAC session
  3. 03Server Actions
  4. 04Supabase service-role client
  5. 05PostgreSQL + Storage
/api/admin/auth

Mutation 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.