7 min read

StokumNET/Architecture: Building a Secure Multi-Tenant Platform

StokumNET/Architecture: Building a Secure Multi-Tenant Platform

"Stokum" means "my inventory" in Turkish. "Net" means "clear" or "exact." Together: My inventory is exact. That precision extends to how I built the infrastructure.

When I decided to build StokumNET, I wanted to create something that would teach me as much as it would serve users. The result is a multi-tenant platform running on private cloud infrastructure with zero-trust principles built in from the start.

Here's how it all fits together.

Design Goals

Before writing any code, I established clear requirements:

Multi-tenancy from day one — Multiple organizations using the same platform, each seeing only their own data

Zero-trust architecture — No implicit trust based on network location; every request authenticated and authorized

Defense in depth — Security controls at every layer, not just the perimeter

Operational simplicity — Containerized services that can be deployed, scaled, and updated independently

High-Level Architecture

Network Architecture

Edge Layer

All traffic enters through an edge server with a static public IP. This server handles several responsibilities:

Perimeter Security: A firewall allows only necessary ports. Intrusion prevention monitors traffic patterns and automatically blocks IPs showing malicious behavior—brute force attempts, scanning, or other suspicious activity.

Traffic Routing: A reverse proxy examines incoming requests and routes them based on domain. Application traffic forwards through an encrypted site-to-site tunnel to the private cloud. Other services are handled directly at the edge.

Supporting Services: The edge server also runs email infrastructure (SMTP, IMAP, spam filtering, DKIM signing) and authoritative DNS for my domains.

Encrypted Tunnel

Traffic destined for StokumNET travels through an encrypted site-to-site VPN tunnel. This provides several benefits:

No direct exposure — The private cloud has no public IP; the only way in is through the tunnel

Encryption in transit — All traffic between edge and private cloud is encrypted

Stable connectivity — The tunnel maintains a persistent connection regardless of dynamic IP changes

Private Cloud

The application infrastructure runs on private cloud hardware with redundant network connectivity. Primary connection is high-speed fiber with automatic failover to cellular backup if the primary link goes down.

Application Stack

All services run in containers, providing isolation, reproducibility, and independent scaling.

Ingress Controller

The ingress controller sits at the entry point of the container network. It handles TLS termination (with automatic certificate management), routes requests to appropriate backend services, and provides traffic observability.

Frontend: React and Next.js

The web interface uses React with Next.js for server-side rendering on initial loads and client-side navigation afterward. This provides fast first paint and smooth interactions.

The frontend is stateless—it holds no data, making API calls to the backend for everything. This clean separation allows independent updates and simpler reasoning about the system.

Backend: Go with Gin

I chose Go for specific reasons: performance, security, and operational simplicity.

Go compiles to a single binary with no runtime dependencies. It handles concurrent requests efficiently. The type system catches bugs at compile time. The Gin framework provides a fast, lightweight foundation for REST APIs.

The backend handles all business logic: authentication, inventory management, purchase and sale records, reporting queries. It validates every input, enforces authorization rules, and never trusts the frontend.

Database: PostgreSQL

StokumNET's data lives in PostgreSQL. I designed the schema for multi-tenancy from the start—each organization's data is logically separated, with row-level security ensuring queries only access data belonging to the authenticated tenant.

PostgreSQL handles the reporting features well: trend analysis, comparative statistics, aggregations across time periods.

Secrets Management

Secrets don't belong in environment variables or configuration files. A dedicated secrets manager serves as the single source of truth for sensitive configuration: database credentials, API keys, JWT secrets, encryption keys.

Applications authenticate to the secrets manager and retrieve secrets at runtime. When a secret needs rotation, I update it centrally, and applications pick up the change without redeployment.

Source Code Management

All source code lives in a self-hosted Gitea instance running on a Debian VPS I manage. This provides complete control over the development infrastructure with no third-party dependencies for code storage. Gitea handles repositories for all StokumNET components—backend, frontend, mobile apps, infrastructure configuration, and this blog.

Security Architecture

Zero Trust Implementation

I built StokumNET with zero-trust assumptions:

Authentication: Users authenticate via JWT tokens. The backend validates tokens on every request—no session state to hijack. Tokens are short-lived; refresh tokens allow users to stay logged in without long-lived credentials.

Authorization: Authentication tells us who is making a request. Authorization determines what they can do. Every API endpoint checks both. A valid token from User A cannot access User B's inventory.

Transport Security: All traffic is encrypted. The site-to-site tunnel encrypts traffic between edge and private cloud. The ingress controller terminates TLS for external traffic. Container-to-container communication uses isolated networks.

