Commit Graph

137 Commits

Author SHA1 Message Date
Benjamin 84e7743429 fix(ci): use Node.js 20 for E2E tests to fix nyc compatibility
The @cypress/code-coverage package bundles nyc@15 which is incompatible
with Node.js 22+. Downgrade to Node.js 20 for E2E tests only to maintain
coverage collection while other workflows use Node.js 22.
2025-11-24 10:23:32 +01:00
Benjamin ecd47fd8ec fix(ci): set locales and templates directories for E2E tests
Add ACKIFY_LOCALES_DIR and ACKIFY_TEMPLATES_DIR environment variables
to point to backend directories when running the binary from repo root.
2025-11-24 09:47:53 +01:00
Benjamin aae9ab111a fix(build): suppress vue-i18n currentInstance warning
Add Rollup onwarn handler to filter the known MISSING_EXPORT warning
where vue-i18n accesses internal Vue APIs (currentInstance).
This is a known compatibility issue that doesn't affect runtime behavior.
2025-11-24 09:44:56 +01:00
Benjamin f842aedf11 fix(deps): eliminate deprecated npm dependencies
Use npm overrides to force modern versions:
- glob: v7.2.3 → v10.5.0
- rimraf: v3.0.2 → v5.0.10
- inflight: replaced (no longer needed with glob v10+)

This eliminates all deprecation warnings during npm install.
2025-11-24 09:41:02 +01:00
Benjamin 050351620c fix(i18n): handle literal dots in translation keys
The check-i18n script now correctly handles keys with literal dots
(e.g., 'document.created') instead of treating them as nested paths.
2025-11-24 09:33:46 +01:00
Benjamin f7a22efc3b fix(ci): create empty web/dist directory before backend tests
The go:embed directive in main.go requires web/dist to exist during compilation.
Backend tests don't need the actual frontend, just an empty directory to satisfy the embed directive.
2025-11-24 09:21:28 +01:00
Benjamin 41e18c914f test(frontend): add comprehensive unit tests for stores, services and components
Add business logic tests to improve frontend code coverage and reliability:
- Pinia stores: auth, signatures, ui (87 tests)
- Services: checksumCalculator (19 tests)
- Components: SignButton, NotificationToast (21 tests)

Focus on critical business flows: authentication, signature management,
notification system, and file validation. All tests passing (143 total).
2025-11-24 01:04:41 +01:00
Benjamin a46715a2f3 fix: robust coverage calculation in test suite script
Fix bash arithmetic syntax error when calculating coverage percentages
from LCOV files. The issue occurred when grep results contained whitespace
or when values were empty strings.
2025-11-24 00:23:56 +01:00
Benjamin a1c71a023c fix: enable Istanbul code instrumentation for E2E coverage
Fix Cypress code coverage collection by properly configuring vite-plugin-istanbul
to instrument code when CYPRESS_COVERAGE=true.
2025-11-23 23:50:19 +01:00
Benjamin a7891618c1 feat: comprehensive CI/CD refactoring with unified code coverage
Reorganize GitHub Actions workflows into reusable components and implement
complete code coverage tracking across backend, frontend, and E2E tests.

**CI/CD Improvements:**
- Split monolithic ci.yml into 6 specialized reusable workflows
- New workflows: test-backend, test-frontend, test-e2e, build-docker, security, coverage-report
- Orchestrated execution with proper dependencies and parallel jobs
- Codecov integration with multi-flag coverage (backend/frontend/e2e)

**Frontend Testing:**
- Add Vitest for unit testing with coverage-v8 provider
- Create test setup with window mocks for Ackify globals
- Add 34 unit tests for titleExtractor, referenceDetector, and http utils
- Configure Istanbul instrumentation for E2E coverage collection
- Integrate @cypress/code-coverage for E2E test coverage

