Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
0d4ef9a
Add documentation for agents, architecture, authentication, database …
billalxcode Jul 15, 2026
746315c
Implement JWT token management with access and refresh tokens, add to…
billalxcode Jul 15, 2026
b01bdb6
Implement repository management with creation functionality, validati…
billalxcode Jul 15, 2026
c038933
feat(migrations): add repositories table migration scripts
billalxcode Jul 15, 2026
c4d0bbf
feat(migrations): add user credentials tables for SSH keys and person…
billalxcode Jul 16, 2026
d60b445
feat(user): implement user management with SSH keys and personal acce…
billalxcode Jul 16, 2026
2a1c90f
feat(routes): update AuthMiddleware to accept database transaction
billalxcode Jul 16, 2026
bcebfe7
feat(middlewares): enhance AuthMiddleware to validate credentials wit…
billalxcode Jul 16, 2026
ee676d7
feat(services): update authorization logic to use authenticated usern…
billalxcode Jul 16, 2026
8f44a8d
feat(services): implement permission checks for repository access in …
billalxcode Jul 16, 2026
b73686f
fix(helper): correct hash generation in GenerateRepositoryPath function
billalxcode Jul 16, 2026
65fe899
docs(repo.go): remove redundant comments from RepositoryResponse stru…
billalxcode Jul 16, 2026
68c1968
refactor(db): drop physical_path column and unique constraint from re…
billalxcode Jul 16, 2026
0d0033f
refactor(githttp): derive repository storage path from repo ID instea…
billalxcode Jul 16, 2026
fbdecf8
refactor(repo): remove physical_path column and related methods, deri…
billalxcode Jul 16, 2026
9fc04f0
feat(migrations): add user roles and repository members tables with c…
billalxcode Jul 16, 2026
b74f2bb
feat(rbac): implement role-based access control middleware and tests
billalxcode Jul 16, 2026
6cfb667
feat(rbac): implement EvaluatePolicy function and related tests for r…
billalxcode Jul 16, 2026
41641aa
feat(rbac): add role and policy models with associated methods and tests
billalxcode Jul 16, 2026
3aad0e9
feat(rbac): add PolicyRepository and RepoMemberRepository implementat…
billalxcode Jul 16, 2026
55422c5
feat(rbac): refactor AuthMiddleware to enhance authentication logic a…
billalxcode Jul 16, 2026
5a18117
feat(rbac): refactor permission checks to use context and add integra…
billalxcode Jul 16, 2026
4b6868a
set default log level to info
billalxcode Jul 19, 2026
de10596
feat(rbac): implement RequestID middleware for trace logging and add …
billalxcode Jul 19, 2026
4a99915
feat(rbac): enhance logging in AuthMiddleware and authorizeRepo for b…
billalxcode Jul 19, 2026
cb13993
feat(rbac): enhance logging in info-refs, permission, and receive-pac…
billalxcode Jul 19, 2026
9927592
feat(rbac): add logging to UploadPack method for better traceability
billalxcode Jul 19, 2026
fe48acb
feat(rbac): add log_level configuration to gitxyz.yaml for improved l…
billalxcode Jul 19, 2026
d4a4567
feat(rbac): update .gitignore to include docs/superpowers and gitxyz …
billalxcode Jul 19, 2026
6268b33
feat(rbac): implement repository management and policy handling in Re…
billalxcode Jul 19, 2026
4402121
feat(rbac): add collaborator and policy management routes in RepoCont…
billalxcode Jul 19, 2026
bec0400
feat(rbac): enhance RepoService with repository and collaborator mana…
billalxcode Jul 19, 2026
b8f7c2c
feat(rbac): add repository role constants and validation functions; e…
billalxcode Jul 19, 2026
ac97d50
feat(rbac): implement UploadPack method in GitHTTPController and upda…
billalxcode Jul 19, 2026
9355596
feat(rbac): implement UploadPack method in GitHTTPController with err…
billalxcode Jul 19, 2026
e0aca95
Merge pull request #1 from billalxcode/feat/rbac
billalxcode Jul 19, 2026
3e83655
feat(repo): implement repository listing and branch management endpoi…
billalxcode Jul 19, 2026
dd919de
fix(permission): update user ID context key for read/write permission…
billalxcode Jul 19, 2026
98d94a5
Merge pull request #2 from billalxcode/feat/repo-api
billalxcode Jul 19, 2026
bea9bf7
feat(issues): create issues, labels, and related tables with necessar…
billalxcode Jul 19, 2026
a4a3197
feat(issues): implement issue management endpoints and data transfer …
billalxcode Jul 19, 2026
d01a834
feat(issue): add issue and label models with repository interface for…
billalxcode Jul 19, 2026
48df586
feat(auth): enhance user ID resolution in AuthRequired middleware and…
billalxcode Jul 19, 2026
7db3d7c
feat(issues): refactor issue routes for improved organization and rea…
billalxcode Jul 19, 2026
16764cf
Merge pull request #3 from billalxcode/feat/issues-api
billalxcode Jul 20, 2026
8c85183
feat(patches): add migration scripts for patch requests and related t…
billalxcode Jul 20, 2026
d9b4a4b
feat(patch): implement patch controller and DTOs for patch requests
billalxcode Jul 20, 2026
9c3836a
feat: implement patch request management
billalxcode Jul 20, 2026
6cc4be1
feat(patch): enhance response handling with standardized envelope str…
billalxcode Jul 20, 2026
088a7c4
feat(patch): enhance error handling for author and merger validation
billalxcode Jul 20, 2026
b0a61f1
feat(patch): add author existence validation and handle soft-deleted …
billalxcode Jul 20, 2026
ba6d332
feat(patch): enhance patch state validation and reviewer assignment l…
billalxcode Jul 20, 2026
d9a430d
Merge pull request #5 from billalxcode/feat/patch-request-api
billalxcode Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .air.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ tmp_dir = "tmp"
cmd = "go build -o ./tmp/main ."
delay = 1000
entrypoint = ["./tmp/main"]
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_dir = ["assets", "tmp", "vendor", "testdata", ".agents", ".claude", "db"]
exclude_file = ["skills-lock.json"]
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
Expand Down Expand Up @@ -41,6 +41,7 @@ tmp_dir = "tmp"
watcher = "cyan"

