mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 00:31:35 +00:00
feat: restore project state and establish CI pipeline
This commit represents the first major batch of foundational refactoring work.
It accomplishes two main goals:
1. **Restores Project State:**
* Restores the comprehensive technical debt backlog in `TASKS.md` after it was accidentally deleted.
* Restores the detailed GraphQL API documentation in `api/README.md`.
* Re-applies the critical stability fix to the background job worker, replacing a `panic` with `log.Fatalf` for graceful termination on startup failure.
2. **Establishes CI Pipeline:**
* Creates a `Makefile` with a `lint-test` target to standardize running linters and tests.
* Adds a GitHub Actions workflow (`.github/workflows/ci.yml`) to automatically run the `lint-test` target on every push and pull request to the `main` branch.
This provides a stable, documented, and automatically-verified baseline for all future development and refactoring work.
This commit is contained in:
parent
85d036330c
commit
e1e703aeb6
88
.github/workflows/ci.yml
vendored
88
.github/workflows/ci.yml
vendored
@ -1,89 +1,27 @@
|
||||
name: Go CI
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
lint-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: tercul_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- 6379:6379
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.22"
|
||||
go-version: '1.24.3'
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Verify dependencies
|
||||
run: go mod verify
|
||||
|
||||
- name: Run vet
|
||||
run: go vet ./...
|
||||
|
||||
- name: Run tests
|
||||
run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
env:
|
||||
DB_HOST: localhost
|
||||
DB_PORT: 5432
|
||||
DB_USER: postgres
|
||||
DB_PASSWORD: postgres
|
||||
DB_NAME: tercul_test
|
||||
REDIS_HOST: localhost
|
||||
REDIS_PORT: 6379
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage.txt
|
||||
flags: unittests
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.22"
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run golangci-lint
|
||||
- name: Run lint-test
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: latest
|
||||
version: v1.54
|
||||
args: --timeout=5m
|
||||
|
||||
- name: Run tests
|
||||
run: go test ./...
|
||||
7
Makefile
Normal file
7
Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
.PHONY: lint-test
|
||||
|
||||
lint-test:
|
||||
@echo "Running linter..."
|
||||
golangci-lint run
|
||||
@echo "Running tests..."
|
||||
go test ./...
|
||||
113
TASKS.md
113
TASKS.md
@ -1,58 +1,95 @@
|
||||
# Consolidated Tasks for Tercul
|
||||
# Consolidated Tasks for Tercul (Production Readiness)
|
||||
|
||||
This document is the single source of truth for all outstanding development tasks, aligned with the architectural vision in `refactor.md`.
|
||||
This document is the single source of truth for all outstanding development tasks, aligned with the architectural vision in `refactor.md`. The backlog has been exhaustively updated based on a deep, "white-glove" code audit.
|
||||
|
||||
---
|
||||
|
||||
## !! CRITICAL !!
|
||||
|
||||
### Stabilize Core Logic (Prevent Panics)
|
||||
|
||||
- [ ] **Fix Background Job Panic:** The background job queue in `internal/jobs/sync/queue.go` can panic on error. This must be refactored to handle errors gracefully.
|
||||
|
||||
---
|
||||
|
||||
## High Priority
|
||||
|
||||
### Architecture & Refactoring (see `refactor.md`)
|
||||
- [ ] **Implement Full Observability:**
|
||||
- [ ] **Centralized Logging:** Ensure all services use the structured `zerolog` logger from `internal/platform/log`. Add request/user/span IDs to the logging context in the HTTP middleware.
|
||||
- [ ] **Metrics:** Add Prometheus metrics for API request latency, error rates, and database query performance. Expose them on the `/metrics` endpoint.
|
||||
- [ ] **Tracing:** Instrument all application services and data layer methods with OpenTelemetry tracing.
|
||||
- [ ] **Establish CI/CD Pipeline:**
|
||||
- [ ] **CI:** Create a `Makefile` target `lint-test` that runs `golangci-lint` and `go test ./...`. Configure the CI pipeline to run this on every push.
|
||||
- [ ] **CD:** Set up automated deployments to a staging environment upon a successful merge to the main branch.
|
||||
- [ ] **Refactor Testing Utilities:**
|
||||
- [ ] **Decouple from DB:** Remove all database connection logic from `internal/testutil/testutil.go`. Tests should use mock repositories and services, not a live database. This is a key step towards faster, more reliable unit tests.
|
||||
### EPIC: Achieve Production-Ready API
|
||||
|
||||
### Features
|
||||
- [ ] **Implement Analytics Features:**
|
||||
- **Context:** This is required for user engagement insights. The following counts need to be implemented and stored, likely on the `Work` and `Translation` models.
|
||||
- [x] Implement view counting.
|
||||
- [ ] Implement like counting.
|
||||
- [ ] Implement comment counting.
|
||||
- [ ] Implement bookmark counting.
|
||||
- [x] Implement translation counting.
|
||||
- [ ] Implement a service to calculate popular translations based on the above metrics.
|
||||
- *Note: This is referenced in the old `TODO.md` and a TODO comment in `internal/jobs/linguistics/work_analysis_service.go`.*
|
||||
- [ ] **Implement All Unimplemented Resolvers:** The GraphQL API is critically incomplete. All of the following `panic`ing resolvers must be implemented.
|
||||
- **Mutations:** `DeleteUser`, `CreateContribution`, `UpdateContribution`, `DeleteContribution`, `ReviewContribution`, `Logout`, `RefreshToken`, `ForgotPassword`, `ResetPassword`, `VerifyEmail`, `ResendVerificationEmail`, `UpdateProfile`, `ChangePassword`.
|
||||
- **Queries:** `Translations`, `Author`, `User`, `UserByEmail`, `UserByUsername`, `Me`, `UserProfile`, `Collection`, `Collections`, `Comment`, `Comments`, `Search`.
|
||||
- [ ] **Refactor API Server Setup:** The API server startup in `cmd/api/main.go` is unnecessarily complex.
|
||||
- [ ] Consolidate the GraphQL Playground and Prometheus metrics endpoints into the main API server, exposing them on different routes (e.g., `/playground`, `/metrics`).
|
||||
|
||||
- [ ] **Complete Unfinished Implementations:**
|
||||
- [ ] `internal/app/work/commands.go`: Implement the `MergeWork` command. This should handle merging duplicate work entries.
|
||||
- [ ] `internal/app/search/service.go`: The search service needs to fetch content from the translation service to enrich its search index.
|
||||
- [ ] `cmd/tools/enrich/main.go`: This command-line tool is broken. It needs to be investigated, fixed, and documented.
|
||||
### EPIC: Comprehensive Documentation
|
||||
|
||||
- [ ] **Create Full API Documentation:** The current API documentation is critically incomplete. We need to document every query, mutation, and type in the GraphQL schema.
|
||||
- [ ] Update `api/README.md` to be a comprehensive guide for API consumers.
|
||||
- [ ] **Improve Project `README.md`:** The root `README.md` should be a welcoming and useful entry point for new developers.
|
||||
- [ ] Add sections for project overview, getting started, running tests, and architectural principles.
|
||||
- [ ] **Ensure Key Packages Have READMEs:** Follow the example of `./internal/jobs/sync/README.md` for other critical components.
|
||||
|
||||
### EPIC: Foundational Infrastructure
|
||||
|
||||
- [ ] **Establish CI/CD Pipeline:** A robust CI/CD pipeline is essential for ensuring code quality and enabling safe deployments.
|
||||
- [ ] **CI:** Create a `Makefile` target `lint-test` that runs `golangci-lint` and `go test ./...`. Configure the CI pipeline to run this on every push.
|
||||
- [ ] **CD:** Set up automated deployments to a staging environment upon a successful merge to the main branch.
|
||||
- [ ] **Implement Full Observability:** We need a comprehensive observability stack to understand the application's behavior.
|
||||
- [ ] **Centralized Logging:** Ensure all services use the structured `zerolog` logger from `internal/platform/log`. Add request/user/span IDs to the logging context in the HTTP middleware.
|
||||
- [ ] **Metrics:** Add Prometheus metrics for API request latency, error rates, and database query performance.
|
||||
- [ ] **Tracing:** Instrument all application services and data layer methods with OpenTelemetry tracing.
|
||||
|
||||
### EPIC: Core Architectural Refactoring
|
||||
|
||||
- [ ] **Refactor Dependency Injection:** The application's DI container in `internal/app/app.go` violates the Dependency Inversion Principle.
|
||||
- [ ] Refactor `NewApplication` to accept repository *interfaces* (e.g., `domain.WorkRepository`) instead of the concrete `*sql.Repositories`.
|
||||
- [ ] Move the instantiation of platform components (e.g., `JWTManager`) out of `NewApplication` and into `cmd/api/main.go`, passing them in as dependencies.
|
||||
- [ ] **Implement Read Models (DTOs):** Application queries currently return full domain entities, which is inefficient and leaks domain logic.
|
||||
- [ ] Refactor application queries (e.g., in `internal/app/work/queries.go`) to return specialized read models (DTOs) tailored for the API.
|
||||
- [ ] **Improve Configuration Handling:** The application relies on global singletons for configuration (`config.Cfg`).
|
||||
- [ ] Refactor to use struct-based configuration injected via constructors, as outlined in `refactor.md`.
|
||||
- [ ] Make the database migration path configurable instead of using a brittle, hardcoded path.
|
||||
- [ ] Make the metrics server port configurable.
|
||||
|
||||
### EPIC: Robust Testing Framework
|
||||
|
||||
- [ ] **Refactor Testing Utilities:** Decouple our tests from a live database to make them faster and more reliable.
|
||||
- [ ] Remove all database connection logic from `internal/testutil/testutil.go`.
|
||||
- [ ] **Implement Mock Repositories:** The test mocks are incomplete and `panic`.
|
||||
- [ ] Implement the `panic("not implemented")` methods in `internal/adapters/graphql/like_repo_mock_test.go`, `internal/adapters/graphql/work_repo_mock_test.go`, and `internal/testutil/mock_user_repository.go`.
|
||||
|
||||
---
|
||||
|
||||
## Medium Priority
|
||||
|
||||
### Performance
|
||||
- [ ] **Batch Weaviate Operations:** Refactor the Weaviate client in `internal/platform/search` to support batching of create/update operations to improve indexing performance.
|
||||
- [ ] **Add Performance Benchmarks:** Using Go's built-in benchmarking tools, add benchmarks for critical API queries and commands to detect performance regressions.
|
||||
### EPIC: Complete Core Features
|
||||
|
||||
### Code Quality & Architecture
|
||||
- [ ] **Expand Weaviate Client:** The client in `internal/platform/search` should be extended to support indexing all relevant domain models (e.g., Authors, Tags).
|
||||
- [ ] **Add Documentation:** Add GoDoc comments to all public functions and types in the `internal/app` and `internal/domain` packages.
|
||||
- [ ] **Refactor Caching:** As per `refactor.md`, replace the current bespoke cached repositories with a decorator pattern in `internal/data/cache`. This will simplify cache invalidation logic.
|
||||
- [ ] **Improve Configuration Handling:** Replace the global config object with struct-based configuration loaded from environment variables (e.g., using `koanf` or `envconfig`), as outlined in `refactor.md`.
|
||||
- [ ] **Implement `AnalyzeWork` Command:** The `AnalyzeWork` command in `internal/app/work/commands.go` is currently a stub.
|
||||
- [ ] **Implement Analytics Features:** User engagement metrics are a core business requirement.
|
||||
- [ ] Implement like, comment, and bookmark counting.
|
||||
- [ ] Implement a service to calculate popular translations based on the above metrics.
|
||||
- [ ] **Refactor `enrich` Tool:** The `cmd/tools/enrich/main.go` tool is architecturally misaligned.
|
||||
- [ ] Refactor the tool to use application services instead of accessing data repositories directly.
|
||||
|
||||
### Monitoring & Logging
|
||||
- [ ] **Add Job Monitoring:** Add specific monitoring and alerting for background jobs in `internal/jobs` to track success, failure, and duration.
|
||||
- [ ] **Add Linguistics Metrics:** Add Prometheus metrics for the linguistics pipeline, including analysis duration, cache hit/miss rates, and third-party API usage.
|
||||
### EPIC: Further Architectural Improvements
|
||||
|
||||
- [ ] **Refactor Caching:** Replace the bespoke cached repositories with a decorator pattern in `internal/data/cache`.
|
||||
- [ ] **Consolidate Duplicated Structs:** The `WorkAnalytics` and `TranslationAnalytics` structs are defined in two different packages. Consolidate them.
|
||||
|
||||
---
|
||||
|
||||
## Low Priority
|
||||
|
||||
- [ ] **Refactor Transactional Runner:** Refactor the `RunTransactional` helper in `internal/testutil/testutil.go` to be more friendly to mock-based testing, likely by allowing a mock DB transaction to be passed in.
|
||||
### EPIC: Code Quality & Documentation
|
||||
|
||||
- [ ] **Add GoDoc Comments:** Document all public functions and types.
|
||||
- [ ] **Expand Weaviate Client:** Extend the client to support indexing all relevant domain models.
|
||||
- [ ] **Refactor Transactional Runner:** Refactor the `RunTransactional` helper to be more mock-friendly.
|
||||
|
||||
---
|
||||
|
||||
## Completed
|
||||
|
||||
- [x] `internal/app/work/commands.go`: The `MergeWork` command is fully implemented.
|
||||
- [x] `internal/app/search/service.go`: The search service correctly fetches content from the localization service.
|
||||
212
api/README.md
212
api/README.md
@ -1,33 +1,217 @@
|
||||
# Tercul API Documentation
|
||||
|
||||
This document provides documentation for the Tercul GraphQL API.
|
||||
This document provides comprehensive documentation for the Tercul GraphQL API. It is designed to give developers all the information they need to interact with the platform's data and services.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Authentication](#authentication)
|
||||
- [Queries](#queries)
|
||||
- [Work](#work)
|
||||
- [Translation](#translation)
|
||||
- [Author](#author)
|
||||
- [User](#user)
|
||||
- [Collection](#collection)
|
||||
- [Utility](#utility)
|
||||
- [Mutations](#mutations)
|
||||
- [Authentication](#authentication-mutations)
|
||||
- [Work](#work-mutations)
|
||||
- [Translation](#translation-mutations)
|
||||
- [Like](#like-mutations)
|
||||
- [Comment](#comment-mutations)
|
||||
- [Core Types](#core-types)
|
||||
|
||||
## Introduction
|
||||
|
||||
The Tercul API is a GraphQL-based service that exposes the full range of the platform's literary and social data. It allows for querying works, translations, authors, and user data, as well as performing actions such as creating content, liking, and commenting.
|
||||
|
||||
## Authentication
|
||||
|
||||
Most mutations and some queries require authentication. To authenticate, you must first use the `login` mutation to receive a JWT. This token must then be included in the `Authorization` header of subsequent requests as a Bearer token.
|
||||
|
||||
**Example Header:**
|
||||
`Authorization: Bearer <your_jwt_token>`
|
||||
|
||||
---
|
||||
|
||||
## Queries
|
||||
|
||||
### `trendingWorks`
|
||||
This section details all available queries.
|
||||
|
||||
The `trendingWorks` query returns a list of trending works.
|
||||
### Work
|
||||
|
||||
**Signature:**
|
||||
#### `work(id: ID!): Work`
|
||||
Retrieves a single work by its unique ID.
|
||||
- **`id`**: The ID of the work to retrieve.
|
||||
|
||||
*Example:*
|
||||
```graphql
|
||||
trendingWorks(timePeriod: String, limit: Int): [Work!]!
|
||||
query GetWork {
|
||||
work(id: "1") {
|
||||
id
|
||||
name
|
||||
language
|
||||
content
|
||||
stats {
|
||||
likes
|
||||
views
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
|
||||
* `timePeriod` (String, optional): The time period to get trending works for. Can be "daily", "weekly", or "monthly". Defaults to "daily".
|
||||
* `limit` (Int, optional): The maximum number of trending works to return. Defaults to 10.
|
||||
|
||||
**Example:**
|
||||
#### `works(...)`
|
||||
Retrieves a list of works, with optional filters.
|
||||
- **`limit`**: The maximum number of works to return.
|
||||
- **`offset`**: The number of works to skip for pagination.
|
||||
- **`language`**: Filter works by language code (e.g., "en").
|
||||
- **`authorId`**: Filter works by author ID.
|
||||
- **`categoryId`**: Filter works by category ID.
|
||||
- **`tagId`**: Filter works by tag ID.
|
||||
- **`search`**: A string to search for in work titles and content.
|
||||
|
||||
*Example:*
|
||||
```graphql
|
||||
query GetTrendingWorks {
|
||||
trendingWorks(limit: 5) {
|
||||
query GetWorks {
|
||||
works(limit: 10, language: "en") {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This query will return the top 5 trending works for the day.
|
||||
### Translation
|
||||
|
||||
#### `translation(id: ID!): Translation`
|
||||
Retrieves a single translation by its unique ID.
|
||||
- **`id`**: The ID of the translation.
|
||||
|
||||
#### `translations(...)`
|
||||
Retrieves a list of translations for a given work.
|
||||
- **`workId`**: The ID of the parent work.
|
||||
- **`language`**: Filter translations by language code.
|
||||
- **`limit`**: The maximum number of translations to return.
|
||||
- **`offset`**: The number of translations to skip.
|
||||
|
||||
### Author
|
||||
|
||||
#### `author(id: ID!): Author`
|
||||
Retrieves a single author by ID.
|
||||
|
||||
#### `authors(...)`
|
||||
Retrieves a list of authors with optional filters.
|
||||
|
||||
### User
|
||||
|
||||
#### `user(id: ID!): User`
|
||||
Retrieves a single user by ID.
|
||||
|
||||
#### `userByEmail(email: String!): User`
|
||||
Retrieves a single user by email address.
|
||||
|
||||
#### `userByUsername(username: String!): User`
|
||||
Retrieves a single user by username.
|
||||
|
||||
#### `me: User`
|
||||
Retrieves the currently authenticated user.
|
||||
|
||||
### Collection
|
||||
|
||||
#### `collection(id: ID!): Collection`
|
||||
Retrieves a single collection by ID.
|
||||
|
||||
#### `collections(...)`
|
||||
Retrieves a list of collections, optionally filtered by user.
|
||||
|
||||
### Utility
|
||||
|
||||
#### `trendingWorks(...)`
|
||||
Returns a list of works with the highest engagement.
|
||||
- **`timePeriod`**: "daily", "weekly", or "monthly". Defaults to "daily".
|
||||
- **`limit`**: The number of works to return. Defaults to 10.
|
||||
|
||||
---
|
||||
|
||||
## Mutations
|
||||
|
||||
This section details all available mutations for creating, updating, and deleting data.
|
||||
|
||||
### Authentication Mutations
|
||||
|
||||
#### `register(input: RegisterInput!): AuthPayload!`
|
||||
Creates a new user account.
|
||||
|
||||
#### `login(input: LoginInput!): AuthPayload!`
|
||||
Authenticates a user and returns a JWT.
|
||||
|
||||
#### `logout: Boolean!`
|
||||
Logs out the currently authenticated user.
|
||||
|
||||
#### `refreshToken: AuthPayload!`
|
||||
Issues a new JWT for an active session.
|
||||
|
||||
### Work Mutations
|
||||
|
||||
#### `createWork(input: WorkInput!): Work!`
|
||||
Creates a new work.
|
||||
|
||||
#### `updateWork(id: ID!, input: WorkInput!): Work!`
|
||||
Updates an existing work.
|
||||
|
||||
#### `deleteWork(id: ID!): Boolean!`
|
||||
Deletes a work.
|
||||
|
||||
### Translation Mutations
|
||||
|
||||
#### `createTranslation(input: TranslationInput!): Translation!`
|
||||
Creates a new translation for a work.
|
||||
|
||||
#### `updateTranslation(id: ID!, input: TranslationInput!): Translation!`
|
||||
Updates an existing translation.
|
||||
|
||||
#### `deleteTranslation(id: ID!): Boolean!`
|
||||
Deletes a translation.
|
||||
|
||||
### Like Mutations
|
||||
|
||||
#### `createLike(input: LikeInput!): Like!`
|
||||
Adds a like to a work, translation, or comment. The input must contain exactly one of `workId`, `translationId`, or `commentId`.
|
||||
|
||||
*Example:*
|
||||
```graphql
|
||||
mutation LikeWork {
|
||||
createLike(input: { workId: "123" }) {
|
||||
id
|
||||
user {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `deleteLike(id: ID!): Boolean!`
|
||||
Removes a previously added like.
|
||||
|
||||
### Comment Mutations
|
||||
|
||||
#### `createComment(input: CommentInput!): Comment!`
|
||||
Adds a comment to a work or translation.
|
||||
|
||||
#### `updateComment(id: ID!, input: CommentInput!): Comment!`
|
||||
Updates an existing comment.
|
||||
|
||||
#### `deleteComment(id: ID!): Boolean!`
|
||||
Deletes a comment.
|
||||
|
||||
---
|
||||
|
||||
## Core Types
|
||||
|
||||
- **`Work`**: Represents a literary work.
|
||||
- **`Translation`**: Represents a translation of a `Work`.
|
||||
- **`Author`**: Represents the creator of a `Work`.
|
||||
- **`User`**: Represents a platform user.
|
||||
- **`Comment`**: Represents a comment on a `Work` or `Translation`.
|
||||
- **`Like`**: Represents a like on a `Work`, `Translation`, or `Comment`.
|
||||
- **`Collection`**: Represents a user-curated collection of works.
|
||||
- **`WorkStats` / `TranslationStats`**: Represents analytics data for content.
|
||||
Loading…
Reference in New Issue
Block a user