Proposal: Build Kubernetes-native Git Server #53

Closed
opened 2026-01-07 20:50:52 +00:00 by HugoNijhuis · 5 comments
Owner

Overview

Proposal to build a modern, Kubernetes-native git server that could:

  1. Replace our current Gitea instance
  2. Serve as an open-source project to build awareness for Flowmade One
  3. Prove our stack (Aether + IRIS) in a real application

Architecture Alignment

This proposal aligns with our architecture beliefs:

Belief Pattern How This Applies
Auditability by default Event Sourcing Full event-sourced domain: RepositoryCreated, PullRequestOpened, etc. Complete history for every repo and PR.
Business language in code Domain-Driven Design Aggregates map to git concepts: Repository, PullRequest, User, Organization. Ubiquitous language shared with users.
Independent evolution Event-driven communication NATS pub/sub enables real-time UI updates and CI runners without coupling. New features subscribe to existing events.
Explicit over implicit Commands and Events Clear separation: CreateRepository (command) → RepositoryCreated (event). Intent and outcome are distinct.

See software-architecture.md for full pattern documentation.

Why Build This?

Feature GitHub GitLab Gitea Proposed
Self-hosted Enterprise
Cloud option Limited
K8s native Partial Native
Horizontal scale N/A Complex Single Built-in
Runner scaling Manual Manual Manual KEDA native
Event sourcing Full audit
Single dependency N/A PG+Redis+... PostgreSQL NATS only
Real-time UI Polling Polling Polling WebSocket

Technical Background

How Git Servers Work

  • Git itself has almost no access control - just transport (SSH/HTTP) and hooks
  • Gitea/GitHub/GitLab add: users, permissions, PRs, issues, branch protection - all stored in a database
  • Gitea shells out to the git binary for every operation (no persistent git daemon)
  • This means storage I/O directly impacts performance

Why Gitea Doesn't Scale Horizontally

Multiple Gitea replicas all need access to the same git repositories on disk:

  • Requires RWX shared filesystem
  • NFS overhead kills performance (~233 file opens per README render)
  • Git's lock files create contention
  • Each instance has separate caches (stale data)

GitLab solved this with Gitaly - a dedicated gRPC service that owns git operations, so web/API instances are stateless.

Proposed Architecture

                                Ingress
          ┌───────────────────────┼───────────────────────┐
          │                       │                       │
          ▼                       ▼                       ▼
     ┌─────────┐           ┌───────────┐           ┌───────────┐
     │  IRIS   │           │ Git SSH   │           │ Git HTTP  │
     │ (WASM)  │           │ Gateway   │           │ Gateway   │
     └────┬────┘           └─────┬─────┘           └─────┬─────┘
          │                      │ gRPC                  │
          ▼                      ▼                       ▼
     ┌─────────────────────────────────────────────────────────┐
     │                   Git Server Domain                      │
     │                                                          │
     │  Aggregates:              Projections:                  │
     │  ├── Repository           ├── repo-list                 │
     │  ├── PullRequest          ├── pr-list                   │
     │  ├── User                 ├── permissions               │
     │  └── Organization         └── ssh-key-lookup            │
     └─────────────────────────────────────────────────────────┘
                                │
                          built on
                                │
     ┌─────────────────────────────────────────────────────────┐
     │                       Aether                             │
     │  git.flowmade.one/flowmade-one/aether                   │
     │                                                          │
     │  - Aggregate lifecycle     - Cluster primitives         │
     │  - Event store             - Sharding                   │
     │  - Projections framework   - Leader election            │
     └─────────────────────────────────────────────────────────┘
                                │
                          powered by
                                │
     ┌─────────────────────────────────────────────────────────┐
     │                    NATS JetStream                        │
     │  (implementation detail managed by Aether)              │
     └─────────────────────────────────────────────────────────┘

     Separate concern:
     ┌─────────────────────────────────────────────────────────┐
     │             Git Storage Service (StatefulSet)           │
     │  - gRPC API wrapping git operations                     │
     │  - Sharded by consistent hashing                        │
     │  - Local SSD or hcloud-volumes per shard                │
     └─────────────────────────────────────────────────────────┘

     CI/CD:
     ┌─────────────────────────────────────────────────────────┐
     │                    Action Runners                        │
     │  - KEDA ScaledJob based on NATS queue depth             │
     │  - Pull jobs from NATS, stream logs back                │
     └─────────────────────────────────────────────────────────┘