**Test Infrastructure:**
- Create run-tests-suite.sh for local comprehensive test execution
- Proper Docker Compose orchestration for integration and E2E tests
- Automatic cleanup handlers with trap for test environments
- Coverage summary aggregation across all test types

**Bug Fixes:**
- Fix backend config tests after OAuth/MagicLink validation changes
- Update tests from panic expectations to error checking
- Ensure OAUTH_COOKIE_SECRET is properly configured in tests

**Configuration:**
- Add .codecov.yml for coverage reporting with flags
- Add .nycrc.json for E2E LCOV generation
- Update .gitignore for test artifacts and coverage reports
- Configure Vite for test environment and code instrumentation
2025-11-23 23:36:02 +01:00
Benjamin 5cd91654e0 feat: configurable rate limiting and comprehensive E2E test suite
Rate Limiting Configuration:
- Add ACKIFY_AUTH_MAGICLINK_RATE_LIMIT_EMAIL (default: 3/hour)
- Add ACKIFY_AUTH_MAGICLINK_RATE_LIMIT_IP (default: 10/hour)
- Add ACKIFY_AUTH_RATE_LIMIT (default: 5/min)
- Add ACKIFY_DOCUMENT_RATE_LIMIT (default: 10/min)
- Add ACKIFY_GENERAL_RATE_LIMIT (default: 100/min)

E2E Test Suite:
- 01-signature-workflow: Complete signature flow validation
- 02-signature-uniqueness: Constraint enforcement and duplicate prevention
- 03-admin-signers-management: Expected signers CRUD operations
- 04-admin-email-reminders: SMTP reminder functionality
- 05-document-creation-by-url: URL-based document initialization
- 06-my-signatures-page: User signature list and navigation
- 07-admin-document-deletion: Cascade deletion verification
- 08-admin-route-protection: Access control validation
- 09-complete-workflow: End-to-end multi-user scenario
- 10-unexpected-signatures: Handling of non-expected signers
2025-11-23 22:27:55 +01:00
Benjamin 779aada760 fix(test): fix configuration for e2e tests and improve en var loading for gracefull stop on error 2025-11-23 11:44:41 +01:00
Benjamin e885c63f92 test: remove trivial and redundant tests for better maintainability 2025-11-23 11:23:41 +01:00
Benjamin c579e95a67 feat(frontend): enable TypeScript strict mode for better type safety
Enable strict TypeScript compilation options in the Vue 3 frontend
to catch more potential bugs at compile time and improve code quality.
2025-11-23 01:06:44 +01:00
Benjamin eecb2565bc refactor(checksum): propagate context for HTTP request cancellation
Add context.Context parameter to checksum computation functions
to enable request cancellation, timeout propagation, and better
observability for remote document downloads.
2025-11-23 01:01:40 +01:00
Benjamin ddb44df7d0 refactor(crypto): propagate context.Context for observability support
Add context.Context parameter to cryptographic signature operations
to enable distributed tracing, timeout propagation, and cancellation
handling throughout the signature creation pipeline.

This is a breaking change for the cryptoSigner interface but
maintains backward compatibility at the API level.
2025-11-23 00:50:18 +01:00
Benjamin 353b720453 feat(email): add jitter to retry logic to prevent thundering herd
Improve the email retry mechanism by adding 0-30% random jitter
to the exponential backoff calculation. This prevents multiple
failed emails from retrying at exactly the same time, which could
cause load spikes on the SMTP server.

