documentation

Architecture

#Overview

SCS Spider is the front door of the Silk City Solution school-management platform. Dozens of schools use the platform, each with its own domain (epanel.rmscraj.edu.bd, epanel.harimohanschool.edu.bd, …) and its own database on a shared SQL Server 2012 instance. Instead of deploying the web application once per school, every school domain points at Spider. Spider resolves domain → database source and redirects the user to the single SCS Web App, which opens the correct database.

user ──▶ epanel.rmscraj.edu.bd (DNS → nginx → SCS Spider) │ ▼ ┌─────────────────────┐ resolve host against tenant registry │ SCS SPIDER │ epanel.rmscraj.edu.bd → rmsc_db_new └─────────────────────┘ │ HTTP 302 ▼ https://app.silkcitysolution.com/?token=scs1.<encrypted>AES-256-GCM: server, database,user, password, domain · 5 min TTL ▼ ┌─────────────────────┐ decrypts token, opens rmsc_db_new on │ SCS WEB APP │ the private SCS SQL Server └─────────────────────┘

The token in the redirect is encrypted — domain, database name and credentials are not guessable or readable from the URL. The SCS Web App either decrypts it locally with the shared PayloadKey or posts it to /api/v1/token/decrypt. Full crypto details and a copy-paste decryption sample are in /llms.txt.

#Request flow

The resolver runs first in the middleware pipeline, before static files and routing. Any request whose Host header matches a registered, active tenant is redirected immediately — the landing page, admin console and API are only reachable on non-tenant hosts (the app's own domain, localhost, server IP).

Tenant lookups are served from an in-memory cache with a 30-second TTL, so a redirect costs no database round-trip in the hot path. Edits in the admin console invalidate the cache instantly. Inactive tenants receive an HTTP 403 notice instead of a redirect. Every decision is written to the request log.

#Data model

Spider keeps its own database (scs_spider_db) on the same SQL Server:

TablePurposeKey fields
Tenants Domain → database mapping per school Domain (unique), DatabaseName, TargetUrl, IsActive
ApiClients External apps allowed to call the API ApiKey (unique), IsActive, LastUsedAtUtc
RequestLogs Every redirect / resolution event Domain, Action, TenantId, ClientIp, OccurredAtUtc
AdminUsers Console logins (PBKDF2-SHA256 hashes) Username (unique), PasswordHash

#API reference

Interactive documentation with live "try it out" lives at /swagger (OpenAPI 3 JSON at /swagger/v1/swagger.json). Integrating with an AI agent or LLM tool? Point it at /llms.txt — a single self-contained markdown document with every endpoint, schema, error format and copy-paste examples. Summary:

EndpointAuthPurpose
GET /api/v1/resolve?domain=… API key Resolve a domain to its full database source (server, db, credentials, token).
POST /api/v1/token/decrypt API key Decrypt and validate a redirect token.
GET /api/v1/tenants API key List all tenants.
POST /api/v1/tenants API key Register a tenant.
PUT /api/v1/tenants/{id} API key Update a tenant.
DEL /api/v1/tenants/{id} API key Remove a tenant.
GET /api/v1/health none Service + SQL Server health.
GET /api/v1/info none Machine-readable architecture description.
GET /go/{domain} none Demo redirect — simulate a tenant domain without DNS.

#Authentication

Protected endpoints require an API key issued from the admin console. Send it in the X-Api-Key header (preferred) or as an api_key query parameter. Missing keys get 401; revoked or unknown keys get 403. The admin console itself uses cookie sign-in, separate from API keys.

#Examples

# resolve a school domain curl -H "X-Api-Key: scs_your_key_here" \ "https://spider.example/api/v1/resolve?domain=epanel.rmscraj.edu.bd"
# register a new school curl -X POST -H "X-Api-Key: scs_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "schoolName": "New Govt. High School", "domain": "epanel.newschool.edu.bd", "databaseName": "newschool_db", "isActive": true }' \ "https://spider.example/api/v1/tenants"
# health check (no key needed) curl "https://spider.example/api/v1/health"

#Deployment — nginx with dynamic domains

Publish with dotnet publish -c Release -o published, upload to the server, and run Kestrel on 127.0.0.1:5217 behind nginx as a systemd service. The point of the nginx layout is that school domains are dynamic: one wildcard server block forwards every matching host to Spider with the original Host header, and Spider resolves the tenant at request time from its registry.

# (1) dynamic tenant domains — register via API, works instantly server { listen 80; server_name ~^epanel\..+$; # widen or use default_server for custom domains location / { proxy_pass http://127.0.0.1:5217; proxy_set_header Host $host; # <- Spider resolves by this proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } # (2) management domain — admin, API, docs (add SSL with certbot --nginx) server { listen 80; server_name spider.silkcitysolution.com; location / { proxy_pass http://127.0.0.1:5217; proxy_set_header Host $host; } }

Adding a school is then a pure API operation: POST /api/v1/tenants (or the admin panel), point the domain's DNS at the server — no nginx edit, no restart, no redeploy. The complete walkthrough (systemd unit, certbot SSL, legacy-TLS note for SQL Server 2012, redeploy commands) is in /llms.txt under Deployment.