Bounded Contexts

Following DDD patterns, the git server has these contexts:

Context Aggregates Responsibility
Repository Repository, Branch, Commit Git storage, branches, commits, files
Collaboration PullRequest, Review, Comment PRs, reviews, discussions
Identity User, Organization, SSHKey Users, orgs, permissions, keys
CI/CD Pipeline, Job, Artifact Runners, jobs, logs, artifacts

Each context owns its aggregates and publishes events for cross-context communication.

Key Design Decisions

1. Built on Aether

The git server is an Aether application. Domain logic uses Aether's primitives:

type Repository struct {
    aether.AggregateBase
    Name       string
    Owner      string
    Visibility Visibility
}

func (r *Repository) HandleCommand(cmd aether.Command) ([]aether.Event, error) {
    switch c := cmd.(type) {
    case *CreateRepository:
        return []aether.Event{&RepositoryCreated{...}}, nil
    }
}

func (r *Repository) ApplyEvent(evt aether.Event) {
    switch e := evt.(type) {
    case *RepositoryCreated:
        r.Name = e.Name
    }
}

This proves Aether works in a real application before betting the low-code platform on it.

2. NATS as Infrastructure (via Aether)

NATS is an implementation detail managed by Aether, not a direct dependency:

  • Event store (JetStream streams)
  • Read models (KV buckets)
  • Service communication
  • Job queues for CI
  • Real-time pub/sub to UI

3. IRIS for Frontend

WASM-based UI with reactive signals. WebSocket connection for real-time updates.

4. Kubernetes-Native Deployment

helm install gitserver flowmade/gitserver \
  --set domain=git.company.com \
  --set auth.oidc.issuer=https://dex.company.com

Components to Build

Component Effort Notes
Domain model Low Go structs, Aether aggregates
Git Storage Service Medium-High gRPC wrapper around git
SSH Gateway Medium Auth + route to storage
HTTP Git Gateway Low Standard smart protocol
IRIS UI High File browser, PR view, diff, etc.
Runner integration Medium NATS queue + KEDA

Already available:

  • Aether (git.flowmade.one/flowmade-one/aether) - ES runtime
  • IRIS (git.flowmade.one/flowmade-one/iris) - UI framework

Open Questions

Naming

  • Need a name recognizable as a git server
  • Need available domain
  • Options: Gitquay, Githarbor, Gitkeep, Gitledger, etc.
  • Should it be under Flowmade One brand or separate identity?

Positioning

  • Is Flowmade One the product name or company with separate products?
  • Git server as part of "One platform" vs separate product?
  • Cloud version: git.flowmade.one? Separate domain?

Strategy

  • Open-source to build awareness for Flowmade One low-code SaaS
  • Self-hosted option + cloud offering (open core model)
  • Use git.flowmade.one (Gitea) as source of truth during development
  • Eventually dogfood by self-hosting
  • Aether: git.flowmade.one/flowmade-one/aether
  • IRIS: git.flowmade.one/flowmade-one/iris
  • Current Gitea setup on git.flowmade.one
  • NATS infrastructure already deployed
  • KEDA already in cluster for runner scaling

This issue captures a discussion about building a Kubernetes-native git server.