[log]
log = "air.log"
main_only = false
silent = false
time = false
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@ volumes
tmp
.idea
./gitxyz
.envs
.env

.agents
.claude

docs/superpowers
gitxyz
41 changes: 41 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# AGENTS

Panduan ini untuk agent yang bekerja di repo ini. Tujuan utamanya adalah menjaga konsistensi arsitektur, keamanan, dan pengalaman pengembangan untuk backend Go yang menggabungkan auth serta fitur Git hosting.

## Ringkasan repo

- Bahasa: Go
- Framework HTTP: Gin
- ORM: GORM
- Database: PostgreSQL
- Konfigurasi: Viper dengan file YAML
- Auth: JWT untuk route yang dilindungi

## Struktur utama

- [main.go](main.go): entry point aplikasi
- [internal/bootstrap](internal/bootstrap): inisialisasi database dan router
- [internal/api](internal/api): controller, service, middleware, DTO, dan route
- [internal/models](internal/models): model domain dan hooks GORM
- [internal/repository](internal/repository): akses data
- [modules/githttp](modules/githttp): logika Git HTTP dan protocol terkait

## Aturan kerja penting

1. Pertahankan arsitektur yang ada: controller -> service -> repository.
2. Pisahkan route publik dan route yang membutuhkan auth.
3. Gunakan middleware auth untuk route yang dilindungi.
4. Hindari perubahan besar yang mengganggu kompatibilitas API.
5. Selalu tangani error secara eksplisit dan jangan sembunyikan error.
6. Pertahankan validasi input di DTO dan service.
7. Saat mengubah model atau skema, pikirkan dampaknya pada GORM dan migrasi.
8. Verifikasi hasil perubahan dengan go test dan, bila perlu, uji endpoint lewat curl atau HTTP client.
9. Jangan menjalankan aplikasi secara manual dengan go run. Jika pemilik proyek ingin menjalankan server, gunakan Air sesuai instruksi pemilik.
10. Jika ada kebutuhan menjalankan aplikasi untuk verifikasi, minta izin pemilik terlebih dahulu atau ikuti arahan yang sudah disepakati.

## Dokumen terkait

