generated from coulomb/repo-seed
Reorganize documentation into canonical repository layout
Adopt CoulombSocial/HelixForge/MarkiTect documentation structure: - research/260608-yawex-prior-art/ — yawex exploration and sources - demand/ — inbound NetKingdom integration requirements - spec/ — PRD, TSD, UseCaseCatalog, ArchitectureBlueprint scaffolds - docs/ — stakeholder documentation and repository-layout guide - wiki/, issues/, history/ — scaffolded directories Add SCOPE.md and AGENTS.md. Update workplan paths and README.
This commit is contained in:
14
docs/README.md
Normal file
14
docs/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# docs/
|
||||
|
||||
Stakeholder-facing documentation for users, developers, humans, and agents.
|
||||
|
||||
Rewrite docs when they become wrong or stale — they should reflect what the
|
||||
repo actually does.
|
||||
|
||||
| Document | Audience |
|
||||
|----------|----------|
|
||||
| `repository-layout.md` | All — how documentation is organized in this repo |
|
||||
| `../README.md` | New visitors — project entry point |
|
||||
| `../AGENTS.md` | Agents — working conventions and layout |
|
||||
| `../INTENT.md` | Architects — aspiration and boundaries |
|
||||
| `../SCOPE.md` | Contributors — current achievement and planning |
|
||||
@@ -1,145 +0,0 @@
|
||||
# Architecture blueprint — shard-wiki access & history model
|
||||
|
||||
Status: **draft for review** · Date: 2026-06-08 · Resolves pending decision
|
||||
"Scope of a minimal access model in shard-wiki core".
|
||||
|
||||
This blueprint settles how shard-wiki handles access control and change history. It
|
||||
realizes the INTENT principles *Open by default, progressively governed*, *History as
|
||||
the safety net*, and *Authorization in core, authentication delegated*.
|
||||
|
||||
---
|
||||
|
||||
## 1. The core idea: one core, a ladder of modes
|
||||
|
||||
shard-wiki ships **one** authorization core. What changes between deployments is how much
|
||||
of it is switched on. No re-architecture is needed to climb the ladder — only
|
||||
configuration and the presence (or absence) of an external identity provider.
|
||||
|
||||
This mirrors the NetKingdom **capability-progression ladder** ("capability-driven, not
|
||||
scale-driven"): start lightweight, expand when the need appears.
|
||||
|
||||
| Mode | Identity provider | Who can read/write | External deps | Analogue |
|
||||
|------|------------------|--------------------|---------------|----------|
|
||||
| **L0 — Open (c2)** | none (everyone is `anonymous`) | everyone reads + writes | **none** | Ward Cunningham's original c2 wiki |
|
||||
| **L1 — Attributed** | local/optional | open writes, but edits are attributed when an identity is presented | none | classic "sign your edits" wiki |
|
||||
| **L2 — Authenticated** | user-engine (OIDC via net-kingdom lightweight) | authenticated principals; simple read-all / write-authenticated | user-engine + net-kingdom (OIDC/PKCE) | small team wiki |
|
||||
| **L3 — Role/Group** | user-engine memberships | per-shard/per-namespace roles (reader/author/maintainer) | user-engine groups | departmental wiki |
|
||||
| **L4 — Multi-tenant enterprise** | user-engine + net-kingdom expanded (Keycloak/SAML) | per-tenant isolation, per-page ACL, SSO/MFA, audit | full IAM stack | enterprise-grade |
|
||||
|
||||
**Invariant:** L0 must always be reachable with zero external dependencies. Access control
|
||||
is *additive*; removing the identity provider degrades gracefully back down the ladder, it
|
||||
never bricks the wiki.
|
||||
|
||||
---
|
||||
|
||||
## 2. Why history is the floor, not access control
|
||||
|
||||
In L0 the wiki trusts every writer. The protection against accidental loss, vandalism, or
|
||||
mistakes is therefore **not** gatekeeping but **complete, recoverable history**:
|
||||
|
||||
- Every write is a Git commit on the information space's coordination layer (per INTENT's
|
||||
Git-addressable coordination principle).
|
||||
- Any revision of any page is restorable; deletion is a commit, never destruction.
|
||||
- History exists identically in **all** modes — L4's access control *hardens* the wiki but
|
||||
the recoverability guarantee is the same one that makes L0 safe to run open.
|
||||
|
||||
This is the inversion of yawex, which gated with htpasswd and kept only a single `page~`
|
||||
backup. We keep the openness, replace the gate with history, and make the gate optional.
|
||||
|
||||
---
|
||||
|
||||
## 3. Component model
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ shard-wiki │
|
||||
request ───► │ ┌────────────┐ ┌──────────────────────┐ │
|
||||
(principal?) │ │ Policy │ │ Authorization core │ │
|
||||
│ │ Enforcement├──►│ (PDP): capability │ │
|
||||
│ │ Point (PEP)│ │ decisions per │ │
|
||||
│ └─────┬───────┘ │ page / shard / tenant│ │
|
||||
│ │ └──────────┬───────────┘ │
|
||||
│ ▼ │ │
|
||||
│ ┌────────────┐ ┌──────▼───────────┐ │
|
||||
│ │ Shard │ │ IdentityProvider │ │
|
||||
│ │ adapters │ │ (interface) │ │
|
||||
│ │ (+capability│ └──────┬───────────┘ │
|
||||
│ │ profile) │ │ │
|
||||
│ └─────┬───────┘ │ │
|
||||
│ ▼ │ │
|
||||
│ Git-backed coordination journal │ │
|
||||
└──────────────────────────────────┼─────────────┘
|
||||
│ (L2+ only)
|
||||
┌────────────────────────▼───────────────────┐
|
||||
│ user-engine (accounts, memberships, │
|
||||
│ profiles, audit, events) │
|
||||
│ backed by net-kingdom IAM │
|
||||
│ (OIDC/PKCE lightweight · Keycloak/SAML exp) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Owned by shard-wiki core:**
|
||||
- **Principal** — a resolved actor: `anonymous`, or an identity token + claims from the
|
||||
provider. Core never stores credentials.
|
||||
- **IdentityProvider interface** — a thin pluggable contract. The **null provider**
|
||||
(everyone = `anonymous`) is the L0 default and ships in-core.
|
||||
- **Authorization core (PDP)** — pure capability decisions: given (principal, action,
|
||||
target page/shard/tenant), return allow/deny. Actions: `read, write, patch, merge,
|
||||
administer`. Layered on each adapter's **capability profile** (a shard that can't write
|
||||
can't be written regardless of policy).
|
||||
- **Policy Enforcement Point (PEP)** — wraps every adapter operation; calls the PDP.
|
||||
- **Tenant boundary** — a *root entity* is the unit of multi-tenancy. Shards attach to a
|
||||
root; an L4 tenant maps to a root entity (or a set of them).
|
||||
- **Change history** — Git commits on the coordination journal; the recovery substrate.
|
||||
|
||||
**Delegated to the identity provider (L2+):**
|
||||
- Authentication (who you are) — net-kingdom IAM (OIDC/PKCE → Keycloak/SAML).
|
||||
- Identity lifecycle, user directory, credentials, secrets — net-kingdom / user-engine.
|
||||
- Memberships, groups, profiles, org structure, audit sink — user-engine.
|
||||
|
||||
---
|
||||
|
||||
## 4. Request flow (L4, fully governed)
|
||||
|
||||
1. Caller presents an OIDC token (issued by net-kingdom IAM) to shard-wiki.
|
||||
2. The configured **IdentityProvider** validates the token and resolves a **Principal**
|
||||
(subject + tenant + group/role claims), enriching via **user-engine** memberships.
|
||||
3. The **PEP** intercepts the requested action on a target page/shard.
|
||||
4. The **PDP** decides using: tenant isolation → shard role bindings → optional per-page
|
||||
ACL → adapter capability profile.
|
||||
5. On allow, the adapter performs the op; the write lands as a **Git commit** and an
|
||||
**audit event** is emitted to user-engine.
|
||||
6. On deny, the op is refused; nothing mutates.
|
||||
|
||||
**The same code path at L0:** step 1 is skipped, the null provider returns `anonymous`,
|
||||
the PDP's open policy allows read+write, the write still lands as a Git commit. History is
|
||||
identical; only the gate differs.
|
||||
|
||||
---
|
||||
|
||||
## 5. Design rules
|
||||
|
||||
- **Fail open only at L0, fail closed at L2+.** The mode is explicit configuration, never
|
||||
inferred from whether the provider happens to be reachable (a flaky IAM must not silently
|
||||
open an enterprise wiki). If an L2+ deployment loses its provider, it denies, it does not
|
||||
fall back to open.
|
||||
- **Authorization is pure and offline-capable.** Once a Principal is resolved, decisions
|
||||
need no network call — role/ACL data is carried on the Principal or cached, so a federated
|
||||
read of a projected page doesn't require a live IAM round-trip per page.
|
||||
- **Per-page ACL is opt-in (L4).** Default scoping is per-shard / per-namespace (L3). Per-page
|
||||
ACL is supported but off by default to avoid yawex's per-directory `AccessControl` sprawl.
|
||||
- **Provenance carries authorization context.** A federated page records not just its source
|
||||
shard and freshness but the authorization context under which it was read, so the union
|
||||
view never leaks content a principal couldn't see at source.
|
||||
|
||||
---
|
||||
|
||||
## 6. Open questions (carry into requirements)
|
||||
|
||||
1. Token format/claims contract with net-kingdom (OIDC scopes, tenant claim name).
|
||||
2. user-engine membership/role query shape and caching/TTL.
|
||||
3. Audit event schema shard-wiki emits to user-engine.
|
||||
4. How tenant ↔ root-entity mapping is configured and discovered.
|
||||
5. Whether L1 "attributed but open" is worth shipping or we jump L0 → L2.
|
||||
|
||||
See `requirements-user-engine-netkingdom.md` for the concrete asks these imply.
|
||||
58
docs/repository-layout.md
Normal file
58
docs/repository-layout.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Repository documentation layout
|
||||
|
||||
This repository follows the CoulombSocial / HelixForge / MarkiTect documentation
|
||||
layout. It is a **recommendation** for efficient information retrieval, not a
|
||||
strict law.
|
||||
|
||||
## Operating model
|
||||
|
||||
- `INTENT.md` captures aspiration and boundaries.
|
||||
- `SCOPE.md` captures a top-level view of what we achieve.
|
||||
- Work closes the gap from SCOPE to INTENT while learning and refining both.
|
||||
|
||||
## Directories
|
||||
|
||||
### `research/`
|
||||
|
||||
Exploration results in the problem and solution space. Use a `yymmdd-` prefix
|
||||
on markdown files or subdirectories when multiple files or sources are involved.
|
||||
|
||||
### `demand/`
|
||||
|
||||
Inbound feature requests, requirements, and suggestions not yet reviewed into
|
||||
`spec/` or `workplans/`. Raw material — needs scrutiny before implementation.
|
||||
|
||||
### `spec/`
|
||||
|
||||
Implementation guardrails. Typical files:
|
||||
|
||||
- `ProductRequirementsDocument.md`
|
||||
- `TechnicalSpecificationDocument.md`
|
||||
- `UseCaseCatalog.md`
|
||||
- `ArchitectureBlueprint.md`
|
||||
|
||||
Background: InfoTechPrimers on coulomb.social.
|
||||
|
||||
### `workplans/`
|
||||
|
||||
State Hub–registered workplans with implementation tasks. Finished or canceled
|
||||
workplans move to `history/` with a `yymmdd-` archive prefix.
|
||||
|
||||
### `docs/`
|
||||
|
||||
Stakeholder documentation (this directory).
|
||||
|
||||
### `wiki/`
|
||||
|
||||
Interconnected collective knowledge without a single perspective. Powerful when
|
||||
connected to a wiki UI for creators, users, and investors.
|
||||
|
||||
### `issues/`
|
||||
|
||||
Optional mirror of relevant open tickets from customer support, dev-sec-ops, or
|
||||
other ticket systems.
|
||||
|
||||
### `history/`
|
||||
|
||||
Archived material no longer needed for daily work. Use `yymmdd-` prefixes.
|
||||
Consult only for research or diagnostics.
|
||||
@@ -1,103 +0,0 @@
|
||||
# Requirements seed — review of yawex prior art
|
||||
|
||||
Source: `history/priorart/yawex-0.7.4/` — a filesystem-backed CGI/Perl wiki engine
|
||||
(2004–2005, "Yet Another Wiki engine eXtended"). This document distills that prior
|
||||
art into requirements for `shard-wiki`, the Markdown-first, Git-backed wiki
|
||||
**federation/orchestration layer** described in `INTENT.md`.
|
||||
|
||||
Each item is tagged **KEEP** (adopt the idea), **TRANSFORM** (keep the intent, change
|
||||
the mechanism), or **DROP** (engine/era artifact or INTENT non-goal). Decisions below
|
||||
reflect a review discussion on 2026-06-08.
|
||||
|
||||
---
|
||||
|
||||
## Orientation: what yawex was
|
||||
|
||||
- Pages = plain files on disk. **Topics = directories.** A topic's "gateway" page
|
||||
shares the directory name (`SubContext/SubContext`).
|
||||
- One CGI/Perl binary did everything: routing, page resolution, markup rendering,
|
||||
auth, templating, storage.
|
||||
- The most-developed and most-tested component is **`PageLookUp`** — a context-relative
|
||||
page-resolution state machine. It is the part most worth mining.
|
||||
|
||||
---
|
||||
|
||||
## KEEP — ideas that prefigure federation
|
||||
|
||||
- **Page-resolution state space.** yawex resolved a requested name from a current page
|
||||
through ordered states: `LOCAL, CLIMB, DROP, GLOBAL, REMOTE, SWITCH, JUMP, VIRTUAL,
|
||||
FAILED`. Two states foreshadow federation directly:
|
||||
- `REMOTE` — "jump to pages in a remote wiki" → a **remote shard**.
|
||||
- `VIRTUAL` — "process locally but get content elsewhere" → a **projection / cache**.
|
||||
- **Decision (2026-06-08): _inspiration only_.** Do NOT inherit yawex's structure as
|
||||
the resolve contract. Design shard-wiki resolution fresh for the federation case;
|
||||
treat these states as prior art and a checklist of cases the new resolver must
|
||||
handle, not as the interface.
|
||||
- **Topic = namespace hierarchy** with relative (`../`) and absolute (`/`) paths, plus
|
||||
path normalization. Becomes the union path/namespace model across shards.
|
||||
- **Page classes (local / global / virtual).** Map to **shard roles**
|
||||
(canonical / cross-cutting / projected-computed).
|
||||
- **Derived/computed views**: BackLinks, RecentChanges, AllPages, SiteMap, full-text
|
||||
Search. Natural **union-level views** over the federated page graph; BackLinks
|
||||
(link-graph) is squarely shard-wiki's concern.
|
||||
- **Provenance hooks.** `Page::info` exposed modtime and TODO'd last-editor/hits/edits.
|
||||
Serves INTENT's explicit-provenance-and-freshness principle.
|
||||
- **Blueprint pages** — create-from-template, duplicating topic structure. A
|
||||
page/topic templating primitive.
|
||||
- **Append/comment workflow** — add to a page without a full edit. Maps to the
|
||||
**overlay / lightweight-patch** model for shards you don't fully own.
|
||||
- **Multi-wiki config** (`Conf::TestWiki / FriendsWiki / ManusysWiki`). Literally
|
||||
multiple distinct wikis with their own storage/identity = **multiple shards/roots**.
|
||||
|
||||
## TRANSFORM — keep intent, change mechanism
|
||||
|
||||
- **Markup → CommonMark + extension.** yawex had CamelCase WikiLinks, `[[free links]]`,
|
||||
red-`?` links for nonexistent pages, `::` labels, `**bold**`. Keep the *semantics*
|
||||
(auto-link, link-to-nonexistent) as a wikilink/red-link Markdown extension; drop the
|
||||
bespoke syntax. INTENT mandates Markdown-first.
|
||||
- **Backup-on-write → Git history.** The `page~` rename hack becomes Git commits. Keep
|
||||
the recoverability intent.
|
||||
- **Render pipeline → mostly out of scope.** The chunk+line renderer is engine/UI work.
|
||||
Keep only the **link-resolution / normalization** slice that federation needs.
|
||||
|
||||
## DROP — engine/era artifacts and non-goals
|
||||
|
||||
- CGI/Perl runtime, Makefile install, `eval("action_$x")`, shell-outs (`rm`, `htpasswd`,
|
||||
`echo >`), `umask 0000`, `fatalsToBrowser` — implementation and security debt.
|
||||
- JS editor toolbar / textarea editor — UI layer; INTENT decouples UI from storage.
|
||||
- Form chunks (`Formular` + KEY= data store) and Blog chunks — app-specific page
|
||||
semantics that INTENT says core must not own.
|
||||
|
||||
---
|
||||
|
||||
## Contested decision: a minimal access model IN CORE
|
||||
|
||||
yawex coupled identity and permissions into the engine: Apache/htpasswd auth, a members
|
||||
file, self-registration with auto-created user pages, and per-topic `AccessControl` files
|
||||
with levels `denied / view / form / edit / admin`.
|
||||
|
||||
INTENT.md currently lists this as a **non-goal**: *"Solve organizational permissions,
|
||||
identity management, or secret storage by itself."*
|
||||
|
||||
**Decision (2026-06-08): shard-wiki WILL own _some_ auth in core** — a deliberate
|
||||
revision of that non-goal. Proposed tight scope so it doesn't become an identity system:
|
||||
|
||||
- **In scope:** a thin, pluggable **authorization gate** expressed as capabilities —
|
||||
who may read / write / patch / merge a given page or shard — layered on top of the
|
||||
per-adapter capability model (read/write/diff/merge/lock/publish).
|
||||
- **Out of scope (still):** credential storage, organizational identity management, user
|
||||
directories. Identity is supplied by a pluggable provider; shard-wiki authorizes, it
|
||||
does not authenticate-from-scratch or store secrets.
|
||||
|
||||
> ⚠️ **This revises an INTENT non-goal and therefore needs an INTENT amendment plus a
|
||||
> ratified decision** (per INTENT's Stability Note, redefining scope is an architectural
|
||||
> change). Tracked as an open decision; do not treat the access model as settled until
|
||||
> INTENT is updated.
|
||||
|
||||
---
|
||||
|
||||
## Open questions for the next pass
|
||||
|
||||
1. Exact boundary of "some auth in core" — is per-page ACL in scope, or only per-shard?
|
||||
2. Does the wikilink/red-link extension belong in shard-wiki core, or in a reference UI?
|
||||
3. Which derived views (BackLinks / RecentChanges / Search) are core vs. adapter-provided?
|
||||
@@ -1,88 +0,0 @@
|
||||
# Requirements — what shard-wiki needs from user-engine & net-kingdom
|
||||
|
||||
Status: **draft for review** · Date: 2026-06-08
|
||||
|
||||
Derived from `access-model-blueprint.md`. These are the integration contracts shard-wiki
|
||||
needs to climb from L0 (open, standalone) to L4 (multi-tenant enterprise) **without
|
||||
changing its core**. They are requirements *on* the NetKingdom domain repos, to be
|
||||
negotiated with their owners — not assumptions about their current implementation.
|
||||
|
||||
Reference deployment roles:
|
||||
- **net-kingdom** — IAM/SSO backend. Issues and validates identities. OIDC/PKCE in
|
||||
lightweight mode (KeyCape: Authelia + LLDAP + privacyIDEA), Keycloak/SAML in expanded
|
||||
mode. Owns authentication, credentials, MFA, the NetKingdom IAM Profile.
|
||||
- **user-engine** — headless user-domain service: accounts, memberships, profiles,
|
||||
catalogs, projections, audit, events. Owns the *membership/role/tenant* read model
|
||||
shard-wiki authorizes against.
|
||||
|
||||
shard-wiki authorizes; it never authenticates or stores identity. Everything below is a
|
||||
**read or emit** contract — shard-wiki must not need write access to identity data.
|
||||
|
||||
---
|
||||
|
||||
## A. From net-kingdom (authentication / IAM)
|
||||
|
||||
1. **Token issuance & validation (OIDC/PKCE).** A standard OIDC relationship shard-wiki can
|
||||
register as a confidential or public client; ability to validate presented access/ID
|
||||
tokens (JWKS endpoint or introspection). Lightweight mode must work without Keycloak.
|
||||
2. **Stable subject identifier.** A durable `sub` that does not change across renames/email
|
||||
changes, usable as the Principal key.
|
||||
3. **Tenant claim.** A claim that identifies the tenant/organization a token is scoped to
|
||||
(claim name TBD), so shard-wiki can map token → tenant → root entity.
|
||||
4. **Group/role claims (optional fast path).** If groups/roles can ride in the token, L3/L4
|
||||
decisions need no extra round-trip. Otherwise shard-wiki resolves them via user-engine (B).
|
||||
5. **Expanded-mode parity.** The same claim contract must hold when the backend is swapped
|
||||
to Keycloak/SAML, so climbing L3→L4 is a deployment change, not a shard-wiki change.
|
||||
6. **Logout / token revocation signal** so shard-wiki can drop cached Principals.
|
||||
|
||||
## B. From user-engine (membership / authorization read model)
|
||||
|
||||
1. **Resolve principal → memberships.** Given a `sub` (and tenant), return the principal's
|
||||
group/role memberships relevant to wiki access. Read-only, low-latency, cacheable with a
|
||||
stated TTL.
|
||||
2. **Tenant ↔ root-entity mapping.** A way to resolve which tenant(s) a principal belongs to
|
||||
and how those map to shard-wiki root entities. Either user-engine owns this mapping or it
|
||||
exposes the primitives for shard-wiki to hold it as config.
|
||||
3. **Role vocabulary.** An agreed, minimal role set that maps onto shard-wiki actions:
|
||||
`reader → read`, `author → read+write+patch`, `maintainer → +merge+administer`. Custom
|
||||
roles allowed but must declare which actions they grant.
|
||||
4. **Profile lookup for attribution.** Given a `sub`, return display name / handle so edits
|
||||
and signatures are attributable (the L1 "sign your edits" need, generalized).
|
||||
5. **Stable, versioned read API.** A versioned contract (REST/gRPC) for B1–B4 so shard-wiki
|
||||
isn't coupled to user-engine internals; INTENT requires stable adapter contracts.
|
||||
6. **Bulk/batch resolution.** Resolving memberships for many principals (e.g. rendering a
|
||||
BackLinks/history view) must not be N+1; provide batch lookup.
|
||||
|
||||
## C. Audit / events (shard-wiki → user-engine)
|
||||
|
||||
1. **Audit event sink.** shard-wiki emits access-relevant events (page read-denied,
|
||||
write, patch, merge, admin change) to user-engine's audit/event stream. Need the
|
||||
**event schema** and transport (user-engine already lists "audit" and "events" as owned
|
||||
concerns — align to that).
|
||||
2. **Non-blocking emission.** Audit emission must be async/best-effort so an audit outage
|
||||
never blocks a wiki write (history in Git remains the source of truth regardless).
|
||||
|
||||
## D. Cross-cutting / non-functional
|
||||
|
||||
1. **Graceful degradation contract.** A defined behavior when the provider is unreachable in
|
||||
L2+: shard-wiki **fails closed** (denies), and must be able to distinguish "provider down"
|
||||
from "principal unauthorized" for operability. (L0/L1 never depend on the provider.)
|
||||
2. **No secret custody in shard-wiki.** Client secrets / keys are provisioned and rotated by
|
||||
net-kingdom; shard-wiki consumes them via the deployment's secret mechanism, never stores
|
||||
or commits them. (Consistent with INTENT non-goal on secret storage.)
|
||||
3. **Offline authorization.** After Principal resolution, decisions must be computable without
|
||||
per-page network calls (carry claims on the Principal or cache memberships).
|
||||
4. **Capability-progression alignment.** The integration should slot into NetKingdom's
|
||||
C0–C6 ladder so shard-wiki's L0–L4 modes correspond to recognizable NetKingdom capability
|
||||
levels rather than introducing a parallel scheme.
|
||||
|
||||
---
|
||||
|
||||
## Next actions
|
||||
|
||||
- [ ] Send this as a **capability request / interface negotiation** to the netkingdom domain
|
||||
(user-engine + net-kingdom owners) via the state hub.
|
||||
- [ ] Lock the **token claim contract** (A2–A4) and the **membership read API** (B1–B5) first
|
||||
— they gate everything L2+.
|
||||
- [ ] Define shard-wiki's **audit event schema** (C1) against user-engine's existing audit model.
|
||||
- [ ] Resolve blueprint open questions §6 once the above are answered.
|
||||
Reference in New Issue
Block a user