## Overview Proposal to build a modern, Kubernetes-native git server that could: 1. Replace our current Gitea instance 2. Serve as an open-source project to build awareness for Flowmade One 3. Prove our stack (Aether + IRIS) in a real application ## Architecture Alignment This proposal aligns with our [architecture beliefs](./manifesto.md#architecture-beliefs): | Belief | Pattern | How This Applies | |--------|---------|------------------| | Auditability by default | Event Sourcing | Full event-sourced domain: `RepositoryCreated`, `PullRequestOpened`, etc. Complete history for every repo and PR. | | Business language in code | Domain-Driven Design | Aggregates map to git concepts: `Repository`, `PullRequest`, `User`, `Organization`. Ubiquitous language shared with users. | | Independent evolution | Event-driven communication | NATS pub/sub enables real-time UI updates and CI runners without coupling. New features subscribe to existing events. | | Explicit over implicit | Commands and Events | Clear separation: `CreateRepository` (command) → `RepositoryCreated` (event). Intent and outcome are distinct. | See [software-architecture.md](./software-architecture.md) for full pattern documentation. ## Why Build This? | Feature | GitHub | GitLab | Gitea | Proposed | |---------|--------|--------|-------|----------| | Self-hosted | ❌ Enterprise | ✅ | ✅ | ✅ | | Cloud option | ✅ | ✅ | Limited | ✅ | | K8s native | ❌ | Partial | ❌ | ✅ Native | | Horizontal scale | N/A | Complex | ❌ Single | ✅ Built-in | | Runner scaling | Manual | Manual | Manual | ✅ KEDA native | | Event sourcing | ❌ | ❌ | ❌ | ✅ Full audit | | Single dependency | N/A | PG+Redis+... | PostgreSQL | NATS only | | Real-time UI | Polling | Polling | Polling | ✅ WebSocket | ## Technical Background ### How Git Servers Work - Git itself has almost no access control - just transport (SSH/HTTP) and hooks - Gitea/GitHub/GitLab add: users, permissions, PRs, issues, branch protection - all stored in a database - Gitea shells out to the git binary for every operation (no persistent git daemon) - This means storage I/O directly impacts performance ### Why Gitea Doesn't Scale Horizontally Multiple Gitea replicas all need access to the same git repositories on disk: - Requires RWX shared filesystem - NFS overhead kills performance (~233 file opens per README render) - Git's lock files create contention - Each instance has separate caches (stale data) GitLab solved this with **Gitaly** - a dedicated gRPC service that owns git operations, so web/API instances are stateless. ## Proposed Architecture ``` Ingress ┌───────────────────────┼───────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────┐ ┌───────────┐ ┌───────────┐ │ IRIS │ │ Git SSH │ │ Git HTTP │ │ (WASM) │ │ Gateway │ │ Gateway │ └────┬────┘ └─────┬─────┘ └─────┬─────┘ │ │ gRPC │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────┐ │ Git Server Domain │ │ │ │ Aggregates: Projections: │ │ ├── Repository ├── repo-list │ │ ├── PullRequest ├── pr-list │ │ ├── User ├── permissions │ │ └── Organization └── ssh-key-lookup │ └─────────────────────────────────────────────────────────┘ │ built on │ ┌─────────────────────────────────────────────────────────┐ │ Aether │ │ git.flowmade.one/flowmade-one/aether │ │ │ │ - Aggregate lifecycle - Cluster primitives │ │ - Event store - Sharding │ │ - Projections framework - Leader election │ └─────────────────────────────────────────────────────────┘ │ powered by │ ┌─────────────────────────────────────────────────────────┐ │ NATS JetStream │ │ (implementation detail managed by Aether) │ └─────────────────────────────────────────────────────────┘ Separate concern: ┌─────────────────────────────────────────────────────────┐ │ Git Storage Service (StatefulSet) │ │ - gRPC API wrapping git operations │ │ - Sharded by consistent hashing │ │ - Local SSD or hcloud-volumes per shard │ └─────────────────────────────────────────────────────────┘ CI/CD: ┌─────────────────────────────────────────────────────────┐ │ Action Runners │ │ - KEDA ScaledJob based on NATS queue depth │ │ - Pull jobs from NATS, stream logs back │ └─────────────────────────────────────────────────────────┘ ``` ## Bounded Contexts Following DDD patterns, the git server has these contexts: | Context | Aggregates | Responsibility | |---------|------------|----------------| | **Repository** | Repository, Branch, Commit | Git storage, branches, commits, files | | **Collaboration** | PullRequest, Review, Comment | PRs, reviews, discussions | | **Identity** | User, Organization, SSHKey | Users, orgs, permissions, keys | | **CI/CD** | Pipeline, Job, Artifact | Runners, jobs, logs, artifacts | Each context owns its aggregates and publishes events for cross-context communication. ## Key Design Decisions ### 1. Built on Aether The git server is an **Aether application**. Domain logic uses Aether's primitives: ```go type Repository struct { aether.AggregateBase Name string Owner string Visibility Visibility } func (r *Repository) HandleCommand(cmd aether.Command) ([]aether.Event, error) { switch c := cmd.(type) { case *CreateRepository: return []aether.Event{&RepositoryCreated{...}}, nil } } func (r *Repository) ApplyEvent(evt aether.Event) { switch e := evt.(type) { case *RepositoryCreated: r.Name = e.Name } } ``` This proves Aether works in a real application before betting the low-code platform on it. ### 2. NATS as Infrastructure (via Aether) NATS is an implementation detail managed by Aether, not a direct dependency: - Event store (JetStream streams) - Read models (KV buckets) - Service communication - Job queues for CI - Real-time pub/sub to UI ### 3. IRIS for Frontend WASM-based UI with reactive signals. WebSocket connection for real-time updates. ### 4. Kubernetes-Native Deployment ```bash helm install gitserver flowmade/gitserver \ --set domain=git.company.com \ --set auth.oidc.issuer=https://dex.company.com ``` ## Components to Build | Component | Effort | Notes | |-----------|--------|-------| | Domain model | Low | Go structs, Aether aggregates | | Git Storage Service | Medium-High | gRPC wrapper around git | | SSH Gateway | Medium | Auth + route to storage | | HTTP Git Gateway | Low | Standard smart protocol | | IRIS UI | High | File browser, PR view, diff, etc. | | Runner integration | Medium | NATS queue + KEDA | **Already available:** - Aether (`git.flowmade.one/flowmade-one/aether`) - ES runtime - IRIS (`git.flowmade.one/flowmade-one/iris`) - UI framework ## Open Questions ### Naming - Need a name recognizable as a git server - Need available domain - Options: Gitquay, Githarbor, Gitkeep, Gitledger, etc. - Should it be under Flowmade One brand or separate identity? ### Positioning - Is Flowmade One the product name or company with separate products? - Git server as part of "One platform" vs separate product? - Cloud version: git.flowmade.one? Separate domain? ### Strategy - Open-source to build awareness for Flowmade One low-code SaaS - Self-hosted option + cloud offering (open core model) - Use git.flowmade.one (Gitea) as source of truth during development - Eventually dogfood by self-hosting ## Related - Aether: `git.flowmade.one/flowmade-one/aether` - IRIS: `git.flowmade.one/flowmade-one/iris` - Current Gitea setup on git.flowmade.one - NATS infrastructure already deployed - KEDA already in cluster for runner scaling --- *This issue captures a discussion about building a Kubernetes-native git server.*
Author
Owner