Example retry times (with jitter):
- 1st retry: 1.0-1.3 minutes
- 2nd retry: 2.0-2.6 minutes
- 3rd retry: 4.0-5.2 minutes
2025-11-23 00:43:54 +01:00
Benjamin 3811741401 feat(database): configure PostgreSQL connection pool settings
Add connection pool configuration to optimize database performance and resource usage
2025-11-23 00:37:34 +01:00
Benjamin f6c75b3497 refactor(security): use structured logger to prevent sensitive data exposure
Changes:
- Replace fmt.Println with logger.Logger.Warn in config loading
- Remove client_id and auth URLs from OAuth provider logs
- Remove user email, name, and sub from authentication logs
- Use structured logging for worker shutdown errors
- Fix MagicLink status logging (only log when actually enabled)
2025-11-23 00:36:49 +01:00
Benjamin 066374ca33 refactor(api): centralize pagination logic in shared package
Changes:
- Add PaginationParams struct for query parameter handling
- Add ParsePaginationParams() to parse and validate pagination from HTTP requests
- Add Validate() method with configurable min/max constraints
- Support both 'limit' and 'page_size' query parameters for flexibility
- Migrate documents handler (default: 20/page, max: 100)
- Migrate admin handler (default: 100/page, max: 200)
- Remove duplicated strconv imports and validation logic
2025-11-23 00:22:29 +01:00
Benjamin 0c3ba254ee feat(email): implement smart error categorization and adaptive retry strategy
Changes:
- Add EmailErrorType enum (Retryable, Permanent, RateLimited)
- Implement categorizeError() to analyze SMTP codes and error messages
  - Detect permanent errors (5xx codes, invalid emails)
  - Detect rate limiting (421/429/450 codes)
  - Detect temporary errors (4xx codes, network/DNS issues)
- Implement calculateRetryDelay() with adaptive backoff strategies
  - Retryable: 1min × 2^retry (standard exponential backoff)
  - RateLimited: 5min × 3^retry (aggressive backoff)
  - Permanent: no retry
- Add MarkAsFailedWithDelay() to repository for custom retry delays
- Maintain backward compatibility with existing MarkAsFailed()
2025-11-23 00:22:15 +01:00
Benjamin 93d9e2e575 feat(search): implement full-text document search across public and admin APIs
Backend:
- Add Search() method to DocumentRepository for ILIKE pattern matching on doc_id, title, url, description
- Add Count() method to accurately count total matching documents (used for pagination)
- Update admin handler to support search query parameter with proper pagination
- Implement full public documents API with search support (previously stub)
- Update test mocks to include new repository methods