- [docs/agents/architecture.md](docs/agents/architecture.md)
- [docs/agents/auth-and-routing.md](docs/agents/auth-and-routing.md)
- [docs/agents/database-and-models.md](docs/agents/database-and-models.md)
- [docs/agents/testing-and-verification.md](docs/agents/testing-and-verification.md)
3 changes: 2 additions & 1 deletion config/gitxyz.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
database_url: host=localhost user=gitxyz password=gitxyz-kece-banget dbname=gitxyz port=5432 sslmode=disable TimeZone=Asia/Jakarta
volume_path: ./volumes
executable: /usr/bin/git
executable: /usr/bin/git
log_level: info
1 change: 1 addition & 0 deletions db/migrations/000001_create_users_table.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS users;
19 changes: 19 additions & 0 deletions db/migrations/000001_create_users_table.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
CREATE TABLE users (
id UUID PRIMARY KEY,
full_name VARCHAR(255) NOT NULL,
username VARCHAR(255) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT true,
avatar VARCHAR NOT NULL DEFAULT '',
bio TEXT,
location VARCHAR,
last_login_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);

CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_deleted_at ON users(deleted_at);
1 change: 1 addition & 0 deletions db/migrations/000002_create_repositories_table.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS repositories;
18 changes: 18 additions & 0 deletions db/migrations/000002_create_repositories_table.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CREATE TABLE repositories (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
physical_path VARCHAR NOT NULL,
is_private BOOLEAN NOT NULL DEFAULT false,
is_active BOOLEAN NOT NULL DEFAULT true,
user_id UUID NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE(name),
UNIQUE(physical_path)
);

CREATE INDEX idx_repositories_user_id ON repositories(user_id);
CREATE INDEX idx_repositories_deleted_at ON repositories(deleted_at);
2 changes: 2 additions & 0 deletions db/migrations/000003_create_user_credentials_table.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS personal_access_tokens;
DROP TABLE IF EXISTS ssh_keys;
34 changes: 34 additions & 0 deletions db/migrations/000003_create_user_credentials_table.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
CREATE TABLE ssh_keys (
id UUID PRIMARY KEY,
title VARCHAR(255) NOT NULL,
public_key TEXT NOT NULL,
fingerprint VARCHAR(255) NOT NULL,
user_id UUID NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE(fingerprint)
);

CREATE INDEX idx_ssh_keys_user_id ON ssh_keys(user_id);
CREATE INDEX idx_ssh_keys_deleted_at ON ssh_keys(deleted_at);

CREATE TABLE personal_access_tokens (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
token_hash VARCHAR(255) NOT NULL,
token_prefix VARCHAR(16) NOT NULL,
scopes TEXT,
last_used_at TIMESTAMP,
expires_at TIMESTAMP,
user_id UUID NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE(token_hash)
);

CREATE INDEX idx_personal_access_tokens_user_id ON personal_access_tokens(user_id);
CREATE INDEX idx_personal_access_tokens_deleted_at ON personal_access_tokens(deleted_at);
2 changes: 2 additions & 0 deletions db/migrations/000004_drop_repositories_physical_path.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE repositories ADD COLUMN physical_path VARCHAR NOT NULL DEFAULT '';
ALTER TABLE repositories ADD CONSTRAINT repositories_physical_path_key UNIQUE (physical_path);
2 changes: 2 additions & 0 deletions db/migrations/000004_drop_repositories_physical_path.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE repositories DROP CONSTRAINT IF EXISTS repositories_physical_path_key;
ALTER TABLE repositories DROP COLUMN IF EXISTS physical_path;
2 changes: 2 additions & 0 deletions db/migrations/000005_add_user_role.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE users DROP CONSTRAINT IF EXISTS chk_user_role;
ALTER TABLE users DROP COLUMN IF EXISTS role;
6 changes: 6 additions & 0 deletions db/migrations/000005_add_user_role.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ALTER TABLE users
ADD COLUMN role VARCHAR(20) NOT NULL DEFAULT 'user';

ALTER TABLE users
ADD CONSTRAINT chk_user_role
CHECK (role IN ('owner', 'admin', 'maintainer', 'user', 'guest'));
1 change: 1 addition & 0 deletions db/migrations/000006_create_repository_members.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS repository_members;
14 changes: 14 additions & 0 deletions db/migrations/000006_create_repository_members.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
CREATE TABLE repository_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
repo_id UUID NOT NULL REFERENCES repositories(id) ON DELETE CASCADE,
role VARCHAR(20) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(user_id, repo_id),
CONSTRAINT chk_repo_member_role
CHECK (role IN ('owner', 'maintainer', 'triager', 'reader', 'guest'))
);