Input Validation: The backend treats all input as potentially malicious. Parameters are validated against expected types and ranges. SQL queries use parameterized statements. User content is sanitized before storage and escaped before display.

Network Segmentation

Container networking provides isolation between services. The frontend can reach the backend API but cannot access the database directly. The backend can query PostgreSQL and the secrets manager but cannot reach the blog platform. Each service has only the network access it needs.

Defense in Depth

Security controls exist at every layer:

LayerControls
PerimeterFirewall, intrusion prevention, encrypted tunnel
TransportTLS everywhere, VPN encryption, isolated networks
ApplicationJWT auth, authorization checks, input validation
DataRow-level security, tenant isolation, secrets management

Multi-Tenancy Design

StokumNET supports multiple organizations simultaneously, each seeing only their own data.

Tenant Isolation: Every database record includes a tenant identifier. Every query includes a tenant filter. The application layer enforces this, and PostgreSQL's row-level security provides defense in depth.

Tenant Context: When a user authenticates, their JWT includes their tenant ID. The backend extracts this on every request and scopes all data access accordingly. There's no way for application code to "forget" to filter by tenant—it's built into the data access layer.

What I Learned

Building this infrastructure reinforced lessons that documentation alone couldn't teach:

Complexity compounds. Every component creates new interactions. The ingress controller needs certificates, which require DNS validation, which depends on the authoritative DNS server, which needs its own security configuration. One thread reveals five more.

Operational concerns matter. Designing a system is one thing. Operating it is another. Backups, log rotation, certificate renewal, security updates—not glamorous, but essential.

Security trade-offs are real. Every security control has a cost: complexity, performance, user friction. Making those trade-offs yourself builds different intuition than advising someone else.

Current State

The core platform works. Users can manage inventory, record transactions, track suppliers, and generate reports. Mobile apps for iOS and Android are in development, sharing the same backend API.

Building StokumNET has made me a better security engineer—not because I learned new tools, but because I experienced the decisions that developers face every day.

What's Next

Building the foundation was just the beginning. Here's the security roadmap I'm working through:

Observability & Detection

Tamper-proof centralized logging — Collecting logs from all services into an immutable, centralized system. I'm evaluating Fluent Bit for collection, OpenSearch for storage, and Wazuh for security event correlation. The goal is behavioral anomaly detection that can identify potential security incidents before they become breaches.

DevSecOps Pipeline

CI/CD with integrated security gates — Building a pipeline with Gitea Actions that includes SAST scanning, dependency checking, container image scanning, and automated testing at every stage. No code reaches production without passing security checks.

Code signing — Implementing GPG-signed commits and Cosign for container images. Every artifact will have cryptographic proof of origin.

Supply chain security — Setting up dependency proxying with Nexus or Verdaccio, generating SBOMs with Syft, and implementing policy enforcement. Trust but verify—every dependency.

Shift-Left Security

IDE-integrated scanning — Semgrep and SonarLint in the development environment, catching issues before they're committed.

Infrastructure-as-Code scanning — Checkov and Trivy for detecting misconfigurations in Terraform and Kubernetes manifests.

DAST in staging — OWASP ZAP automated scans against the staging environment before any production deployment.

Secrets detection — Gitleaks in pre-commit hooks and CI pipeline to prevent credential leaks.

Data Protection

Optional end-to-end encryption for tenants — Implementing a DEK+KEK (Data Encryption Key + Key Encryption Key) architecture. Tenants who opt in will have their data encrypted with keys only they control. The trade-off is explicit: if you lose your key, your data is unrecoverable. This is a feature for tenants who need it, not a default—because the risk of data loss from forgotten passwords is real.

Hardening

Security headers — I've already implemented SameSite, HttpOnly, and Secure cookie attributes. Next: Content-Security-Policy, Subresource Integrity, Referrer-Policy, and Permissions-Policy. Defense in depth at the browser level.

AI Integration

AI-assisted security — Exploring how to integrate LLMs into the development workflow: automated threat modeling from architecture documents, AI-assisted code review for security issues, and intelligent triage of vulnerability scan results. Also investigating anomaly detection for transaction patterns to identify potential fraud or errors.

Stress Testing

Load and resilience testing — Using k6 for load testing the API and frontend. Planning chaos engineering experiments to verify the system degrades gracefully under failure conditions.

I'll write detailed posts about each of these as I implement them. The goal isn't just to add security features—it's to document the real trade-offs and decisions that go into building enterprise-grade security into a production application.


http://stokum.net