Skip to content

Architecture

Overall architecture

Central is a single-process Go HTTP service that:

  1. Serves the AcuGIS portal HTML/JS under / (optional BASE_PATH prefix)
  2. Issues and validates platform authentication (cookie sessions and PATs)
  3. Stores portal cards and shared identity/ACL tables in PostgreSQL
  4. Aggregates downstream discovery feeds into GET /api/catalog
  5. Stores uploaded card thumbnails on the local filesystem

Apache (evidenced in the parent repository) terminates TLS and reverse-proxies Central at the site root while mounting other services under their own prefixes.

flowchart TB
  U[Browser / acugis CLI / API clients] --> A[Apache TLS proxy]
  A -->|/ login logout selected /api| C[Central :8888]
  A -->|/dashboard /qgis-publish-service /tileserver /jasper-report-services /geovault ...| S[Downstream services]
  C --> PG[(PostgreSQL<br/>cards · users · sessions · PATs · ACLs)]
  C --> TH[Filesystem thumbnails]
  C --> MEM[In-memory catalog cache]
  C -->|same-origin discovery + session cookie| S

Major components

Component Location Responsibility
HTTP mux / portal pages main.go Route registration, HTML pages, health/catalog/portal handlers
Admin auth API admin_auth.go Users, groups, resources, permission rows
ACL editor API admin_resource_acl.go Overview + replace matrix
PAT / account user_tokens.go Account page and token CRUD for current user
Portal store internal/portal/store.go Schema ensure, cards, pool lifecycle
Auth adapters internal/portal/auth.go, pat_store.go, auth_admin.go, authz_store.go, acl_admin.go shared/auth providers and admin SQL
Discovery internal/portal/discovery.go Static service registry + normalize discovery payloads
Catalog aggregator internal/portal/catalog.go TTL cache + bucketed catalog response
Thumbnails internal/portal/thumbnails.go Validate and write image uploads
Base path helpers internal/web/basepath.go BASE_PATH, forwarded prefix/proto
Shared auth ../shared/auth Sessions, PATs, password hashing, middleware helpers
Shared UI ../shared/ui Federation shell assets at /shared/ui/
Web UI web/ Templates and browser JS

Directory layout

central/
  main.go
  admin_auth.go
  admin_resource_acl.go
  user_tokens.go
  build.sh / build.ps1
  go.mod / go.sum
  internal/
    portal/
    web/
  web/
  deploy/
    systemd/
    sql/
  docs/

Request flow

sequenceDiagram
  participant C as Client
  participant P as Proxy
  participant H as Central handler chain
  participant A as shared/auth AttachUser
  participant D as Handler + Postgres/cache

  C->>P: HTTPS request
  P->>H: HTTP + X-Forwarded-* 
  H->>H: ApplyForwardedProto
  H->>A: AttachUser (if DB configured)
  A->>A: Cookie acugis_session then Bearer PAT
  A->>D: Handler with optional user context
  D-->>C: JSON / HTML / redirect / static file

Middleware order:

  1. proxyHeaders applies X-Forwarded-Proto
  2. When auth is configured: authService.AttachUser
  3. Exact method+path registrations on http.ServeMux
  4. Catch-all mount("/") portal handler for HTML/static files

Admin API handlers call requireAdmin (session/PAT + IsAdmin). Authenticated account/PAT handlers call requireAuthenticatedUser.

Authentication flow

sequenceDiagram
  participant B as Browser
  participant C as Central
  participant DB as PostgreSQL

  B->>C: POST /login (username, password, next)
  C->>DB: Load dashboard_users by username
  C->>C: Verify PBKDF2 password
  C->>DB: Insert hashed session into dashboard_sessions
  C-->>B: 303 + Set-Cookie acugis_session
  B->>C: Subsequent APIs with cookie
  C->>DB: Lookup session hash + enabled user + groups

PAT path:

  1. Authenticated user creates token via POST /api/me/tokens
  2. Plaintext agp_... returned once
  3. Later requests send Authorization: Bearer agp_...
  4. Central hashes and looks up personal_access_tokens

Cookie takes precedence; invalid/expired cookies fall through to bearer validation.

Database interactions

  • Pool: pgxpool.New with DSN; no explicit pool sizing in Central
  • Schema: EnsureSchema at startup (unversioned CREATE TABLE IF NOT EXISTS / additive ALTERs)
  • Transactions: card reorder, replace user groups, replace resource ACL
  • Auth schema bootstrap also seeds default groups and platform service resources

Details: Database.

Background workers

None verified. There are:

  • No goroutine workers
  • No cron/systemd timers owned by Central
  • No queue consumers

Related one-shot startup work (not recurring):

  • Delete expired sessions during empty-admin bootstrap
  • Ensure schema, seed groups, ensure platform service resources
  • Create thumbnails directory

Caching

Cache Scope TTL Key
Catalog discovery Process memory CENTRAL_CATALOG_CACHE_TTL (default 45s) service_key + "|" + full Cookie header

No Redis/Memcached. Cache is lost on restart. There is no global size bound or proactive eviction beyond overwrite on fetch.

File storage

Asset Location Persistence
Templates/static UI CENTRAL_WEB_ROOT (web/) Deployed with binary
Thumbnails CENTRAL_THUMBNAILS_DIR Local disk; URL stored in portal_cards.image_url
Shared UI FEDERATION_SHARED_UI_ROOT / discovered shared/ui Read-only assets

Thumbnail rules: max 5 MiB; JPEG/PNG/WebP/GIF; random hex filename. No garbage collection when cards are deleted.

External integrations

Hard-coded same-origin discovery endpoints (internal/portal/discovery.go):

Service key Display name Discovery path
dashboard-service Dashboards /dashboard/api/discovery
qgis-publish-service QGIS Maps /qgis-publish-service/api/discovery
acugis-tileserver Tileserver /tileserver/api/discovery
jasper-report-service Reports /jasper-report-services/api/discovery/index.php
geovault GeoVault /geovault/api/discovery

Behavior:

  • Origin built from X-Forwarded-Proto / TLS and X-Forwarded-Host / Host
  • Current acugis_session cookie is forwarded
  • Failures become catalog warnings (catalog still returns HTTP 200)
  • Stub endpoints GET /api/maps|reports|forms|datasets are not wired to these services yet

Resource-sync admin page derives sync URLs by replacing /api/discovery with /api/resource-sync (Jasper uses /api/resource-sync/index.php).

Logging

  • Standard library log to stdout/stderr
  • systemd: journald with SyslogIdentifier=central
  • No structured logging, request IDs, metrics, or tracing subsystem was found