CREATE INDEX idx_repo_members_repo_id ON repository_members(repo_id);
CREATE INDEX idx_repo_members_user_id ON repository_members(user_id);
1 change: 1 addition & 0 deletions db/migrations/000007_create_policies.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS policies;
15 changes: 15 additions & 0 deletions db/migrations/000007_create_policies.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE TABLE policies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
subject_type VARCHAR(20) NOT NULL,
subject_id VARCHAR(255) NOT NULL,
action VARCHAR(50) NOT NULL,
resource_type VARCHAR(20) NOT NULL,
resource_id VARCHAR(255) NOT NULL DEFAULT '*',
effect VARCHAR(10) NOT NULL DEFAULT 'allow',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(subject_type, subject_id, action, resource_type, resource_id),
CONSTRAINT chk_policy_effect CHECK (effect IN ('allow', 'deny'))
);

CREATE INDEX idx_policies_lookup
ON policies(subject_type, subject_id, action, resource_type, resource_id);
5 changes: 5 additions & 0 deletions db/migrations/000008_create_issues_table.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DROP TABLE IF EXISTS issue_assignees;
DROP TABLE IF EXISTS issue_comments;
DROP TABLE IF EXISTS issue_labels;
DROP TABLE IF EXISTS labels;
DROP TABLE IF EXISTS issues;
63 changes: 63 additions & 0 deletions db/migrations/000008_create_issues_table.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
CREATE TABLE issues (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
number INTEGER NOT NULL,
repo_id UUID NOT NULL REFERENCES repositories(id) ON DELETE CASCADE,
title VARCHAR(255) NOT NULL,
body TEXT,
state VARCHAR(10) NOT NULL DEFAULT 'open',
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
assignee_id UUID REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
closed_at TIMESTAMPTZ,
deleted_at TIMESTAMPTZ,
UNIQUE(repo_id, number),
CONSTRAINT chk_issue_state CHECK (state IN ('open', 'closed'))
);

CREATE INDEX idx_issues_repo_id ON issues(repo_id);
CREATE INDEX idx_issues_state ON issues(state);
CREATE INDEX idx_issues_deleted_at ON issues(deleted_at);

CREATE TABLE labels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
repo_id UUID NOT NULL REFERENCES repositories(id) ON DELETE CASCADE,
name VARCHAR(50) NOT NULL,
color VARCHAR(7) NOT NULL DEFAULT '#cccccc',
description TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ,
UNIQUE(repo_id, name)
);

CREATE INDEX idx_labels_repo_id ON labels(repo_id);
CREATE INDEX idx_labels_deleted_at ON labels(deleted_at);

CREATE TABLE issue_labels (
issue_id UUID NOT NULL REFERENCES issues(id) ON DELETE CASCADE,
label_id UUID NOT NULL REFERENCES labels(id) ON DELETE CASCADE,
PRIMARY KEY (issue_id, label_id)
);

CREATE TABLE issue_comments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
issue_id UUID NOT NULL REFERENCES issues(id) ON DELETE CASCADE,
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
body TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ
);

CREATE INDEX idx_issue_comments_issue_id ON issue_comments(issue_id);

CREATE TABLE issue_assignees (
issue_id UUID NOT NULL REFERENCES issues(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (issue_id, user_id)
);

CREATE INDEX idx_issue_assignees_issue_id ON issue_assignees(issue_id);
CREATE INDEX idx_issue_assignees_user_id ON issue_assignees(user_id);
3 changes: 3 additions & 0 deletions db/migrations/000009_add_deleted_at_to_issues.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE issues DROP COLUMN deleted_at;
ALTER TABLE labels DROP COLUMN deleted_at;
ALTER TABLE issue_comments DROP COLUMN deleted_at;
8 changes: 8 additions & 0 deletions db/migrations/000009_add_deleted_at_to_issues.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ALTER TABLE issues ADD COLUMN deleted_at TIMESTAMPTZ;
CREATE INDEX idx_issues_deleted_at ON issues(deleted_at);

ALTER TABLE labels ADD COLUMN deleted_at TIMESTAMPTZ;
CREATE INDEX idx_labels_deleted_at ON labels(deleted_at);

ALTER TABLE issue_comments ADD COLUMN deleted_at TIMESTAMPTZ;
CREATE INDEX idx_issue_comments_deleted_at ON issue_comments(deleted_at);
8 changes: 8 additions & 0 deletions db/migrations/000010_create_patches_table.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DROP TABLE IF EXISTS patch_comments;
DROP TABLE IF EXISTS patch_reviews;
DROP TABLE IF EXISTS patch_reviewers;
DROP TABLE IF EXISTS patch_files;
DROP TABLE IF EXISTS patch_commits;
DROP TABLE IF EXISTS patch_requests;

ALTER TABLE repositories DROP COLUMN IF EXISTS last_item_number;
Loading