- Backend: Python com Flask
- Banco de Dados: PostgreSQL
- Acesso a dados: SQL puro via SQLAlchemy Core (sem ORM) — veja Arquitetura da Camada de Persistência
- Frontend: Jinja2, HTMX, CSS
GroupUp/
├── app/
│ ├── __init__.py # Cria e configura o Flask app (db, blueprints)
│ ├── database.py # Instância do SQLAlchemy e helpers de query raw
│ ├── queries/ # Queries SQL reutilizáveis
│ ├── static/ # Arquivos estáticos
│ │ └── css/
│ │ ├── style.css
│ │ ├── chat.css
│ │ ├── groups.css
│ │ └── resources.css
│ └── templates/ # Templates Jinja2
│ ├── base.html
│ ├── auth/ # login.html, register.html, restricted.html
│ ├── chat/ # group_chat.html, direct_messages.html
│ ├── groups/ # my_groups.html, edit_group.html, create_group_modal.html
│ ├── main/ # index.html (feed), explore.html
│ │ └── partials/ # Fragmentos HTMX
│ ├── members/ # group_members_admin.html, group_members_user.html
│ ├── profile/ # my_profile.html, edit_profile.html, connection_profile.html
│ └── resources/ # group_resources.html, modais
│
├── sql/
│ └── schema.sql # Schema do banco de dados
│
├── routes.py # Blueprints e rotas da aplicação
├── config.py # Classe Config (DATABASE_URL, SECRET_KEY, pool)
├── run.py # Ponto de entrada: python run.py
├── requirements.txt
└── .env # Variáveis de ambiente (não versionado)
A camada de persistência é a parte do código responsável por gravar e ler dados de um
armazenamento permanente (o PostgreSQL). Ela fica isolada em app/queries/ e
app/database.py: nenhuma rota em routes.py e nenhum template Jinja2 monta SQL
diretamente — eles sempre passam por essa camada.
flowchart TD
GUI["🖥️ Interface Gráfica (GUI)<br/>Templates Jinja2 + HTMX<br/>app/templates/**/*.html"]
APP["⚙️ Aplicação / Controle<br/>Rotas e Blueprints do Flask<br/>routes.py"]
PERSIST[["💾 Camada de Persistência<br/>SQL puro<br/>app/queries/*.py + app/database.py"]]
DB[("🗄️ Banco de Dados<br/>PostgreSQL<br/>sql/schema.sql")]
GUI -- "requisição HTTP" --> APP
APP -- "HTML renderizado" --> GUI
APP -- "chamada de função Python" --> PERSIST
PERSIST -- "dict / list prontos" --> APP
PERSIST -- "SQL via SQLAlchemy Core" --> DB
DB -- "linhas (rows)" --> PERSIST
| Camada | Responsabilidade | Onde está |
|---|---|---|
| Interface Gráfica | HTML renderizado no servidor (Jinja2); HTMX troca fragmentos sem recarregar a página inteira | app/templates/**/*.html |
| Aplicação / Controle | Recebe a requisição HTTP, valida sessão, decide o que fazer e escolhe o template de resposta | routes.py (main_bp, auth_bp, groups_bp, members_bp, resources_bp, chat_bp) |
| Persistência | Única parte que escreve SQL; expõe funções por assunto que a camada de aplicação chama | app/queries/{grupos,auth,chat,conexoes,publicacoes,academico}.py + app/database.py (execute, execute_one, execute_write, execute_returning) |
| Banco de Dados | Armazenamento definitivo: tabelas, views e triggers (ex.: recálculo de qtdCurtidas a cada curtida) |
sql/schema.sql (PostgreSQL) |
Essa separação permite trocar como os dados são armazenados/consultados sem tocar nas rotas ou nos templates, e mantém a interface gráfica sempre a um passo de distância do banco — ela só recebe dados já prontos (dicts/listas), nunca uma linha de SQL.
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activatepip install -r requirements.txtCrie um arquivo .env na raiz do projeto:
DATABASE_URL=postgresql://usuario:senha@localhost:5432/DB
SECRET_KEY=sua-chave-secretapsql -U usuario -f sql/schema.sqlpython run.pyOu via Flask CLI:
flask --app app run --debug