Additional Context

Manifesto Alignment

This proposal now aligns with a core belief added to the manifesto:

Resource Efficiency

  • Software should run well on modest hardware
  • Cloud cost and energy consumption matter
  • ARM64-native where possible - better performance per watt
  • Bloated software is a sign of poor engineering, not rich features

GitLab fails this principle. Gitea fails on scalability. Building our own solves both.

Specific Pain Points with Gitea/Forgejo

  1. Forgejo CLI gaps - No action runner support in CLI, had to switch to Gitea
  2. Gitea CLI gaps - Had to fork and maintain tea to add runner features
  3. HA doesn't work - RWX shared filesystem (Longhorn) kills performance due to git's file access patterns (~233 file opens per README render)
  4. GitLab solved it but too heavy - Gitaly is the right architecture, but GitLab's resource appetite is a disqualifier

Reframed Purpose

This isn't just "build a git server" - it's:

  1. Prove the stack - Validate ES primitives, NATS-only, IRIS in a real application before betting the low-code platform on them
  2. Scratch our own itch - Real pain that isn't going away
  3. Live our values - Resource-efficient, ARM64-native, K8s-native
## Additional Context ### Manifesto Alignment This proposal now aligns with a core belief added to the manifesto: **Resource Efficiency** - Software should run well on modest hardware - Cloud cost and energy consumption matter - ARM64-native where possible - better performance per watt - Bloated software is a sign of poor engineering, not rich features GitLab fails this principle. Gitea fails on scalability. Building our own solves both. ### Specific Pain Points with Gitea/Forgejo 1. **Forgejo CLI gaps** - No action runner support in CLI, had to switch to Gitea 2. **Gitea CLI gaps** - Had to fork and maintain tea to add runner features 3. **HA doesn't work** - RWX shared filesystem (Longhorn) kills performance due to git's file access patterns (~233 file opens per README render) 4. **GitLab solved it but too heavy** - Gitaly is the right architecture, but GitLab's resource appetite is a disqualifier ### Reframed Purpose This isn't just "build a git server" - it's: 1. **Prove the stack** - Validate ES primitives, NATS-only, IRIS in a real application before betting the low-code platform on them 2. **Scratch our own itch** - Real pain that isn't going away 3. **Live our values** - Resource-efficient, ARM64-native, K8s-native
Author
Owner

