16 Commits

Author SHA1 Message Date
ee251c8727 feat: implement audit repo and service
AuditRepo.Log resolves action_type_id/object_type_id via SQL subqueries.
AuditRepo.List supports dynamic filtering by user, action, object type/ID,
and date range with COUNT(*) OVER() for total count.
AuditService.Log reads user from context, marshals details to JSON,
and delegates to the repo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 01:19:24 +03:00
a8ec2a80cb feat: implement ACL repo and service
Add postgres ACLRepo (List/Get/Set) and ACLService with CanView/CanEdit
checks (admin bypass, public flag, creator shortcut, explicit grants)
and GetPermissions/SetPermissions for the /acl endpoints.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 01:13:21 +03:00
6c9b1bf1cd fix: wire handler layer in main.go and fix migration issues
cmd/server/main.go: replace stub router with full wiring —
  UserRepo, SessionRepo, AuthService, AuthMiddleware, AuthHandler,
  NewRouter; use postgres.NewPool instead of pgxpool.New directly.

migrations/001_init_schemas.sql: wrap uuid_v7 and uuid_extract_timestamp
  function bodies with goose StatementBegin/End so semicolons inside
  dollar-quoted strings are not treated as statement separators.

migrations/007_seed_data.sql: add seed admin user (admin/admin,
  bcrypt cost 10, is_admin=true, can_create=true) for manual testing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:54:54 +03:00
caeff6786e feat: implement auth handler, middleware, and router
domain/context.go: extend WithUser/UserFromContext with session ID

handler/response.go: respondJSON/respondError with domain→HTTP status
  mapping (404/403/401/409/400/415/500)
handler/middleware.go: Bearer JWT extraction, ParseAccessToken,
  domain.WithUser injection; aborts with 401 JSON on failure
handler/auth_handler.go: Login, Refresh, Logout, ListSessions,
  TerminateSession
handler/router.go: /health, /api/v1/auth routes; login and refresh
  are public, session routes protected by AuthMiddleware

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:43:41 +03:00
296f44b4ed feat: implement auth service with JWT and session management
Login: bcrypt credential validation, session creation, JWT pair issuance.
Logout/TerminateSession: soft-delete session (is_active = false).
Refresh: token rotation — deactivate old session, issue new pair.
ListSessions: marks IsCurrent by comparing session IDs.
ParseAccessToken: for use by auth middleware.

Claims carry uid (int16), adm (bool), sid (int). Refresh tokens are
stored as SHA-256 hashes; raw tokens never reach the database.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:38:21 +03:00
f7cf8cb914 feat: implement db helpers and postgres pool/transactor
- Add is_blocked to core.users (002_core_tables.sql)
- Add is_active to activity.sessions for soft deletes (005_activity_tables.sql)
- Implement UserRepo: List, GetByID, GetByName, Create, Update, Delete
- Implement MimeRepo: List, GetByID, GetByName
- Implement SessionRepo: Create, GetByTokenHash, ListByUser,
  UpdateLastActivity, Delete, DeleteByUserID
- Session deletes are soft (SET is_active = false); is_active is a
  SQL-only filter, not mapped to the domain type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:34:45 +03:00
1b3fc04e06 feat: implement db helpers and postgres pool/transactor
db/db.go: TxFromContext/ContextWithTx for transaction propagation,
Querier interface (QueryRow/Query/Exec), ScanRow generic helper,
ClampLimit/ClampOffset pagination guards.

db/postgres/postgres.go: NewPool with ping validation, Transactor
backed by pgxpool (BeginTx → fn → commit/rollback), connOrTx helper
that returns the active transaction from context or falls back to pool.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:15:17 +03:00
d8f6364008 feat: implement port interfaces (repository and storage)
Define all repository interfaces in port/repository.go:
FileRepo, TagRepo, TagRuleRepo, CategoryRepo, PoolRepo, UserRepo,
SessionRepo, ACLRepo, AuditRepo, MimeRepo, and Transactor.
Add OffsetParams and PoolFileListParams as shared parameter structs.

Define FileStorage interface in port/storage.go with Save, Read,
Delete, Thumbnail, and Preview methods.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:11:06 +03:00
8dd2d631e5 refactor: strengthen domain layer types and add missing page types
- DomainError struct with Code() string method replaces plain errors.New
  sentinels; errors.Is() still works via pointer equality
- UUIDCreatedAt(uuid.UUID) time.Time helper extracts timestamp from UUID v7
- Add TagOffsetPage, CategoryOffsetPage, PoolOffsetPage
- FileListParams fields grouped with comments matching openapi.yaml params
- Fix mismatched comment on UserPage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:06:44 +03:00
a9209ae3a3 feat: initialize SvelteKit frontend with Tailwind and OpenAPI types
- SvelteKit SPA mode with adapter-static (index.html fallback)
- Tailwind CSS v4 via @tailwindcss/vite with custom color palette
- CSS custom properties for dark/light theme (dark is default)
- Epilogue variable font with preload
- openapi-typescript generates src/lib/api/schema.ts from openapi.yaml
- Friendly domain type aliases in src/lib/api/types.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 00:00:26 +03:00
ba0713151c feat: config, migrations embed, and server entrypoint
- internal/config: typed Config struct loaded from env vars via godotenv;
  all fields from docs (listen addr, JWT, DB, storage, thumbs, import)
- migrations/embed.go: embed FS so goose SQL files are baked into the binary
- cmd/server/main.go: load config → connect pgxpool → goose migrations
  (embedded) → Gin server with GET /health returning 200 OK
- .env.example: documents all required and optional env vars
- go.mod: bump to Go 1.26, add gin/pgx/goose/godotenv as direct deps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:57:17 +03:00
b692fabed5 refactor: split monolithic migration into 7 goose files
001_init_schemas  — extensions, schemas, uuid_v7 functions
002_core_tables   — core.users, mime_types, object_types
003_data_tables   — data.categories, tags, tag_rules, files, file_tag, pools, file_pool
004_acl_tables    — acl.permissions
005_activity_tables — activity.action_types, sessions, file_views, pool_views, tag_uses, audit_log
006_indexes       — all indexes across all schemas
007_seed_data     — object_types and action_types reference rows

Each file has -- +goose Up / Down annotations; downs drop in reverse
dependency order.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:40:36 +03:00
830e411d92 docs: add reference Python/Flask implementation
Previous version of Tanabata used as visual and functional reference
for the new Go + SvelteKit rewrite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:36:05 +03:00
b7995b7e4a chore: add .gitignore and .gitattributes
.gitignore covers env/secrets, OS files, IDE, Go build artifacts,
frontend build output, data dirs, and vendored reference libs.
.gitattributes enforces LF line endings, marks binaries, configures
diff drivers per language, and sets Linguist hints for repo stats.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:35:22 +03:00
f043d38eb2 feat: initialize Go module and implement domain layer
- Add go.mod (module tanabata/backend, Go 1.21) with uuid dependency
- Implement internal/domain: File, Tag, TagRule, Category, Pool, PoolFile,
  User, Session, Permission, ObjectType, AuditEntry + all pagination types
- Add domain error sentinels (ErrNotFound, ErrForbidden, etc.)
- Add context helpers WithUser/UserFromContext for JWT propagation
- Fix migration: remove redundant DEFAULT on exif jsonb column

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:28:33 +03:00
780f85de59 chore: initial project structure 2026-04-01 16:17:37 +03:00