Skip to content

Repository files navigation

Synclet

Synclet is an AI-assisted Django/Vue reference application for exploring contact synchronization, typed APIs, validation, testing, and delivery workflows. Its deliberately small reference use case manages private contact lists and synchronizes contacts from CSV files. The feature is real enough to demonstrate architecture, authentication, validation, transactions, generated API types, UI states, automated tests, containers, and CI without pretending to be a complete SaaS product.

Product tour

Synclet dashboard with contact and synchronization summary

Searchable and paginated contact list
Contact management — Search, edit, and delete contacts in an isolated workspace.
Form for creating a contact
Validated forms — Create and update contacts with clear field constraints.
CSV import workflow with status tracking
CSV import — Track file selection, atomic processing, and row-level results.
Synchronization history with counters and row details
Sync history — Inspect outcomes, counters, duplicate handling, and errors.

What works

  • Email/password registration, session login, logout, and current-user lookup with CSRF protection.
  • User-isolated contact CRUD, search, ordering, and pagination.
  • Atomic CSV import with file limits, row validation, deterministic duplicate handling, upserts, and persisted synchronization results.
  • Dashboard, contact management, import results, and synchronization history in a responsive Vue UI.
  • OpenAPI/Swagger documentation and generated TypeScript types used by one central API client.
  • Ruff, pytest, Biome, TypeScript/Vue typechecks, Vitest, Playwright, Docker healthchecks, and CI.
  • Correlated JSON request logs and Prometheus-compatible HTTP/synchronization metrics.

Architecture

Synclet uses a modular Django monolith and a Vue single-page application. PostgreSQL is the only stateful infrastructure dependency. Synchronous CSV processing is isolated behind a SyncProvider interface so a background job or external provider can be added without changing contact ownership rules.

flowchart LR
    Browser[Vue SPA] -->|same-origin session + CSRF| API[Django REST API]
    API --> Accounts[Accounts]
    API --> Contacts[Contacts]
    API --> Sync[Sync orchestration]
    Sync --> CSV[CSV provider]
    Accounts --> DB[(PostgreSQL)]
    Contacts --> DB
    Sync --> DB
    API --> Schema[OpenAPI schema]
    Schema --> Types[Generated TypeScript types]
    Types --> Client[Typed API client]
    Client --> Browser
Loading

See Architecture, API, Security, and ADR 0001 for the detailed decisions.

Repository layout

apps/
  api/                    Django project and domain logic
  web/                    Vue 3/Vite single-page application
packages/
  api-client/             Typed, framework-independent browser API client
  api-contract/           Committed OpenAPI schema and generated TypeScript types
  config-biome/           Shared Biome configuration
  config-typescript/      Shared strict TypeScript configurations
  shared/                 Framework-independent constants
  ui/                     Reusable project-specific Vue components
docs/
  adr/                    Architecture decision records
.github/workflows/ci.yml  Continuous integration

Domain logic intentionally remains in apps/api; packages contain only genuinely reusable code.

Prerequisites and setup

Install mise and Docker with the Compose plugin. mise installs the pinned Node.js, pnpm, Python, uv, and Task versions; no globally installed project packages are required.

mise install
pnpm install
task setup
task docker:up
task db:migrate
task dev

Copy .env.example to .env before changing local defaults. Never reuse its development values in production. The web application runs at http://localhost:5173, Django at http://localhost:8000, Swagger at http://localhost:8000/api/docs/, and PostgreSQL at port 5432.

task dev starts Django and Vite together. Vite proxies /api to Django so cookies and CSRF behave like the production same-origin topology.

To run the complete containerized stack instead:

task docker:full

The web application is then available on http://localhost:8080. The full Compose profile applies migrations before starting Gunicorn. The default task docker:up starts only PostgreSQL to avoid conflicting with native development servers.

Developer commands

Command Purpose
task setup Install locked dependencies and regenerate the API contract
task dev Run Django and Vite concurrently
task dev:api / task dev:web Run one development server
task test Run pytest and all workspace unit tests
task test:api / task test:web Run one unit-test suite
task test:e2e Migrate and run Playwright against the real local stack
task lint Run Ruff and Biome without rewriting files
task format Apply Ruff and Biome formatting/fixes
task typecheck Run Django checks and all TypeScript/Vue typechecks
task build Run Django deployment checks and all production builds
task api:openapi Regenerate and validate openapi.yaml
task api:sync Regenerate OpenAPI and TypeScript API types
task api:lock Refresh apps/api/uv.lock
task api:shell Open the Django shell
task api:manage -- <command> Run an arbitrary Django management command
task db:migrate Apply migrations
task db:reset Confirm, delete the named local DB volume, recreate, and migrate
task docker:up / task docker:down Start or stop local infrastructure
task docker:full Build and run the containerized full stack

API contract

Django serializers and views are the source of truth. drf-spectacular writes packages/api-contract/openapi.yaml; openapi-typescript generates packages/api-contract/src/schema.d.ts. Applications must import API types from the contract or client package rather than redefine them.

After any backend API change, run:

task api:sync

CI repeats generation and fails if committed contract files drift. See API documentation.

Testing strategy

  • pytest uses PostgreSQL and covers auth/CSRF, isolation, CRUD, search, pagination, CSV validation, duplicates, upserts, rollback behavior, synchronization states, dashboard isolation, and errors.
  • Vitest covers the API client's CSRF/multipart/error behavior and frontend auth/error state.
  • Playwright registers a real user, creates a contact, imports CSV, and verifies synchronization history through live Django and Vite servers.
  • CI additionally checks migrations, OpenAPI drift, production builds, and both Dockerfiles.

Run the normal quality gate with:

task lint
task typecheck
task test
task build

Security summary

The repository contains no real secrets. Production fails fast without DJANGO_SECRET_KEY. Session cookies are HTTP-only, unsafe requests require a CSRF token, CORS/CSRF origins are explicit, user ownership is applied at both queryset and import-service boundaries, uploads are limited and validated, and API errors hide internal exceptions. Production should terminate TLS before Django and set secure-cookie/redirect/HSTS values appropriately. Read Security before deployment.

Deliberate simplifications and limitations

  • CSV import is synchronous and capped at 5 MiB/10,000 rows; there is no Celery or Redis.
  • CSV is the only provider. Google Contacts, Microsoft Graph, and CRM integrations are interfaces, not fake implementations.
  • There is no email verification, password reset, rate limiter, audit log, organization model, or multi-factor authentication.
  • Registration immediately creates a session. Accounts are single-user workspaces.
  • Deployment manifests, managed secret stores, observability storage, backup automation, and zero-downtime migration orchestration are environment-specific and intentionally excluded.
  • TypeScript 5.9.3 is pinned because openapi-typescript 7.13 declares TypeScript 5 compatibility; upgrading to TypeScript 7 waits for upstream support.

Sensible next steps

  1. Add password reset/email verification and request throttling.
  2. Move large imports to a durable queue while preserving SyncProvider semantics.
  3. Add encrypted provider credentials and an OAuth lifecycle for one real provider.
  4. Add organization membership and role-based permissions if the product becomes collaborative.
  5. Add tracing, Prometheus alert rules/dashboards, backup/restore drills, deployment manifests, and dependency scanning for the chosen hosting platform.

About

AI-assisted Django/Vue reference application for exploring contact synchronization, typed APIs, validation, testing, and delivery workflows.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages