Content Management that can withstand the plundering hoards

Viking CMS — historical project plan

Historical design, not current instructions. This document preserves the initial proposal and its section numbering. Several proposals were superseded: authentication is built into the CMS (no Basic auth or ingress auth adapter), both PVCs use RWX, themes/WordPress/plugins are implemented, and the project license is Apache-2.0 under LICENCE, not the proposed MIT license below. Use current contracts, installation and current status for supported behaviour. Unimplemented proposals here are not commitments or available commands. All active open work is tracked in TODO.md; completed or superseded proposals below remain only as historical context.

Project: Viking CMS
Owner: TLSPU Limited
Status: Initial architecture and implementation plan
Version: 0.1.0-draft
License: MIT (proposed; confirm before publication)
Repository: Single Git repository (monorepo)
Primary platform: Kubernetes
Preferred deployment: TAK-OS Orbit Deploy
Preferred ingress: TAK-OS Ingress


1. Executive Summary

Viking CMS is a Kubernetes-native visual content management and static website hosting platform developed by TLSPU Limited.

Its purpose is to provide an alternative to traditional web hosting stacks, including Apache/PHP-based hosting systems and WordPress, without sacrificing the ease of use expected by nontechnical website owners.

Viking CMS separates website creation, content management, publication and delivery into independent components.

The public-facing website is served by an extremely lightweight, high-performance HTTP server. It does not execute application code, query databases, communicate with the CMS, or require access to private website content.

Website owners manage content through an authenticated, browser-based visual CMS. The CMS generates complete static websites and publishes them to shared storage using an atomic publication mechanism.

Kubernetes Custom Resources define websites and their required infrastructure. A dedicated operator provisions and maintains the corresponding Kubernetes resources.

Viking CMS is a standalone TLSPU Limited product.

It integrates naturally with the TAK-OS ecosystem but must operate on ordinary Kubernetes clusters without mandatory TAK-OS dependencies.

1.1 Core principles

  1. Kubernetes-native: Website infrastructure is declared through Kubernetes Custom Resources.
  2. Static serving: Public-facing servers serve files only.
  3. Separation of concerns: Authoring, publishing, storage, routing and serving remain independent.
  4. Security by design: The public-facing serving process has minimal privileges and no access to private CMS data.
  5. Visual editing: Website owners should not require programming, template-language or Kubernetes knowledge.
  6. Independent scaling: Each website has its own Deployment and can scale independently.
  7. Atomic publishing: Visitors must not encounter partially generated websites.
  8. Interchangeable components: TAK-OS integrations are preferred but optional.
  9. Small footprint: Runtime images and resource requirements should be minimised.
  10. Open source: The project should be suitable for public development and independent adoption.
  11. Declarative operation: Infrastructure changes are reconciled by the operator rather than applied manually.
  12. No unnecessary complexity: Avoid introducing databases, message queues, frameworks or distributed services without a demonstrated requirement.

1.2 Non-goals

Viking CMS is not intended to:

These capabilities may be provided by independent external services where necessary.


2. Technology and Development Standards

2.1 Repository structure

The entire project shall be maintained in one Git repository.

This includes:

Components may produce separate container images and have independent release lifecycles, but their source code shall remain in the same repository.

Proposed structure

viking-cms/
 |- cms/ - All CMS source and Dockerfile here
 |- controller - All Controller source and Dockerfile here.
 |- frontend - All frontend source and Dockerfile here. This is the highspeed flatfile webserver
 |- deploy/ - Sample K8S manifests ready to apply with kubectl
 |- orbit-deployments/default/ - Manifests in Orbit Deploy format with deployment.json files etc. This is a symlink created manually only in this development environment (not checked into this repo) to ease updating the production deployment manifests
 |- README.md - Agents to keep this updated as a simple, very high level project overview
 |- docs/ - Detailed project documentation layed out in a logical structure, ready to be rendered into a flat website
 |- docs/planning/project-plan.md - This file - The description of what we are trying to create.
 |- LICENSE - Apache 2.0
 |- .gitlab-ci.yml - CI

Each of the key components will have its own tests folder, containing tests appropriate to its function and structure. They shall be called in test jobs at stage test in .gitlab-ci.yml

This is an initial layout and may evolve as implementation progresses.

2.2 Go development requirements

Go is the preferred implementation language for:

All Go applications MUST be compiled with:

CGO_ENABLED=0

All Go runtime containers MUST use:

FROM scratch

This is a mandatory project requirement, not a recommendation.

Go applications must be statically compiled and must not depend on a distribution userspace.

Recommended build flags:

CGO_ENABLED=0 GOOS=linux \
  go build -trimpath -ldflags="-s -w"

Architecture-specific builds must set the appropriate GOARCH.

The build system should support at least:

Other architectures may be added later.

Go container requirements

Go containers must:

Where outbound TLS connections require CA certificates, copy the required CA bundle from the build stage into the scratch image.

Example:

FROM golang:1.26-alpine AS builder

WORKDIR /src

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=0 GOOS=linux \
    go build -trimpath -ldflags="-s -w" \
    -o /application ./cmd/application

FROM scratch

COPY --from=builder /application /application
COPY --from=builder /etc/ssl/certs/ca-certificates.crt \
    /etc/ssl/certs/ca-certificates.crt

USER 65532:65532

ENTRYPOINT ["/application"]

The builder image must be pinned to a supported Go version and preferably an immutable digest in production CI.

The example assumes the builder contains a populated CA bundle; the build must install or generate it if necessary.

Certificates should only be copied when the application needs them.

2.3 Other languages

Where another language is more appropriate, such as JavaScript/TypeScript for the visual editor, its runtime container MUST use an Alpine Linux base.

Exceptions require an explicit architectural decision and documentation.

Frontend assets may be compiled during CI and embedded into a Go executable or copied into its scratch image.

A JavaScript build toolchain does not imply that Node.js must be present in the production container.

The CMS frontend should preferably be compiled to static assets.

2.4 Dependencies

Dependencies should be:

Prefer Go standard-library functionality where it provides acceptable performance and maintainability.

Do not introduce dependencies solely for developer convenience when their functionality is trivial to implement safely.

2.5 CI/CD

GitLab CI is the primary build and release system.

CI must include:

  1. Source formatting checks.
  2. Static analysis and linting.
  3. Unit tests.
  4. Integration tests.
  5. Kubernetes manifest validation.
  6. Dependency vulnerability scanning.
  7. Container image scanning.
  8. Container build verification.
  9. Multi-architecture builds.
  10. Release artifact generation.

Tagged releases should produce:

Container images must be tagged with both the release version and immutable digest.

Releases should be reproducible where practical.


3. System Architecture

3.1 Major components

Viking CMS consists of four primary components.

Viking Website Operator

A Kubernetes controller responsible for reconciling Website custom resources into Kubernetes infrastructure.

Viking Webserver

A high-performance static HTTP server responsible exclusively for serving published website files.

Viking CMS

An authenticated, browser-based visual content management system.

Viking Publisher

The component responsible for rendering, validating and atomically publishing completed websites.

The publisher may initially be integrated into the CMS backend but must retain a clearly defined internal interface.

3.2 Logical architecture

                       Kubernetes API
                             |
                        Website CRD
                             |
                             v
                    +------------------+
                    | Viking Operator  |
                    +------------------+
                             |
                 Reconciles resources
                             |
          +------------------+------------------+
          |                                     |
          v                                     v
  PUBLIC SERVING STACK                    PRIVATE CMS STACK

  +--------------------+                +--------------------+
  | Public Ingress     |                | Authenticated      |
  | TAK-OS or standard |                | CMS Ingress        |
  +--------------------+                +--------------------+
           |                                      |
           v                                      v
  +--------------------+                +--------------------+
  | ClusterIP Service  |                | ClusterIP Service  |
  +--------------------+                +--------------------+
           |                                      |
           v                                      v
  +--------------------+                +--------------------+
  | Webserver          |                | Visual CMS         |
  | Deployment         |                | Deployment         |
  | Initial replicas:2 |                | Initial replicas:1 |
  +--------------------+                +--------------------+
           |                                      |
       READ ONLY                              READ/WRITE
           |                                      |
           v                                      v
  +--------------------+                +--------------------+
  | Published RWX PVC  |<---Publish-----| Private CMS PVC    |
  | Static files only  |                | Drafts/Templates   |
  +--------------------+                +--------------------+

The CMS publisher writes completed releases to the published RWX PVC.

The public webserver must not access the CMS API, private PVC, drafts, credentials or publishing controls.

3.3 Deployment environments

Viking CMS must support:

TAK-OS

Preferred environment.

Kubernetes with TAK-OS components

Individual TAK-OS components may be used independently.

For example:

Plain Kubernetes

The complete core product must work without TAK-OS components.

Standard Kubernetes Ingress resources shall be supported.

Ingress-specific authentication or advanced features may require a compatible controller or additional supporting components.

The operator must report unsupported functionality rather than silently deploying an insecure or incomplete configuration.


4. Website Custom Resource

4.1 API

Initial API:

apiVersion: cms.tlspu.com/v1alpha1
kind: Website

The final API group should be confirmed before the first public release.

The Website resource is namespace-scoped.

Each Website represents one independently managed public website and its associated CMS.

4.2 Proposed specification

apiVersion: cms.tlspu.com/v1alpha1
kind: Website
metadata:
  name: example
  namespace: websites
spec:
  domain: example.com

  aliases:
    - www
    - shop
    - blog.example.net

  cms:
    hostname: cms.example.com

    authentication:
      oauth2:
        clientSecretRef:
          name: example-cms-oauth2

  storage:
    published:
      size: 5Gi
      storageClassName: cephfs

    private:
      size: 2Gi
      storageClassName: standard

  publishing:
    retainReleases: 0

  frontend:
    replicas: 2

  ingress:
    className: tak-os

This is the proposed initial schema, subject to implementation validation.

4.3 Domain and aliases

spec.domain defines the primary website hostname.

spec.aliases contains alternate hostnames.

Alias resolution rules:

Example:

domain: example.com
aliases:
  - www
  - shop
  - blog.example.net

Produces:

example.com
www.example.com
shop.example.com
blog.example.net

The operator must detect hostname conflicts with other Website resources under its management.

4.4 CMS hostname

spec.cms.hostname defines the externally accessible CMS hostname.

It must not conflict with any public website hostname.

The CMS hostname is always protected by authentication.

The CMS hostname must not be exposed through an unauthenticated ingress.

4.5 Authentication

The CMS supports exactly one configured ingress authentication mechanism.

Initial supported mechanisms:

Credentials must be stored in Kubernetes Secrets, not plaintext Website fields.

OAuth2/OIDC

Example:

cms:
  hostname: cms.example.com
  authentication:
    oauth2:
      clientSecretRef:
        name: example-oauth2

OAuth2 integration must account for:

These values may be provided through operator-level defaults and per-Website references.

The authentication adapter must support TAK-OS Ingress where possible and provide a documented portable alternative for other ingress controllers.

Basic authentication

Example:

cms:
  hostname: cms.example.com
  authentication:
    basic:
      secretRef:
        name: example-basic-auth

The referenced Secret should contain credentials in a format appropriate for the selected authentication adapter.

Password hashes are preferred over plaintext password storage.

Basic authentication must only be exposed over HTTPS.

Authentication validation

The CRD and operator must reject:

The operator must not silently fall back to unauthenticated access.

4.6 Storage

Each Website requires two persistent volumes.

Published content PVC

Private CMS PVC

The storage classes and capacities must be configurable.

PVC expansion should be supported where the storage provider permits it.

PVC deletion must be conservative and explicitly controlled.

4.7 Frontend replicas

Default:

frontend:
  replicas: 2

Two replicas provide capacity for rolling restarts without planned downtime, subject to successful readiness checks and sufficient cluster capacity.

The operator should use:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

The operator should configure topology spreading where practical.

Independent HPA support is planned.

Initial implementation may use fixed replica counts.

4.8 Website status

The operator should expose:

status:
  observedGeneration: 1
  conditions:
    - type: Ready
      status: "True"
      reason: ComponentsReady

    - type: FrontendReady
      status: "True"
      reason: Available

    - type: CMSReady
      status: "True"
      reason: Available

    - type: StorageReady
      status: "True"
      reason: Bound

    - type: Published
      status: "True"
      reason: ReleaseAvailable

  currentRelease: "000001"

Status conditions must reflect observed state, not merely successful resource creation.


5. Website Operator

5.1 Responsibilities

The operator watches Website resources and reconciles their desired state.

For each Website, it creates or maintains:

Public frontend

CMS backend

Optional resources

5.2 Reconciliation requirements

Reconciliation must be:

The operator must detect and handle:

5.3 Ownership and deletion

Generated resources should use Kubernetes owner references where appropriate.

Persistent data must not be automatically destroyed simply because a Website resource is deleted.

Default policy:

retentionPolicy: Retain

Retention and cleanup behaviour must be documented.

The operator should use finalizers where necessary to coordinate safe cleanup.

5.4 Operator permissions

RBAC must follow least privilege.

The operator should only receive the permissions required to reconcile supported resources.

It must not require cluster-admin privileges during normal operation.

Cluster-scoped installation permissions for CRDs and controller RBAC should be separated from runtime permissions.

5.5 Namespace boundaries

Website resources are namespace-scoped.

The generated serving and CMS workloads must reside in the namespace containing their PVCs.

The initial implementation may deploy multiple Websites into one namespace, but must not assume that all Websites share a namespace.

Cross-namespace PVC mounting is not supported.


6. Static Webserver

6.1 Purpose

The Viking Webserver is a small, high-performance, file-only HTTP server.

It has no knowledge of:

Each website receives its own Deployment.

Ingress routing determines which Deployment receives each request.

6.2 Language selection

Candidate languages:

Go is the initial preference because of implementation simplicity, ecosystem maturity and straightforward static compilation.

Potential Go implementations:

The final choice must be based on benchmarks using realistic static-file workloads.

Performance should be evaluated against Apache HTTPD with a minimal configuration.

The design must not assume that fasthttp is faster for all workloads.

6.3 Runtime interface

The server should require minimal configuration.

Example:

viking-webserver \
  --root=/www/current \
  --listen=:8080

Configuration may be provided through flags or environment variables.

The server must not require a Kubernetes API connection.

6.4 HTTP features

Required:

Optional:

Not supported:

6.5 Security

The webserver must:

The webserver should not require a writable temporary directory.

Unknown paths must not expose internal filesystem details.

6.6 Performance

The server should make effective use of Linux filesystem caching.

Initial implementation should rely on kernel page caching rather than introducing a custom application-level cache.

Benchmark workloads should include:

Metrics should include:

The previously observed TAK-OS Ingress throughput of over 93,000 requests per second during a security researcher's attack run provides useful context, but is not a validated Viking CMS performance target.

6.7 Health endpoints

Suggested:

/healthz
/readyz
/metrics

Health and metrics endpoints should preferably be exposed on a separate internal listener or otherwise protected from public access.

Readiness must reflect the availability of the active published content.

The server should return an appropriate unavailable response when no valid publication exists.


7. Visual CMS

7.1 Purpose

The CMS must provide an approachable, visual website creation and editing experience.

The target user is someone comfortable with WordPress-style editing but without programming knowledge.

Users must not need to understand:

7.2 Initial editor candidate

GrapesJS Open Source is the initial candidate for the visual editing engine.

This is not a final technology decision.

The editing experience, extensibility, export behaviour and licensing must be evaluated before adoption.

Other visual editors may be considered.

7.3 CMS features

Initial target features:

Future candidates:

7.4 User experience principles

The CMS should prioritise content editing over technical configuration.

Users should be able to:

  1. Open the CMS.
  2. Select a page.
  3. Click content to edit it.
  4. Add images or components.
  5. Preview changes.
  6. Save a draft.
  7. Publish.

Advanced design controls should not obstruct ordinary editing tasks.

Where practical, distinguish between:

7.5 CMS storage

The CMS initially uses ordinary filesystem storage.

No database is required for the MVP.

The private PVC may contain:

/cms/
??? project/
?   ??? project.json
?   ??? pages/
?   ??? settings.json
?   ??? components/
?
??? assets/
??? templates/
??? drafts/
??? working/

The exact format depends on the selected editor.

Editable project state must be preserved independently of generated HTML.

Generated output must not be treated as the authoritative editable source.

7.6 CMS runtime

The CMS backend may be written in Go.

The browser editor may use JavaScript or TypeScript.

Compiled browser assets should be served by the Go CMS backend where practical.

The Go CMS backend must use CGO_ENABLED=0 and a scratch runtime container.

If another runtime language is selected, its runtime image must use Alpine Linux.

7.7 CMS security

The CMS must:

Authentication at ingress is an access boundary, but the CMS must still treat browser input as untrusted.


8. Publishing Engine

8.1 Purpose

The publisher transforms editable CMS content into a complete static website.

Publication is independent of public request handling.

Rendering speed is not a critical performance requirement.

A publication may take seconds or minutes without affecting the currently published website.

8.2 Publication process

The publisher must:

  1. Save or snapshot the current editable project state.
  2. Allocate a new release directory.
  3. Generate all required HTML.
  4. Generate CSS and JavaScript assets.
  5. Copy or transform media.
  6. Generate metadata and sitemap files.
  7. Validate the completed release.
  8. Atomically activate the new release.
  9. Update publication metadata.
  10. Clean up obsolete releases according to retention policy.

The active release must never be modified in place.

8.3 Directory structure

Proposed:

/www/
??? releases/
?   ??? 000001/
?   ??? 000002/
?   ??? 000003/
?
??? current -> releases/000003

Each release directory is immutable once published.

8.4 Atomic activation

The publisher creates a new symbolic link pointing to the completed release.

Example:

ln -s releases/000003 current.new
mv -Tf current.new current

The replacement of the current symlink must be implemented using an atomic rename operation on the same filesystem.

The actual implementation must not depend on shell utilities being available inside the runtime container.

For Go implementations, use the appropriate filesystem APIs.

The implementation must verify the semantics of the selected RWX storage provider.

A pair of ordinary directory renames must not be treated as a single atomic transaction.

8.5 Publication consistency

The server must resolve the active publication correctly.

The design must avoid permanently caching an obsolete symlink target.

Kubernetes subPath mounts must not pin the server to an obsolete release.

Old releases must remain available long enough for in-flight requests to finish.

Versioned asset URLs or content-hashed asset names are preferred to avoid mixed-release page loads.

8.6 Release retention

Website configuration:

publishing:
  retainReleases: 0

Default:

0

Meaning:

Retention is distinct from temporary cleanup delays required for safe publication.

Rollback history is not a replacement for storage backups.

8.7 Rollback

Where retained releases exist, the CMS should provide a rollback operation.

Rollback changes the active release pointer.

Rollback must not require rerendering the website.

The publisher should record:

8.8 Failure handling

If rendering fails:

If activation fails:

Concurrent publication requests must be serialized or otherwise coordinated to prevent conflicting activations.


9. Ingress Integration

9.1 General requirements

Viking CMS must use standard Kubernetes networking resources wherever possible.

The operator creates:

TLS termination occurs at the ingress controller.

The webserver and CMS may communicate with ingress over internal HTTP.

9.2 TAK-OS Ingress

TAK-OS Ingress is the preferred implementation.

Where available, Viking CMS may use TAK-OS-specific capabilities for:

Such integrations must remain optional.

9.3 Standard Kubernetes ingress

On plain Kubernetes, Viking CMS must support standard networking.k8s.io/v1 Ingress resources.

Ingress controllers differ in their support for authentication annotations and other extensions.

Viking CMS must not assume that arbitrary authentication annotations work across controllers.

A portable authentication implementation may require an additional authentication proxy or adapter.

Unsupported configurations must produce clear status conditions.

9.4 TLS

The operator should support existing TLS Secrets and optional integration with certificate automation.

Certificate provisioning must not be hardwired to one implementation.

TLS configuration should be separately configurable for public and CMS hostnames.


10. Observability

10.1 Principles

All components must provide structured logs and operational metrics.

The system must integrate with common Kubernetes observability stacks.

Preferred compatibility targets:

No observability backend is mandatory for basic operation.

10.2 Metrics

Prometheus-compatible metrics should include:

http_requests_total
http_request_duration_seconds
http_response_size_bytes
http_requests_in_flight

Additional metrics:

Metric labels must have controlled cardinality.

Do not use arbitrary URLs, unvalidated Host headers or user-controlled values as unrestricted metric labels.

10.3 Logging

Logs should be emitted to stdout/stderr.

JSON structured logging is preferred.

Access logs should contain:

Forwarded client-address headers must only be trusted from known proxies.

Sensitive request data must not be logged unnecessarily.

10.4 Website statistics

The initial system should provide metrics and logs suitable for external dashboards.

Future reporting may include:

These features may be provided by Grafana dashboards or an optional analytics component.

Viking CMS should not require a database solely for website statistics.


11. Security Model

11.1 Isolation

Each Website has an independent frontend Deployment and Service.

This provides:

Kubernetes namespace isolation may provide additional boundaries.

11.2 Public serving layer

The serving layer must have:

The published filesystem contains only public data.

11.3 CMS layer

The CMS is authenticated and isolated from public serving traffic.

The CMS requires write access to the private PVC and the published RWX PVC.

NetworkPolicy should prevent public serving Pods from connecting to CMS services.

The publisher must validate generated output and uploaded content.

11.4 Container security

Required security settings where supported:

securityContext:
  runAsNonRoot: true
  runAsUser: 65532
  runAsGroup: 65532
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL
  seccompProfile:
    type: RuntimeDefault

ServiceAccount token automounting must be disabled for components that do not need Kubernetes API access.

11.5 Supply-chain security

CI should include:

Runtime images must not contain build tools.


12. Installation and Distribution

12.1 Preferred installation

TAK-OS Orbit Deploy is the standard and recommended installation mechanism.

The project should provide a ready-to-use Orbit Deploy configuration.

12.2 Portable installation

Viking CMS must also support installation through standard Kubernetes manifests.

Helm must not be required.

The installation process should be documented for:

12.3 Installation components

The core installation includes:

Website-specific workloads are created by the operator when Website resources are applied.

12.4 Upgrades

Upgrades must preserve:

CRD schema evolution must be planned carefully.

Breaking changes require documented migration procedures.


13. Testing Strategy

13.1 Unit tests

Cover:

13.2 Integration tests

Cover:

13.3 End-to-end tests

Use a disposable Kubernetes environment where practical.

Verify:

  1. Install Viking CMS.
  2. Create a Website resource.
  3. Wait for resources to become ready.
  4. Access the CMS.
  5. Create a page.
  6. Publish.
  7. Retrieve the page through ingress.
  8. Modify and republish.
  9. Confirm the old release remains available until activation.
  10. Confirm the new release becomes active.
  11. Verify data retention during deletion.

13.4 Performance tests

Benchmark the serving layer independently from ingress.

Then benchmark the complete request path.

Compare:

Performance results must distinguish:

No unsupported performance claims should be made.

13.5 Security tests

Include:


14. Development Workstreams

The project should support parallel development by multiple agents.

Each workstream must have a defined interface and ownership boundary.

Workstream A ? Kubernetes Operator

Primary responsibility: Website CRD and resource reconciliation.

Deliverables:

Dependencies:

Workstream B ? Static Webserver

Primary responsibility: High-performance static file delivery.

Deliverables:

Dependencies:

This workstream should be independently executable without Kubernetes.

Workstream C ? CMS Backend

Primary responsibility: Editable project management.

Deliverables:

Dependencies:

Workstream D ? Visual Editor

Primary responsibility: Nontechnical website editing experience.

Deliverables:

Dependencies:

GrapesJS adoption remains provisional until evaluated.

Workstream E ? Publisher

Primary responsibility: Static rendering and publication.

Deliverables:

Dependencies:

Workstream F ? CI/CD and Deployment

Primary responsibility: Build, testing and release automation.

Deliverables:

Dependencies:


15. Development Coordination

15.1 Shared contracts

Before parallel implementation begins, agree on:

  1. Website CRD schema.
  2. Resource naming conventions.
  3. Container image names.
  4. Container ports.
  5. Health endpoint paths.
  6. Metrics endpoint paths.
  7. CMS API conventions.
  8. Editable project storage format.
  9. Publisher interface.
  10. Published filesystem layout.
  11. Release metadata format.
  12. Authentication adapter interface.

These contracts should be documented under docs/architecture/.

15.2 Agent working rules

Each agent should:

Shared API changes must be coordinated before implementation.

15.3 Integration

Integration should occur continuously rather than at the end of development.

Each component must have a standalone test path.

The operator, webserver, CMS and publisher should be independently testable.


16. Implementation Milestones

Milestone 1 ? Repository and Architecture

Goal: Establish the monorepo and shared contracts.

Tasks:

Acceptance criteria: All workstreams can begin without inventing incompatible interfaces.

Milestone 2 ? Static Serving Prototype

Goal: Serve a website from a read-only mounted directory.

Tasks:

Acceptance criteria: A statically compiled, non-root Go container reliably serves static files from a read-only PVC.