Update: Monorepo Split Complete

The split discussed in this issue has been completed via #54. Here's what was done:

Created external repos (Apache 2.0):

  • git.flowmade.one/flowmade-one/iris - WASM reactive UI framework
  • git.flowmade.one/flowmade-one/aether - Distributed actor/ES primitives (was proposed as 'eskit')

Aether includes:

  • Event/EventStore interfaces
  • Memory and JetStream store implementations
  • NATS event bus
  • Cluster primitives (consistent hashing, leader election, sharding)
  • EventStorming model types

Arcadia (proprietary) keeps:

  • pkg/adl/ - ADL compiler
  • pkg/aether/ - Runtime layer (imports external aether)
  • cmd/server/ - Backend entry point
  • web/designer/ - EventStorming canvas UI

Naming:

  • Used 'aether' instead of 'eskit' for the ES library
  • Renamed internal components for clarity (lyra→designer, aether-backend→server)

The 'Arcadia Monorepo Impact' and 'Potential Repo Split' sections of this issue are now complete. The remaining content about the git server architecture is still relevant if this project moves forward.

## Update: Monorepo Split Complete The split discussed in this issue has been completed via #54. Here's what was done: **Created external repos (Apache 2.0):** - `git.flowmade.one/flowmade-one/iris` - WASM reactive UI framework - `git.flowmade.one/flowmade-one/aether` - Distributed actor/ES primitives (was proposed as 'eskit') **Aether includes:** - Event/EventStore interfaces - Memory and JetStream store implementations - NATS event bus - Cluster primitives (consistent hashing, leader election, sharding) - EventStorming model types **Arcadia (proprietary) keeps:** - `pkg/adl/` - ADL compiler - `pkg/aether/` - Runtime layer (imports external aether) - `cmd/server/` - Backend entry point - `web/designer/` - EventStorming canvas UI **Naming:** - Used 'aether' instead of 'eskit' for the ES library - Renamed internal components for clarity (lyra→designer, aether-backend→server) The 'Arcadia Monorepo Impact' and 'Potential Repo Split' sections of this issue are now complete. The remaining content about the git server architecture is still relevant if this project moves forward.
Author
Owner

Architecture Alignment Update

The architecture repository now documents our beliefs and patterns in software-architecture.md. This proposal aligns well with our organizational approach:

Beliefs → Patterns → This Proposal

Belief Pattern How This Proposal Applies
Auditability by default Event Sourcing Full event-sourced domain: RepositoryCreated, PullRequestOpened, etc. Complete history for every repo and PR.
Business language in code Domain-Driven Design Aggregates map to git concepts: Repository, PullRequest, User, Organization. Ubiquitous language shared with users.
Independent evolution Event-driven communication NATS pub/sub enables real-time UI updates and CI runners without coupling. New features subscribe to existing events.
Explicit over implicit Commands and Events Clear separation: CreateRepository (command) → RepositoryCreated (event). Intent and outcome are distinct.

Bounded Contexts (Proposed)

Following DDD patterns, the git server could have these contexts:

  • Repository - git storage, branches, commits, files
  • Collaboration - pull requests, reviews, comments
  • Identity - users, organizations, SSH keys, permissions
  • CI/CD - runners, jobs, logs, artifacts

Each context owns its aggregates and publishes events for cross-context communication.

Reference

See software-architecture.md for full pattern documentation and manifesto.md for the underlying beliefs.