Frontend:
- Replace client-side filtering with server-side search in admin dashboard
- Add debounced search input (300ms delay) to reduce API calls
- Separate loading states: initial page load vs. search/pagination (prevents input focus loss)
- Add visual feedback: spinning loader icon in search field during active search
- Enable pagination during search (previously disabled)
- Pass search parameter to API service
2025-11-23 00:21:59 +01:00
ArnaudFra ec947afc24 feat(mail): add ACKIFY_MAIL_INSECURE_SKIP_VERIFY option (#6)
* feat(mail): add option to skip TLS certificate verification

Add ACKIFY_MAIL_INSECURE_SKIP_VERIFY environment variable to allow
bypassing TLS certificate verification for self-signed certificates.

This is useful for development/testing environments with self-signed
SMTP certificates while maintaining secure defaults (false by default).

* docs: add ACKIFY_MAIL_INSECURE_SKIP_VERIFY documentation
2025-11-22 22:20:34 +01:00
Benjamin da1f300d2d feat(admin): improve email reminders UX and fix signer deletion
Backend changes:
- Add SMTPEnabled flag to distinguish SMTP service from MagicLink authentication
- Fix URL-encoded email decoding in DELETE /signers/{email} endpoint
- Add detailed error logging for expected signer removal operations
- Initialize ReminderAsync and MagicLink services unconditionally
- Update config tests to reflect new MagicLink requires explicit enabling

Frontend changes:
- Add ACKIFY_SMTP_ENABLED window variable for feature detection
- Hide delete button for expected signers who have already signed
- Show email reminders card only when SMTP enabled or history exists
- Display informative alert when SMTP disabled but reminder history present
- Add i18n translations for email service disabled message (5 languages)

These changes improve admin experience by preventing invalid operations
(deleting signers who signed, sending emails without SMTP) and providing
clear feedback about feature availability.
v1.2.2
2025-11-22 00:43:35 +01:00
Benjamin 34146fb02d fix(auth): enable logout for MagicLink users
- Move /logout route outside OAuth-only block to support both OAuth
and MagicLink authentication methods.

- Also fix notification icon alignment in AuthChoicePage.

- And add press-kit inside /docs
v1.2.1
2025-11-08 00:02:35 +01:00
Benjamin 5ed7127ec7 doc: update screenshot with new UI 2025-11-07 12:08:34 +01:00
Benjamin 2ec9a8b13d Fix: Increment timeouts (5s -> 15s) for CI latency 2025-11-06 19:05:27 +01:00
Benjamin aa5fee90f6 feat(admin): add option to restrict document creation to admins only
Add new configuration option ACKIFY_ONLY_ADMIN_CAN_CREATE (default: false) to control who can create documents.

Backend changes:
- Add OnlyAdminCanCreate config field to AppConfig
- Implement authorization checks in document handlers
- Protect POST /documents and GET /documents/find-or-create endpoints
- Add unit tests for admin-only document creation (4 tests)

Frontend changes:
- Inject ACKIFY_ONLY_ADMIN_CAN_CREATE to window object
- Hide DocumentForm component for non-admin users when enabled
- Add i18n translations (en, fr, es, de, it)
- Display warning message for non-admin users

Documentation:
- Update .env.example files with new variable
- Update configuration docs (en/fr)
- Update install script to prompt for restriction option
- Update install/README.md

When enabled, only users listed in ACKIFY_ADMIN_EMAILS can create new documents. Both direct creation and find-or-create endpoints are protected.
2025-11-06 16:08:03 +01:00
Benjamin a5c376bae5 fix(ci): build frontend before running go vet
Add Node.js setup and frontend build steps before Go verification
to ensure web/dist directory exists for go:embed directive.
2025-11-06 14:09:40 +01:00
Benjamin a27f051838 feat(auth): implement reminder authentication tokens
Add authentication tokens embedded in reminder emails allowing users to
authenticate and sign documents in one click.

Changes:
- Add 'purpose' (login/reminder_auth) and 'doc_id' columns to magic_link_tokens
- Implement CreateReminderAuthToken (24h validity) and VerifyReminderAuthToken
- Create reminder auth handler and route (/api/v1/auth/reminder-link/verify)
- Update ReminderService and ReminderAsyncService to generate auth tokens
- Fix table name mismatch: magic_links → magic_link_tokens throughout
- Reorder service initialization in server.go for proper dependencies

Token validity:
- Magic Link: 15 minutes (login)
- Reminder Auth: 24 hours (document signature)

The reminder auth flow:
1. Admin sends reminder
2. User receives email with auth link
3. User clicks link → auto-authenticated if not logged in
4. User redirected to document signature page
5. If already authenticated with correct account, skip auth step
2025-11-06 13:43:49 +01:00
Benjamin 46e6bdab24 feat(auth): magic link email now uses frontend language
The magic link email is now sent in the same language as the frontend
at the time of the request, matching the behavior of reminder emails.

Changes:
- Modified MagicLinkService.RequestMagicLink to accept locale parameter
- Handler extracts locale using i18n.GetLangFromRequest() from HTTP headers
- Falls back to "en" if locale is empty
- Consistent with reminder email locale detection
2025-11-06 12:04:23 +01:00
Benjamin d28283f6ed feat(webapp): complete i18n implementation and admin document input enhancement
- feat(admin): accept URLs, file paths, and IDs in document creation form
  - Modified AdminDashboard to use findOrCreateDocument service
  - Now matches user UI functionality for flexible document references

- feat(i18n): replace all hardcoded French texts with translation keys
  - Added 50+ new translation keys across admin and user interfaces
  - Updated 7 Vue components: AdminDashboard, AdminDocumentDetail,
    DocumentForm, SignButton, SignatureList, SignaturesPage, EmbedPage
  - Synchronized all new keys to 5 languages (fr, en, es, de, it)

- All templates now use vue-i18n with proper parameterized translations
- Zero hardcoded texts remaining in HTML templates
2025-11-06 11:02:14 +01:00
Benjamin cff602c812 fix(tests): update OAuth tests to use correct signature URL path
Change test URLs from '/sign?doc=' to '/?doc=' to match the correct
frontend route after the URL path correction in reminder emails.

Updated base64 encoded state in callback test:
- Old: L3NpZ24_ZG9jPXRlc3Q (decodes to /sign?doc=test)
- New: Lz9kb2M9dGVzdA (decodes to /?doc=test)
2025-11-06 01:15:45 +01:00
Benjamin 7b1f69ade6 fix(email): correct signature reminder URL path
Change signature URL in reminder emails from '/sign?doc=' to '/?doc='
to match the correct frontend route.

Updated in:
- ReminderService.sendSingleReminder
- ReminderAsyncService.queueSingleReminder
- Email helper tests
2025-11-06 01:09:44 +01:00
Benjamin 2dd7d8686c fix(email): correct SMTP TLS/STARTTLS configuration for Gmail
Backend changes:
- Use 'else if' to prevent activating both TLS and STARTTLS simultaneously
- Add StartTLSPolicy = MandatoryStartTLS for proper STARTTLS enforcement
- Add comments explaining TLS modes (implicit SSL vs explicit STARTTLS)

Install script changes:
- Auto-detect TLS configuration based on port number
- Port 465 → TLS=true, STARTTLS=false (implicit SSL)
- Port 587 → TLS=false, STARTTLS=true (explicit TLS/STARTTLS)
- Non-standard ports → manual configuration with clear prompts

This fixes timeout errors when sending emails via Gmail SMTP (port 587)
which requires STARTTLS, not direct TLS connection.
2025-11-06 00:05:16 +01:00
Benjamin d3f7aa4853 fix(install): always write auth method enabled flags to .env
- Add ACKIFY_AUTH_OAUTH_ENABLED=true when OAuth is configured
- Add ACKIFY_AUTH_OAUTH_ENABLED=false when OAuth is not configured
- Write ACKIFY_AUTH_MAGICLINK_ENABLED with true/false value explicitly
- Provides clear visibility of enabled authentication methods in .env

These variables are already passed to containers via compose files.
2025-11-05 23:48:12 +01:00
Benjamin e71528a76b fix(install): correct mail template directory path
Change ACKIFY_MAIL_TEMPLATE_DIR from 'templates/emails' to 'templates'
to match actual directory structure where templates are in /app/templates.
2025-11-05 23:44:42 +01:00
Benjamin 4269b66c18 fix: add ACKIFY_ prefix to all variables in .env.example files
Update both .env.example files to use correct variable names:

Root .env.example:
- Remove obsolete APP_NAME and APP_DNS variables
- Add ACKIFY_DB_DSN example
- Add ACKIFY_ADMIN_EMAILS section
- Remove deprecated ACKIFY_TEMPLATES_DIR

install/.env.example:
- Fix all variable names to use ACKIFY_ prefix
- Update OAuth variables (PROVIDER, CLIENT_ID, etc.)
- Update Mail/SMTP variables (HOST, PORT, USERNAME, etc.)
- Update Auth variables (AUTH_OAUTH_ENABLED, AUTH_MAGICLINK_ENABLED)
- Update Admin variables (ADMIN_EMAILS)
- Update all references in comments and instructions
2025-11-05 23:41:00 +01:00
Benjamin c13ce508c7 fix(install): add all missing env variables to compose files
Complete both compose.yml and compose-traefik.yml with missing environment
variables:

OAuth variables:
- OAUTH_SCOPES, OAUTH_GITLAB_URL, OAUTH_AUTO_LOGIN
- AUTH_OAUTH_ENABLED, AUTH_MAGICLINK_ENABLED
- Add fallback defaults (:-) for all OAuth variables

Mail/SMTP variables:
- MAIL_USERNAME, MAIL_PASSWORD, MAIL_TIMEOUT
- MAIL_SUBJECT_PREFIX, MAIL_TEMPLATE_DIR, MAIL_DEFAULT_LOCALE
- Fix MAIL_TLS and MAIL_STARTTLS to use env variables instead of hardcoded false

This ensures MagicLink authentication works properly when SMTP is configured.
2025-11-05 23:38:20 +01:00
Benjamin 4386a02a8c fix(install): generate hex password to avoid URL encoding issues
Use openssl rand -hex instead of -base64 for database password to prevent
special characters (/, +, =) from breaking the DSN URL parsing
2025-11-05 22:35:28 +01:00
Benjamin 12ef046bea fix(install): add missing env variables and fix key name
- Add ACKIFY_LOG_LEVEL=info to prevent Docker Compose warning
- Fix ACKIFY_ED25519_PRIVATE_KEY_B64 -> ACKIFY_ED25519_PRIVATE_KEY
  to match expected variable name in backend code
2025-11-05 22:25:43 +01:00
Benjamin 6efb1b6aba fix(install): improve domain extraction and password input
- Use cut with dot counting for more robust subdomain removal
  (sign.kolapsis.com -> kolapsis.com)
- Redirect password prompt newline to stderr to avoid polluting
  captured variable value
2025-11-05 22:24:39 +01:00
Benjamin 10d3406a80 fix(install): use domain instead of DNS for email addresses
Extract APP_DOMAIN from APP_DNS (removing subdomain and port) and use it
for default email addresses (noreply@domain.com, admin@domain.com) instead
of using the full DNS (noreply@subdomain.domain.com).
2025-11-05 22:16:42 +01:00
Benjamin fa85dba6e2 fix(install): add ACKIFY_ prefix to all environment variables
Corrects all environment variable names in the installation script to match
the expected configuration format. Adds missing ACKIFY_DB_DSN variable.
2025-11-05 22:11:21 +01:00
Benjamin 2209f13006 fix(e2e): wait for page reload in rate limiting test
The rate limiting test was failing in CI because after reloading the page
with cy.visitWithLocale('/auth'), it immediately tried to access form
elements without waiting for the page to be fully loaded.

In local environments this worked because it's faster, but in CI the timing
was different causing the test to fail with 'expected to find content:
Check your email but never did'.

Added explicit waits for #app and 'Sign in to Ackify' after each page
reload to ensure the page is fully loaded before continuing.
2025-11-05 21:48:46 +01:00
Benjamin 264f3d40d5 fix(e2e): copy webapp/dist to backend embed location before build
The Go binary embeds static files from backend/cmd/community/web/dist
via go:embed directive. The e2e-tests workflow was building the frontend
in webapp/dist but not copying it to the embed location before compiling,
resulting in an empty app (no Vue frontend loaded).

This commit adds the missing copy step, matching the Dockerfile build process.
2025-11-05 21:17:04 +01:00
Benjamin bba992102b fix: copy locales and templates for e2e-tests GitHub Actions workflow
The e2e-tests workflow was failing because the application couldn't find
the locales/en.json and templates files. These files are in backend/locales
and backend/templates, but the standalone binary expects them at the root.

This commit adds a step to copy these directories before starting the server.
2025-11-05 21:02:26 +01:00
Benjamin c88508897f fix: github actions tests runs 2025-11-05 20:43:13 +01:00
Benjamin b45d332c26 fix: migrations path in e2e-tests.yml workflow 2025-11-05 17:51:55 +01:00
Benjamin b867acb61d feat: improve install script + installation readme 2025-11-05 17:17:55 +01:00