Milestone 3 ? Website Operator

Goal: Provision the frontend automatically.

Tasks:

Acceptance criteria: Applying a Website resource creates a working public static website without manual resource creation.

Milestone 4 ? CMS Infrastructure

Goal: Provision a private, authenticated CMS environment.

Tasks:

Acceptance criteria: The operator provisions a CMS that is accessible only through configured authentication.

Milestone 5 ? Visual Editor Proof of Concept

Goal: Validate the selected editing technology.

Tasks:

Acceptance criteria: A nontechnical user can create and edit a simple multipage website without writing code.

Decision gate: Confirm GrapesJS or select an alternative.

Milestone 6 ? Publishing

Goal: Publish complete websites without interrupting serving.

Tasks:

Acceptance criteria: A website can be edited, rendered and atomically published while the existing version remains available.

Milestone 7 ? Complete CMS Workflow

Goal: Deliver the end-to-end user experience.

Tasks:

Acceptance criteria: A site owner can create, edit and publish a website entirely through the browser.

Milestone 8 ? Portability and Hardening

Goal: Validate operation across supported Kubernetes environments.

Tasks:

Acceptance criteria: Core Viking CMS functionality works without mandatory TAK-OS dependencies.

Milestone 9 ? Initial Public Release

Goal: Publish a usable open-source release.

Tasks:

Acceptance criteria: An independent Kubernetes administrator can install Viking CMS and publish a website using the documentation.


17. Open Design Decisions

The following items remain deliberately unresolved.

Area Decision required
HTTP server Go net/http, fasthttp, or Rust
Visual editor GrapesJS or alternative
CMS project format Final editable content schema
CMS backend Go preferred, subject to editor needs
Authentication Portable OAuth2/OIDC implementation
Ingress integration Adapter interface and feature detection
Storage Default storage class and filesystem guarantees
Publication Release metadata and safe cleanup strategy
Scaling Fixed replicas initially; HPA metrics later
CMS availability Single replica initially
Backup PVC snapshot and off-cluster backup strategy
Licensing Confirm MIT and dependency compatibility
API group Confirm cms.tlspu.com
Website analytics Grafana dashboards or dedicated UI
Multi-user editing Initial scope and conflict handling
Site templates Bundled starter templates and format

These decisions must not block independent development where interfaces can be agreed in advance.


18. Future Enhancements

Potential future development includes:

These should remain outside the initial MVP unless needed to validate a fundamental architectural assumption.


19. Definition of Done

The initial Viking CMS release is complete when:

  1. A Kubernetes administrator can install the operator using standard manifests or Orbit Deploy.
  2. A Website custom resource provisions the required frontend and CMS resources.
  3. The public frontend starts with two replicas.
  4. The frontend serves static files from a read-only RWX PVC.
  5. The CMS stores editable project data on a separate private PVC.
  6. The CMS is protected by exactly one supported authentication mechanism.
  7. A nontechnical user can create and edit a simple website visually.
  8. The CMS can generate a complete static publication.
  9. Publication switches the live website atomically.
  10. Failed publications do not replace the active website.
  11. Release retention defaults to zero historical releases.
  12. Optional retained releases can be rolled back.
  13. The public webserver has no access to private CMS data.
  14. Go binaries are built with CGO_ENABLED=0 and run in scratch containers.
  15. Other language runtimes use Alpine-based containers.
  16. Metrics and structured logs are available.
  17. Core functionality works on plain Kubernetes.
  18. Automated tests cover the critical paths.
  19. Security and performance testing have been completed.
  20. Installation, operation and user documentation are available.

20. Final Architectural Statement

Viking CMS is a Kubernetes-native, visually managed, statically published website hosting platform.

It combines the accessibility of a visual CMS with the operational advantages of Kubernetes and the performance and security characteristics of a minimal static HTTP server.

Website creation and content management are deliberately isolated from public content delivery.

Each website is independently provisioned, deployed and scaled through a Kubernetes Custom Resource.

The platform uses ordinary Kubernetes APIs, integrates preferentially with TAK-OS Orbit Deploy and TAK-OS Ingress, and remains independently usable on standard Kubernetes.

The primary objective is not to recreate the complexity of conventional web hosting.

It is to eliminate the complexity that is no longer necessary.


Viking CMS
A TLSPU Limited project.