## Architecture Alignment Update The architecture repository now documents our beliefs and patterns in `software-architecture.md`. This proposal aligns well with our organizational approach: ### Beliefs → Patterns → This Proposal | Belief | Pattern | How This Proposal Applies | |--------|---------|---------------------------| | Auditability by default | Event Sourcing | Full event-sourced domain: `RepositoryCreated`, `PullRequestOpened`, etc. Complete history for every repo and PR. | | Business language in code | Domain-Driven Design | Aggregates map to git concepts: `Repository`, `PullRequest`, `User`, `Organization`. Ubiquitous language shared with users. | | Independent evolution | Event-driven communication | NATS pub/sub enables real-time UI updates and CI runners without coupling. New features subscribe to existing events. | | Explicit over implicit | Commands and Events | Clear separation: `CreateRepository` (command) → `RepositoryCreated` (event). Intent and outcome are distinct. | ### Bounded Contexts (Proposed) Following DDD patterns, the git server could have these contexts: - **Repository** - git storage, branches, commits, files - **Collaboration** - pull requests, reviews, comments - **Identity** - users, organizations, SSH keys, permissions - **CI/CD** - runners, jobs, logs, artifacts Each context owns its aggregates and publishes events for cross-context communication. ### Reference See [software-architecture.md](./software-architecture.md) for full pattern documentation and [manifesto.md](./manifesto.md#architecture-beliefs) for the underlying beliefs.
Author
Owner

Clarification: Built on Aether

The git server should be built on Aether, not extract primitives from it or use NATS directly.

Since the monorepo split (#54), Aether exists as git.flowmade.one/flowmade-one/aether with:

  • Event/EventStore interfaces
  • JetStream store implementation
  • Cluster primitives (consistent hashing, leader election, sharding)
  • NATS event bus

Updated Architecture View

┌─────────────────────────────────────────────────────────┐
│                   Git Server Domain                      │
│                                                          │
│  Aggregates:              Projections:                  │
│  ├── Repository           ├── repo-list                 │
│  ├── PullRequest          ├── pr-list                   │
│  ├── User                 ├── permissions               │
│  └── Organization         └── ssh-key-lookup            │
└─────────────────────────────────────────────────────────┘
                          │
                    built on
                          │
┌─────────────────────────────────────────────────────────┐
│                       Aether                             │
│                                                          │
│  - Aggregate lifecycle     - Cluster primitives         │
│  - Event store             - Sharding                   │
│  - Projections framework   - Leader election            │
└─────────────────────────────────────────────────────────┘
                          │
                    powered by
                          │
┌─────────────────────────────────────────────────────────┐
│                   NATS JetStream                         │
└─────────────────────────────────────────────────────────┘

NATS becomes an implementation detail that Aether manages. The git server is an Aether application with domain-specific aggregates and projections.

This also fulfills the stated goal of "proving the stack" - real usage of Aether reveals API gaps before betting the low-code platform on it.

## Clarification: Built on Aether The git server should be **built on Aether**, not extract primitives from it or use NATS directly. Since the monorepo split (#54), Aether exists as `git.flowmade.one/flowmade-one/aether` with: - Event/EventStore interfaces - JetStream store implementation - Cluster primitives (consistent hashing, leader election, sharding) - NATS event bus ### Updated Architecture View ``` ┌─────────────────────────────────────────────────────────┐ │ Git Server Domain │ │ │ │ Aggregates: Projections: │ │ ├── Repository ├── repo-list │ │ ├── PullRequest ├── pr-list │ │ ├── User ├── permissions │ │ └── Organization └── ssh-key-lookup │ └─────────────────────────────────────────────────────────┘ │ built on │ ┌─────────────────────────────────────────────────────────┐ │ Aether │ │ │ │ - Aggregate lifecycle - Cluster primitives │ │ - Event store - Sharding │ │ - Projections framework - Leader election │ └─────────────────────────────────────────────────────────┘ │ powered by │ ┌─────────────────────────────────────────────────────────┐ │ NATS JetStream │ └─────────────────────────────────────────────────────────┘ ``` NATS becomes an implementation detail that Aether manages. The git server is an **Aether application** with domain-specific aggregates and projections. This also fulfills the stated goal of "proving the stack" - real usage of Aether reveals API gaps before betting the low-code platform on it.
Author
Owner

Proposal has been turned into a dedicated repository: https://git.flowmade.one/flowmade-one/arbor

The vision and initial structure have been established. Work will continue in that repo.

Proposal has been turned into a dedicated repository: https://git.flowmade.one/flowmade-one/arbor The vision and initial structure have been established. Work will continue in that repo.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: flowmade-one/architecture#53